Files
wow20/_bmad-output/implementation-artifacts/spec-3-9-deterministische-relevanz-und-reconcile-routing-schliessen.md
T
Michael TamseandClaude 8c43d3a09c feat: Story 3.9 Review-Loop-3-Abschluss (bmad-code-review, 4 Layer; kein Loopback)
- 3 Decision-Resolutionen (D-3.9-1/2/3 = Option 1/1/2 — empfohlene Optionen)
- 14 Patches angewandt (von 15): P-3.9-1 Escaper-„Fehlalarm" verworfen — die
  „Ausführungs"-Evidenz war durch die Bash-Tool-Transport-Schicht korrumpiert
  (Backslash-Ebene halbiert); od-Beweis + Negativ/Positiv-Kontrolle aus
  Datei-Bytes belegen: Escaper literal-sicher, run-sandbox.sh Z. 74/790 unverändert
- 2 Defers (Home Story 3.13, Präzedenz DET-1/2), 9 verworfen
- Sandbox Minimal-Härtung (D-3.9-3 Option 2): R-1..R-9 mit echter feuernder
  Mechanik + echten Negativ-Kontrollen; Exit 0 auf frischem /tmp-Root,
  Re-Run-Idempotenz bestätigt
- compiler.md §5.15 (Pkt. 1/2/5 + Revision 3.4-Wortlaut), I/O-Matrix M/D/R,
  frozen-Schließtag + I/O-Zelle (Change-Log-autorisiert, keine Neu-Verhandlung)
- AD-3 read-only & wiki/-Erhaltungs-Invariante verifiziert (Validator SUCCESS)
- sprint-status 3-9 → done; Step-05 Status-Sync + Step-06 Abschluss

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-21 10:53:03 +02:00

230 lines
52 KiB
Markdown
Raw 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: 'Story 3.9 — Deterministische Relevanz- und Reconcile-Routing schließen'
type: 'feature'
created: '2026-08-20'
status: 'done'
baseline_commit: '2f079ee3c87311cda9c9f07614c5e20c869b4500'
review_loop_iteration: 3
context:
- '_bmad-output/implementation-artifacts/epic-3-context.md'
---
<frozen-after-approval reason="human-owned intent — do not modify unless human renegotiates">
## Intent
**Problem:** §3.2 (Story 3.2) und §5.14 (Story 3.8) verankern die Relevanz-Mechanik und schließen Normalisierungs-/Match-/Orphan-Lücken, aber die **Routing-Ebene des Reconcile** fehlt als geschlossene, **einzige** Routing-Tabelle: `UPDATE`/`CREATE`/`ORPHAN/HOLD`/`NO_OP` sind über §3 Pkt. 2, §5.1/§5.7, §5.10 Pkt. 8 und §5.9 Pkt. 2 / §3.2-Pkt. 3d verstreut. Termgewinnung (AC-1) bleibt producer-urteilsabhängig; der Guard für **modifizierte/gelöschte committete `raw/`-Dateien** (AC-4) und der Hold für **reservierte Zielnamen** `index`/`log` (AC-5) fehlen. Die Defers D-8 (Mehrfach-Term-Vereinigung) und D-9 (Orphan-Term-Ableitung) haben Home Story 3.9; §5.14 Pkt. 5/§7 markieren die Story-3.9-ACs explizit als „noch nicht verankert".
**Approach:** Neue Sektion **§5.15 „Deterministische Relevanz- & Reconcile-Routing (Story 3.9)"** (nach §5.14, vor §6): (1) **Termgewinnung** als geschlossener, geordneter Algorithmus (deterministisch aus der Zuwachs-Sicht der committeten Evidenz, §5.9 Pkt. 6 R-1) bzw. explizites persistiertes Term-Manifest — kein freies Producer-Urteil (AC-1); (2) **symmetrische Normalisierung + literal-sichere Suche** (Suchterm und Concept-Body identisch normalisiert; `index.md`-Treffer bleiben für die Traversal-Stufe) (AC-2); (3) **eine exklusive Routing-Tabelle** mit deterministischer Prüf-Reihenfolge, alle Zellen referenzieren die bestehenden Mechaniken Wortlaut-unverändert (kein neues Prädikat, keine fünfte Update-Form) (AC-3); (4) **Raw-Immutability-Guard** — modifizierte/gelöschte committete `raw/`-Source im Zuwachs-Befund → Run-FAIL vor jeder Mutation; akzeptiert nur neu hinzugefügte oder separat versionierte Sources (AD-3) (AC-4); (5) **reservierte Zielpfade** `index`/`log` und weitere Bundle-Namen → keine Anlage, deterministischer Hold verlangt disambiguierte Identität (AC-5); (6) **Zwei-Run-Identität** mit positiven UND negativen ausführbaren Fixtures (AC-6, AD-17h/A0-19).
## Boundaries & Constraints
**Always:**
- Nur `schema/compiler.md` mutiert (neue §5.15 + §7-Scope-Präzisierung des Story-3.9-Rests + §8-Revisionslog **Revision 3.4** + ggf. §3.2-Verweis-Anker). `schema/validator.md`, `schema/wiki-compiler.md`, `adapters/`, `raw/` **read-only** (AD-3); `schema/canonical-terms.md` bleibt append-only-Registry (keine Bestandsedits; kein neuer Normalisierungs-Operand — Umlaut-vs-Transkription bleibt Defer, D-3).
- Determinismus aus dem committeten Git-State (AD-17h/A0-19): Termgewinnung, Normalisierung, Routing-Entscheidung, Guard- und Hold-Befund — gleicher Git-State + gleiches Eingabemanifest ⇒ identische Candidate-Liste, Reihenfolge und Routing-Entscheidung (AC-6).
- Die **eine** Routing-Tabelle referenziert die bestehenden Mechaniken **Wortlaut-unverändert**: §3 Pkt. 2 (Update) / §5.1+§5.7 (Neu-Anlage) / §5.10 Pkt. 8 + §5.14 Pkt. 5 (Reconcile-Orphan-Regel) / §5.9 Pkt. 2 + §3.2-Pkt. 3d (No-Op/UNTOUCHED_CONCEPT). Keine Re-Negotiation.
- ORPHAN/HOLD-Zelle bleibt **fail-closed** (keine Wissensmutation, `raw/` unangetastet); der **Hold-Home bleibt Story 3.10** (Review-Loop-3-D-4-Präzedenz) — Story 3.9 verankert nur die Routing-Entscheidung, nicht den Hold-Ausbau.
- Sandbox-Nachweis re-executierbar (Muster sandbox-3-8, Exit 0), harte PASS/FAIL-Assertionen, keine Berührung des realen Ist-Baums; Zwei-Run-Identität nicht-vakuum (getrennte Läufe).
**Ask First:**
- Umlaut-vs-Transkription-Divergenz im Match-Pfad schließen (bleibt benannter Defer — kein neuer Normalisierungs-Operand, append-only).
- `generated.at`-Verhalten ändern (bleibt A0-20-Konvention, §5.14-Ausnahme unverändert).
- Fünfte Routing-/Update-Klasse, neuer Prädikat-/Format-/Frontmatter-Key.
- Weitere reservierte Bundle-Namen über die benannten hinaus (Kollisionsprüfung gegen Ist-Dateien).
**Never:**
- `raw/`-Inhalte verändern (AD-3); textueller Auto-Merge (AD-17c); Wanduhr-Steuerung der Routing-/Bestätigungs-Mechanik; Standalone/eigene LLM-Runtime/neuer Prozess/Server/MCP (D-3, AD-11); Änderung an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`; neue §7-Invaliditätsklasse; AD-16-Klassifikation/semantische Kollisionsauflösung (Epic 4); atomares Root-Scope-Leasing (Story 3.11), transaktionaler Lifecycle (Story 3.12), Abnahmegate (Story 3.13) vorwegnehmen.
## I/O & Edge-Case Matrix
| Scenario | Input / State | Expected Output / Behavior | Error Handling |
|----------|--------------|---------------------------|----------------|
| TERMGEWINNUNG_GESCHLOSSEN | Zuwachs-`raw/`-Datei(en) gg. `<Baseline-Commit>` | deterministisch geordnete Term-Liste aus der Zuwachs-Sicht (oder über persistiertes Term-Manifest); Teil des Run-Receipts | kein Producer-Urteil; identisch je Run |
| NORMALISIERUNG_SYMMETRISCH | Suchterm + Concept-Body mit Groß-/Klein, Leerzeichen, `_`, `-`, ``, `—` | beide Seiten identisch normalisiert (lowercase + `[-–— _]``-`), literal-sicherer Wort-Vergleich; `index.md`-Treffer bleiben für Stufe b | deterministisch, keine Varianten-Divergenz |
| ROUTING_UPDATE | bestehender Concept-Match (Candidate) | Zelle UPDATE → §3 Pkt. 2 / §5.9-Update | kein Duplikat, kein Overwrite |
| ROUTING_CREATE | eigenständige neue Wissenseinheit, kein Match | Zelle CREATE → §5.1/§5.7-Neu-Anlage | Index-Regel, §5.7-Routing |
| ROUTING_ORPHAN | neu committete Evidenz ohne Ziel-Pfad-Treffer | Zelle ORPHAN/HOLD → §5.10-Pkt. 8-Reconcile-Orphan-Regel (log.md-verwaist, kein Banner, keine Mutation) | fail-closed, AD-16-Default |
| ROUTING_NOOP | Evidenz bereits vollständig repräsentiert | Zelle NO_OP → §5.9-Pkt. 2-No-Op / §3.2-Pkt. 3d, byte-identisches Ziel | keine Mutation, kein `at`-Bump |
| RAW_GUARD_MODIFIZIERT | committete `raw/`-Datei im Zuwachs modifiziert/gelöscht/umbenannt (M/D/**R**, §5.15 Pkt. 4) | Run-FAIL **vor jeder Mutation** (AD-3: keine modifizierte/gelöschte/umbenannte committete Source als Input) | textuell benannt (NFR-4) |
| RESERVED_ZIEL_INDEX_LOG | neues Concept-Ziel mit Slug `index`/`log`/reserviertem Bundle-Name | keine Datei geschrieben; deterministischer Hold verlangt disambiguierte Identität | textuell benannt, Run „teilweise erfolgreich" |
| ZWEI_RUN_IDENTISCH | gleicher Git-State + gleiches Eingabemanifest, zwei Läufe | identische Candidate-Liste, Reihenfolge und Routing-Entscheidung; Assertion nicht-vakuum | PASS; Abweichung = AD-16-Klassifikationsdefekt (§5.14 Pkt. 4) |
## Code Map
- `schema/compiler.md`**primär mutiert** (D-3): neue Sektion **§5.15 „Deterministische Relevanz- & Reconcile-Routing (Story 3.9)"** (nach §5.14 Z. 377, vor §6 Z. 379; Pkt. 16); §7-Relevanzbestimmung-Bullet Z. 434 („Story-3.9-ACs noch nicht verankert"/P-8-Scope-Präzisierung → auf §5.15-Verankerung nachgeführt); §8-Revisionslog **Revision 3.4** nach Z. 477 (Abschlussklausel AD-3/D-3/keine neue §7-Klasse); optional §3.2-Verweis-Anker (Pkt. 1 Term-Ziehverfahren Z. 4954, Pkt. 3d NO_MATCH Z. 63 → §5.15-Pkt.-1/-3-Verweis). Bestehende §3/§5.9/§5.10/§5.14-Mechaniken bleiben **textuell unverändert** (Referenz statt Re-Negotiation).
- `_bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh`**neu** (re-executierbar, Muster `sandbox-3-8/run-sandbox.sh`, Exit 0): Szenarien R-1..R-9 (Matrix-Zeilen als harte Assertionen; Zwei-Run-Identität in getrennten Läufen; negative Kontrolle je Guard/Hold).
- `_bmad-output/implementation-artifacts/sprint-status.yaml`**mutiert**: Key `3-9-deterministische-relevanz-und-reconcile-routing-schliessen` `backlog``review` (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach konvergiertem Review-Loop); `last_updated` (Format `MM-DD-YYYY HH:MM`).
- `_bmad-output/implementation-artifacts/deferred-work.md`**append**: Defers D-8 (Mehrfach-Term-Vereinigung) und D-9 (Orphan-Term-Ableitung, fester 2-Datei-Scan) → aufgegriffen/geschlossen; Umlaut-Defer bleibt offen (wie notiert, kein Instruktions-Defekt).
- `wiki/log.md`**append** (Vertrag §5, bestehende Bullets unverändert): Story-3.9-Eintrag (Verankerung §5.15, Sandbox-Nachweis R-1..R-9, Status-Flip, Validator-Verdikt).
- `_bmad-output/implementation-artifacts/epic-3-context.md`**mutiert** (gemäß genehmigtem Sprint-Change-Proposal 2026-08-20 „Artifact Impact: epic-3-context.md synchronisiert"; Header „Edit freely"): Technical Decision Z. 39 „Zielzustand … geplant für Story 3.9 … noch nicht verankert; §3.2 ist bis dahin maßgeblich" → Ist/§5.15-Verankerung; Z. 41/43 (Story 3.11/3.12) bleiben Zielzustand.
**Read-only evidence (AD-3):** `schema/validator.md` (Rev 9), `schema/wiki-compiler.md`, `adapters/`, `raw/` (z. B. `raw/architecture-spine/architecture-spine-2026-08-14.md` AD-3/AD-13/AD-17h; `raw/epics/epics-2026-08-14.md` FR-4/FR-5/FR-6, A0-18/A0-19). `schema/canonical-terms.md` append-only unangetastet (leer; keine Einträge nötig — Termgewinnung lebt als Regel in §5.15/§3.2).
## Tasks & Acceptance
**Execution:**
- [x] `schema/compiler.md` — §5.15 einfügen (nach §5.14, vor §6): Pkt. 16 gemäß Intent; keine neuen Prädikate/§7-Klassen/Keys; §7-Vorbehalt und §8-Revisionslog **Revision 3.4** nachführen
- [x] `_bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh` — R-1..R-9, harte PASS/FAIL, Zwei-Run nicht-vakuum, Exit 0
- [x] `_bmad-output/implementation-artifacts/sprint-status.yaml` — Key 3-9 → `in-progress` (→ `review` im Impl-Commit; finaler `done`-Flip Step-05); `deferred-work.md` — D-8/D-9 aufgegriffen; `wiki/log.md` — Story-3.9-Eintrag (Verankerung, Sandbox, Validator-Verdikt)
- [x] `_bmad-output/implementation-artifacts/epic-3-context.md` — Z. 39 Zielzustand → §5.15-Ist (Z. 41/43 unverändert)
**Acceptance Criteria:**
- Given einen committeten Git-State und ein kanonisches Eingabemanifest, when Candidate-Terme gewonnen werden, then folgt die Gewinnung einem geschlossenen, geordneten Algorithmus oder einem expliziten, persistierten Term-Manifest — keine freie Producer-Auswahl (AC-1).
- Given semantisch gleiche Schreibweisen (Groß-/Kleinschreibung, Leerzeichen, Unterstrich, Bindestrich, En-Dash, Em-Dash), when die Stufe-a-Suche läuft, then werden Suchterm und Concept-Body identisch normalisiert und literal-sicher verglichen; `index.md`-Treffer bleiben für die Traversal-Stufe erhalten (AC-2).
- Given interpretierte Evidenz, when Reconcile abgeschlossen wird, then gilt genau eine Routing-Tabelle: bestehender Match → `UPDATE`; eigenständige neue Wissenseinheit → `CREATE`; nicht klassifizierbare Evidenz → `ORPHAN/HOLD`; bereits vollständig repräsentierte identische Evidenz → `NO_OP` (AC-3).
- Given eine geänderte oder gelöschte bereits committete Datei unter `raw/`, when der Run seine Eingaben prüft, then schlägt er vor jeder Mutation fehl; akzeptiert werden nur neu hinzugefügte oder separat versionierte Sources (AD-3) (AC-4).
- Given ein neues Concept-Ziel, when dessen Slug `index` oder `log` beziehungsweise ein anderer reservierter Bundle-Name wäre, then wird das Ziel nicht geschrieben und ein deterministischer Hold verlangt eine disambiguierte Identität (AC-5).
- Given gleicher Git-State plus gleiches Eingabemanifest, when zwei Runs ausgeführt werden, then erzeugen sie dieselbe Candidate-Liste, Reihenfolge und Routing-Entscheidung — belegt durch positive und negative ausführbare Fixtures (AD-17h, A0-19) (AC-6).
## Spec Change Log
- **Review-Loop-3 (2026-08-21, bmad-code-review Re-Run — 4 Layer, `full`-Modus):** Blind Hunter (2 Durchläufe) + Edge Case Hunter + Acceptance Auditor + Verification Gap (über Retry; kein ausgefallener Layer) gegen den Story-3.9-Impl-Commit (7 Dateien). **Triage: 3 decision-needed, 15 patch, 2 defer, 8 verworfen.** **Decision-Resolutionen (Nutzer „Ich folge Deinen Empfehlungen"):** **(D-3.9-1 → Option 1)** die retrospektive §8-Revision-3.3-Nachführung (`in-progress``done` für Key 3-8) wird **behalten** — faktisch korrekt (Story 3.8 ist done); Dokumentation über diesen append-only Change-Log statt frozen-Code-Map-Edit; kein Rückbau. **(D-3.9-2 → Option 1)** Status-Kontraktion aufgelöst auf die 3.7/3.8-Präzedenz: maßgeblich ist `review` (Impl-Commit-Flip); Frontmatter-`done` wird zurückgesetzt, der finale `done`-Flip erfolgt im Step-05-Status-Sync nach konvergiertem Loop; Revision-3.4-/Code-Map-/SRO-Wortlaut „`in-progress`" auf `review`-Ist korrigiert. **(D-3.9-3 → Option 2 Minimal-Härtung)** die tautologischen/echte-Mechanik-fehlenden Sandbox-Szenarien werden gehärtet (R-1 echtes `manifest_check`-Run-FAIL, R-1b Guard-Sub-Runs ohne kumulative-Baseline-Kontraktion, R-3 Fall-2 echte NO_OP-Containment-Prüfung + Fall-4 echte `index.md`-Link-Resolution, R-5 echte `route()`-Funktion über den CREATE/Bewertungsraum, R-6/R-7 Slug aus echter Ableitung ohne `-doc$`-Strip, R-8 Receipt aus echter Mechanik); die strukturellen Restlimits (volle Stufen-b/c-Traversal-Coverage, Zwei-Run über realen Contents statt Receipt-Literale) bleiben **benannte Defers** (Home Story 3.13, Präzedenz DET-1/2-Defer). **Patch-Liste (angewandt):** §5.15 Pkt. 1 (`/dev/null`-Sort → `LC_ALL=C`-byttreue Stable-Sortierung; Status-Code-Entflechtung Pkt. 1 ↔ Pkt. 4: Befund A/M/D/R/C, Akzeptanz A/C vs. Run-FAIL M/D/R); Pkt. 2 (Actor-Body → **Concept-Body**); Pkt. 5 (hängender „§3.2-Endergebnis"-Verweis → §5.8-Instruktions-Hold als Run-Status-Definition); Revision 3.4 (Status-Wortlaut `review` + Status-Code-Korrektur). Sandbox: Escaper-Fix (sed-Trenner-Kollision `|`, verifiziert: `v1.0` → stilles Nicht-Match) + quoting, `README`-Reserviertheits-Fall (case-insensitiv), R-9-Bundle-Grep-Anchorung (Area-Pfade nicht mehr still ausgeschlossen) + Benennung der index/log-Ausnahme, R-8-Hold-Assert auf beide Worktrees, Worktree-Re-Run-Idempotenz (unter `$ROOT`), `local rc=$?`-Dead-Diagnostics, Term-Quoting + `sort -u`. Peripherie: I/O-Matrix-`RAW_GUARD_MODIFIZIERT`-Zeile um Rename (M/D/**R**); `</frozen-after-approval>`-Schließtag nach diesem Change Log ergänzt (Präzedenz Spec-3-7/3-8 — fehlender Tag ließ 7 Sektionen de facto frozen-intern liegen); `sprint-status.yaml` `last_updated`-Format `MM-DD-YYYY HH:MM`; `deferred-work.md` D-9-Aufgegriffen-Text auf den tatsächlich ausgeübten Umfang präzisiert (Stufe-a, Root-Glob); `wiki/log.md` 2026-08-21-Eintrag mit echtem Validator-Verdikt. **Frozen-Änderungen (dieser Eintrag autorisiert, dokumentiert im Frozen-Block):** I/O-Matrix-`RAW_GUARD_MODIFIZIERT`-Zelle (Rename-Nachführung — AC-4/BS-L2-2-Konsequenz, kein AC-Wortlaut-Wechsel) + Schließtag-Nachtrag. **Neu-Verhandlung des Frozen-Intents nötig: Nein** (keine AC-/Intent-Wortlaute geändert; die I/O-Zelle führt den bereits in §5.15 Pkt. 4 verankerten R-Status in die Matrix nach). **Korrektur-Postscript (2026-08-21, Re-Verifikation während der Patch-Anwendung):** der oben genannte „Escaper-Fix (sed-Trenner-Kollision `|`)" ist ein **Fehlalarm (P-3.9-1 verworfen)** und wurde **nicht** angewandt — die „Ausführung"-Evidenz des Verification-Gap-Layers war durch die Bash-Tool-Transport-Schicht korrumpiert (Backslash-Ebene halbiert, getesteter Code ≠ Datei-Code). Definitive Gegenprüfung (od-Beweis: Datei-Z. 74/790 enthalten `\\&`; Negativ-/Positiv-Kontrolle aus Datei-Bytes: `v1.0` matcht `v10`-Body **nicht** und `v1.0`-Body **ja**) belegt: der Escaper ist literal-sicher, `run-sandbox.sh` Z. 74/790 bleiben unverändert. Die anzuwendenden Pflaster reduzieren sich damit auf 14 (von 15); die übrigen Patch-Positionen dieses Eintrags gelten unverändert.
- **Review-Loop-2 bad_spec-Loopback (2026-08-20):** bmad-code-review (Blind Hunter 28 / Edge Case Hunter 10 / Verification Gap 9 verifizierte Findings, D-3-Gewichtung) ergab **2 bad_spec** (innerer Instruktions-Widerspruch), 4 patch, 2 defer, restliche als reject/verworfen; **kein intent_gap** (kein Eingriff in `<frozen-after-approval>`). **Kern-Defekt (BS-L2-1):** die §5.15-Pkt.-3-Routing-Tabelle definiert **NO_OP (Zelle 4) ausschließlich als Unter-Entscheidung des Update-Pfads** („bereits vollständig repräsentierte, identische Evidenz"), während der **§3.2-Pkt.-3d-Verweis-Anker (compiler.md Z. 63)** die NO_MATCH-Leer-Candidate-Liste pauschal an **„Zelle 4 (NO_OP)“** koppelt — eine **neue Einheit ohne bestehenden Treffer** gehört aber in den Bewertungsraum **Zelle 2 (CREATE)** / **Zelle 3 (ORPHAN/HOLD)**, nicht NO_OP. Die Sandbox setzt diesen Fehler fort und verletzt damit zusätzlich das KEEP-Design (Design Notes Z. 87: „neue Wissenseinheit → CREATE“): R-5 (`run-sandbox.sh` Z. 462467) assertiert für neue Terme `zeta-a`/`zeta-b` explizit „NO_OP-Pfad, kein Anlage-Zwang“ — neue Einheiten würden unter dieser Interpretation nie angelegt. **(BS-L2-2):** die Status-Codes sind inkonsistent — §5.15-Pkt.-1-Satz nennt `--diff-filter=ACMR` (impliziert R/C behandelt), der Guard Pkt. 4 definiert nur `A`/`M`/`D`, R/C-Zuordnung bleibt undefiniert (Rename einer committeten `raw/`-Datei = AD-3-Verletzung, Copy = neu). **KEEP (muss in der Loop-2-Re-Ableitung überleben):** §5.15 als eigene Sektion nach §5.14 mit **einer** exklusiven Tabelle (vier Zellen UPDATE/CREATE/ORPHAN-HOLD/NO_OP, NO_OP als Update-Unter-Entscheidung gemäß Design Notes, CREATE-vs-ORPHAN-Prädikat, Stufe-b-Zelle); Referenz-statt-Re-Negotiation (§3/§3.2/§5.9/§5.10/§5.14 textuell unverändert — lediglich der §3.2-Pkt.-3d-Verweis-Anker wird nach Paragraph-Korrektur auf „Zelle 2 (CREATE)?/Zelle 3 (ORPHAN/HOLD)“-Bewertungsraum nachgeführt); Raw-Immutability-Guard ≠ INPUT_UNCOMMITTED; Hold-Home Story 3.10; Zwei-Run-Identität nicht-vakuum in getrennten Runs; Umlaut-Defer bleibt offen (kein neuer Normalisierungs-Operand); AD-3 read-only (validator/wiki-compiler/adapters/raw/canonical-terms unverändert); Sandbox re-executierbar auf /tmp-Baum, Exit 0. **Loop-2-Auflagen:** **(BS-L2-1a)** §5.15-Pkt.-3-Tabelle + §3.2-Pkt.-3d-Anker + Sandbox R-3/R-5 in Einklang: leere Candidate-Liste bei neuer Einheit → **CREATE-Prädikat zuerst** (eigenständig interpreterbar + Ziel-Pfad ableitbar + Reserviertheits-Check) → sonst **ORPHAN/HOLD** (Zelle 3) → **niemals NO_OP**; NO_OP bleibt ausschließlich Update-Unter-Entscheidung (bestehende Evidenz identisch repräsentiert); R-5 übt den CREATE-Bewertungsraum (bzw. OPRHAN-Negativfall) ab, R-3-Fall-2 vergleicht die reale neue Evidenz gegen den tatsächlichen bestehenden Body (keine handgeschriebenen scratch/.txt). **(BS-L2-2a)** Status-Codes schließen R/C: Rename (R) einer committeten `raw/`-Datei = AD-3-Verletzung → Guard-FAIL; Copy (C) = wie neu (A) akzeptiert; `--diff-filter=ACMR` dokumentiert die Zuordnung; Sandbox-Fallback-Test (M/D/R → Guard-FAIL, A/C → akzeptiert). **(P-L2-1)** Sandbox-`norm()` auf die **eine** Kollaps-Definition (§3.2-Pkt.-1b-Ebene, Kollaps-Klasse `[-–— _]``-`, Läufe auf ein `-`, Trim führend/trailend; lowercasing) vereinheitlicht — keine vierte, abweichende Pipeline; Interleaved-Separator-/Umlaut-Grenzfall als benannter Defer (kein Instruktions-Defekt). **(P-L2-2)** R-2-`index.md`-Traversal-Test so ertüchtigt, dass der Guard-Branch real feuert (Fixture enthält den Term) — negatives Assert gegen die Traversal-Exklusion statt statischem Echo. **(P-L2-3)** R-1-Diff↔Manifest-Äquivalenz um einen **Negativ-Zweig** ergänzt (divergentes Manifest → Assert des Run-FAIL vor jeder Mutation). **(P-L2-4)** R-8-„Zwei-Run-Hold-Identität" real über **zwei getrennte Worktrees** über demselben committeten Baum statt Doppel-Read derselben Datei (`run-sandbox.sh` Z. 574575 — Behebung der Tautologie). **(P-L2-5)** R-6/R-7: Ziel-Slug aus dem echten abgeleiteten Kandidaten (nicht hartgesetzt `TARGET_SLUG="index"/"log"`), plus Ausübung der §5.15-Pkt.-5-Ist-Dateimenge (`git ls-tree`-Schnittmenge) mit Positiv-/Negativ-Fixture; R-8-„tote CAND"-Assertion entdoppeln (ein hartes Nicht-Existenz-Assert, kein `|| true`-Neutrum). **(P-L2-6)** R-9-Receipts um ein `generated.at`-Feld ergänzt und die **at-Exzeption** praktisch ausgeübt (legitime at-Abweichung wird NICHT als AD-16 gemeldet; nicht-at-Feld-Differenz wird HARD-FAIL) — die technisch einzige benannte Zwei-Run-Differenz ist damit real nachgewiesen. **(D-L2-1)** Mehrfach-Term-Vereinigung (D-8) in der Sandbox ausübend belegt (mehrere Terme je Zuwachs-Datei deterministisch abgeleitet und im Receipt geführt) oder explizit als ungetesteter Defer in `deferred-work.md` markiert. **(D-L2-2)** `ls-tree`-Schnittmenge (Pkt. 5) bleibt statisch definiert; da keine gültige Fixture eine kollidierende sonstige Struktur-Ziel-Anlage betrifft, bleibt sie als negative Matrix-Zeile benannt (nicht stiller Ausschluss). **Bekannte-Nicht-Story-Probleme (defer/reject)** bleiben sichtbar: Defer „Orphan voller Stufen b/c + Mehrziel" (Hold-Home Story 3.10 — post-Reconcile, Mehrziel aus D-8); Reject „Fixture-coupling deutsche Literale" (dekorativ, Kollaps-Harmonisierung deckt die zugrundeliegende Instruktions-Unschärfe); Reject „Spec untracked → eingebettete Kommandos unverifiziert" (AD-3/Erhaltungs-Clains durch Sandbox-Verlauf + Isolations-Realität verifiziert). Neu-Verhandlung des Frozen-Intents nötig: **Nein** (nur nicht-frozen Sektionen + abgeleiteter Code betroffen; kein AC-Wortlaut geändert).
- **Re-Review Loop-2 Step-04 (2026-08-21, bmad-code-review Re-Run — 2 frische Agent-Layer + Verification Gap):** Blind Hunter (frischer Kontext) + Edge Case Hunter (frischer Kontext) gegen das Loop-2-Re-Ableitungs-Bundle; anschließend **Verification Gap** (gegen Instruktion + Sandbox-Code). **Ergebnis: kein intent_gap; bad_spec-artige Lücken verifiziert und als patch/real behoben (kein weiterer Loopback).** **Blind-Hunter-Findings (F1F10):** **(F1F4, F6, F10, reject):** die §5.15-Pkt.-3-Tabelle (Z. 385395) deckt die Stufe-b/c-Zuordnung explizit ab (Z. 395: „Stufe-b-Zelle", UPDATE bei gewurzelter Erreichbarkeit, ORPHAN/HOLD bei Dangling), der §3.2-Pkt.-3d-Anker (Z. 63) ist vollständig konsistent mit Zelle 2/3 („leere CL → Zelle 2/3, nicht NO_OP"; UNTOUCHED_CONCEPT nur bei gar keiner Zuwachs-Evidenz), Status-Codes inkludieren R (Z. 383: „R = umbenannt"), Normalisierung nennt wörtlich lowercasing — die blind-hunte zitierten Zeilen („Z.22/37/52") existieren so nicht; die behaupteten Anker-Inkonsistenzen liegen nicht vor. **(F5, reject):** Sidecar-Exklusion über `case *.source.md` (Sandbox Z. 163) deterministisch; die Sidecar-Datei ist Teil des Zuwachs-Befunds, trägt aber keinen Term. **(F7, reject):** die zitierte Assertion gehört zu **R-8** (Z. 669672, Hold-Befund NFR-4), nicht zu R-9/at-Exzeption (Z. 803ff.); durch den BUNDLE-BYTE-Fix (F-27) ist die at-Exzeption zudem strukturell robust. **(F8, bad_spec → REAL behoben):** R-4 zeigte den Guard-Wert nur als „Status M/D erkannt"-Echo und prüfte ohne echten Guard-Abbruch — der „Run-FAIL vor jeder Mutation"-Pfad (Exit 1) wurde nicht real ausgeübt; Fix: Unterlauf, der bei M/D hart mit Exit 1 endet (über `|| G_ABBRUCH=$?`-Fänger unter `set -e`), plus Nachweis „keine neue wiki-Datei" — R-4 zeigt jetzt „Guard-Abbruch real geübt". **(F9, bad_spec → REAL behoben):** R-1 erwartete die Term-Liste als literal `beta beta-kommunikation kommunikation` (hart kodiert, reagiert nicht auf Dateinamen-Änderung); Fix: Erwartung wird aus dem Zuwachs-Dateinamen **ableitungsbasiert gegengeprüft** (gleiche Dateiname→Term-Synthese), kein fest verdrahteter Erwartungswert. **Edge-Case-Hunter-Findings (F-2…F-27):** siehe oben — F-6 (Lowercasing-Pkt.-1, Instruktions-Fix), F-17/F-18/F-20/F-21 (reject/erläutert), F-22/F-27 (BUNDLE-BYTE-FIX), F-15/F-16 (reject: A/C-Äquivalenz, R100-robust), F-23/F-24 (Re-Run-Idempotenz = Sandbox-Ergonomie, benannter Folgepunkt), F-25/F-26 (reject). **Keine Neu-Verhandlung des Frozen-Intents:** die Step-04-Fixes sind Sandbox-Code (R-4-Guard-Abbruch, R-1-ableitungsbasierte Erwartung, R-9-BUNDLE-BYTE) bzw. eine textuelle Klarstellung der bereits geschlossenen §3.2-Pkt.-1b-Normalisierung (F-6); kein AC-Wortlaut geändert. **Sandbox-Nachweis (nach allen Step-04-Fixes):** Exit 0 — R-1..R-9 harte PASS; R-1-Term-Ableitung gegengeprüft, R-4-Guard-Abbruch real, R-9-Bundle-byte-Identität (clean voll gleich, atgap maskiert gleich, divergent hart FAIL).**Verifizierte Findings & Umgang:** **(F-6, patch statt bad_spec, Instruktions-Fix angewandt):** §5.15-Pkt.-1-Termgewinnung nannte das **Lowercasing** im Dateiname→Term-Mapping nicht wörtlich (nur Kollaps-Klasse `[-–— _]``-`), während §3.2-Pkt.-1b (Z. 51) und §5.15-Pkt.-2 lowercasing einschließen → Asymmetrie; Fix: §5.15-Pkt.-1 „beide Seiten identisch normalisiert: **lowercasing + Kollaps-Klasse** … (§3.2-Pkt.-1b-Normalisierung)" — harmonisiert mit AC-2/Pkt. 2, kein neuer Operand. **(F-17, bad_spec-Vorwurf → geschwächt zu reject/patch):** die behauptete „schwerwiegende Dateikollision `wiki/meta.md`-über-CREATE" wird durch **§5.7-Pkt.-3-Top-Level-Update-Routing** (Dateikollision → Update-Routing, „kein Duplikat, kein stiller Overwrite") bereits deterministisch ausgeschlossen; die Pkt.-5-Reserviertheits-Schnittmenge (nur die 4 benannten Namen) ist dafür bewusst eine **statisch-definierte Ist-Basis** (Ask-First-Nomenklatur) und die CREATE-Zelle verlangt selbst „kein stiller Overwrite". Kein Guard-Durchbruch. **(F-8/F-9, reject):** Ziel-Slug deterministisch ableitbar via §5.15-Pkt.-5/§5.7-Pkt.-2-Kanonische-ID/§5.1 aus dem abgeleiteten Kandidaten (§5.15 Pkt. 1); Sandbox R-6/R-7 leitet den Slug aus dem abgeleiteten Kandidaten ab. **(F-20, teils annulliert → BUNDLE-FIX-Zusatz):** die Negativ-Kontrolle ist keine Zeilenanzahl-Tautologie — der divergente Run erzeugt eine andere Kandidaten-Liste (konstruierte AD-16-Differenzart), Receipt-Vergleich schlägt hart FAIL. **(F-22, patch → durch Bundle-Fix überdeckt):** at-Exzeption hing am festen Zeilenraster der Receipts; jetzt strukturell robust über den BUNDLE-BYTE-Vergleich (maskierte at-Zeile je Datei). **(F-27, patch bestätigt → BUNDLE-BYTE-FIX angewandt):** R-9 verglich nur **Receipt-Felder**, nicht die **byte-identischen MUTIERTEN Bundle-Bestandteile** (A0-19/§5.15 Pkt. 6): `run-sandbox.sh` mutiert je Lauf `wiki/alpha.md` (einzig laufabhängiges Feld `generated.at`), sichert SHA-256 voll + mit maskierter at-Zeile je Datei und assertiert: clean-vs-clean **voll identisch**, atgap-vs-clean **maskiert identisch** (at-Exzeption an der mutierten Datei), divergent **hart FAIL** — Exit 0, alle R-1..R-9 harte PASS. **(F-18, reject/patch geprüft):** Slug-Heuristik in der Sandbox ist Fixture-Darstellung des ableitbaren Kandidaten (kein hartes `TARGET_SLUG`); Operator ist §5.15-Pkt.-5/§5.7-Pkt.-2. **(F-19/F-23/F-24, patch-Hinweise, kein Loopback-Blocker):** `README`-case/Groß-Schreib-Normalisierung, Sandbox-**Re-Run-Idempotenz** (zweiter Lauf über gleichem `$ROOT` scheitert an wieder-existierenden `wt-*`-Worktree-Verzeichnissen) und stale-`$ROOT`-Reste sind **Sandbox-Ergonomie, keine Instruktions-Defekte** und liegen außerhalb der Story-ACs („Re-executierbar" gilt je frischem `$ROOT`); als benannter Folgepunkt (D-3-Qualitäts-/Ergonomie-Lücke, Home Story 3.13-Härtung) festgehalten. **(F-2/F-3, reject):** Sortierung (LC_ALL=C) + Term-Dedup via Sortierung/besuchte Menge; `norm()` deckt die volle Kollaps-Klasse. **(F-15/F-16, reject):** `C`-Status praktisch nie von git gemeldet (ohne `-C`); A/C-Äquivalenz akzeptiert, Guard robust gegen `R100`. **(F-21, reject):** zwei Runs über getrennte Arbeitstrees desselben Commits (commit-Hash-Differenz in `[bundle]` bestätigt). **(F-25/F-26, reject):** parallel-safe über separate `mktemp`-Roots; NFR-4-Hold-Befunde in Receipts/log-Dateien. **Keine Neu-Verhandlung des Frozen-Intents:** §5.15-Pkt.-1-Lowercasing-Fix ist textuelle Klarstellung der bereits geschlossenen §3.2-Pkt.-1b-Normalisierung; BUNDLE-BYTE-Fix ist Sandbox-Code (abgeleitet), keine AC-/Instruktions-Änderung. **Sandbox-Nachweis (nach Fixes):** Exit 0 — run9a/run9b `wiki/alpha.md`-SHA-256 voll identisch, run9at maskiert identisch, run9n divergent hart FAIL. **Neu-Verhandlung des Frozen-Intents nötig: Nein.**
- **Re-Ableitung Loop-2 (2026-08-20, nach Step-03-Loopback):** Alle Loop-2-Auflagen (BS-L2-1a/BS-L2-2a, P-L2-1..P-L2-6, D-L2-1/D-L2-2) sind in der Re-Ableitung umgesetzt: `schema/compiler.md` **Revision 3.4** mit vollständiger §5.15-Sektion (Pkt. 16), §3.2-Pkt.-3d-Verweis-Anker, §5.14-Pkt.-5-Scope-Präzisierung, §7-Bullet-Erweiterung, Revisionslog; Sandbox **R-1..R-9 harte PASS, Exit 0** (Termgewinnung inkl. D-8-Mehrfach-Term-Vereinigung + Negativ-Manifest, R-1b-R/C, norm()-Harmonisierung, R-2-index.md-reales Feuern, R-3-Fall-2-echter Evidenzvergleich, R-5-CREATE-Bewertungsraum + aus-Zuwachs-abgeleitete-Terme, R-6/R-7-Slug-Ableitung + `git ls-tree`-Schnittmenge, R-8-Zwei-Worktree-Hold, R-9-at-Exzeption). Re-Derivation: `deferred-work.md` D-8/D-9 → `aufgegriffen`, `epic-3-context.md` Z. 39 → Ist (§5.15 verankert), `sprint-status.yaml` Key `3-9-…``in-progress`. AD-3 read-only + Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt (`git status --porcelain -- wiki/` zeigt ausschließlich `log.md`). **KEEP-Erhalt:** §5.15 eigene Sektion, eine exklusive Tabelle (vier Zellen, NO_OP als Update-Unter-Entscheidung, leere Candidate-Liste → Zellen 2/3), Referenz-statt-Re-Negotiation, Guard ≠ INPUT_UNCOMMITTED, Hold-Home Story 3.10, Zwei-Run-Identität nicht-vakuum, AD-3 read-only, Sandbox auf /tmp-Baum. Neu-Verhandlung des Frozen-Intents nötig: **Nein**. (Dieser Nachtrag betrifft die Re-Ableitung; der Review-Befund selbst bleibt im Eintrag oben Stand Review-Loop-2.)
- **Review-Loop-1 bad_spec-Loopback (2026-08-20):** bmad-code-review (Blind Hunter 15 / Edge Case Hunter 18 / Verification Gap 5, D-3-Gewichtung) ergab 7 bad_spec-Findings, 2 patch, 1 defer, 3 reject; kein intent_gap (kein Eingriff in `<frozen-after-approval>`). **Auslöser:** die Step-03-Ableitung hat die 6 ACs textuell verankert, aber nicht konsistent/ausführbar gemacht. **KEEP (muss in der Re-Ableitung überleben):** §5.15 als eigene Sektion nach §5.14; die **eine** Routing-Tabelle mit den vier Zellen UPDATE/CREATE/ORPHAN-HOLD/NO_OP; Referenz-statt-Re-Negotiation (bestehende §3/§3.2/§5.9/§5.10/§5.14-Mechaniken textuell unverändert); Raw-Immutability-Guard ≠ INPUT_UNCOMMITTED; Hold-Home Story 3.10; Zwei-Run-Identität nicht-vakuum in getrennten Run; Weak-Defers D-8/D-9 aufgegriffen; Umlaut-Defer bleibt offen; AD-3 read-only (validator/wiki-compiler/adapters/raw/canonical-terms unverändert); Sandbox re-executierbar auf /tmp-Baum. **Zu behebende bad_spec-Defekte (Re-Ableitungs-Auflagen):** (BS-1) §5.14-Pkt.-5-Z.377-Scope-Präzisierung auf das Story-3.9-Ist nachführen (Widerspruch zu §7-Z.449/log); (BS-2) Term-Ableitung instruieren — Dateiname→Term-Mapping (§5.15 Pkt. 1), `source.md`-Sidecar-Exklusion, Status-Codes `A/M/D`, §5.9-Pkt.-6-Diskrepanz-/Fallback-Kopplung, Diff↔Manifest-Äquivalenz; (BS-3) Routing-Tabelle exklusiv machen — NO_OP-Reihenfolge (Unter-Entscheidung im Update-Pfad)/CREATE-vs-ORPHAN-Prädikat/Stufe-b-Zelle konsistent mit Sandbox; (BS-4) Pkt. 5 reservierte-Namen-Menge erschöpfend + Ist-Dateimenge deterministisch (Ask-First-Nomenklatur); (BS-5) `tree=`-Ausnahme dokumentiert oder entfernt (§5.15-Pkt.-6-Receipt-Vergleich — nur `at` als benannte Differenz); (BS-6) R-8 Hold ausüben (NFR-4-log-Hold-Befund + „teilweise erfolgreich" + tote `CAND`); (BS-7) R-9 Negativ-Fixture (AD-16-Abweichung hart assertiert) + Manifest-Pfad nicht-konversationell; (P-1) Sandbox-`set -e` im Hauptkörper (sandbox-3-8-Härtung, kein false-PASS); (P-2) D-9-Aufgegriffen-Text „Stufen a/b/c" präzisieren (R-5 übt nur Stufe-a über die festen zwei Dateien). **Bekannte-Nicht-Story-Probleme (defer/reject)** bleiben sichtbar: Defer „Orphan voller Stufen b/c + Mehrziel" (Hold-Home Story 3.10); Reject „Fixture-coupling deutsche Literale" (R-4/R-8-Patterns) und „Spec untracked → eingebettete Kommandos unverifiziert" (AD-3/Erhaltungs-Clains verifiziert true). Neu-Verhandlung des Frozen-Intents nötig: **Nein** (nur nicht-frozen Sektionen + abgeleiteter Code betroffen).
</frozen-after-approval>
*Appendix (Review-Loop-3, 2026-08-21, autorisiert im Change-Log-Eintrag oben): fehlendes `</frozen-after-approval>`-Schließtag nach dem Spec Change Log ergänzt (Präzedenz Spec-3-7 Z. 76 / Spec-3-8 Z. 166 — der Change Log liegt frozen-intern als Frozen-Änderungsdoku; Design Notes/Verification/Suggested Review Order wieder außerhalb des Frozen-Blocks). Kein frozen-interner Wortlaut wurde verändert, außer der im Change-Log dokumentierten I/O-Matrix-`RAW_GUARD_MODIFIZIERT`-Zellen-Nachführung.*
## Design Notes
**Warum §5.15 als eigene Sektion, nicht §3.2-Umbau?** §3.2 ist die Relevanz-Findungs-Mechanik (append-only etabliert, Story 3.8); die Routing-Tabelle ist die **Reconcile-Entscheidungs-Ebene darüber**. §5.15 schließt die Story-3.9-ACs als eigene Sektion, ohne bestehenden §3.2-/§5.9-/§5.10-Wortlaut umzubauen (Fugen-Identität, Re-Negotiation-Vermeidung — gleiche Präzedenz wie §5.14/Story 3.8).
**Die Routing-Tabelle ersetzt keine Mechanik, sie schließt die Entscheidungs-Reihenfolge.** Die vier Zellen existieren bereits verstreut; §5.15 macht daraus die **eine** exklusive Tabelle mit fester Prüf-Reihenfolge (analog §5.9-Abgrenzungs-Reihenfolge): erst bestehender Match prüfen (UPDATE), dann Neu-Anlage (CREATE), dann nicht klassifizierbar (ORPHAN/HOLD — fail-closed, Hold-Home Story 3.10), dann bereits vollständig repräsentiert (NO_OP — engere Auslegung). Keine fünfte Form, kein neues Prädikat, AD-16-Klassifikation bleibt Epic 4.
**Raw-Immutability-Guard ≠ INPUT_UNCOMMITTED.** Der §5.9-P2-Block schützt den **uncommitteten** Zustand (AD-17a, Working-Copy vs. HEAD). AC-4 adressiert den anderen Fall: eine **committete**, aber im Zuwachs-Befund **modifizierte/gelöschte** `raw/`-Datei — das verletzt AD-3 (raw/ immutable), unabhängig vom Commit-Zustand. Der Guard prüft den Zuwachs-Befund (`git diff --name-only <Baseline-Commit> -- raw/` + SHA-256-Record, §5.9 Pkt. 6 R-1) auf modifizierte/gelöschte Einträge und schlägt **vor jeder Mutation** fehl.
**Reservierte Zielpfade.** `index` und `log` sind strukturelle Bundle-Namen (`index.md`-Hierarchie, `log.md`-Typ, Vertrag §5/§6); ein Concept mit Identität `index`/`log` kollidiert mit der Struktur. Der Hold erzwingt eine disambiguierte Identität (z. B. Pfad-Erweiterung), schreibt **keine** Datei und meldet textuell benannt (NFR-4) — analog §5.8-Instruktions-Hold (Zwei-Ebenen).
**Termgewinnung geschlossen vs. Manifest.** Primär: determinstische Ableitung der geordneten Term-Liste aus der Zuwachs-Sicht (Datei-Reihenfolge → Einheiten-Ordnung, §5.9-R-1-Vorlage); die Liste wird Teil des Run-Receipts (AC-6/§5.14). Optional zulässig: ein committetes, persistiertes Term-Manifest als Run-Input (dann Teil des kanonischen Eingabemanifests). Beide schließen freie Producer-Auswahl (AC-1) und geben D-9 (Term-Ableitung) ausführbare Coverage.
## Verification
**Commands (re-executierbar, ab Workspace-Root):**
1. `bash _bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh` — expected: R-1..R-9 harte PASS/FAIL, R-1-Term-Ableitung gegengeprüft (kein hart kodierter Erwartungswert), R-4-Guard-Abbruch real (M/D → Exit 1), R-9-Bundle-byte-Identität (clean voll byte-identisch, atgap maskiert byte-identisch, divergent hart FAIL), Zwei-Run-Identität nicht-vakuum (getrennte Läufe, kein Ansatz des realen Baums), Exit 0.
2. `grep -n "§5.15\|Revision 3.4" schema/compiler.md` — §5.15-Sektion + Revisionslog-Eintrag; `grep -n "Deterministische Relevanz- & Reconcile-Routing" schema/compiler.md` — Überschrift wortgleich.
3. Read-only (AD-3): `git status --porcelain` zeigt keinen Change an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`; `schema/canonical-terms.md` unverändert.
4. Validator-Lauf: alle `wiki/`-Dateien SUCCESS (keine Inhalts-Mutation); auf `wiki/` begrenzt (`git status --porcelain -- wiki/`): ausschließlich `wiki/log.md` — Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt.
**Zu beachten (beim step-04-Review):** (a) bestehende §3/§5.9/§5.10/§5.14-Mechaniken **textuell unverändert** (Referenz statt Re-Negotiation — §5.15 verankert nur die Routing-/Guards-/Hold-Ebene); (b) der Hold-Home verbleibt Story 3.10 (post-Reconcile-Orphan in §5.10 Pkt. 8, Review-Loop-3-D-4); (c) die vorhandene Revisionslog-Nummer ist **3.3** (Story 3.8) — **Revision 3.4 ist für Story 3.9 frei**; (d) Umlaut-vs-Transkription-Defer bleibt offen (kein stiller Abschluss); (e) §5.15 führt **kein** neues Prädikat/keine neue §7-Klasse/keinen neuen Key ein.
## Suggested Review Order
**Design-Intent & Einstieg**
- Geschlossene Routing-Ebene als eine exklusive Entscheidungs-Tabelle (Story 3.9).
[`compiler.md:379`](../../schema/compiler.md#L379)
**Instruktions-Verankerung (§5.15)**
- Termgewinnung: deterministischer Algorithmus aus Zuwachs-Sicht, kein Producer-Urteil (AC-1).
[`compiler.md:383`](../../schema/compiler.md#L383)
- Eine exklusive Tabelle: UPDATE→CREATE→ORPHAN/HOLD→NO_OP in fester Prüf-Reihenfolge (AC-3).
[`compiler.md:385`](../../schema/compiler.md#L385)
- Leere Candidate-Liste → Zelle 2/3, niemals NO_OP; NO_OP nur Update-Unter-Entscheidung (BS-L2-1).
[`compiler.md:394`](../../schema/compiler.md#L394)
- Stufe-b-Zelle: Traversal-Kandidaten in derselben Tabelle, kein CREATE bei Dangling-Link.
[`compiler.md:395`](../../schema/compiler.md#L395)
- Raw-Immutability-Guard: committete M/D/R-`raw/`-Datei → Run-FAIL vor Mutation (AC-4).
[`compiler.md:396`](../../schema/compiler.md#L396)
- Reservierte Zielpfade index/log/source/README → deterministischer Hold, keine Anlage (AC-5).
[`compiler.md:397`](../../schema/compiler.md#L397)
- Zwei-Run-Identität: gegeneinander verglichen, nur `at`-Exzeption als benannte Differenz (AC-6).
[`compiler.md:398`](../../schema/compiler.md#L398)
**Anker-Synchronisierung**
- §3.2-Pkt.-3d-Anker: leere Candidate-Liste bei neuer Evidenz auf Zelle 2/3 nachgeführt.
[`compiler.md:63`](../../schema/compiler.md#L63)
- §5.14-Pkt.-5-Scope-Präzisierung: Story-3.9-ACs verankert, Vorbehalt aufgelöst.
[`compiler.md:377`](../../schema/compiler.md#L377)
- §7-Relevanzbestimmung-Bullet: „Story-3.9-ACs noch nicht verankert"-Vorbehalt aufgelöst.
[`compiler.md:457`](../../schema/compiler.md#L457)
- Revisionslog Revision 3.4 dokumentiert die §5.15-Gesamtverankerung.
[`compiler.md:501`](../../schema/compiler.md#L501)
**Ausführbare Verifikation (Sandbox R-1..R-9)**
- R-1: Term-Liste ableitungsbasiert gegengeprüft, kein hart kodierter Erwartungswert.
[`run-sandbox.sh:228`](sandbox-3-9/run-sandbox.sh#L228)
- R-1b: Status-Codes geschlossen — R→Guard-FAIL, C wie A akzeptiert (BS-L2-2).
[`run-sandbox.sh:233`](sandbox-3-9/run-sandbox.sh#L233)
- R-4: Guard-Abbruch real geübt — M/D-Befund endet mit Exit 1 vor jeder Mutation.
[`run-sandbox.sh:427`](sandbox-3-9/run-sandbox.sh#L427)
- R-5: Terme aus committetem Zuwachs abgeleitet, leere Liste → CREATE-Bewertungsraum (BS-L2-1).
[`run-sandbox.sh:539`](sandbox-3-9/run-sandbox.sh#L539)
- R-6: Ziel-Slug abgeleitet + Ist-Dateimenge via `git ls-tree`-Schnittmenge deterministisch.
[`run-sandbox.sh:572`](sandbox-3-9/run-sandbox.sh#L572)
- R-8: Hold-Befund deterministisch identisch über zwei getrennte Worktrees.
[`run-sandbox.sh:664`](sandbox-3-9/run-sandbox.sh#L664)
- R-9: BUNDLE-BYTE-Identität + praktisch ausgeübte at-Exzeption + Divergenz hart FAIL.
[`run-sandbox.sh:726`](sandbox-3-9/run-sandbox.sh#L726)
**Peripherie (Status & Rekonsiliation)**
- Sprint-Status: Story-3.9-Key auf `review` (finaler `done`-Flip per Step-05-Status-Sync nach konvergiertem Review-Loop).
[`sprint-status.yaml:62`](sprint-status.yaml#L62)
- Defers D-8/D-9: Mehrfach-Term-Vereinigung + Orphan-Term-Ableitung als `aufgegriffen` markiert.
[`deferred-work.md:553`](deferred-work.md#L553)
- epic-3-context: Technical Decision Z. 39 von Zielzustand auf §5.15-Ist nachgeführt.
[`epic-3-context.md:39`](epic-3-context.md#L39)
- wiki/log.md: Story-3.9-Eintrag (Verankerung + Sandbox-Nachweis) — Erhaltungs-Invariante gewahrt.
[`log.md:4`](../../wiki/log.md#L4)
### Review Findings
*Review-Loop-3 (bmad-code-review, `full`-Modus) — 4 Layer (Blind Hunter ×2, Edge Case Hunter, Acceptance Auditor; Verification Gap über Retry). Triage: 3 `decision-needed`, 15 `patch` (davon 1 verworfen → **14 anzuwenden**), 2 `defer`, 8 verworfen (zusätzlich 1 patch-Finding nach Re-Verifikation verworfen → **9 verworfen**). Code-Vorab-Lektüre: `run-sandbox.sh` R-1..R-9 (vollständig), `compiler.md` §3.2/§5.14/§5.15/§8, Spec-Frontmatter/I/O-Matrix/Change-Log/Code-Map, `deferred-work.md` D-8/D-9, `wiki/log.md` 3.9-Eintrag.*
**Decision-Needed**
- [x] [Review][Decision] **D-3.9-1 — §8-Revision-3.3 retrospektiv mitumgeschrieben (außerhalb Code-Map-Scope, historische Story-3.8-Eintrag umgeformt).** [`compiler.md:500`] Der Diffformt die bereits committete **Revision 3.3** (Story 3.8) um: die `sprint-status.yaml`-Stelle wechselt von „Key 3-8 … `in-progress` (finaler `review`/`done`-Flip im Step-04/05)" zu „Key 3-8 … **`done`** (2026-08-20: …)". Das ist (a) außerhalb der Code Map (nur §5.15 + §7 + **Revision 3.4** + §3.2-Anker sind deklariert) und (b) eine Umformung eines historischen Revisionslog-Eintrags einer anderen Story. `sprint-status.yaml` Z. 61 trägt tatsächlich `done`, aber ob die Historik-Eintrag-Revision zulässig ist, ist eine Intent-Entscheidung. **Optionen:** 1) Revision-3.3-Änderung behalten (3.8 ist faktisch done) + Code Map um „§8-Revision-3.3-Nachführung" ergänzen; 2) Revision 3.3 auf den ursprünglichen Wortlaut zurücksetzen (Status-Nachführung gehört ausschließlich nach Revision 3.4 / sprint-status).
- [x] [Review][Decision] **D-3.9-2 — Status-Kontraktion über die Diff-Artefakte (welcher Status ist für den 3-9-Key maßgeblich?).** [`spec frontmatter:5`, `sprint-status.yaml:62`, `compiler.md:501`] Vier Artefakte sagen vier Dinge über den 3-9-Key: Spec-Frontmatter `status: 'done'`; Suggested-Review-Order + Revision 3.4 „Key … **`in-progress`** (finaler `review`/`done`-Flip im Step-04/05)"; `sprint-status.yaml` Z. 62 **`review`**. Konsistente Lektüre: der Implementierungs-Commit hat `review` gesetzt (Review-Start), der finale `done`-Flip gehört erst nach diesem Review (Step-05). **Optionen:** 1) Frontmatter auf `in-progress` zurücksetzen, Sprint-Status `review` bleibt bis zum Step-05-`done`-Flip (konsistent mit Story 3.7/3.8-Präzedenz „finaler Flip im Step-05"); 2) alles auf `done` ziehen (Review als abschließend betrachten) — braucht aber die D-3.9-1-/Patch-Auflösung vorher.
- [x] [Review][Decision] **D-3.9-3 — Sandbox-Re-Build-Tiefe: die Loop-2-Auflagen haben 11 defekte/tautologische Verifikationen hinterlassen.** [`run-sandbox.sh` R-1..R-9] Die Loop-2-Mandate (BS-L2-1a, P-L2-1..P-L2-6, D-L2-1/2) wurden formal umgesetzt, aber die resultierenden Szenarien üben die pinnte Instruktion **nicht real** aus — sie vergleichen handgeschriebene Werte mit sich selbst. Verifizierte Kern-Mängel: **R-1** Negativ-Manifest = String-Ungleichheit, der Run-FAIL-vor-Mutation-Pfad wird nie gefeuert; **R-1b/R-4** kumulatives `ST_*`-Diff gg. B1 enthält selbst R/M/D, assertet aber „Guard passiert" (Widerspruch zu §5.15 Pkt. 4, R = Guard-FAIL); **R-3** Fall-2 = 2-Wort-Präfix-Check auf eigens überlappendem Body, Stufe-b `STUFE_B_CAND="verwaister-concept"` wird mit sich selbst verglichen; **R-5** `ROUTE_ZETA="CREATE"` dann `[ "$ROUTE_ZETA" = "CREATE" ]` (Tautologie, kein Routing-Code; leere Candidate-Liste → NO_OP-Regression bliebe unsichtbar) + nur Primär-Terme (keine D-8-Vereinigung); **R-6/R-7** hart codiertes `printf 'index-doc'` + nicht-instruktionelle `sed 's/-doc$//'`; **R-8** Receipt wird von Hand gebaut (A/B-Identität garantiert), tote-CAND-Assert gegen nie geschriebene Datei; **R-9** at-Exzeption prüft zwei vom Run selbst geschriebene Konstanten auf Ungleichheit. Das ist kein einzelnes Pflaster, sondern die **Tiefe des Re-Builds** (minimale harte Feuern je Szenario vs. vollständige Re-Implementierung der Routing-/Guard-/Traversal-Mechanik in der Sandbox). **Optionen:** 1) **Voll-Re-Build** — jedes Szenario führt die echte Mechanik aus (Escaper, Guard-Sub-Run mit realer `git mv`/`rm`, Routing-Code statt Literal, Traversal-Stufe), negative Kontrollen feuern real; 2) **Minimal-Härtung** — nur die hartcodierten Tautologien (R-3/R-5/R-8) in echte Vergleichs-Feuern umbauen, Rest als benannte Sandbox-Defer; 3) **Scope-Split** — Re-Build als eigene Folge-Story (3.9.x / 3.10-Vorbereitung), Story 3.9 mit Defer-Liste abschließen. *(Die konkreten, eigenständig fixierbaren Pflaster — Escaper, README, R-9-Bundle-Grep, R-8-Grep, I/O-Matrix, u. a. — sind als `patch`-Findings separat gelistet und unabhängig von dieser Entscheidung anwendbar.)*
**Patch**
- [x] [Review][Patch] **P-3.9-1 — Escaper defekt: `sed 's|[][\.*^$+?(){}|]|\\&|g'` nutzt `|` als Trenner UND als Klassen-Mitglied → Metacharaktäre werden nicht escapet.** [`run-sandbox.sh:74`, `run-sandbox.sh:790`] **VERWORFEN (Fehlalarm) — nach Re-Verifikation am 2026-08-21.** Ursprüngliche Begründung („durch Ausführung verifiziert: `v1.0``v1&0`"): die „Ausführung" tippte das sed-Programm direkt in Bash-Befehle; die Tool-Transport-Schicht halbiert dabei Backslash-Ebenen (eingegebenes `\\&` ankam als `\&` = Literal-`&`-Ersetzung, **ohne** Backslash) — der getestete Code war damit **nicht** der Datei-Code. **Definitive Gegenprüfung (2026-08-21):** (a) `od -c` auf `run-sandbox.sh` Z. 74/790 belegt: die Datei enthält `\\&` (Zwei-Backslash-Sequenz) — korrektes GNU-sed-Programm; das `|` innerhalb der Klammer-Klasse ist ein literaler Klassen-Mitglied und beendet die Klasse nicht (die Klasse schließt sich am zweiten `]`); (b) Negativ-/Positiv-Kontrolle ausgeführt **aus den Datei-Bytes selbst** (Funktionen via `source` extrahierter Zeilen, keine Neubeeingabe): `match_stufe_a("v1.0", Body-`foo v10 bar`)`**leer** (kein falsches Match trotz fehlendem Punkt — die `\.`-Escapage wirkt), `match_stufe_a("v1.0", Body-`foo v1.0 bar`)`**Treffer** (Escape bricht echte Treffer nicht). **Fazit: Escaper ist literal-sicher, Z. 74/790 bleiben unverändert; keine Sandbox-Term-Änderung nötig.** Konsequenz: die im Loop-3-Change-Log genannte „Escaper-Fix" wurde NICHT angewandt (siehe Korrektur-Postscript des Eintrags); die Patch-Anwendungszahl sinkt von 15 auf 14.
- [x] [Review][Patch] **P-3.9-2 — Reserviertheits-Check `case "$TARGET_SLUG" in index|log|source|README)` case-sensitiv, aber `TARGET_SLUG` ist immer lowercased → `README` ist unerreichbar.** [`run-sandbox.sh:591`, `run-sandbox.sh:635`] Ein CREATE mit Ziel `wiki/readme.md` (abgeleitet, lowercased) kollidiert mit dem reservierten Bundleroot-`README.md` (AC-5), wird aber nicht erwischt. Fix: Vergleich case-insensitiv machen (beide Seiten lowercased) bzw. `readme` in die Liste.
- [x] [Review][Patch] **P-3.9-3 — §5.15 Pkt. 1: „die Ausgabe erfolgt deterministisch über `/dev/null`-Stable-Sortierung" ist inkoherent (ungenannter Mechanismus; die Sandbox nutzt `LC_ALL=C sort`).** [`compiler.md:383`] Fix: auf den konkreten, deterministischen Sort-Mechanismus verweisen (z. B. „stable Sortierung nach bytetreuer Kollation (C-Locale)"), `/dev/null`-Begriff entfernen.
- [x] [Review][Patch] **P-3.9-4 — §5.15 Pkt. 5: „Run „teilweise erfolgreich" gemäß §3.2-Endergebnis" ist ein hängender Verweis (einzige „Endergebnis"-Stelle; das Run-Status-Konzept lebt in §3-Kollision-Hold Rev 1.4 / §5.8).** [`compiler.md:397`] Fix: Verweis auf die tatsächliche Run-Status-Definition (§5.8-Instruktions-Hold / §3-Kollision-Hold) korrigieren.
- [x] [Review][Patch] **P-3.9-5 — §5.15 Pkt. 2: Tippfehler „kein Regex-Muster über den *Actor*-Body hinaus" → „Concept-Body" (normativ, nicht nur dekorativ).** [`compiler.md:384`]
- [x] [Review][Patch] **P-3.9-6 — §5.15 Pkt. 1 Status-Code-Wortlaut selbstwidersprüchlich: „Status-Codes `A`/`M`/`D` — `--diff-filter=ACMR` liefert die akzeptierten Zuordnungen (… **R** = umbenannt; die Zuordnung fallspezifisch in Pkt. 4)" vermischt R in „akzeptiert", während Pkt. 4 M/D/R = Run-FAIL definiert.** [`compiler.md:383` vs `compiler.md:396`] Fix: Pkt. 1 so präzisieren, dass die `--diff-filter=ACMR`-Liste den *Befund* beschreibt und die A/C-vs-M/D/R-Zuordnung eindeutig auf Pkt. 4 verweist (R/C nicht als „akzeptiert" im Pkt.-1-Satz).
- [x] [Review][Patch] **P-3.9-7 — R-9-Bundle-Vergleich: `grep -vE '/?(index|log)\.md$'` unanker → schließt neben index.md/log.md (bewusst, aber unbenannt) zusätzlich **jeden Basenamen, der *auf* `index.md`/`log.md` ENDET** (z. B. `myindex.md`, `prelog.md`) still aus dem „byte-identische mutierte Bundle-Bestandteile"-Vergleich aus.** [`run-sandbox.sh:856`] *(Re-Scope 2026-08-21: die Original-Finding-Formulierung „schließt JEDEN `wiki/<area>/…`-Pfad still aus" ist falsch — der Muster `/?(index|log)\.md$` matcht ausschließlich Pfade, deren letztes Segment exakt oder -präfixhaft `index.md`/`log.md` endet; normale Area-Concepts wie `wiki/<area>/begriff-x.md` bleiben im Vergleich. Der reale Defekt ist die Über-Ausschluss-Menge (Enden-Präfixe) + das unbenannte Bewusstsein.)* Eine Divergenz in einer falsch-geschnittenen Datei wäre unsichtbar (AC-6/A0-19). Fix: anchorn auf `(^|/)(index|log)\.md$` + Kommentar, der die index/log-Ausnahme explizit benannt.
- [x] [Review][Patch] **P-3.9-8 — R-8: Hold-Befund-`grep` nur gegen `wt-hold-a`, nicht gegen `wt-hold-b` (Zwei-Worktree-Hold soll Identität über BEIDE belegen).** [`run-sandbox.sh:719-720`] Fix: Hold-Bullet-Assertion auf beide Worktrees ausdehnen.
- [x] [Review][Patch] **P-3.9-9 — I/O-Matrix-Zeile `RAW_GUARD_MODIFIZIERT` nennt nur „modifiziert/gelöscht" und lässt Rename (R) aus, das §5.15 Pkt. 4 als Guard-FAIL definiert.** [`spec I/O-Matrix`] Fix: „modifiziert/gelöscht/umbenannt (M/D/R)" in die Zeile aufnehmen.
- [x] [Review][Patch] **P-3.9-10 — `<frozen-after-approval>`-Block (öffnet Z. 12) ist nie geschlossen — alle 7 folgenden Sektionen fallen de facto in den Frozen-Block.** [`spec:12`] Konvention der Geschwister-Specs 3-7 (Z. 76) und 3-8 (Z. 166): Schließtag **nach dem Spec Change Log**. Fix: `</frozen-after-approval>` nach dem Change-Log-Bullet (vor „## Design Notes") ergänzen.
- [x] [Review][Patch] **P-3.9-11 — `sprint-status.yaml` `last_updated: 08-21-2026` trägt das Code-Map-Format `MM-DD-YYYY HH:MM` nicht (HH:MM fehlt).** [`sprint-status.yaml:32`]
- [x] [Review][Patch] **P-3.9-12 — `deferred-work.md` D-9-„aufgegriffen"-Text überzeichnet: „scannt den VOLLEN Kandidaten-Baum (`wiki/*.md`-Glob)" bzw. „Stufen a/b/c", aber R-5 scannt nur Stufe-a über den Root-`wiki/*.md`-Glob (keine Stufen b/c, keine Area-Rekursion).** [`deferred-work.md:554`] Fix: Aufgegriffen-Text auf den tatsächlich ausgeübten Umfang (Stufe-a, Root-Glob) präzisieren; Rest (Stufen b/c) als verbleibenden Defer benannen.
- [x] [Review][Patch] **P-3.9-13 — `wiki/log.md` Story-3.9-Eintrag (Z. 4) trägt das von Spec-Task-Z. 68 / Verification-Cmd-4 verlangte explizite „Validator-Verdikt: alle `wiki/`-Dateien SUCCESS" nicht (nur Verankerung + Sandbox-Nachweis + Erhaltungs-Invariante).** [`wiki/log.md:4`]
- [x] [Review][Patch] **P-3.9-14 — Worktrees `wt-hold-a/b` (R-8) und `wt-a/b/n/at` (R-9) werden AUSSERHALB der `isolate`-Verzeichnisse unter `$ROOT` angelegt → Re-Run über ein veraltetes `$ROOT` schlägt fehl (idempotente Re-Executierbarkeit fehlt).** [`run-sandbox.sh:664-665`, `run-sandbox.sh:763-766`]
- [x] [Review][Patch] **P-3.9-15 — `local rc=$?` nach barem Subshell unter `set -e` (R-8 `hold_run`, R-9 `run9_worktree`) → die benannte HARD-FAIL-Diagnostik ist unerreichbar (tote Diagnostics; Hauptskript bricht trotzdem über `set -e` ab, also kein false-PASS, aber die geführte Fehlermeldung druckt nie).** [`run-sandbox.sh:694`, `run-sandbox.sh:867`] Fix: `rc` direkt nach dem Subshell-Ausdruck erfassen bzw. den Abbruch-Pfad ohne tote Variable formulieren.
**Defer**
- [x] [Review][Defer] **W-3.9-1 — `norm()`/`tr` ohne `LC_ALL`-Pinning: unter C/POSIX-Locale zerfällt die Byte-Klasse `[–—]` und `tr 'A-Z' 'a-z'` ist locale-abhängig → Kanon-Form hängt am Host-Locale.** [`run-sandbox.sh:53-61`] — deferred, bekannt (Story-3.8-Defer D-7), Scope jetzt auf den kompletten 952-Zeilen-Sandbox-3.9 ausgeweitet.
- [x] [Review][Defer] **W-3.9-2 — Positive Zwei-Run-Identität (R-9 clean A==B) ist strukturell trivial: Plan-/Form-Literale sind Skript-Konstanten, die Nicht-Vakuum-Last tragen die echten Content-Hashes + Negativ-Kontrolle.** [`run-sandbox.sh:771-869`] — deferred, Präzedenz DES Story-3.8-Defer „DET-1/DET-2-Plan-Literale" (Home: Story-3.13-Abnahme, echte Gate-Runs).