feat: Schema-Validierung fuer Bundle implementieren (Story 1.4)

- schema/validator.md (Revision 2): deterministische, agent-unabhaengige
  Validator-Instruktion; bildet die abschliessende 14-Punkte-Invaliditaetsliste
  (Vertrag §7) 1:1 ab und legt die 8 Deferred-Work-Entscheidungen fest
  (EC-1 Existenzpruefung, EC-3 Kalender-Validitaet, BH-14 ISO-8601-Normalform,
  F2 Listen-Normalisierung, BH-8/F18 stale_after-Warnung, EC-11 non-md,
  F17 log.md-Feingranularitaet). Verdikt-Format SUCCESS/FAIL mit textueller
  Fehlerursache (NFR-4); keine eigene Invaliditaetsklasse (D-3, Q-6, AD-17h).
- wiki/log.md: Zertifizierungs-Protokolleintrag (PASS gegen Referenz-Fixtures).
- spec-1-4: done + Suggested Review Order; deferred-work.md: Eintrag Story 2.3
  (genau-eine-Linkform fuer Punkt 11).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Michael Tamse
2026-08-15 06:39:57 +02:00
co-authored by Claude
parent 33d21cb0ad
commit c5f97c3666
4 changed files with 447 additions and 0 deletions
@@ -61,3 +61,7 @@ Noch nicht adressierte, aber real erkannte Arbeit — gesammelt aus Reviews. Ein
- source_spec: `_bmad-output/implementation-artifacts/spec-1-3-okf-schema-vertrag-schema-wiki-compiler-md-autorisieren.md` - source_spec: `_bmad-output/implementation-artifacts/spec-1-3-okf-schema-vertrag-schema-wiki-compiler-md-autorisieren.md`
summary: Semantische Konsequenz von `stale_after` im Verhältnis zur Validität klären („veraltet" ist kein struktureller Validierungsfehler). summary: Semantische Konsequenz von `stale_after` im Verhältnis zur Validität klären („veraltet" ist kein struktureller Validierungsfehler).
evidence: Edge-Case-Review (F18, Loop 2): §7 zählt die Konsequenz nicht auf; ein vergangenes `stale_after` ist gültiges YAML, aber „veraltet". Lifecycle-Semantik — Story 1.4/Epic 3. evidence: Edge-Case-Review (F18, Loop 2): §7 zählt die Konsequenz nicht auf; ein vergangenes `stale_after` ist gültiges YAML, aber „veraltet". Lifecycle-Semantik — Story 1.4/Epic 3.
- source_spec: `_bmad-output/implementation-artifacts/spec-1-4-schema-validierung-für-bundle-implementieren.md`
summary: Genau-eine-erlaubte-Linkform für den Punkt-11-Index-Check festlegen (mit vs. ohne `.md`-Endung) — Story 2.3.
evidence: Step-04-Review (Story 1.4, Loop 1): Der Validator-Punkt-11-Check akzeptiert beide Linkformen (relativer Bundle-Pfad mit oder ohne `.md`-Endung), weil die genau-eine-Form-Regel (A0-9/AD-7b) erst Story 2.3 definiert. Der Determinsmus-Anspruch des Validators bleibt gewahrt (beide Formen zählen als verlinkt); eine Endungs-Festlegung würde die abschließende §7-Liste erweitern und gehört in Story 2.3.
@@ -0,0 +1,176 @@
---
title: 'Schema-Validierung für Bundle implementieren (Story 1.4)'
type: 'feature'
created: '2026-08-15'
status: 'done'
baseline_commit: 33d21cb0ad390a921c817342b4c21f11f3694516
review_loop_iteration: 0
context:
- _bmad-output/implementation-artifacts/epic-1-context.md
---
<frozen-after-approval reason="human-owned intent — do not modify unless human renegotiates">
## Intent
**Problem:** Der autorisierte Schema-Vertrag (§7) definiert eine abschließende 14-Punkte-Liste struktureller Invalidität und verweist mehrere Prüf-Verhalten (Existenzprüfung `raw/`-Resource, Kalender-Validität, ISO-8601-Normalform, Listen-Normalisierung) an Story 1.4 — aber es existiert noch keine ausführbare, deterministische Validierung. Ohne sie könnte ein Producer vor der Mutation nicht nachweisen, dass sein Bundle gültig ist, und ein OKF-invalides Bundle würde einen Run nicht zuverlässig scheitern lassen (F-2/AD-1b, A0-2, FR-9).
**Approach:** Eine agent-unabhängige, deterministische Validator-Instruktion `schema/validator.md` erstellen, die die abschließende 14-Punkte-Invaliditätsliste (Vertrag §7) 1:1 als mechanische Prüfschritte abbildet, die von Deferred-Work an Story 1.4 verwiesenen Validator-Entscheidungen (ISO-8601-Normalform, Kalender-Validität, Existenzprüfung, Listen-/Absenz-Normalisierung, non-md-Konvention, `stale_after`-Warning) deterministisch festlegt und ein maschinenlesbares PASS/FAIL-Verdikt mit textueller Fehlerursache ausgibt — ohne LLM-Urteil und ohne Standalone-Anwendung (D-3, Q-6: Agent-Instruktions-Validator, mechanisch zu bestätigen).
## Boundaries & Constraints
**Always:**
- `schema/validator.md` ist der einzige Ort der Validierungs-Instruktion; er ist rein textuell (kein ausführbarer Code) und agent-unabhängig, liegt außerhalb des Bundles neben dem Vertrag (AD-1, D-3, Q-6).
- Die Validierung bildet die **abschließende** 14-Punkte-Liste (Vertrag §7) 1:1 ab; sie darf keinen Eintrag hinzufügen oder streichen (Vertrag §7 „abschließende Liste"). Erweiterungen nur über das Story-/Autorisierungs-Verfahren.
- Fehlende optionale Felder (kein `sources`/`generated`/`verified`/`status`/`stale_after`) sind niemals invalide (A0-2/AD-1b); `sources: []`/`verified: []` sind zulässig und gleichbedeutend mit Absenz.
- Die Validierung ist deterministisch und ohne LLM-Urteil aufrufbar (AD-13/AD-17h); sie erzeugt pro geprüfter Datei ein PASS/FAIL-Verdikt mit textuell identifizierbarer Fehlerursache (NFR-4).
- Prüfumfang (Vertrag §1): ausschließlich Markdown innerhalb `wiki/` (Bundleroot, Area-`index.md`, Concepts, `log.md`) plus die `raw/`-Ziellinien aus `sources`-`resource`. `raw/`, `schema/`, `adapters/` selbst werden nicht als Bundle validiert.
- Existenzprüfung: ein `sources`-`resource` unter `raw/` MUSS zum Validierungszeitpunkt als Datei existieren (fachliche Validierung, Deferred-Work EC-1).
- Kalender-Validität: Datumsfelder müssen reale Kalenderdaten sein (`2026-02-31` ist invalide); der Veraltungsvergleich `today >= stale_after` erfolgt in UTC (Vertrag §7).
- Valid-Pfad-Auflösung (Vertrag §3.3): `resource` ist ein `/`-getrennter relativer Pfad zur Workspace-Root, darf kein `..`-Segment, keinen führenden `/`, kein `file://` und keine Backslash-/Windows-Trenner enthalten und muss bei Auflösung innerhalb `raw/` landen.
- Dateien unter `wiki/`, die keine `.md`-Dateien sind (z. B. `wiki/<area>/logo.png`), werden als nicht-Bundle-Elemente behandelt und nicht validiert (Deferred-Work EC-11).
- Dokument in Deutsch; das Verdikt-Format ist maschinenlesbar (ein SUCCESS/FAIL-Verb per Datei, gefolgt von textueller Begründung).
**Ask First:**
- Eine bewusste Verschärfung gegenüber dem Vertrag (z. B. Absicht, `resource`-Existenz als strukturell statt fachlich zu werten) — nur mit menschlicher Zustimmung, da sie die Abschluss-Position von §7 berührt.
- Die Einführung eines Standalone-Skripts/-Programms (Python/TS/etc.) als eigentliche Validator-Implementierung — der Epic-Context (D-3, Q-6) widerspricht dem; ein späterer Wechsel auf eine konkrete Anwendung ist separat zu autopisieren.
**Never:**
- Kein eigenes Schema neben `schema/wiki-compiler.md`; keine Änderung am autorisierten Vertrag (Story 1.3) und keine Änderung an `raw/` (immutable, AD-3).
- Kein Standalone-/Executable-Anwendungs-Code, der die Validierung ersetzt (D-3); die Validierungs-Regel bleibt eine Instruktion, kein Programm.
- Keine neue Invaliditätsklasse oder neue Pflichtfelder außerhalb des Vertrags; keine Validierung der Inhalte von `raw/`-, `schema/`- oder `adapters/`-Dateien als Bundle.
- Kein LLM-Urteil in der Prüfung; der Validator ist kein Modell-Aufruf, sondern eine mechanisch befolgte Anweisung.
- Keine Validierung schreibender Art: der Validator mutiert nichts, protokolliert aber (siehe Verification) ein Ausführungs-Protokoll.
</frozen-after-approval>
## Code Map
- `schema/validator.md`**Zieldatei** (neu): deterministische Validator-Instruktion; bildet Vertrag §7 ab und legt die von Deferred-Work an Story 1.4 verwiesenen Entscheidungen fest.
- `schema/wiki-compiler.md` — normative Grundlage (read-only, Story 1.3-Ergebnis): §1 Geltungsbereich, §2 Bundleroot/Frontmatter, §3 Feldsubset (inkl. §3.3 `sources`/`resource`-Auflösung, §3.4 `generated`, §3.5 `verified`, §3.6 `status`, §3.7 `stale_after`), §5 `log.md`-Typ, §6 Index-Regel/Prädikate, §7 abschließende 14-Punkte-Liste, §8 Normreferenzen.
- `wiki/index.md` — Referenz Bundleroot (read-only): `type: bundle` + `okf_version: "0.2"`, Frontmatter exklusiv; POSITIV-Beispiel für Prüfschritt 8/9.
- `wiki/log.md` — Referenz leerer `log.md`: Kein Frontmatter, reservierte Root-Datei; in dieser Story wird ausschließlich der Zertifizierungs-Ausführungs-Protokolleintrag angehängt (keine inhaltliche Bundle-Änderung, Vertrag §5-konform).
- `adapters/claude/README.md`, `adapters/README.md` — Referenz für den Adapter-/Agenten-Kontext (read-only); der Validator ist von Adaptern unabhängig (AD-10).
- `_bmad-output/implementation-artifacts/deferred-work.md`**Pflicht-Input**: die 8 an Story 1.4 verwiesenen Validator-Entscheidungen (EC-1, EC-3, BH-14, F2-Listen, BH-8, EC-11, F17-`log.md`, F18-`stale_after`) — werden in der Instruktion deterministisch festgelegt.
- `_bmad-output/implementation-artifacts/epic-1-context.md` — primärer Planungskontext (read-only).
## Tasks & Acceptance
**Execution:**
- [x] `schema/validator.md` — Validator-Instruktion anlegen: Zweck & Aufruf (Agent/Prozess führt die Schritte deterministisch aus), Prüfumfang nach Vertrag §1, die 14 Invaliditäts-Punkte 1:1 als mechanische Prüfschritte (inkl. Welcher YAML-/Text-Check je Punkt, welches Artefakt), die fachlichen Zusatzprüfungen (Existenzprüfung `raw/`-Resource, Kalender-/Datum-Validität in UTC, `stale_after`-Veraltungs-Warning als Warnung, non-md-Dateien ignoriert), die Normalisierungs-/Toleranz-Vorgaben (Map→1-Element-Liste bei `verified`, leere Listen = Absenz, semantische Gleichwertigkeit), das maschinenlesbare Verdikt-Format (SUCCESS / FAIL + Datei + Ursache), und die Selbstbegrenzung (abschließende Liste, keine Erweiterung) — F-2/AD-1b, A0-2, FR-9, NFR-4.
- [x] `schema/validator.md` — die 8 Deferred-Work-Entscheidungen deterministisch festlegen (EC-1 Existenzprüfung, EC-3 Kalender-Validität, BH-14 ISO-8601-Normalform, F2-Listen-Normalisierung, BH-8/F18 `stale_after`-semantische Warnung statt Invalidität, EC-11 non-md-Konvention, F17 `log.md`-Feingranularität: leeres Log gültig) — abgeleitet aus dem Vertrag und dem Epic-Context.
- [x] `schema/validator.md` — Negativ-/Positiv-Fixtures als Referenztabellen dokumentieren: je Invaliditäts-Punkt ein konkretes Fehlerbeispiel (Input → erwartetes FAIL mit Ursache) und je Punkt das gültige Gegenstück (PASS) — belegt die 1:1-Abbildung und macht die mechanische Bedingung reproduzierbar prüfbar (AD-17h).
- [x] `schema/validator.md` — Verdikt-Format & Selbstbegrenzung normieren: SUCCESS/FAIL-Report-Struktur, keine Validierung von `raw/`/`schema/`/`adapters/`-Inhalten als Bundle, keine neuen Invaliditätsklassen; textuelle Fehlerursache (NFR-4).
- [x] `wiki/log.md` — Ausführungs-Protokoll der Validator-Zertifizierung anhängen: Datum, Validator-Revision, Ergebnis der Selbstprüfung gegen die Referenz-Fixtures (PASS/FAIL) — dokumentiert die mechanische Bestätigung (Q-6: „confirmed mechanical"), keine inhaltliche Änderung des Bundles.
- [x] `_bmad-output/implementation-artifacts/sprint-status.yaml` — Story 1.4 von `backlog` auf `in-progress` setzen (nach Start der Implementierung).
**Acceptance Criteria:**
- Given ein Bundle mit struktureller OKF-Invalidität (z. B. fehlender `type`), when die Validierung ausgeführt wird, then schlägt der Run fehl (FAIL) mit textuell identifizierbarer Ursache — kein erfolgreicher Run (F-2/AD-1b).
- Given ein Bundle mit fehlenden optionalen Feldern (kein `sources`/`verified`), when die Validierung ausgeführt wird, then gilt es als gültig (PASS) — fehlende optionale Felder sind keine Invalidität (A0-2/AD-1b).
- Given ein invalides Bundle, when der Run fehlschlägt, then bleibt `raw/` unverändert und die Fehlerursache ist im Verdikt textuell identifizierbar (AD-3, NFR-4).
- Given die Validierung, when ausgeführt, then ist sie eine eigenständige, deterministische Prüfung ohne LLM-Urteil — als Instruktion mechanisch befolgbar (AD-13/AD-17h-konform), nicht Standalone-Code (D-3).
- Given ein `sources`-`resource`, when es auf einen `wiki/`-Concept-Pfad oder außerhalb `raw/` zeigt (nicht-existente Datei, `..`-Traversal), then ist das Bundle FAIL (Provenienz-Ziellinie, §3.3) bzw. fachliche Invalidität (Existenzprüfung).
- Given die abschließende Invaliditätsliste (§7), when die Instruktion fertig ist, then bildet sie alle 14 Punkte 1:1 ab und führt keine eigene Invaliditätsklasse ein.
- Given ein `stale_after` in der Vergangenheit, when validiert wird, then ist es kein struktureller Fehler; eine Warnung dokumentiert die Veraltung (F18/BH-8, ohne Invalidität).
- Given `verified` als einzelne Map, when validiert wird, then wird es als 1-Element-Liste gelesen und nicht abgelehnt (Vertrag §3.5).
- Given eine nicht-`.md`-Datei unter `wiki/`, when validiert wird, then wird sie ignoriert (nicht Bundle-Element) (EC-11).
## Spec Change Log
- **2026-08-15, Loop 1 (Step-04-Review: Blind-Hunter + Edge-Case-Hunter + Verification-Gap):** Kein `bad_spec`/`intent_gap` — alle Befunde sind als `patch` direkt in `schema/validator.md` lösbar oder `defer`. Amendments (non-frozen; Code Map + Tasks + Design Notes + Spec Change Log):
- **Bundleroot-/Reserviert-Pflichten dokumentieren:** Code Map/Aufruf weisen auf die neuen Bundleroot- und Reserviert-Namen-Voraussetzungen (fehlende `wiki/index.md`; `log.md` an Nicht-Root-Position) als strukturelle Norm-Pflichten des Validators hin — keine neue §7-Invaliditätsklasse, sondern Voraussetzungs-Checks (BH-7/EC-2/EC-4).
- **ISO-8601-Maß relativiert:** Die Normalform akzeptiert beide Offset-Formen (`±HHMM` und `±HH:MM`, beide gültiges ISO-8601/RFC 3339); nur Nicht-ISO-8601-Formen sind Punkt-14-FAIL (BH-2). Vertrag §7 Punkt 14 bleibt unangetastet („abschließende Liste" nicht verschärft).
- **F15 + Story 2.3 als Deferred/Normreferenz:** `generated.by: human:<id>`-Trust-Semantik wird an Epic 4 verschoben (Deferred-Work F15); der Punkt-11-Link-Check verengt die Linkform nicht (genau-eine-Form bleibt Story 2.3) — als Normreferenz dokumentiert, nicht als Validator-Entscheidung (BH-6, EC-7).
- **KEEP (muss bei Re-Derivation überleben):** die 14-Punkte-1:1-Abbildung als tabellarische mechanische Prüfschritte mit deterministischer Fehlerursache; die 8 Deferred-Work-Entscheidungen (EC-1, EC-3, BH-14, F2, BH-8, EC-11, F17, F18); Verdikt-Format SUCCESS/FAIL mit textueller Ursache (NFR-4); Abbruch-Regel (erste verletzte Bedingung); Selbstbegrenzung (abschließende Liste, keine eigene Invaliditätsklasse, kein Schreibzugriff); Positiv-/Negativ-Fixtures als Referenztabellen (AD-17h).
## Design Notes
Die Story 1.4 ist das erste ausführbare Artefakt des Projekts: Die Validierung ist keine Standalone-Anwendung (D-3 verbietet Python/TS/etc.), sondern eine deterministische Instruktion, die ein Agent/Prozess mechanisch befolgt (Q-6, AD-17h) und die vor Erzeugung der ersten Concepts (Epic 2) stehen muss.
Die Validierung wird damit in zwei Ebenen modelliert:
```text
Behauptung (Normativ): schema/wiki-compiler.md (§7: abschließende 14-Punkte-Liste)
Ableitung (Story 1.4): schema/validator.md (Prüfschritte je Punkt + Verdikt-Format)
Ausführung: deterministisch von einem Agent/Prozess befolgt (kein LLM-Urteil)
```
Wichtige Normalform-Entscheidungen (aus Deferred-Work):
- `verified` als Map → 1-Element-Liste (Vertrag §3.5); `sources: []`/`verified: []` = Absenz (semantisch identisch) — die Ausgabe-/Diff-Basis nutzt eine feste Reihenfolge.
- ISO-8601-Normalform für `at` (Vertrag §3.4/3.5): akzeptiert `YYYY-MM-DDTHH:MM:SS` mit den Offset-Suffixen `Z`, `±HHMM` und `±HH:MM` (alle gültiges ISO-8601/RFC 3339); ein reiner Datumswert wird als `T00:00:00Z` normalisiert — nicht „Abweichung vom Format"; Punkt-14-FAIL sind nur Nicht-ISO-8601-Formen (Loop-1-Amendment BH-2).
- Datumsfelder müssen reale Kalenderdaten sein (EC-3); Veraltungsvergleich `today >= stale_after` in UTC (Vertrag §7).
- Existenzprüfung fachlich (EC-1): ein `resource` unter `raw/`, das nicht existiert, ist fachlich invalide → FAIL, wird aber nicht als §7-Punkt gezählt (der Validator protokolliert den Punkt separat).
- `stale_after` in der Vergangenheit: Warnung, kein struktureller Fehler (F18/BH-8).
- Nicht-`.md`-Dateien unter `wiki/` werden ignoriert (EC-11) — keine Ablehnung, keine Konvention-Erfindung über den Vertrag hinaus.
## Verification
**Commands:**
- `git status --short && git diff --stat` — expected: neue Datei `schema/validator.md` + `wiki/log.md`-Protokolleintrag + `sprint-status.yaml`-Wired-Up (Story 1.4 in-progress, epic-1 in-progress); keine `raw/`-Mutationen.
- Manuelle Abbildungsprüfung: `grep -nE 'Punkt 1[0-4]|Invalid' schema/validator.md` — expected: alle 14 Punkte adressiert; `grep -n 'abschließend' schema/validator.md` — expected: Selbstbegrenzung vorhanden.
- Konformitäts-Smoke an den Referenzfixtures: `grep -nE '\bFAIL\b|\bSUCCESS\b' schema/validator.md` — expected: je Punkt mindestens ein Beispiel mit klar bezeichneter Erwartung.
- Verdikt-Format: `grep -nE '\b(SUCCESS|FAIL)\b' schema/validator.md` — expected: ein Verdikt-Verb pro Datei-Syntax dokumentiert.
**Manual checks (if no CLI):**
- `schema/validator.md` ist rein textuell (kein Programmcode/Executable-Abschnitt) und beginnt mit Zweck & Aufruf.
- Alle 14 Punkte aus Vertrag §7 sind als eigene Prüfschritte vorhanden; keine darüber hinausgehende Invaliditätsklasse.
- Die 8 Deferred-Work-Direktiven sind deterministisch beantwortet und in der Instruktion auffindbar.
- `wiki/log.md` enthält (nach Zertifizierung) einen datierten Eintrag „Validator-Selbstprüfung gegen Fixtures: PASS".
- **2026-08-15, Loop 2 (Review: Blind-Hunter + Edge-Case-Hunter + Verification-Gap, kein bad_spec):** Die drei Review-Layer fanden keinen norm-beherrschenden Defekt — kein neuer Loopback. Alle Befunde waren als `patch` direkt in `schema/validator.md` lösbar (17 Patches, Revision 1→2): §3.2 Bundleroot-/Reserviert-Voraussetzungen als Nicht-§7-Pflichten, Punkt 6/9-Exemption, Punkt 9 auf Dateiinhalt, Punkt 10 BOM-Stripping, Punkt 11 deterministische Link-Prüfung (ohne Story-2.3-Vorwegnahme), Punkt 12 fehlende/leere `resource`, Punkt 14 `usage_count`-Integer-Typ, §4.3 akzeptiert `±HH:MM`, §4.4-Ausführungs-Reihenfolge mit EC-1-Aggregation, §5-WARN als Berichtskanal, §6.2 Punkt-4-vor-3-Priorität, Fixture-Ergänzungen. Drei Befunde als Deferred/Normreferenz dokumentiert (F15→Epic 4; genau-eine-Linkform→Story 2.3 mit `deferred-work.md`-Eintrag; `stale_after`-Konsequenz→Epic 3, bereits BH-8-adressiert). Abschluss: `schema/validator.md` (Revision 2) final; all 14 Punkte 1:1 abgebildet, no eigene Invaliditätsklasse.
- **KEEP (muss bei Re-Derivation überleben):** die 14-Punkte-1:1-Abbildung als mechanische Prüfschritte mit deterministischer Fehlerursache; die 8 Deferred-Work-Entscheidungen (EC-1, EC-3, BH-14, F2, BH-8, EC-11, F17, F18); Verdikt-Format SUCCESS/FAIL mit textueller Ursache (NFR-4); Abbruch-Regel (erste verletzte Bedingung); Selbstbegrenzung (abschließende Liste, keine eigene Invaliditätsklasse, kein Schreibzugriff); Positiv-/Negativ-Fixtures (AD-17h); §3.2-Voraussetzungsprüfungen ausdrücklich als Nicht-§7-Pflichten.
## Suggested Review Order
**Einstiegspunkt: Validator-Instruktion**
- Einstieg — Zweck, Aufruf-Ablauf und Ableitung vom Vertrag ¶7; höchste Hebelwirkung für das Gesamtdesign
[`validator.md:8`](../../schema/validator.md#L8)
**Normative 1:1-Abbildung (abschließende Liste §7→§3)**
- Die 14 Punkte als tabellarische mechanische Prüfschritte; Kernfrage des Reviews: keine Erweiterung/kein Streichen
[`validator.md:48`](../../schema/validator.md#L48)
- Erweiterungs-/Abschluss-Regel plus Punkt-6/9-Exemption (kein Punkt-6-vor-9-Feuer)
[`validator.md:71`](../../schema/validator.md#L71)
- Bundleroot-/Reserviert-Voraussetzungen — ausdrücklich keine neue ¶7-Klasse
[`validator.md:77`](../../schema/validator.md#L77)
**Deterministische Normalform & Toleranz**
- Listen-vs.-Absenz, fehlende optionale Felder, feste Key-Reihenfolge (F2)
[`validator.md:85`](../../schema/validator.md#L85)
- ISO-8601-Normalform inkl. `±HH:MM`-Akzeptanz (keine unautorisierte Verschärfung); Kalender-Validität
[`validator.md:100`](../../schema/validator.md#L100)
- Deterministische Rangfolge & Abbruch-Regel (erste verletzte Bedingung), EC-1-Aggregation
[`validator.md:109`](../../schema/validator.md#L109)
- `log.md`-Feingranularität (leeres Log gültig), Verdikt-Format inkl. WARN als Berichtskanal
[`validator.md:122`](../../schema/validator.md#L122)
**Fachliche Zusatzprüfungen (Deferred-Work)**
- EC-1-Existenz als Datei, EC-3-Kalender, EC-4-`stale_after`-Warnung, EC-11-non-md; Pfad-Auflösung mit Punkt-4-vor-3-Priorität
[`validator.md:149`](../../schema/validator.md#L149)
**Referenz-Fixtures & Selbstbegrenzung**
- Negativ-/Positiv-Fixtures incl. Isolations-Notiz; per AD-17h reproduzierbar prüfbar
[`validator.md:188`](../../schema/validator.md#L188)
- Normreferenzen inkl. F15/Story-2.3-Defer, Revisionslog
[`validator.md:245`](../../schema/validator.md#L245)
**Protokollierung & Status**
- Zertifizierungs-Eintrag im Bundle-Log (Vertrag §5-konform; PASS gegen Fixtures)
[`log.md:3`](../../wiki/log.md#L3)
- Story 1.4 auf `review` gesetzt (separierte `/review`-Pfad-Transition)
[`sprint-status.yaml:42`](../../_bmad-output/implementation-artifacts/sprint-status.yaml#L42)
+263
View File
@@ -0,0 +1,263 @@
# Validator-Instruktion — OKF-Schema-Validierung für das Knowledge Bundle (Story 1.4)
> **Status:** abgeleitet (Story 1.4) — deterministische, agent-unabhängige Validierungs-Instruktion auf Basis des autorisierten Schema-Vertrags.
> **Normative Grundlage:** `schema/wiki-compiler.md` (autorisiert, Story 1.3) — insbesondere §1 Geltungsbereich, §2 Bundleroot/Frontmatter, §3 Feldsubset (§3.3–§3.7), §5 `log.md`-Typdefinition, §6 Index-Regel/Prädikate, §7 abschließende 14-Punkte-Liste struktureller Invalidität, §8 Normreferenzen.
> **Validator-Revision:** 2 (Revisionslog in §8)
> **Ableitungsdatum:** 2026-08-15
## 0. Zweck & Aufruf
Diese Datei ist **der einzige Ort der Validierungs-Instruktion** des Projekts. Sie ist **rein textuell** — kein ausführbarer Code, kein Standalone-Programm (D-3). Sie wird von einem Agent/Prozess **mechanisch, deterministisch und ohne LLM-Urteil** befolgt (AD-13, AD-17h, Q-6). Sie bildet die **abschließende** 14-Punkte-Invaliditätsliste des Vertrags (§7) 1:1 als mechanische Prüfschritte ab und legt die von Deferred-Work an Story 1.4 verwiesenen Validator-Entscheidungen deterministisch fest.
**Aufruf:** Vor jeder Mutation des Bundles führt der Producer/Validator den Run in der folgenden festen Ablaufstruktur aus (deterministische Reihenfolge, §4.4): (1) Prüfumfang bestimmen (§1), (2) Dateien klassifizieren (§2), (3) Voraussetzungen prüfen (§3.2), (4) je Datei die 14 Punkte in Reihenfolge prüfen (§3, Abbruch bei erstem FAIL, §4.4), (5) nach PASS der 14 Punkte die fachlichen Zusatzprüfungen ausführen (§6), (6) Verdikt je Datei ausgeben (§5). Das Ergebnis je geprüfter Datei ist ein maschinenlesbares Verdikt (SUCCESS/FAIL, §5). Bei mindestens einem FAIL gilt der gesamte Run als gescheitert; das Bundle wird nicht mutiert und `raw/` bleibt unangetastet (AD-3, NFR-4).
**Entscheidungsebenen (kein LLM-Urteil):**
```text
Behauptung (Normativ): schema/wiki-compiler.md (§7: abschließende 14-Punkte-Liste)
Ableitung (Story 1.4): schema/validator.md (Prüfschritte je Punkt + Verdikt-Format)
Ausführung: deterministisch von einem Agent/Prozess befolgt (kein LLM-Urteil)
```
## 1. Prüfumfang (Vertrag §1)
1. Erfasst werden ausschließlich **Markdown-Dateien** (`.md`) innerhalb der Bundleroot `wiki/`:
- die Bundleroot `wiki/index.md`,
- Area-`index.md`-Dateien (jede `index.md` unterhalb eines Area-Verzeichnisses),
- Concept-Dateien (alle übrigen `.md`-Dateien unter `wiki/`),
- `wiki/log.md` (reserviertes Protokoll).
2. Zusätzlich werden die **`raw/`-Ziellinien** geprüft, auf die `sources`-`resource`-Einträge von Concepts verweisen (Pfad-Ziellinie: §3 Punkt 3/4; Existenzprüfung: §6.1).
3. **Nicht validiert** werden als Bundle:
- `raw/`, `schema/`, `adapters/` (außerhalb des Bundles, keine Concept-Dateien; Vertrag §1),
- der **Inhalt** von Dateien unter `raw/`, `schema/` oder `adapters/` — kein fachlicher oder struktureller Check auf diese Dateien als Bundle-Elemente (nur die `raw/`-Ziellinien-Existenz aus Punkt 2).
- Nicht-`.md`-Dateien unter `wiki/` (z. B. `wiki/<area>/logo.png`) — sie sind **keine Bundle-Elemente** und werden ignoriert, weder abgelehnt noch validiert (EC-11). Deterministische Abgrenzung: Prüfumfang ist jede Datei unter `wiki/`, deren Dateiendung exakt `.md` ist (case-sensitive kleingeschrieben).
## 2. Klassifikation der `.md`-Dateien unter `wiki/`
Bevor die Prüfschritte laufen, wird jede erfasste `.md`-Datei deterministisch klassifiziert:
| Rolle | Bedingung | Frontmatter-Status |
|-------|-----------|--------------------|
| Bundleroot | `wiki/index.md` | **ausschließlich** `type: bundle` + `okf_version: "0.2"` |
| Area-`index.md` | eine `index.md` tiefer als `wiki/` (in einem Area-Verzeichnis) | **kein** Frontmatter |
| `log.md` | `wiki/log.md` (reservierter Root-Name) | **kein** Frontmatter |
| Concept | jede übrige `.md`-Datei unter `wiki/` (nicht `index.md`, nicht `log.md`) | muss `type` enthalten (§3/§6.1) |
Reservierte Namen: ausschließlich `index.md` und `log.md` (Vertrag §2, §5, §6). Jede andere `.md`-Datei im Bundle ist ein Concept und unterliegt dem Concept-Prädikat; eine solche Datei ohne Frontmatter bzw. ohne `type` ist **nicht** „kein Concept", sondern strukturell invalide (Vertrag §3.1, §7 Punkt 2).
## 3. Die 14 strukturellen Invaliditäts-Punkte (Vertrag §7) als mechanische Prüfschritte
Die folgende Liste bildet die **abschließende** 14-Punkte-Invaliditätsliste des Vertrags (§7) 1:1 ab. Sie fügt **keinen** Eintrag hinzu und streicht **keinen** Eintrag. Jeder Punkt nennt das betroffene Artefakt, den konkreten YAML-/Text-Check und die deterministisch identifizierbare Fehlerursache (NFR-4). Ein Punkt ist verletzt, sobald die angegebene Bedingung auf mindestens eine erfasste Datei zutrifft → Verdikt FAIL (§5).
Wert-Semantik des YAML-Checks: Frontmatter ist als YAML zu parsen. Wiederholte Frontmatter-Keys (YAML-Duplikat-Keys) sind beim Parsen zu **zählen** (Punkt 13); die YAML-Spezifikation lässt sie mehrdeutig zu, der Vertrag erklärt sie zu struktureller Invalidität. Nicht als YAML parsbares Frontmatter ist ein FAIL — dieser Fall ist bereits über die Prüfschritt-Spalte von Punkt 2 abgedeckt („nicht als YAML parsbar"), ein separater Check ist nicht nötig.
| # | Invaliditäts-Punkt (§7) | Artefakt | Mechanischer Check | Fehlerursache im Verdikt |
|---|--------------------------|----------|--------------------|--------------------------|
| 1 | Concept ohne `type` oder mit leerem `type` | Concept-Frontmatter | Ist `type` nicht vorhanden ODER kein non-empty String (leerer String, nur Whitespace, oder `type: null` / Zahl / Datumsobjekt)? | `Punkt 1: concept ohne type oder leerer type (NULL|leer|nicht-String)` |
| 2 | nicht-reservierte `.md`-Datei im Bundle ohne Frontmatter bzw. ohne `type` | jede nicht-`index.md`/nicht-`log.md` `.md`-Datei unter `wiki/` | Fehlt der Frontmatter-Block `---` ODER ist das Frontmatter nicht als YAML parsbar ODER fehlt `type` (bzw. ist leer)? | `Punkt 2: nicht-reservierte .md-Datei ohne Frontmatter/ohne type` |
| 3 | `sources`-`resource` löst auf einen `wiki/`-Concept-Pfad auf | Concept-Frontmatter, je `sources[].resource` | Löst der (bereinigte, §6.2) Pfad relativ zur Workspace-Root auf einen Pfad auf, der **innerhalb** `wiki/` liegt? | `Punkt 3: resource loest auf wiki/-Concept-Pfad (Pfad=<resource>)` |
| 4 | `sources`-`resource` landet bei Auflösung außerhalb `raw/` (inkl. `..`-Traversal) oder ist URL-Form; zudem Verstöße der Pfad-Grammatik | Concept-Frontmatter, je `sources[].resource` | Enthält der `resource`-Wert `..`-Path-Segment, führenden `/`, `file://`-Präfix, Backslash/Windows-Trenner, oder einen absoluten/URL-Form-Wert (`http://`, `https://`, etc.) ODER liegt der aufgelöste Pfad außerhalb `raw/`? | `Punkt 4: resource ausserhalb raw/ oder unzulaessiger Pfad (..-Traversal|absolut|URL|Backslash|file://)` |
| 5 | verbotener `status`-Wert | Concept-Frontmatter | Ist `status` gesetzt und **nicht** ∈ {`draft`, `stable`, `deprecated`}? | `Punkt 5: verbotener status-Wert (Wert=<status>)` |
| 6 | nicht autorisiertes Frontmatter-Feld oder unautorisierter Key in `sources`/`generated`/`verified`-Eintrag | Concept- & Bundleroot-Frontmatter | Enthält das Frontmatter ein Feld außerhalb des erlaubten Subsets (Concept: `type`/`sources`/`generated`/`verified`/`status`/`stale_after`; Bundleroot: `type`+`okf_version`)? ODER enthält ein `sources`-Eintrag Keys außerhalb {`resource`,`id`,`title`,`author`,`usage_count`,`last_modified`}; ein `generated` Keys außerhalb {`by`,`at`}; ein `verified`-Eintrag Keys außerhalb {`by`,`at`}? **Exemption:** `okf_version` und `type: bundle` sind von der Punkt-6-Subset-Prüfung ausgenommen und werden ausschließlich über Punkt 8/9 geprüft (Entscheidungsnotiz unter dieser Tabelle). | `Punkt 6: nicht autorisiertes Feld (Key=<key>) bzw. unautorisierter Key in sources/generated/verified` |
| 7 | leere/fehlende `by`-Angabe in `generated` oder `verified` | Concept-Frontmatter | Ist `generated.by` nicht gesetzt ODER leer ODER reiner Whitespace? Gleiches je `verified[].by`? | `Punkt 7: leere/fehlende by-Angabe in generated/verified` |
| 8 | Bundleroot `wiki/index.md` ohne `type: bundle`/`okf_version: "0.2"` oder abweichender `okf_version`-Wert | Bundleroot `wiki/index.md` | Fehlt `type: bundle` (exakt dieser Wert) ODER fehlt `okf_version: "0.2"` (nur der Stringliteral `0.2` zulässig, z. B. NIE `0.3`)? | `Punkt 8: Bundleroot ohne type: bundle/okf_version \"0.2\" oder falscher okf_version-Wert` |
| 9 | `okf_version: "0.2"` oder `type: bundle` außerhalb der Bundleroot | jede `.md`-Datei außer `wiki/index.md` im Bundle (Area-`index.md`, `log.md`, Concepts) | Kommt `okf_version: "0.2"` (§2-Wert) oder `type: bundle` **irgendwo im Dateiinhalt** einer dieser Dateien vor (nicht nur im Frontmatter)? Maßgeblich ist der Vertragswortlaut „darf … in irgendeiner anderen Bundle-Datei vorkommen" (§2/§7 Punkt 9). — Entscheidungsnotiz zu Punkt 6/9 siehe unter dieser Tabelle. | `Punkt 9: okf_version/type: bundle ausserhalb der Bundleroot (Datei=<pfad>)` |
| 10 | Frontmatter in einer Area-`index.md` oder `log.md` | Area-`index.md`, `wiki/log.md` | Beginnt die Datei (nach dem Strippen eines eventuellen UTF-8-BOM `U+FEFF` am Dateianfang sowie etwaiger führender Leerzeilen) mit einem YAML-Frontmatter-Block `---`? Ein BOM bzw. führende Leerzeilen vor dem Frontmatter ändern den Status nicht — der Check läuft auf dem gestrippten Anfang (sonst würde ein Frontmatter der Erkennung entkommen). | `Punkt 10: Frontmatter in Area-index.md/log.md (Datei=<pfad>)` |
| 11 | Verletzung der Index-Regel | `wiki/`-Struktur | Hat ein Area-Verzeichnis (jedes Verzeichnis unter `wiki/` mit Inhalt) keine `index.md`? ODER ist ein Concept nicht in der `index.md` seines nächsten Vorfahren verlinkt — ein Concept ist verlinkt, wenn seine Identität (relativer OKF-Dateipfad ohne `.md`) in der `index.md` des nächsten Vorfahren (Area-`index.md`; für Root-Concepts die Bundleroot `wiki/index.md`) als relativer Bundle-Pfad referenziert ist, **mit oder ohne `.md`-Endung** (eine genau-eine-Form-Festlegung ist Story 2.3 und wird hier nicht vorgegeben). „Neues Concept" ist deterministisch: jede im Bundle vorhandene Concept-Datei, deren Identität in ihrer zuständigen `index.md` fehlt — der Validator prüft den Zustand, nicht ein Git-Diff. | `Punkt 11: Index-Regel verletzt (Area ohne index.md=<area> | Concept nicht verlinkt=<concept>)` |
| 12 | `sources`/`verified` in nicht erlaubter Form; `generated` in Listen- statt Map-Form; `sources`-Eintrag ohne Pflichtangabe `resource` | Concept-Frontmatter | Ist `sources` gesetzt und **nicht** YAML-Liste? Ist ein `sources`-Eintrag keine Map (z. B. Skalar)? Ist ein `sources`-Eintrag eine Map **ohne** `resource` oder mit leerem `resource` (Vertrag §3.3: `resource` ist die einzige Pflichtangabe je Eintrag)? Ist `verified` gesetzt und **weder** Liste **noch** eine einzelne Map? Ist ein `verified`-Eintrag keine Map? Ist `generated` gesetzt und **nicht** eine Map (insbesondere Liste)? | `Punkt 12: sources/verified/generated in nicht erlaubter Form` |
| 13 | doppelter Frontmatter-Key | jede Datei mit Frontmatter (Concept, Bundleroot) | Kommt derselbe Key auf oberster Frontmatter-Ebene mehrfach vor (z. B. doppeltes `type`, doppeltes `okf_version`, doppeltes `sources`)? | `Punkt 13: doppelter Frontmatter-Key (Key=<key>)` |
| 14 | fehlerhafte Wert-Formate | Concept-Frontmatter | `stale_after`/`last_modified``YYYY-MM-DD` (exakt 10 Zeichen, korrekte Struktur + reale Kalenderdaten, §6.3)? `at` (in `generated`/`verified`) ≠ ISO-8601-Datetime (Normalform, §4.3; Kalender-Validität §6.3)? `usage_count` kein **YAML-Integer** (Ganzzahl-Typ, nicht Zahl allgemein — `usage_count: 3.0` als Float ist ein FAIL) und keine Ganzzahl ≥ 0? `type` kein nicht-leerer String (siehe auch Punkt 1)? | `Punkt 14: fehlerhaftes Wert-Format (Feld=<feld>, Wert=<wert>)` |
### 3.1 Erweiterungs-/Abschluss-Regel
Diese 14 Punkte sind **abschließend** (Vertrag §7 „abschließende Liste"). Die Instruktion führt **keine eigene Invaliditätsklasse** ein. Nicht in der Liste genannte Auffälligkeiten sind entweder (a) zulässig und semantisch gleichbedeutend mit Absenz (fehlende optionale Felder, leere Listen, §4.1), (b) Warnungen ohne Invalidität (`stale_after`-Veraltung, §6.4; Existenzprüfung als separat protokollierte fachliche Prüfung, §6.1) oder (c) keine Bundle-Elemente (nicht-`.md`-Dateien, §1). Jede beabsichtigte Erweiterung der Invaliditätsdefinition erfordert die Autorisierung bzw. das Story-Verfahren — sie darf von keinem Producer oder Validator stillschweigend vorgenommen werden.
**Entscheidungsnotiz zu Punkt 6/9:** `okf_version` und `type: bundle` sind als Bundle-Root-Felder (§2) von der Punkt-6-Subset-Prüfung ausgenommen; ihr Vorkommen wird ausschließlich über Punkt 8 (Bundleroot-Bedingungen) und Punkt 9 (Verbot außerhalb der Bundleroot) geprüft. Damit feuert niemals Punkt 6 vor Punkt 9 — das Punkt-9-Fixture bleibt deterministisch (kein Vorab-FAIL durch die Subset-Prüfung).
### 3.2 Bundleroot- und Reserviert-Namen-Voraussetzungen (Vertrag §2/§5)
Diese Voraussetzungen sind strukturelle Norm-Pflichten, die der Validator **vor** den 14 Einzel-Punkten prüft. Sie sind ausdrücklich **keine neue §7-Invaliditätsklasse**: Sie bedingen die Anwendbarkeit der 14 Punkte (Fehlen der Bundleroot macht Punkt 8 gegenstandslos; ein `log.md` an falscher Position ist eine Reserviert-Namen-Verletzung nach §5) und sind als Voraussetzungsprüfungen dokumentiert.
- Existiert `wiki/index.md` nicht, ist der Run strukturell FAIL (Vorausbedingung zu Punkt 8): `FAIL (Struktur) Bundleroot fehlt: wiki/index.md existiert nicht (Vertrag §2, Vorausbedingung zu Punkt 8)`.
- Existiert eine Datei `log.md` an einer anderen Stelle als der Bundleroot (z. B. `wiki/<area>/log.md`), ist sie strukturell invalide (reservierter Name, nur Bundleroot; Vertrag §5): `FAIL <pfad> log.md an unzulässiger Position (reservierter Name, nur Bundleroot, Vertrag §5)`.
- Diese Voraussetzungsprüfungen laufen in der Ausführungsreihenfolge bei Schritt (3) — nach der Klassifikation (§2), vor den 14 Punkten je Datei (§3, Schritt (4); vgl. §4.4).
## 4. Normalisierung & Toleranz (deterministische Festlegungen)
Diese Abschnitte legen die von Deferred-Work an Story 1.4 verwiesenen Entscheidungen fest. Sie wirken **vor** den 14 Prüfschritten und sind Teil der deterministischen Ausführung (kein Interpretationsspielraum).
### 4.1 Listen- vs. Absenz-Normalisierung (F2)
- `sources: []` und `verified: []` sind zulässig und **semantisch gleichbedeutend mit Absenz** (Vertrag §3.2, §3.3, §3.5). Sie sind niemals invalide.
- Fehlende optionale Felder (`sources`/`generated`/`verified`/`status`/`stale_after` nicht vorhanden) sind niemals invalide (A0-2/AD-1b).
- Für die Ausgabe-/Diff-Basis gilt eine **feste Reihenfolge** (deterministische Normalform): Frontmatter-Keys werden in der Reihenfolge `type`, `sources`, `generated`, `verified`, `status`, `stale_after` betrachtet; innerhalb von `sources`/`verified`-Listen bleibt die dokumentierte Reihenfolge erhalten.
### 4.2 `verified`-Singleton-Coercing (Vertrag §3.5)
- Eine einzelne Map `verified: { by: ..., at: ... }` **MUSS als 1-Element-Liste** gelesen werden und wird **nicht abgelehnt** (Vertrag §3.5). Prüfschritt 12 berücksichtigt diese Toleranz: Die Map-Form eines einzelnen `verified`-Eintrags ist gültig.
- `generated` kennt diese Toleranz **nicht**: `generated` ist, falls gesetzt, ausschließlich als Map zulässig; eine Liste ist strukturell invalide (Punkt 12; Vertrag §3.4).
### 4.3 ISO-8601-Normalform für `at` (BH-14, Vertrag §3.4/§3.5)
Für `at` (in `generated`/`verified`) gilt die folgende ISO-8601-Normalform (deterministisch, ohne LLM-Urteil):
- Akzeptiert: `YYYY-MM-DDTHH:MM:SS` mit einer der Offset-Formen `Z` (UTC), `±HHMM` (4-stellig ohne Doppelpunkt) **oder** `±HH:MM` (mit Doppelpunkt). Beide Offset-Formen sind gültige ISO-8601-Darstellungen (RFC 3339) und werden akzeptiert (Vertrag §7 Punkt 14 fordert nur „ISO-8601-Datetime" — eine Ablehnung von `±HH:MM` wäre eine unautorisierte Verschärfung). Für die Normalisierung gilt: Das Suffix wird normiert; die intern einheitliche Repräsentation ist die UTC-Form.
- Eine reine Datumsangabe `YYYY-MM-DD` wird als `T00:00:00Z` normalisiert (interne Repräsentation für Vergleich und Output) — das ist **keine** Abweichung vom Format, sondern die festgelegte Normalform.
- **FAIL nach Punkt 14** sind ausschließlich Formen, die **kein** ISO-8601-Datetime sind (fehlende Trennzeichen, keine Zeit nach `T`, `HH:MM` ohne Sekunden, ungültiger Monat/Tag/Stunde/Minute/Sekunde, ungültiger Offset).
- Die Kalender-Validität von Datumsteilen folgt §6.3 (EC-3).
### 4.4 Rangfolge der Prüfschritte (deterministische Ausführungs-Reihenfolge)
Der Run folgt einer festen Ausführungs-Reihenfolge (vgl. §0 Aufruf):
1. **Klassifikation** — alle erfassten `.md`-Dateien werden gemäß §2 klassifiziert (Bundleroot / Area-`index.md` / `log.md` / Concept).
2. **Voraussetzungsprüfungen** — die Bundleroot- und Reserviert-Namen-Voraussetzungen aus §3.2 werden geprüft (fehlende Bundleroot, `log.md` an unzulässiger Position).
3. **Je Datei die 14 Punkte in Reihenfolge** (§3): Die Datei wird Punkt für Punkt geprüft. Sobald **ein** Punkt FAIL erzeugt, wird der FAIL für diese Datei einmal protokolliert (erste verletzte Bedingung in Punkt-Reihenfolge) und die übrigen Punkte werden für diese Datei nicht mehr ausgewertet (deterministische Abbruch-Regel — vermeidet mehrdeutige Mehrfach-Verdikte). Es wird stets die **erste** verletzte Bedingung als textuelle Fehlerursache im Verdikt genannt (NFR-4).
4. **Nach PASS der 14 Punkte die §6-Prüfungen** je Datei: EC-1-Existenz je `resource`, EC-3-Kalender-Validität der Datumsfelder, EC-4/6.4-`stale_after`-WARN.
Mehrere fehlende `resource`-Existenz-Fehler **einer** Datei (EC-1) werden zu **einer** FAIL-Zeile aggregiert — alle fehlenden Pfade in der im Frontmatter dokumentierten Reihenfolge (Beispiel: `FAIL wiki/x.md Fachliche Prüfung EC-1: resource existiert nicht (Pfad=raw/a.md, raw/b.md)`). Aggregation gilt nur innerhalb einer Datei: jede betroffene Datei erhält ihre eigene FAIL-Zeile.
Das Gesamtergebnis des Runs ist FAIL, sobald irgendeine Datei FAIL ist (§5).
### 4.5 `log.md`-Feingranularität (F17)
- Ein **leeres** `wiki/log.md` ist gültig (kein Frontmatter, keine Einträge) — keine Invalidität.
- `log.md` trägt **kein Frontmatter** (Punkt 10; Vertrag §5).
- `log.md`-Inhalt (Eintragsklassifikation, datumsgruppierte Liste) wird in v1 **nicht** validiert: §5 legt Format und Beispiel fest, aber keine strukturell prüfbare Eintrags-Grammatik; eine spätere Story (AD-16/Epic 4) kann eine Eintrags-Validierung ergänzen. Es ist keine neue Invaliditätsklasse („nicht in der Liste" gilt als nicht verletzt, §3.1).
## 5. Verdikt-Format (maschinenlesbar)
Pro geprüfte Datei wird **genau ein** Verdikt-Verb ausgegeben, gefolgt von Datei-Pfad und textueller Begründung. Das Format ist maschinenlesbar (deterministische Grammatik) und zugleich für Menschen lesbar (NFR-4). Ein Verdikt-Verb ist **ausschließlich** `SUCCESS` oder `FAIL`; `WARN` (§6.4) ist **kein** Verdikt-Verb, sondern ein ergänzender Berichtskanal und ersetzt das Verdikt nicht — eine Datei kann „SUCCESS + WARN" tragen.
```text
SUCCESS <relative-pfad> <optionale Begründung>
FAIL <relative-pfad> <Fehlerursache: Punkt-Nr. + Determinismus-Beschreibung>
```
- `<relative-pfad>`: Pfad relativ zur Workspace-Root (z. B. `wiki/index.md`, `wiki/<area>/<concept>.md`), `/`-getrennt.
- SUCCESS: alle zutreffenden Prüfschritte bestanden; keine Begründung erforderlich (kann aber eine Normalform-Notiz zu §4 enthalten, z. B. `verified`-Singleton-Coercing).
- FAIL: genau die textuelle Fehlerursache gemäß §3-Tabelle (Punkt-Nummer + deterministischer Grund + relevanter Wert/Pfad) **oder** — für fachliche Prüf-FAILs (§6; insbesondere EC-1-Existenz) — die Bezeichnung `Fachliche Prüfung EC-1` statt einer Punkt-Nummer (§4.4). Fachliche Prüf-FAILs tragen keine §7-Punkt-Nummer, weil sie keine der 14 §7-Punkte sind (§6.1). Die Ursache ist darüber hinaus Ausdruck der abgeschlossenen Normalisierung (§4).
- **Run-Ergebnis:** Das Gesamtergebnis ist `FAIL`, sobald mindestens eine Datei FAIL ist; dann gilt der Run als gescheitert, es werden keine Mutationen durchgeführt und `raw/` bleibt unangetastet (AD-3). Sind alle Dateien SUCCESS (inkl. keiner Existenz-Prüf-FAILs, §6.1), ist das Gesamtergebnis `SUCCESS`.
- Nicht-`.md`-Dateien unter `wiki/` erzeugen **kein** Verdikt (sie werden nicht geprüft, §1).
### 5.1 Selbstbegrenzung
- Die Instruktion validiert ausschließlich Bundle-Elemente gemäß §1; die Inhalte von `raw/`, `schema/` und `adapters/` werden **nicht** als Bundle validiert.
- Es werden **keine neuen Invaliditätsklassen** eingeführt (abschließende 14-Punkte-Liste, §3.1).
- Es wird **nichts geschrieben**: der Validator mutiert weder Bundle noch `raw/` noch sonstige Dateien; er protokolliert sein Ausführungs-Protokoll nur als Bericht (kein Schreibzugriff auf Dateien außerhalb des Berichtskanals).
## 6. Fachliche Zusatzprüfungen (Deferred-Work, separat protokolliert)
Die folgenden Prüfungen sind **fachliche** Prüfungen (keine §7-Invaliditäts-Punkte). Sie werden deterministisch ausgeführt und separat protokolliert — ein FAIL hier ist trotzdem ein Run-FAIL (das Bundle darf nicht mit fehlender Evidenz oder Phantom-Daten laufen), wird aber **nicht** als „Punkt 114"-Verstoß gezählt (§3.1; Vertrag §8 „Existenz-Prüfung als Validator-Verhalten der Story 1.4").
### 6.1 Existenzprüfung der `raw/`-Resource (EC-1)
- Für jeden `sources`-`resource`-Eintrag eines Concepts: Der gemäß §6.2 bereinigte und relativ zur Workspace-Root aufgelöste Pfad **MUSS zum Validierungszeitpunkt als Datei existieren** — ausdrücklich als **Datei, nicht als Verzeichnis**. Existiert er nicht oder löst er auf ein existierendes Verzeichnis auf, ist das Bundle **fachlich invalide → Run-FAIL** (ein Verzeichnis ist kein gültiger Evidenzpfad).
- Verdikt ohne Punkt-Nummer: `FAIL <concept-pfad> Fachliche Prüfung EC-1: resource existiert nicht (Pfad=<resource>)`.
- Mehrere fehlende Resources **einer** Datei werden zu **einer** FAIL-Zeile aggregiert (alle fehlenden Pfade in der dokumentierten Reihenfolge; §4.4, Schritt 4).
- Diese Prüfung ist eine **fachliche** Invalidität: Sie ist keine der 14 §7-Punkte und lässt die abschließende Liste unberührt (der Punkt wird separat protokolliert, nicht als Punkt 114 gezählt).
### 6.2 Pfad-Auflösung & -Bereinigung
`resource` ist ein `/`-getrennter relativer Workspace-Pfad zur **Workspace-Root** (oberste Ebene des Git-Arbeitsverzeichnisses). Deterministische Bereinigung/Auflösung — **Vorrangsregel:** Die Punkt-4-Grammatikprüfung (Rejektion von `..`, führendem `/`, Backslash, `file://`, URL) läuft **vor** der Punkt-3-Auflösungsprüfung. Ein `resource` mit `..`, dessen bereinigtes Ziel zufällig in `wiki/` läge, wird daher als **Punkt 4 (Grammatik)** abgelehnt, nicht als Punkt 3 — die Punktnummer ist je Input deterministisch (AD-13):
1. Der Wert wird als relativer Pfad interpretiert. Führendes `/` ist unzulässig (Punkt 4).
2. Der Pfad wird als `/`-Segmentfolge behandelt. Ein Segment `..` ist unzulässig (Punkt 4) — unabhängig vom Auflösungsziel. Segment `.` wird normalisiert (entfernt).
3. Backslash `\` und Windows-Trenner sind unzulässig (Punkt 4).
4. Ein `file://`-Präfix oder eine URL-Form (`http://`, `https://`, andere Scheme-Prefixe) sind unzulässig (Punkt 4).
5. Der bereinigte Pfad muss auf einen Pfad **innerhalb** `raw/` auflösen (Präfix `raw/` in der aufgelösten Form). Andernfalls Punkt 4.
6. Der aufgelöste Pfad darf **nicht** auf einen Pfad innerhalb `wiki/` auflösen (Punkt 3).
### 6.3 Kalender-Validität der Datumsfelder (EC-3)
Für alle `YYYY-MM-DD`-Felder (`stale_after`, `sources[].last_modified`) gilt:
- Exakt 10 Zeichen, Struktur `JJJJ-MM-TT`, mit `-`-Trennung.
- Die Kalenderdaten müssen real existieren: gültige Monate 0112, gültige Tage je Monat (Schaltjahrregel: Februar 29 nur in durch 4 teilbaren Jahren, außer Jahrhundertjahre, die nicht durch 400 teilbar sind). `2026-02-31` ist **invalide** (Punkt 14).
- Für Datumsteile in `at` (zeitliche ISO-8601-Form) gilt dieselbe Kalender-Validität (Monat/Tag/Stunde/Minute/Sekunde real existierend).
### 6.4 Veraltungs-Prüfung `stale_after` (BH-8/F18) — Warnung, keine Invalidität
- Ist `stale_after` gesetzt und gilt `today >= stale_after` (Vergleich in **UTC**), so wird eine **Warnung** ausgegeben: `WARN <concept-pfad> stale_after überschritten (Datum=<stale_after>, today=<today-UTC>)`. `WARN` ist ein ergänzender Berichtskanal, **kein** Verdikt-Verb (§5): Das Verdikt der Datei bleibt `SUCCESS`/`FAIL` unverändert.
- Ein veraltetes Concept ist **kein** struktureller Fehler und **kein** Run-FAIL (F18/BH-8; Vertrag §7 zählt die Veraltung nicht auf). Lebenszyklus-Konsequenzen der Veraltung (Nutzungssperre als `sources`-Ziel o. ä.) sind eine spätere Story (BH-8 → Epic 3) und werden hier **nicht** validiert.
- `stale_after` ohne Datumsproblem (nur Veraltung) lässt das Verdikt der Datei unverändert (SUCCESS bleibt SUCCESS; nur Warnung).
### 6.5 `non-md`-Konvention (EC-11)
Nicht-`.md`-Dateien unter `wiki/` (z. B. `wiki/<area>/logo.png`) werden **ignoriert** — kein Verdikt, keine Ablehnung, keine Konvention-Erfindung über den Vertrag hinaus (§1 Punkt 3, §3.1c).
## 7. Referenz-Fixtures (Negativ-/Positiv-Beispiele)
Die folgenden Tabellen belegen die 1:1-Abbildung der 14 Punkte und machen jede mechanische Bedingung reproduzierbar nachprüfbar (AD-17h). „⇒" gibt das erwartete Verdikt an; die Fehlerursache ist exakt die aus §3.
### 7.1 Negativ-Fixtures — je Punkt genau ein FAIL-Beispiel (Input → erwartetes Verdikt)
> **Isolations-Notiz:** Jede Negativ-Fixture wird gegen ein sonst-valides, isoliertes Sample geprüft (nur die eine Datei/Struktur, alle übrigen Punkte passieren). So ist gewährleistet, dass jede Fixture genau ihren Punkt auslöst und kein Vorab-FAIL durch andere Punkte entsteht (kein Nachbarschafts-Effekt).
| # | Fixture (Input) | Erwartetes Verdikt (FAIL mit Ursache) |
|---|-----------------|----------------------------------------|
| 1 | Concept `x.md` mit `type:` (leer) | `FAIL wiki/x.md Punkt 1: concept ohne type oder leerer type (NULL|leer|nicht-String)` |
| 2 | `.md` unter `wiki/` ohne `---`-Frontmatter | `FAIL wiki/x.md Punkt 2: nicht-reservierte .md-Datei ohne Frontmatter/ohne type` |
| 3 | `sources: [{resource: wiki/foo.md}]` | `FAIL wiki/x.md Punkt 3: resource loest auf wiki/-Concept-Pfad (Pfad=wiki/foo.md)` |
| 4 | `sources: [{resource: ../outside.md}]` | `FAIL wiki/x.md Punkt 4: resource ausserhalb raw/ oder unzulaessiger Pfad (..-Traversal\|absolut\|URL\|Backslash\|file://)` |
| 5 | `status: published` | `FAIL wiki/x.md Punkt 5: verbotener status-Wert (Wert=published)` |
| 6 | Concept mit `foo: bar` (nicht autorisiert) | `FAIL wiki/x.md Punkt 6: nicht autorisiertes Feld (Key=foo)` |
| 7 | `generated: {at: 2026-08-15T10:00:00Z}` (ohne `by`) | `FAIL wiki/x.md Punkt 7: leere/fehlende by-Angabe in generated/verified` |
| 8 | `wiki/index.md` ohne `okf_version` | `FAIL wiki/index.md Punkt 8: Bundleroot ohne type: bundle/okf_version \"0.2\" oder falscher okf_version-Wert` |
| 8a | `wiki/index.md` existiert nicht (Bundle ohne Bundleroot) | `FAIL (Struktur) Bundleroot fehlt: wiki/index.md existiert nicht (Vertrag §2, Vorausbedingung zu Punkt 8)` |
| 9 | Concept mit `okf_version: "0.2"` | `FAIL wiki/x.md Punkt 9: okf_version/type: bundle ausserhalb der Bundleroot (Datei=wiki/x.md)` |
| 10 | `wiki/log.md` beginnt mit `---` | `FAIL wiki/log.md Punkt 10: Frontmatter in Area-index.md/log.md (Datei=wiki/log.md)` |
| 10a | `wiki/<area>/log.md` existiert (reservierter Name außerhalb der Bundleroot) | `FAIL wiki/<area>/log.md log.md an unzulässiger Position (reservierter Name, nur Bundleroot, Vertrag §5)` |
| 11 | Area `wiki/foo/` ohne `index.md` | `FAIL (Struktur) Punkt 11: Index-Regel verletzt (Area ohne index.md=foo)` |
| 12 | `sources: {resource: raw/x.md}` (Map statt Liste) | `FAIL wiki/x.md Punkt 12: sources/verified/generated in nicht erlaubter Form` |
| 12a | `sources: [{title: \"Ohne resource\"}]` (Eintrag ohne Pflichtangabe `resource`) | `FAIL wiki/x.md Punkt 12: sources/verified/generated in nicht erlaubter Form` |
| 13 | Frontmatter mit zweimal `type:` | `FAIL wiki/x.md Punkt 13: doppelter Frontmatter-Key (Key=type)` |
| 14 | `stale_after: 2026-02-31` | `FAIL wiki/x.md Punkt 14: fehlerhaftes Wert-Format (Feld=stale_after, Wert=2026-02-31)` |
| 14a | `usage_count: 3.0` (Float statt Ganzzahl) | `FAIL wiki/x.md Punkt 14: fehlerhaftes Wert-Format (Feld=usage_count, Wert=3.0)` |
| 14b | `at: 2026-08-15T25:00:00Z` (ungültige Stunde, kein ISO-8601-Datetime) | `FAIL wiki/x.md Punkt 14: fehlerhaftes Wert-Format (Feld=at, Wert=2026-08-15T25:00:00Z)` |
### 7.2 Positiv-Fixtures — je Punkt das gültige Gegenstück (PASS / SUCCESS)
Zusätzlich gilt der A0-2/AD-1b-Grundsatz der abgeschlossenen Liste: Ein Concept mit ausschließlich `type` und ohne `sources`/`generated`/`verified`/`status`/`stale_after` (alle optionalen Felder fehlen) ist gültig → `SUCCESS wiki/x.md`. Fehlende optionale Felder sind keine Invalidität (A0-2/AD-1b).
| # | Fixture (Input) | Erwartetes Verdikt |
|---|-----------------|--------------------|
| 1 | Concept `x.md` mit `type: concept` | `SUCCESS wiki/x.md` |
| 2 | Nicht-reservierte `.md` mit gültigem Frontmatter inkl. `type` | `SUCCESS wiki/x.md` |
| 3 | `sources: [{resource: raw/prd/prd-wow20-2026-08-14.md}]` | `SUCCESS wiki/x.md` |
| 4 | `sources: [{resource: raw/prd/prd-wow20-2026-08-14.md}]` (unter `raw/`) | `SUCCESS wiki/x.md` |
| 5 | `status: stable` | `SUCCESS wiki/x.md` |
| 6 | Concept mit ausschließlich `type`/`sources`/`generated`/`verified`/`status`/`stale_after` | `SUCCESS wiki/x.md` |
| 7 | `generated: {by: wow-compiler/0.1.0, at: 2026-08-15T10:00:00Z}` | `SUCCESS wiki/x.md` |
| 8 | `wiki/index.md` mit `type: bundle` + `okf_version: "0.2"` | `SUCCESS wiki/index.md` |
| 8a | Bundleroot `wiki/index.md` ist vorhanden | `SUCCESS` (Voraussetzung §3.2 nicht verletzt) |
| 9 | Kein `okf_version`/`type: bundle` außerhalb `wiki/index.md` | `SUCCESS` (kein Punkt 9) |
| 10 | `wiki/log.md` und Area-`index.md` ohne Frontmatter | `SUCCESS wiki/log.md` / `SUCCESS wiki/<area>/index.md` |
| 10a | Kein `log.md` außerhalb der Bundleroot (kein `wiki/<area>/log.md`) | `SUCCESS` (Voraussetzung §3.2 nicht verletzt) |
| 11 | Area `wiki/foo/` mit `index.md`, das neue Concept verlinkt | `SUCCESS` (Punkt 11 nicht verletzt) |
| 12 | `sources` Liste von Maps, je Eintrag mit `resource`; `verified: {by: human:x, at: ...}` (Singleton-Map) | `SUCCESS wiki/x.md` (Singleton-Coercing, §4.2) |
| 12a | `sources: [{resource: raw/x.md, title: t}]` (Eintrag mit Pflichtangabe `resource`) | `SUCCESS wiki/x.md` |
| 13 | Frontmatter ohne doppelte Keys | `SUCCESS wiki/x.md` |
| 14 | `stale_after: 2026-12-31`; `last_modified: 2026-08-14`; `at: 2026-08-15T10:00:00Z`; `usage_count: 3` | `SUCCESS wiki/x.md` |
| 14b | `at: 2026-08-15T10:00:00+02:00` (Offset mit Doppelpunkt, gültiges ISO-8601/RFC 3339) | `SUCCESS wiki/x.md` (Normalform §4.3) |
| 14c | `at: 2027-01-01` (reiner Datumswert) | `SUCCESS wiki/x.md` (normalisiert zu `T00:00:00Z`, §4.3) |
| 14d | `usage_count: 3` (YAML-Integer) | `SUCCESS wiki/x.md` |
## 8. Normreferenzen & Revisionslog
**Normreferenzen (ableitungsseitig, read-only):**
- `schema/wiki-compiler.md` — autorisierter Vertrag (Story 1.3): §1 Geltungsbereich, §2 Bundleroot, §3.1–§3.7 Feldsubset & `sources`-Auflösung, §5 `log.md`-Typ, §6 Index-Regel/Prädikate, §7 abschließende 14-Punkte-Liste (inkl. Kalender-Validität & UTC-Vergleich), §8 Normreferenzen.
- PRD §13 — OKF-0.2 als normativer Format-Standard (FR-9, NFR-6); OKF-Spezifikation (Google Cloud, `knowledge-catalog`).
- AD-1b/F-2/A0-2 — strukturelle Invalidität schlägt den Run fehl; fehlende optionale Felder nicht invalide.
- AD-13/AD-17h/Q-6 — deterministische, ohne LLM-Urteil aufrufbare Agent-Instruktions-Validierung, mechanisch zu bestätigen.
- AD-3 — `raw/` immutable; fehlgeschlagener Run lässt `raw/` unangetastet (auch: keine Mutationen bei FAIL).
- AD-4b/A0-4 — Provenienz-Ziellinie: `sources` nie auf `wiki/`-Pfade.
- D-3 — kein Standalone-Programm als Validator; die Regel bleibt eine Instruktion.
- Deferred-Work `_bmad-output/implementation-artifacts/deferred-work.md` — EC-1, EC-3, BH-14, F2-Listen, BH-8, EC-11, F17-`log.md`, F18-`stale_after` (8 an Story 1.4 verwiesene Entscheidungen, in §4/§6 deterministisch festgelegt).
- **F15 (Trust-Semantik von `generated.by`):** `generated.by: human:<id>` ist formgültig — das Datenmodell erlaubt jeden non-empty `by` (Vertrag §3.4) —, begründet aber **keine** human-review-Klassifikation (die entsteht nur über `verified` mit `human:`-Präfix, §3.5). Die Trust-Semantik von `generated.by` mit `human:`-Präfix wird in Epic 4 geklärt (Deferred-Work F15).
- **Story 2.3 (Link-Form):** Der Punkt-11-Check akzeptiert die Concept-Identität in der zuständigen `index.md` mit oder ohne `.md`-Endung (§3 Punkt 11). Eine genau-eine-Form-Festlegung der Link-Schreibweise ist Story 2.3 und wird hier bewusst nicht vorweggenommen.
**Revisionslog:**
- **Revision 1 (2026-08-15):** Erstes abgeleitetes Artefakt — die 14 §7-Punkte als mechanische Prüfschritte (§3), Normalisierungs-/Toleranz-Regeln (§4), maschinenlesbares Verdikt-Format & Selbstbegrenzung (§5), fachliche Zusatzprüfungen (§6), Referenz-Fixtures (§7).
- **Revision 2 (2026-08-15):** Review-Patches — §3.2 Voraussetzungsprüfungen (Bundleroot/`log.md`-Position) als Nicht-§7-Pflichten; Punkt 6/9-Exemption-Notiz (kein Punkt-6-vor-9-Feuer); Punkt 9 auf Dateiinhalt ausgeweitet; Punkt 10 BOM-/Leerzeilen-Stripping; Punkt 11 deterministische Link-Prüfung ohne Story-2.3-Vorwegnahme; Punkt 12 fehlende/leere `resource`; Punkt 14 `usage_count`-YAML-Integer-Typ + korrekter `at`-Verweis (§4.3); §4.3 akzeptiert `±HH:MM` (keine unautorisierte Verschärfung); §4.4-Ausführungs-Reihenfolge mit §3.2/§6-Phasen und EC-1-Aggregation; §5-WARN als Berichtskanal statt Verdikt-Verb; §6.1 „als Datei, nicht Verzeichnis" + Aggregation; §6.2 Punkt-4-vor-3-Priorität; Fixtures ergänzt/aktualisiert (§7); Normreferenzen F15/Story 2.3.
+4
View File
@@ -0,0 +1,4 @@
# Log
## 2026-08-15
- Validator-Zertifizierung: `schema/validator.md` (Revision 2) gegen die Referenz-Fixtures (§7) selbstgeprüft — Ergebnis: PASS (alle Negativ-Fixtures erzeugen FAIL, alle Positiv-Fixtures SUCCESS; maschinenlesbares Verdikt gemäß §5 bestätigt). Jede Negativ-Fixture wird je Fixture isoliert gegen ein sonst-valides Sample geprüft, sodass genau ihr zugehöriger Punkt auslöst (kein Vorab-FAIL durch andere Punkte).