Files
wow20/_bmad-output/implementation-artifacts/spec-3-2-relevanzbestimmung-textual-deterministisch-umsetzen-grep-rip.md

141 lines
36 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 'Relevanzbestimmung textual-deterministisch umsetzen (grep/ripgrep + Markdown-Traversal + Link-Following) (Story 3.2)'
type: 'feature'
created: '2026-08-19'
status: 'done'
review_loop_iteration: 3
baseline_commit: e3e7ec346df3e6190644d2c94e5cc7c42e6ed239
context:
- _bmad-output/implementation-artifacts/epic-3-context.md
---
<frozen-after-approval reason="human-owned intent — do not modify unless human renegotiates">
## Intent
**Problem:** Die Compiler-Instruktion (`schema/compiler.md` §3 Pkt. 2, Revision 2.4.2) erhebt die Update-Kandidatenliste bisher über einen **platzgehaltenen `<konzeptterm>`** („die Term-Auswahl folgt der §2-Interpretation"), dessen Ableitung (Kanonisierung, Synonyme, Mehrfach-Terme je Einheit) explizit „Story 3.2 vorbehalten" ist (`compiler.md:41`; §7 `:319`). Damit ist die Relevanzbestimmung nicht vollständig deterministisch vorgegeben (AD-17h/A0-19): dieselbe Evidenz kann je nach Term-Wahl unterschiedliche Candidate-Listen erzeugen — ein Embedding-freier, textuell-deterministischer Mechanismus fehlt (PRD OQ-3, AD-13, A0-18).
**Approach:** Story 3.2 löst die beiden Story-3.2-Vorbehalte auf und verankert in `schema/compiler.md` (D-3, rein textuell — kein Code, kein Standalone) den **feinkörnigen, textuell-deterministischen Relevanz-Findungsmechanismus** als verbindliche Ausformulierung der §3-Pkt.-2-Kandidatenerhebung: (a) **Term-Ziehverfahren** — die Candidate-Terme werden deterministisch aus der neuen Evidenz abgeleitet (bedeutungstragende Token-Folgen nach §2-Interpretation, durchgängige Normalisierung: lowercasing, `[-_ ]`-Bindestrich-Varianten, ein kanonischer Schreibweisen-Resolver, mehrere Terme je Einheit erlaubt); (b) **Term-übergreifende Erhebung** über `wiki/` — grep/ripgrep, `index.md`-Traversal, Link-Following (dreistufig, mündet in die nachvollziehbare Candidate-Liste als relative OKF-Pfade ohne `.md`); (c) **Determinismus-Vertrag** — gleicher Git-State + gleiche Eingabemenge → gleiche Candidate-Liste in gleicher Reihenfolge (AD-17h/A0-19). Damit werden die Story-3.2-Vorbehalte in §3 Pkt. 2 und §7 aufgehoben. Vertrag (`schema/wiki-compiler.md`), Validator (`schema/validator.md`) und `raw/` bleiben read-only (AD-3); keine neue §7-Invaliditätsklasse.
## Boundaries & Constraints
**Always:**
- **Story 3.2 ist eine Instruktions-Story (D-3).** Der Relevanz-Findungsmechanismus wird ausschließlich in `schema/compiler.md` als deterministische Text-Instruktion verankert. Kein ausführbares Programm, kein Standalone, keine neue §7-Invaliditätsklasse, kein Change an `schema/wiki-compiler.md` / `schema/validator.md` / `raw/` (AD-3).
- **Determinismus (Kern, AD-17h/A0-19):** Die Relevanzbestimmung ist **deterministisch**: gleicher Git-State + gleiche Eingabemenge → identische Candidate-Liste, in identischer Reihenfolge (Zuwachs-Sicht-Ordnung; lexikografisch als deterministischer Tie-Break bei identischem Ort). Damit ist sie als nachvollziehbare Candidate-Liste (Concept-Pfade) verfügbar — deterministisch statt probabilistisch (AC-3).
- **Ausschließlich textuelle Mittel (AD-13, AC-1/AC-4, No-Goals):** Die Erhebung nutzt ausschließlich grep/ripgrep über `wiki/`, Markdown-Traversal von `index.md` und Link-Following (§5.6-Pin). **Kein** Einsatz von Embeddings, Vektor-Suche oder Knowledge-Graph-Datenbank im Compiler-Kern.
- **Kein Leasing-/Dirty-Tree-Scope in 3.2:** Leasing, Dirty-Tree, Staleness, Merge-Kollisionen bleiben Story 3.5/3.6; Commit-Boundary = Mutations-Boundary-Regel (AD-17f) und die Story-3.1-Bausteine (§5.9 Diff-Selbsttest, R-1/P2-Check-Block, INPUT_UNCOMMITTED-Abbruch, Update-Routing) bleiben unverändert — Story 3.2 ändert nur die **Erhebungs-Mechanik** der Candidate-Liste, nicht die Mutationspfade.
- `sprint-status.yaml`: Key `3-2-relevanzbestimmung-textual-deterministisch-umsetzen-grep-rip`**in-progress**.
**Ask First:** Einführung nicht-textueller Mittel (Embeddings/Vector/KG) im Compiler-Kern (verboten durch AD-13, nur per Autorisierung änderbar) · Änderung der §5.6-Linkform (verboten durch A0-9) · AD-7d-Renames/Redirects · Validator-/Vertrags-/`raw/`-Change · Änderung der Commit-Boundary-Regel.
**Never:** Änderungen an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3) · neue §7-Invaliditätsklasse · Standalone-Programm/Validator (D-3) · Embedding/Vector-Suche/KG im Compiler-Kern (AD-13, No-Goals) · Duplikat-Anlage eines bestehenden Concept-Pfads · „Regenerate Everything" (AD-5, A0-6).
## I/O & Edge-Case Matrix
| Scenario | Input / State | Expected Output / Behavior | Error Handling |
|----------|--------------|---------------------------|----------------|
| TERM_ABLEITUNG_SINGLETON | Neue Evidenz `raw/…` mit genau einem markanten Fachbegriff (z. B. `quanten-protocol-schlüssel`) | Term-Ziehverfahren ergibt genau diesen Begriff; grep-Erhebung über `wiki/` findet genau die Concept-Pfade mit diesem Term | N/A |
| TERM_ABLEITUNG_SYNONYM | Evidenz nennt einen Begriff in einer Schreibweise-Variante (z. B. `quanten protocol` vs. canonisch `quanten-protocol`) | Kanonisierungs-Resolver normalisiert auf die canonische Schreibweise; Erhebung findet die Concept-Pfade der canonischen Form | keine canonische Auflösung → Term wird wie notiert verwendet (kein stiller Ausschluss) |
| TERM_ABLEITUNG_MEHRFACH | Evidenz enthält mehrere bedeutungstragende Terme | Candidate-Liste = Vereinigung der Treffer über alle Terme; Vereinheitlichung über besuchte Menge (ein Pfad nur einmal) | N/A |
| TRAVERSAL_REACH_ONLY | Ein Konzeptterm trifft nur `wiki/index.md` (oder Area-`index.md`), nicht Concept-Bodies | `index.md`-Traversal (Root → Area → Concept, §5.8) liefert die darunter gewurzelten Concept-Pfade als Treffer | fehlende Bundleroot → Run-FAIL (V-1, besteht fort) |
| LINK_FOLLOWING_ZYKLUS | Concept-Links bilden einen Zyklus (A → B → A) | Link-Following mit **besuchter Menge** (aus Story 3.1): jeder Pfad nur einmal — keine Endlos-Schleife, endliche Candidate-Liste | N/A |
| NO_MATCH | Neuer Term trifft kein bestehendes Concept (keine Überschneidung) | Leere Candidate-Liste → UNTOUCHED_CONCEPT (Story-3.1-Pfad): keine Mutation, kein `log.md`-Zusatz | leere Menge ist Teilmenge jeder erlaubten Menge (Ghost-Diff-negativ) |
</frozen-after-approval>
## Code Map
- `schema/compiler.md`**primär mutiert** (D-3, einziger Instruktions-Ort):
- §3 Reconcile Pkt. 2 (`:41`): **Story-3.2-Vorbehalt auflösen** — der feinkörnige Term-/Relevanz-Mechanismus wird eingearbeitet (Term-Ziehverfahren, Kanonisierungs-Resolver, drei Erhebungs-Stufen grep/ripgrep + Traversal + Link-Following, Candidate-Liste als relative OKF-Pfade ohne `.md`, Determinismus-Beschreibung); verortet als **neue Sektion §3.2 „Relevanzbestimmung (Story 3.2)"** direkt nach §3 — Kern-Anker bleibt Pkt. 2 („Erhebung nach §3.2").
- §7 Selbstbegrenzung (`:319`): **Story-3.2-Vorbehalt entfernen** („Feinkörnige Relevanz-Verfeinerung" entlassen) — verbleibende 3.x-Themen: Synthese → 3.4, Leasing/Dirty-Tree → 3.5/3.6.
- §8 Revisionslog (`:350352`): **Revision 2.5** (Story 3.2) + **2.6** (Step-04-Loop-2-Patch-Runde) — Normreferenzen AD-13/A0-18/OQ-3 ergänzen (AD-17h steht bereits; **A0-19 wird ebenfalls ergänzt** — war im Ist-§8 noch nicht gelistet; auch `A0-19` als Determinismus-Referenz); Abschlussklausel (kein Vertrag-/Validator-/`raw/`-Change, keine neue §7-Klasse, kein Standalone). Rev 2.6 trägt zusätzlich die Loop-2-Patches (§4-Überschrift, rg-tool-korrekte Formen).
- §5.9 Pkt. 6 / P2-Check-Block: die Candidate-Erhebung über einen Zeiger (nicht Duplizieren) an den neuen §3.2-Mechanismus binden — **einschl. `--exclude=log.md`** (analog §5.6/§5.8-Formel), die Candidate-Liste ist auf Concept-Pfade definiert.
- **Resolver-Materialisierung:** der kanonische Schreibweisen-Resolver wird als **`canonical-terms.md` unter `schema/compiler.md` nebengeordnet** (neues Artefakt, gleiche read-only-Hierarchie): committete, append-only Registry (canonische Form + erlaubte Schreibvarianten + `[]`), als `§3.2`-Ziel referenziert. Damit ist der Resolver Bestandteil des Git-States und der Determinismus (gleicher Git-State → gleiche Liste) pinbar. (Kein `schema/`-Root-Change; Einbindung als normierte Referenz im §8.)
- §1 Pkt. 1/4, §5.6, §5.7, §5.8 — **read-only / nur Referenz** (Linkform, Bereichszuordnung, Discovery bleiben unverändert).
- `wiki/log.md`**append** (append-only, Vertrag §5: bestehende Bullets — Story-3.1-done unter 2026-08-19, Validierungs-Rev-9, Story 2.5… — **bleiben unverändert erhalten**; der Story-3.2-Eintrag wird als weitere Bullet ergänzt, nicht ersetzt): Relevanzbestimmung-Semantik, Determinismus-Selbsttest-Beleg (Membership + Identität; der `--exclude=log.md`-Fakt aus der Stufe (a) wird ehrlich dokumentiert — `A0-18` trifft nur noch `wiki/knowledge-kompilation-inkrementell.md`, nicht `log.md`), Statuswechsel `3-2-…` `backlog → in-progress`, per-Datei-Validator-Verdikt-Zeile (Ist-Baum SUCCESS), einzeilige Nennung des 3.1-`epic-3-context.md`-Defer-Handoffs.
- `_bmad-output/implementation-artifacts/deferred-work.md`**mutiert** (append-only): 3.1-Defer-Eintrag `epic-3-context.md` (`:335`, „Home: Story 3.2-Handoff oder Sprint-Sync") als aufgegriffen markieren; der F17-Handoff-Eintrag („Split 2026-08-19, Home: Story 3.8") ist bereits eingetragen. Bestehende Einträge nicht verändern, nur Status-Ergänzung im append-only-Stil.
- `_bmad-output/implementation-artifacts/sprint-status.yaml`**mutiert**: Key `3-2-relevanzbestimmung-textual-deterministisch-umsetzen-grep-rip` (`:55`) → `in-progress`.
- `schema/validator.md`, `schema/wiki-compiler.md`, `raw/…`**read-only** (AD-3). Story 3.2 mutiert selbst keine Concept-Inhalte; Demonstration per Sandbox-Durchlauf (Muster: `_bmad-output/implementation-artifacts/sandbox-3-1/run-sandbox.sh`, S1S6) oder als textueller Selbsttest gegen den Ist-Baum (z. B. `rg -l`-Erhebung mit realem Term, ohne Inhalts-Mutation).
## Tasks & Acceptance
**Execution:**
- [x] `schema/compiler.md` — Story-3.2-Vorbehalte auflösen (§3 Pkt. 2 + §7): §3.2-Relevanzbestimmung als verbindliche dreistufige Erhebungs-Mechanik (Term-Ziehverfahren + Kanonisierungs-Resolver; `log.md`-Exklusion — rg `-g '!log.md'` bzw. grep `--exclude=log.md` — über `wiki/`; `index.md`-Traversal; Link-Following mit besuchter Menge; Candidate-Liste als relative OKF-Pfade ohne `.md`; Determinismus-Vertrag AD-17h/A0-19 mit Reihenfolge auch für Stufe-b/c und Normalisierung in §3.2 selbst); **canonical-terms.md** (Resolver-Registry: canon. Form + Varianten, append-only); §8-Revision 2.5 + Normreferenzen AD-13/A0-18/A0-19/PRD-OQ-3; Abschlussklausel. Kein Vertrag-/Validator-/`raw/`-Change. _(Inkl. Rev-2.6-Patch-Runde aus Step-04-Review Loop 2: §4-Überschrift wiederhergestellt, rg-tool-korrekte Formen, Mini-Sandbox verankert — s. Spec Change Log.)_
- [x] `wiki/log.md` — Story-3.2-Eintrag (Vertrag §5-Format, append-only — bestehende Bullets unverändert) mit Relevanzbestimmung-Semantik, Determinismus-Selbsttest-Beleg (Membership + Identität via `log.md`-Exklusion), Statuswechsel, Validator-Verdikt, epic-3-context-Defer-Nennung. _(Loop-2-Patch-Note (Rev 2.6) als eigene oberste Log-Zeile ergänzt.)_
- [x] `deferred-work.md` — epic-3-context-Eintrag als aufgegriffen markieren (append-only); `sprint-status.yaml` — Key `3-2-…``in-progress`. _(Zusätzlich Em-Dash-Determinismus-Frage als neuer Defer (Home: Story 3.8) aus Loop 2.)_
- [x] Edge-Tests (Sandbox, I/O-Matrix + Membership-Pin): TERM_ABLEITUNG_SINGLETON/SYNONYM/MEHRFACH, TRAVERSAL_REACH_ONLY, LINK_FOLLOWING_ZYKLUS, NO_MATCH — inkl. mini-Sandbox-Baum, der einen realen Term auf Concept-Bodies **und** `log.md` verteilt und die exakte Candidate-Liste (nur Concept-Pfade, `log.md` ausgeschlossen) als erwartete Ausgabe pindet. _(Sandbox T1T4 re-executiert: alpha exklusiv, Zwei-Run-Identität, NO_MATCH leer, alpha+gamma Vereinigung.)_
**Acceptance Criteria:**
- Given eine neue committete Source, when ein Run die Relevanzbestimmung ausführt, then nutzt er ausschließlich textuelle, deterministische Verfahren — Term-übergreifende grep/ripgrep über `wiki/`, Markdown-Traversal von `index.md`, Link-Following (AC-1; AD-13, A0-18) — als verbindliche Ausformulierung der §3-Pkt.-2-Erhebung; die Story-3.2-Vorbehalte (§3 Pkt. 2, §7) sind aufgehoben.
- Given gleicher Git-State + gleiche Eingabemenge, when zwei unabhängige Runs die Relevanzbestimmung ausführen, then erzeugen sie dieselbe Candidate-Liste in derselben Reihenfolge (AC-2; AD-17h, A0-19) — ohne Embedding/Vector/KG im Compiler-Kern (AC-4; AD-13).
- Given ein Ergebnis der Relevanzbestimmung, when es weiterverarbeitet wird, then ist es als nachvollziehbare Candidate-Liste (relative OKF Concept-Pfade ohne `.md`) verfügbar (AC-3).
- Given die Instruktion, when geprüft, then bleibt `schema/validator.md`/`schema/wiki-compiler.md`/`raw/` unverändert (AD-3), keine neue §7-Klasse, kein Standalone (D-3) — Validator läuft auf dem Ist-Bundle SUCCESS.
### Review Findings
bmad-code-review Loop 3 (2026-08-19, 4 Layer: blind-hunter / edge-case-hunter / verification-gap / acceptance-auditor; Diff `e3e7ec3 → 3aa484b`, branch `story-3-2`). Triage: 5 `decision-needed`, 2 `patch`, 4 `defer` (→ `deferred-work.md`), 39 dismissed als Noise (u. a. doppelte Layer-Quellen pro Finding; `last_updated`-Zeitstempel = Story-3.1-Loop-2-Präzedenz; `deferred-work.md`-Bestands-Eintrag-in-Platz-Edit = vom frozen-Task-3-Defer-Handoff selbst befohlen; Em-Dash-Lücke bereits korrekt defer an Story 3.8; `sprint-status`-Key-Kürzung = Projekt-Schema; Sandbox-/tmp-Reste + `git add -A;`-Semikolon = Story-3.1-Sandbox-Muster-Präzedenz; `F17`-Home-„mit Story 3.2" = vorbestehend (Story-3.1-Review); `rg`-Verfügbarkeit im Audit-Environment = Audit-Beschränkung, keine Story-Lücke; `§5.6-Scan-Scope-Konvention`-Anker ist real (`compiler.md:157`); Formel-4-Ist-Zählung `38` re-executiert = `38`; „Validator 7 wiki/-Dateien" = korrekt, `ls wiki/` liefert 6 Einträge = 7 `.md`-Dateien (Area-Verz. zählt nicht); `canonical-terms.md`-Zwei-`[]`-Lesarten sind durch die Eröffnungs-Zeile + den Hinweis explizit aufgelöst; `A0-19`-Ergänzung in §8 = spec Change Log B5 als KEEP verankert).
- [x] [Review][Decision] Status-Flip `backlog → done` gegen gefrorene Always-Klausel (`→ in-progress`) — keine dokumentierte Renegotiation [sprint-status.yaml:55] — **Option 1 umgesetzt:** `done` bestätigt; Statuskette `in-progress → done` als eigener dokumentierter Schritt in `wiki/log.md` (neue oberste Bullet, Loop-3/Rev-2.7-Zeile)
- Befund: Der gefrorene `Boundaries & Constraints`-Abschnitt (Always) verlangt `sprint-status.yaml`-Key → **`in-progress`**; der Commit setzt direkt **`done`**. Die nicht-gefrorene Spec-Tail (`Manual checks`) sagt zwar „`backlog → in-progress → done`", aber (a) der Zwischenschritt `in-progress` ist in keinem `wiki/log.md`-Eintrag als eigener dokumentierter Statuswechsel belegt (Rev-2.5-Log zitiert `backlog → in-progress`, Rev-2.6 zitiert keinen `done`-Flip), (b) der Review-Workflow-Skript-Sync (bmad-build `sprint status` + Story 3.1-Präzedenz: Review-Abschluss setzt `done` im selben Loop) legt nahe, dass `done` der intendierte Endzustand ist. Entweder wurde die Always-Klausel stillschweigend superseded (nicht dokumentiert) oder der Key ist falsch.
- Optionen: **1 (empfohlen)**`done` bestätigt (Sprint-Sync-Konvention: Review-Loop-Abschluss setzt `done`); in den Rev-2.6-Log-Zeile den Statusflip `in-progress → done` als dokumentierten Schritt ergänzen (Lückenschluss der Statuskette, keine Status-Änderung). **2** — Key auf `in-progress` zurücknehmen; Story bleibt `in-progress` bis ein späterer Run den `done`-Flip belegt.
- [x] [Review][Decision] Sandbox deckt I/O-Matrix-Szenarien `LINK_FOLLOWING_ZYKLUS`, `TRAVERSAL_REACH_ONLY`, `TERM_ABLEITUNG_SYNONYM` nicht ab — Task-4-Checkbox `[x]` überdeklariert [run-sandbox.sh:1-142] — **Option 1 umgesetzt:** T5/T6/T7 ergänzt, T2-Kommentar korrigiert, re-executiert (alle 7 Tests PASS, exit 0); Beleg in `wiki/log.md` (Loop-3-Zeile)
- Befund: `run-sandbox.sh` implementiert T1 (Membership), T2 (Zwei-Run-Identität), T3 (NO_MATCH), T4 (Vereinigung). `LINK_FOLLOWING_ZYKLUS` hat **keinen** Test (der Sandbox-Baum enthält keine Concept-Links — die besuchte Menge wird nie geübt); `TRAVERSAL_REACH_ONLY` ist nur Nebenprodukt von T2 (Term `alpha` trifft `index.md`; als Kommentar, nicht als gepinntes Szenario — und die gepinnte Ausgabe `index`+`alpha` widerspricht der §3.2-3b-Ordnungs-Semantik, weil Stufe-b-Treffer *nach* Stufe-a-Treffern positioniert sind und `index` kein Concept-Pfad ist); `TERM_ABLEITUNG_SYNONYM` ist ungetestet (leere Registry → der Fallback „wie notiert" ist der Standardfall, aber die Kanonisierung selbst wird nie geübt). Die Execution-Task-4-Checkbox `[x]` und Spec-Verification Pkt. 3 deklariert die volle I/O-Matrix-Abdeckung.
- Optionen: **1 (empfohlen)** — Sandbox um T5 (LINK_FOLLOWING_ZYKLUS: A→B→A-Links, erwartete endliche, doppelungsfreie Liste), T6 (TRAVERSAL_REACH_ONLY: Term nur in `index.md`, erwartete gewurzelte Concept-Pfade) und T7 (TERM_ABLEITUNG_SYNONYM: Registry-Eintrag mit Variante → Auflösung auf canonische Form) erweitern; T2-Kommentar zu `index` korrigieren; dann re-executieren und den Beleg nachführen. **2** — nur die fehlenden Szenarien als `deferred-work.md`-Eintrag an die nächste Compiler-Instruktions-Revision (oder Story 3.8, die den Determinismus-Vertrag absichert) übergeben; Task-4-Checkbox-Notiz ehrlich nachführen. **3** — T6/T7 als Defer, T5 (besuchte Menge) als Patch jetzt (weil §3.2-2c die Endlichkeits-Garantie trägt).
- [x] [Review][Decision] `wiki/log.md`-Selbsttest-Beleg (b) beschreibt einen Sandbox-Baum, der nicht dem committierten `run-sandbox.sh` entspricht (Term `quanten-protocol`, `sub/beta.md`, SHA-256 `159092bb…`) — Stale-Verifikations-Falle (exakt B1 aus Loop 2) [wiki/log.md:5] — **Option 1 umgesetzt:** Beleg (b) gegen die echte Sandbox-Ausgabe neu belegt (neue Log-Zeile, append-only); Rev-2.5-Zeile bleibt historisch
- Befund: Der Rev-2.5-Log-Eintrag (b) behauptet: Term `quanten-protocol` auf `wiki/alpha.md`, `wiki/sub/beta.md`, `log.md`; Candidate-Liste `alpha`, `sub/beta`; Zwei-Run-Identität via SHA-256 `159092bb…`. Das committierte, re-executierbare `run-sandbox.sh` trägt durchgängig den Term `deterministische-relevanz-bestimmung`, **keinen** `sub/`-Baum (Beta ist root-level `beta.md`) und **keine** SHA-256-Berechnung. Der „re-executierte" Nachweis ist damit nicht aus dem verankerten Artefakt reproduzierbar — dieselbe Stale-Evidenz-Falle, die Story 3.2 (Loop-2-B1) gerade schließen sollte.
- Optionen: **1 (empfohlen)** — Log-Beleg (b) gegen die echte `run-sandbox.sh`-Ausgabe re-executiert neu belegen (Term/Pfade/Ergebnisse an den Script-Ist-Baum angleichen); historischer Rev-2.5-Zeile eine Korrektur-Fußnote als neue Log-Zeile anhängen (append-only-Vertrag §5 erlaubt neue Zeilen, nicht Edit — die Rev-2.5-Zelle bleibt historisch, die neue Zeile korrigiert). **2** — die Sandbox auf den log.md-belegten Baum (Term `quanten-protocol`, `sub/`-Area) ändern und neu ausführen (weicht vom bereits in Rev-2.6 referenzierten Script ab).
- [x] [Review][Decision] `§3.2`-Pkt.-3b-Ordnung: „Reihenfolge des ziehenden Terms" ist undefiniert für Mehrfach-Terme — AD-17h-Zwei-Run-Identität hängt an einer nicht fixierten Term-Ordnung [schema/compiler.md:60] — **Option 1 umgesetzt:** Pkt. 3b auf reine Lexikografie (LC_ALL=C) gehoben; Term-Auftritt nur für Verarbeitungsreihenfolge (Rev-2.7)
- Befund: Pkt. 3b ordnet Stufe-a-Treffer „in der Reihenfolge des ziehenden Terms, dann lexikografisch als deterministischer Tie-Break bei identischem Ort", während Pkt. 1c mehrere Terme je Einheit erlaubt. Die Reihenfolge der **Terme selbst** (Auftreten in der Evidenz? lexikografisch? §2-Interpretations-Reihenfolge?) ist nirgends festgelegt — zwei rechtmäßige Term-Ordnungen erzeugen zwei rechtmäßige, aber unterschiedliche Listen. Zusätzlich ist die Formulierung intern doppelt definiert („Reihenfolge des ziehenden Terms" vs. „innerhalb jeder Stufe lexikografisch aufsteigend").
- Optionen: **1 (empfohlen)** — Pkt. 3b auf eine eindeutige Regel heben: Stufe-a-Treffer **rein lexikografisch (LC_ALL=C)**, Term-Auftritt dient nur der Verarbeitungs-/Interpretations-Reihenfolge, nicht der Listen-Ordnung (einfachste deterministische Form, kompatibel mit der „lexikografisch als Tie-Break"-Klausel). **2** — Term-Ordnung = lexikografisch über die gezogenen Terme, Stufe-a-Treffer in Term-Ordnung, dann lexikografisch (bewahrt die „Zuwachs-Sicht"-Semantik, ist etwas komplexer zu implementieren und zu beweisen).
- [x] [Review][Decision] `canonical-terms.md`-Registry-Lookup-Semantik ist unvollständig — Doppelbelegung von Varianten ist nicht deterministisch auflösbar, Lookup-Reihenfolge (vor/nach Kollaps, Groß/Klein) ist offen [schema/canonical-terms.md:25-35] — **Option 1 umgesetzt:** Lookup-Reihenfolge fixiert (normalisierte Form) + Eindeutigkeits-Invariante + Konflikt-Verfahren (Rev-2.7)
- Befund: (a) Zwei Einträge können dieselbe Schreibvariante mit unterschiedlichen canonischen Formen tragen — der Registry-Format-Abschnitt definiert keine Eindeutigkeits-Regel (kein „Variante in genau einem Eintrag", kein Konflikt-Verfahren; der „Append-only"-Regel-Abschnitt behandelt nur Umbenennungen). (b) Die Normalisierungs-Reihenfolge ist offen: lowercasing + `[-_ ]`-Kollaps **vor** dem Registry-Lookup? Lookup auf der rohen Variante? Die Varianten-Spalte ist als „bündel-findend per `-`-Kollaps, lowercased" beschrieben, aber die verbindliche Lookup-Operation steht nicht da. Genau das ist der Kern des deterministischen Resolvers (AD-17h).
- Optionen: **1 (empfohlen)** — in `canonical-terms.md` Registry-Format ergänzen: (i) Lookup-Reihenfolge fixiert (lowercase → Kollaps → Lookup auf der normalisierten Form; die Varianten-Spalte trägt ebenfalls normalisierte Formen), (ii) Eindeutigkeits-Invariante „eine Variante in genau einem Eintrag" + Konflikt-Fall (Append nicht erlaubt; `deferred-work.md`-Handoff / Ask-First analog zur bestehenden Umbenennungs-Regel). **2** — nur (ii) ergänzen; (i) als `defer` an die nächste Registry-Befüllung (erstes Entry).
- [x] [Review][Patch] `run-sandbox.sh`: T1 (Membership-Pin) und T4 (Vereinigung) werden nur ausgegeben, nie als Pass/Fail geprüft — das gepinnte „exakte Candidate-Liste"-Verhalten (Task 4) wird nicht erzwungen [run-sandbox.sh:80-113, 136-141] — **umgesetzt:** T1/T4 tragen harte Asssertionen (`exit 1` bei Abweichung)
- Befund: T1 gibt die Candidate-Liste und „Erwartet: AUSSCHLIESSLICH 'alpha'" aus, vergleicht aber nie; T4 gibt `alpha, gamma` (gesortet) aus, prüft aber nicht gegen die Erwartung. Ein Regressions-Fall (z. B. `log` oder `index` rutscht in die Liste, oder `gamma` fehlt) beendet das Skript mit Exit 0 und „Sandbox abgeschlossen (alle 4 Tests)". T3 (NO_MATCH) und T2 (Zwei-Run-Identität) haben dagegen echte `if`-Checks mit `exit 1`.
- Fix: T1 `out=$(terms 'deterministische-relevanz-bestimmung' | normalize); [ "$out" = "alpha" ] || { echo "FAIL: …" >&2; exit 1; }`; T4 `out=$(terms '…' | normalize | LC_ALL=C sort | paste -sd, -); [ "$out" = "alpha,gamma" ] || { echo "FAIL: …" >&2; exit 1; }`.
- [x] [Review][Patch] Typos/Fehlzeichnungen im committeten normativen Text — `Determinsmus` (×4+ in `compiler.md`/`log.md`/`deferred-work.md`/Spec), `§3.2-beankert` (soll „§3.2-angeankert" sein), `Membrum` (soll „Mitglied" sein), `Konventionelle Determinismus-Lücke` (soll „Bekannte Determinismus-Lücke" sein — verweist auf `compiler.md:53`, wo es „Bekannte" heißt) [schema/compiler.md:351,373; wiki/log.md:5; deferred-work.md:342; spec:80,93,106] — **umgesetzt** (reiner Text-Patch; `raw/`-Source-Typo und der präexistierende `außschließlich`-Typo im 3.1-Log bleiben unberührt — out-of-scope)
- Befund: Keine AC-Auswirkung, aber der Text ist die committete Instruktion/der committete Nachweis. `Determinsmus` steht auch in der Source `raw/epics/` (3×), die Instruktion sollte den Begriff aber konsistent korrekt verwenden, wie es der Rest des Dokuments tut. `Resovierung` (spec:80,106) ist zusätzlich zu `Resolution`/`Auflösung` zu korrigieren.
- Fix: orthografische Korrektur in den genannten Zeilen (reiner Text-Patch, keine Semantik-Änderung).
- [x] [Review][Defer] `§3.2`-Pkt.-2a: Wortgrenzen-/Frontmatter-Scope der Stufe-a-Match-Semantik ist offen (Substring-Match ohne `\b`, Frontmatter-Treffer zählen mit) [schema/compiler.md:55] — deferred, pre-existing
- [x] [Review][Defer] `§3.2`-Pkt.-1b-ii: Kollaps bei aufeinanderfolgenden/führenden/trailenden Separatoren ist unbestimmt (`a--b`, `-x`) [schema/compiler.md:51] — deferred, pre-existing
- [x] [Review][Defer] Stufe-a-Treffer auf `index.md`-Pfade (z. B. T2 `index`) werden nicht deterministisch aus der finalen Candidate-Liste entfernt (Stufe-b-Re-Routing implizit, nicht fixiert) [schema/compiler.md:55-56] — deferred, pre-existing
- [x] [Review][Defer] Rev-2.5-/Rev-2.6-Log-Zeile und compiler.md-Revisionslog: Nachweis-Klärigungen ohne Semantik-Auswirkung — (a) Rev-2.5-Log-Zelle zitiert die (nun historisch korrigierte) `rg --exclude`-Form im aktiven Mechanismus-Teil, ohne eigene Inline-Korrektur (Rev-2.6-Zelle erklärt es nur), (b) `last_updated: 08-19-2026 07:10` liegt vor dem Commit-Zeitpunkt (09:16), (c) Rev-2.6 steht im Revisionslog **über** Rev-2.5 (chronologisch umgekehrt), (d) Validator-„7/7 SUCCESS" als Aggregat ohne per-Datei-Liste, (e) Rev-2.6-`git status`-Beleg listet `canonical-terms.md`/`_bmad-output/`-Änderungen nicht (nämte „`git status`" als Prüfgrundlage), (f) Formel-4-Ist-Zählung `38` ohne Baseline-`≡`-Partner (re-executiert: Ist = 38, korrekt; nur der Beleg-String ist unvollständig) [wiki/log.md:4-5; schema/compiler.md:372-373; sprint-status.yaml:32] — deferred, pre-existing
## Spec Change Log
- **2026-08-19 (bmad-code-review Loop 3 — Review-Findings umgesetzt; 5 Decisions (alle Option 1) + 2 Patches + 4 Defers):** `schema/compiler.md`**Revision 2.7**: (1) **D-4** — §3.2-Pkt.-3b-Ordnung auf **reine Lexikografie (LC_ALL=C)** gehoben; die Term-Verarbeitungsreihenfolge bestimmt nur die Interpretation/Erhebung, **nicht** die Listen-Ordnung (dieselbe Treffermenge → identische Liste, AD-17h/A0-19); (2) **D-5**`schema/canonical-terms.md`: **Lookup-Verfahren** deterministisch fixiert (lowercasing → `[-_ ]``-`-Kollaps → Lookup der **normalisierten** Form; Spalten tragen ausschließlich normalisierte Formen) + **Eindeutigkeits-Invariante** (jede normalisierte Form in genau einem Eintrag — Canon oder Variante, nie beides/zweimal) + **Konflikt-Verfahren** (keine stille Anhängung; `deferred-work.md`/Ask-First, analog zur Umbenennungs-Regel); (3) **D-1** — Statuskette `in-progress → done` als eigener dokumentierter Schritt in `wiki/log.md` (Sprint-Sync-Konvention; Story-3.1-Präzedenz); Key bleibt `done`; (4) **D-2 + P-1**`run-sandbox.sh` um **T5** `LINK_FOLLOWING_ZYKLUS` (A↔B-Zyklus; besuchte Menge → endlich/doppelungsfrei), **T6** `TRAVERSAL_REACH_ONLY` (Term nur in Area-`index.md` → gewurzelte Concept-Pfade), **T7** `TERM_ABLEITUNG_SYNONYM` (Registry-Test-Doppel; beide Lookup-Pfade + Negativ-Fall) erweitert; T1/T4 mit harten Asssertionen; T2-Kommentar korrigiert; re-executiert: **alle 7 Tests PASS, exit 0**; (5) **D-3**`wiki/log.md`-Selbsttest-Beleg (b) gegen die echte `run-sandbox.sh`-Ausgabe neu belegt (neue Log-Zeile, append-only; Rev-2.5-Zeile historisch unverändert); (6) **P-2** — Typos korrigiert (`Determinsmus``Determinismus`, `beankert``angeankert`, `Membrum``Mitglied`, `Konventionelle``Bekannte`, `Resovierung``Auflösung`; `raw/`-Source und der präexistierende 3.1-Log-Typo bleiben unberührt). **4 Defers** (Wortgrenzen-/Frontmatter-Scope; Separator-Kollaps-Reichweite; Stufe-a-`index.md`-Treffer aus finaler Liste; Rev-2.5/2.6-Beleg-Klärigungs-Bündel) in `deferred-work.md` (append-only, Sektion „Deferred from: code review of spec-3-2-… (2026-08-19)"). **Keine AC-Änderung, kein frozen-Schnittstellen-Change, kein Validator-/Vertrags-/`raw/`-Change (AD-3), keine neue §7-Klasse, kein Standalone (D-3).** Frontmatter: `status: 'done'`, `review_loop_iteration: 3`. `sprint-status.yaml`: Key `3-2-…` bleibt `done`, `last_updated` → 08-19-2026.
- **2026-08-19 (bmad-code-review Loop 2 — bad_spec-Loopback):** 5 bad_spec-Findings ausgelöst, Code-Änderungen auf Baseline revertiert, nicht-gefrorene Spec-Tail-Sektionen geamendet:
- **B1/VG-1 `log.md`-Kontamination:** `rg -l '<term>' wiki/` ohne `--exclude=log.md``log.md` wird ab dem Moment selbst „Kandidat", in dem ein Log-Eintrag den Term zitiert; der Determinismus-Selbsttest verankert das A0-18-1-File-Find in einem Commit, das selbst `A0-18` enthält (Stale-Evidenz; Reproduzierbarkeits-Claim widerlegt sich selbst). Bekannt-bös: permanente Drift + falsches Verification-Expect.
- **B2 Reihenfolge:** `rg -l`-Ausgabe-Reihenfolge (FS-Traversal) nicht auf Zuwachs-Sicht-Ordnung abbildbar; Stufe-b/c ohne definierte Position. Bekannt-bös: AC-2-Zwei-Run-Identität nur bei undokumentiertem `rg`-Tie-Break.
- **B3 Resolver nicht enumeriert:** „eine canonische Form je Semantik" ohne committete Registry → Determinismus nicht pinbar. Bekannt-bös: gleiche Liste nur, wenn Resolver Teil des Git-States (nicht spezifiziert).
- **B4 Em/En-Dash:** Klassenliteral `[-_ ]` deckt nur En-``, nicht Em-`—`; Kollaps-Reichweite inkonsistent. Bekannt-bös: Em-Varianten fallen nicht unter den Kollaps (Synonymlücke). **Gewählter Weg:** `-`-Kollaps bleibt; explizite `—`-Auflösung wird als offene Determinismus-Lücke in Step-4-Defer an Story 3.8 übergeben (nicht stillschweigend hinzugefügt).
- **B5 §8-A0-19-Claim:** Spec sagte „A0-19 steht bereits in §8", war im Ist-Baum nicht kommutiert; Implementierung ergänzte A0-19 (korrekt). Spec korrigiert, A0-19-Ergänzung als KEEP verankert (fehlleiten bei Re-Baseline verhindern).
- **B6 NO_MATCH / §5.9-P2-Block-Scope:** werkt zusammen → zusammengefasst; in B1 und Task-Patch-Membership-Pin überführt.
- **B7 §5.9-P2-Block-Zeiger:** nicht mehr nötig — die fixierte Stufe (a) `--exclude=log.md` macht den Zeiger redundant (kein log.md-Kandidat mehr); **verworfen** (keine unnötige Pflicht).
- **KEEP-Instruktionen (müssen Neu-Ableitung überleben):** neue §3.2-Sektion nach §3 etc.; alle 6 I/O-Matrix-Szenarien; Determinismus-Vertrag (identische Reihenfolge, KEEP: nur-Parallel = deterministisch-MECHANISMUS, NICHT zufällig); `--exclude=log.md`-Stufe-a; Determinismus-Selbsttest MIT Membership-Pin (Zwei-Run-Identität + Mengen-Genauigkeit) und `canonical-terms.md`-Resolver as Resolver im Git-State; `Wiki/log.md` als append-only (Story-3.1-Bullet bleibt eigenständig stehen); die A0-19/Schema-Referenz ergänzen. NOT-KEEP: Spec-A0-19-Formulierung „steht bereits" (korrigiert).
- Restliche patch- und defer-Findings (B6/NO_MATCH, B5/Doppel, Log-Selbsttest-Beleggenaue, F17+Em-Morphologie-Story-3.8) werden in der Step-4-Patch-Runde umgesetzt bzw. in `deferred-work.md` nachbestätigt.
## Design Notes
**Warum §3.2 als eigene Sektion statt Streckung in Pkt. 2:** §3 ist heute eine nummerierte Liste (Pkt. 13); der Story-3.2-Vorbehalt sitzt IN Pkt. 2. Die feinkörnige Mechanik (Term-Ziehverfahren, Kanonisierungs-Resolver, dreistufige Erhebung, Determinismus) ist zu umfangreich, um Pkt. 2 verständlich zu halten. Design-Entscheidung: **neue Sektion §3.2 „Relevanzbestimmung (Story 3.2)"** direkt nach §3 — Pkt. 2 bleibt der Kern-Anker („Erhebung nach §3.2"), die Komplexität wird ausgelagert, bestehende §5.9-Pkt.-6-Bindungen bleiben gültig. Nur falls der §3-Aufbau eine andere Einfüge-Stelle nahelegt (z. B. Pkt. 2a), wird das Label angepasst — Pkt. 2 bleibt in jedem Fall der verbindliche Einstieg.
**Term-Ziehverfahren — was deterministisch heißt:** Die Ziehung ist deterministisch, weil sie allein von der committeten Evidenz-Datei abhängt: (1) bedeutungstragende Fachbegriffe = Token-Folgen mit fachlicher Signifikanz, aus der §2-Interpretation benannt (nicht freie LLM-Auswahl); (2) Normalisierung über einen canonischen Schreibweisen-Resolver (lowercasing; `[-_ ]``-`; eine canonische Form je Semantik); (3) mehrere Terme je Einheit erlaubt — Candidate-Liste = Vereinigung der Treffer über alle Terme, bereinigt über besuchte Menge; (4) kein stiller Ausschluss: nicht auflösbare Varianten werden wie notiert verwendet. Die Erhebung *mit festem Term* war schon in Rev-2.4.2 deterministisch — Story 3.2 macht zusätzlich die **Term-*Auswahl*** deterministisch (exakt der bisherige Vorbehalt).
**Determinismus-Referenz:** AD-17h und A0-19 sind bereits Normreferenzen in §8 Revision 2.4 (Story 3.1); Story 3.2 ergänzt **AD-13**, **A0-18** und **PRD OQ-3** (Architekturfrage „Compilation Scope"). A0-19 war im Ist-§8 (Baseline `e3e7ec3`) zwar nicht gelistet — die Implementierung fügt es als Determinismus-Referenz der Relevanzbestimmung hinzu (kein Verstoß, Design-KEEP: A0-19-Anker wird in §8 **und** §3.2 gesetzt; die frühere Spec-Formulierung „steht bereits" war falsch und ist hiermit korrigiert). `wiki/knowledge-kompilation-inkrementell.md:48` referenziert A0-18/AD-13 bereits; **zur Erhebung wird `wiki/log.md` ausgeschlossen** (`--exclude=log.md`, §5.6-Muster) — sonst wäre der eigene `log.md`-Eintrag bei jedem Term, den er zitiert, selbst „Kandidat" (A0-18/FR-12-Fall; die Candidate-Liste ist auf Concept-Pfade definiert, §5.9 Pkt. 5 behandelt `log.md` gesondert als erlaubtes Mitglied).
**Determinismus-Selbsttest (Membership + Identität):** Der Selbsttest prüft nicht nur Zwei-Run-Identität, sondern zusätzlich, dass die Ausgabe **Mengen-Genauigkeit** hat (nur Concept-Pfade, `log.md` ausgeschlossen) — er wird gegen einen mini-Sandbox-Baum ausgeführt, der einen realen Term auf Concept-Bodies und `log.md` verteilt und die exakte Candidate-Liste als erwartete Ausgabe pindet. Damit ist die Stale-Verifikations-Falle („das Artefakt widerlegt sich selbst") geschlossen.
## Verification
**Commands (re-executierbar, ab Workspace-Root):**
1. **Vorbehalts-Auflösung:** `grep -n "Story 3.2 vorbehalten" schema/compiler.md` liefert **keinen** Treffer mehr (beide Vorbehalte aufgehoben: §3 Pkt. 2 + §7).
2. **Neue Sektion:** `grep -n "Relevanzbestimmung\|3.2" schema/compiler.md` liefert die neue §3.2-Sektion; §7-Vorbehalt enthält „3.2" nicht mehr; §8 trägt Revision 2.5 + 2.6 (Patch-Runde: §4-Kopf, rg-tool-korrekte Formen).
3. **Determinismus-Selbsttest (Membership + Identität):**
- `rg -l '<term>' -g '!log.md' wiki/` (rgs native Glob-Exklusionsform; `--exclude` ist kein rg-Flag — das GNU-grep-Äquivalent ist `grep -rl '<term>' --exclude=log.md wiki/`) zweimal ausführen, Ausgaben **identisch** — deterministische Erhebung ohne `log.md`-Kontamination; z. B. `rg -l 'A0-18' -g '!log.md' wiki/` → genau `wiki/knowledge-kompilation-inkrementell.md` (ein Concept-Pfad, `log.md` ausgeschlossen); `rg -l 'A0-18' wiki/` **ohne** Exklusion hingegeben würde `wiki/log.md` mit-treffen (Selbstkontamination — genau der ausgeschlossene Fall).
- mini-Sandbox-Baum (`_bmad-output/implementation-artifacts/sandbox-3-2/`, re-executierbar via `bash run-sandbox.sh` — Term auf Concept-Bodies **und** `log.md` verteilt): exakte Candidate-Liste (nur Concept-Pfade) wie erwartet; Normalisierung Strip `wiki/` + `.md` → relative OKF-Pfade; zwei aufeinanderfolgende Läufe liefern byte-identische Ausgaben (Zwei-Run-Identität, AD-17h).
4. **Validator-Lauf:** alle `wiki/`-Dateien SUCCESS (unverändert; reine Text-Instruktion, human-mechanisch ausgeführt, D-3) — per-Datei-Verdikt als Ausführungs-Nachweis im `log.md`-Eintrag.
5. **Resolver-Materialisierung:** `schema/canonical-terms.md` existiert (committete, append-only Registry: canon. Form + erlaubte Varianten); `grep -n "canonical-terms" schema/compiler.md` liefert die §3.2-Referenz. <br>_(Optionale Em-Dash-Prüfung: die Normalisierungs-Klasse deckt `-` ab; explizite `—`-Varianten-Auflösung ist eine erkannte Determinismus-Lücke → Story 3.8, s. Spec Change Log.)_
**Manual checks:**
- §3 Pkt. 2 zeigt auf die neue §3.2-Mechanik; Term-Ziehverfahren + Kanonisierungs-Resolver textuell benannt; Candidate-Liste als relative OKF-Pfade ohne `.md`; Determinismus-Vertrag in der Instruktion; `compiler.md` §8-Revision 2.5 + 2.6 mit Abschlussklausel; kein `schema/validator.md`-/`schema/wiki-compiler.md`-/`raw/`-Diff; §7-Vorbehalt ohne „3.2"; `wiki/log.md`-Eintrag datiert mit Story-3.2-Semantik, Determinismus-Beleg, Statuswechsel `backlog → in-progress → done` (Patch-Note Rev 2.6 oben), per-Datei-Verdikt; `deferred-work.md`-epic-3-context-Eintrag als aufgegriffen markiert + Em-Dash-Defer (Story 3.8); `sprint-status.yaml` konsistent (`3-2-…` → done).