§5.15 „Deterministische Relevanz- & Reconcile-Routing (Story 3.9)" in schema/compiler.md (Revision 3.4): geschlossene Termgewinnung (AC-1), symmetrische Normalisierung + literal-sichere Suche (AC-2), eine exklusive Routing-Tabelle UPDATE→CREATE→ORPHAN/HOLD→NO_OP (AC-3, NO_OP als Update-Unter-Entscheidung), Raw-Immutability-Guard M/D/R→Run-FAIL (AC-4), reservierte Zielpfade index/log/source/README→deterministischer Hold (AC-5), Zwei-Run-Identität nicht-vakuum inkl. praktisch ausgeübter at-Exzeption (AC-6). §3.2-Pkt.-3d-Anker, §5.14-Pkt.-5-Scope und §7-Bullet nachgeführt. Review-Loop-2: 2 bad_spec (BS-L2-1 NO_OP-Leere-Candidate-Liste, BS-L2-2 Status-Codes R/C) durch Re-Ableitung behoben; Step-04-Re-Review (2 frische Layer + Verification Gap) ohne neuen Loopback (F-6 Lowercasing-Pkt.-1, F8 Guard-Abbruch real, F9 ableitungsbasierte Term-Erwartung, F-22/F-27 BUNDLE-BYTE-Nachweis angewandt). Sandbox R-1..R-9 PASS, Exit 0. Re-Derivation: deferred-work.md D-8/D-9 aufgegriffen; epic-3-context.md Z. 39 → Ist; sprint-status.yaml Story-3.9 → review. AD-3 read-only + Erhaltungs-Invariante (nur wiki/log.md) gewahrt. Suggested Review Order in Spec 3.9 angehängt. Co-Authored-By: Claude <noreply@anthropic.com>
191 lines
35 KiB
Markdown
191 lines
35 KiB
Markdown
---
|
||
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: 2
|
||
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 | Run-FAIL **vor jeder Mutation** (AD-3: keine modifizierte/gelöschte 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. 1–6); §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. 49–54, 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` → `in-progress`; `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:**
|
||
- [ ] `schema/compiler.md` — §5.15 einfügen (nach §5.14, vor §6): Pkt. 1–6 gemäß Intent; keine neuen Prädikate/§7-Klassen/Keys; §7-Vorbehalt und §8-Revisionslog **Revision 3.4** nachführen
|
||
- [ ] `_bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh` — R-1..R-9, harte PASS/FAIL, Zwei-Run nicht-vakuum, Exit 0
|
||
- [ ] `_bmad-output/implementation-artifacts/sprint-status.yaml` — Key 3-9 → `in-progress`; `deferred-work.md` — D-8/D-9 aufgegriffen; `wiki/log.md` — Story-3.9-Eintrag (Verankerung, Sandbox, Validator-Verdikt)
|
||
- [ ] `_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-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. 462–467) 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. 574–575 — 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 (F1–F10):** **(F1–F4, F6, F10, reject):** die §5.15-Pkt.-3-Tabelle (Z. 385–395) 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. 669–672, 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. 1–6), §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).
|
||
|
||
## 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 `in-progress` (finaler `review`/`done`-Flip per Step-04/05).
|
||
[`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)
|