---
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
---
## Intent
**Problem:** Die Compiler-Instruktion (`schema/compiler.md` §3 Pkt. 2, Revision 2.4.2) erhebt die Update-Kandidatenliste bisher über einen **platzgehaltenen ``** („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) |
## 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 (`:350–352`): **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`, S1–S6) 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 T1–T4 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 '' 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. 1–3); 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 '' -g '!log.md' wiki/` (rgs native Glob-Exklusionsform; `--exclude` ist kein rg-Flag — das GNU-grep-Äquivalent ist `grep -rl '' --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.
_(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).