Files
wow20/_bmad-output/implementation-artifacts/spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen.md
Michael TamseandClaude c234fc361e fix: Story 3.12 Review-Loop-2-Abschluss (bmad-code-review 4 Layer, konvergiert; D-3.12-1 Option 1, 7 Patches, 2 Defer, 6 dismissed; Sandbox L-1..L-9 9/9 harte PASS/Exit 0)
- D-3.12-1 (Nutzer, Option 1): AC-6/§5.18-Pkt.-6-Grenze an log.md-Praxis — dokumentierte
  Run-Nachweise = notwendige Koordinationsereignisse; §5.18/AC-6 textuell unverändert;
  L-8-Guard auf Kategorie-Hyphenate + Negativ-Kontrolle geschärft
- P1: scopelock_healthy() + LOCK_READ_ERROR-Propagation (korrupter Lock nie en-bloc-stale)
- P2: Release-Fehler negativ geübt (L-7), L-6 "valide committet" hart verifiziert
- P3: Setup-Robustheit (Exit-Checks, verifizierter $BASE, Backup-cp byte-identisch)
- P4: L-9 Ghost-Diff-Probe (Index+Worktree), reg_write real geübt
- P5: AC-1-Ownership-Stale positiv getestet, L-2 Takeover-Exactly-once am CAS
- S1: Spec-Struktur (review_loop_iteration 0->1, </frozen-after-approval>, doppelte
  Change-Log-Überschrift entfernt), Status-Sync vereinheitlicht
- S2: SRO-/Code-Map-/deferred-work-Anker auf Ist-Zeilen (takeover Z. 153, L-2 Z. 367,
  L-3 Z. 442, L-7 Z. 648, L-8 Z. 700; §5.18 Z. 426-439, §6 Z. 441, Rev 3.7 Z. 543)
- Defer: DF1 (AC-3-stash-Variante + AC-5 kombiniert, Home 3.13), DF2 (assert_no_wallclock)
- Status: Spec status done, sprint-status Key 3-12 -> done, last_updated 08-22-2026 07:44;
  wiki/log.md Loop-2-Abschlusseintrag (## 2026-08-22)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 08:14:56 +02:00

34 KiB
Raw Permalink Blame History

title, type, created, status, baseline_commit, review_loop_iteration, context
title type created status baseline_commit review_loop_iteration context
Story 3.12 — Lease-Lifecycle und Commit-Abschluss transaktional schließen feature 2026-08-21 done 80480af3ec 1
_bmad-output/implementation-artifacts/epic-3-context.md

Intent

Problem: Die Koordinations-Dimension ist über §5.11 (Leasing/Dirty-Tree, Story 3.5), §5.12 (Staleness/Recovery, Story 3.6), §5.13 (Phasen-Trennung, Story 3.7) und §5.17 (atomare Root-Scope-Lease-Akquise, Story 3.11) verankert — aber die Lifecycle-Klammer fehlt: Akquise, Dirty-Tree-Schutz, Mutation, Rollback und Freigabe sind nirgends als konsistenter, transaktionaler Lebenszyklus instruiert, der SUCCESS und FAIL jeweils einen sauberen, wiederanlaufbaren Zustand hinterlässt. Konkret unverankert: (a) Liveness einer lebenden Lease (eine höhere Generation macht sie nicht stale; Staleness verlangt bestätigten Abbruch oder abgelaufene Liveness plus atomare Ownership-Prüfung — epic-3-context Z. 43 „Zielzustand Review-Loop-3, P-11" und SCP 2026-08-20 Z. 71 „Staleness/Liveness"); (b) durable Release — nach Release sind Mutation, zulässiger Nachweis und Freigabe dauerhaft, Lock entfernt, Worktree sauber, Folge-Run besteht den Clean-Input-Guard; (c) Baseline-Rollback (Index + Worktree) aus dem bezeichneten Baseline-Commit mit leerem Post-Rollback-Diff (§5.3/§6-Pkt.-3-Mechanik nennt nur Bundle-/git checkout-Wiederherstellung, kein Index); (d) eine eindeutige Abort-/Protect-Zustandsmaschine für getrackte und ungetrackte fremde Änderungen (sandbox-3-5 L4 ist nur Inline-Ablauf, keine Zustandsmaschine); (e) stale-Übernahme genau einmal mit ersetzter Holder-ID und genau einer aktiven Root-Lease; (f) Kill-Point-Tests (termini undefiniert, nirgends verankert); (g) die Grenze des kanonischen Knowledge Logs (wiki/log.md nur vertragskonforme fachliche Änderungen + notwendige Koordinationsereignisse).

Approach: Neue Sektion §5.18 „Lease-Lifecycle & transaktionaler Commit-Abschluss (Story 3.12)" (nach §5.17, vor §6; Revision 3.7): additiv über §5.11/§5.12/§5.13/§5.17, Fugen-Identität — kein Umbau bestehender Wortlaute. Sie instruiert den geschlossenen Ablauf (1) Liveness-Ownership (nur bestätigter Abbruch/abgelaufene Liveness + atomare Ownership-Prüfung macht eine Lease stale; eine höhere Generation allein nicht), (2) stale-Übernahme genau einmal (genau eine aktive Root-Lease, ersetzte Holder-ID im log.md), (3) Abort-/Protect-Zustandsmaschine für fremde getrackte/ungetrackte Änderungen (Scratch-Zone scratch/<run-id>/ bzw. git stash push; byte-identischer Restore) samt UNCOMMITTED_INPUT-Abbruch abgestimmt mit §5.11 Pkt. 3, (4) Baseline-Rollback (Index + Worktree aus <Baseline-Commit>; Post-Rollback-Diff leer; Kill-Punkt nach Mutation/Staging), (5) durable Release (Mutation + zulässiger Log-/Koordinationsnachweis committet, Lock per Ref-Delete entfernt, Worktree sauber, unmittelbar folgender Run besteht den Clean-Input-Guard — sauberer Worktree ohne fremde/geschützte Reste), (6) kanonisches Log (§5/Koordination nur), (7) Kill-Point-Tests (vor Mutation, nach Mutation, vor Commit, nach Commit — je konsistenter Endzustand, §5.13-Pkt.-3-Zustands-Restaurations-Invariante).

Boundaries & Constraints

Always:

  • Nur schema/compiler.md mutiert (neue §5.18 + §7-Bullet-Erweiterung Story-3.12 + §8-Revisionslog Revision 3.7). schema/validator.md, schema/wiki-compiler.md, adapters/, raw/ read-only (AD-3); schema/canonical-terms.md append-only unangetastet. sprint-status.yaml, wiki/log.md, epic-3-context.md, deferred-work.md werden nur append/Sync-gepflegt.
  • Referenz statt Re-Negotiation: §5.11 (Pkt. 17), §5.12 (Pkt. 17), §5.13 und §5.17 bleiben textuell unverändert — §5.18 instruiert die Lifecycle-Ebene darüber und referenziert sie Wortlaut-unverändert. Fugen-Identität: Branch-Form lease/<area>/<id>, Lockfile-Feld-Satz, Root-Scope-Umfang §5.11 Pkt. 2, atomarer scope-bezogener Lock §5.17.
  • Kein neues Prädikat, keine neue §7-Invaliditätsklasse, kein neuer Frontmatter-/Format-Key, kein Standalone (D-3), keine Wanduhr-/Systemzeit-Steuerung (A0-20: keine TTL über Kalenderzeit; Lifecycle deterministisch aus dem committeten Git-State, AD-17h/A0-19). Das generated.at-Wanduhr-Gap (§5.14 Pkt. 3) bleibt unverändert.
  • Sandbox-Nachweis re-executierbar (Muster sandbox-3-11, Exit 0, harte PASS/FAIL, /tmp-Baum, nie der reale Ist-Baum; kein Zugriff auf reales Bundle/raw/).

Ask First:

  • Verhalten des generated.at (A0-20) oder eine TTL-/Wanduhr-Steuerung ändern (bleibt benannter Defer bzw. bindend unverändert).
  • Änderung an §5.17-Pkt.-2-Ask-First-Klausel (atomares create-only-Primitiv nicht zuverlässig → HALT, Alternativ-Primitiv).
  • Änderung an §5.11-Pkt.-1-/Pkt.-2-Wortlaut oder §5.12-Ankern (frozen, Fugen-Identität).
  • Erweiterung des schema/validator.md um Lease-/Koordinations-Prüfpunkte (wäre Epic-1-Vertragsänderung — nicht Teil dieser Story).

Never:

  • Kein Umschreiben bestehender §5.11/§5.12/§5.13/§5.17-Wortlaute; keine Wanduhr-TTL; keine stille Löschung fremder uncommitteter/geschützter Änderungen (AD-17e); keine Wissensmutation bei Orphan/Hold (AD-16-Default); kein textueller Auto-Merge (AD-17c); keine neue eigene LLM-Runtime/Workflow-Engine (AD-11, D-3); kein Standalone; keine Validator-Erweiterung ohne Autorisierung.

I/O & Edge-Case Matrix

Scenario Input / State Expected Output / Behavior Error Handling
LIVENESS_AKTIV lebende Lease mit höherer Generation sichtbar Lease bleibt aktiv; keine Stale-werdung allein durch Generationshöhe (AC-1) kein Release, keine Fremd-Übernahme
STALE_UEBERNAHME nachweislich stale Lease (bestätigter Abbruch / abgelaufene Liveness) Übernahme gelingt genau einmal; ersetzte Holder-ID benannt; genau eine aktive Root-Lease (AC-2) Ownership-Prüfung vor Übernahme; kein Doppel-Übernehmer
DIRTY_GETRACKT fremde getrackte Änderung im Mutationsbereich Abort-/Protect-Zustandsmaschine: schützen (Scratch/Stash), Restore byte-identisch nach Run (AC-3) UNCOMMITTED_INPUT-Abbruch abgestimmt §5.11 Pkt. 3; nie gelöscht
DIRTY_UNGETRACKT fremde ungetrackte Datei im Mutationsbereich Protect: sichern + Restore; keine stillen Löschungen (AC-3) nie gelöscht; log.md-Eintrag
ROLLBACK_NACH_MUTATION Fehler nach Mutation/Staging Rollback aus <Baseline-Commit>: Index + Worktree restauriert; Post-Rollback-Diff leer (AC-4) Kill-Punkt nach Mutation: konsistenter Endzustand
ROLLBACK_NACH_COMMIT_VOR_RELEASE Fehler nach Commit, vor Release Kill-Punkt vor Commit/vor Release: Zustand == Baseline oder valide committet; kein Teilzustand veröffentlicht (AC-4) Commit-Boundary = Mutation-Boundary (AD-17f)
RELEASE_DURABLE erfolgreicher Run Mutation + zulässiger Log-/Koordinationsnachweis committet; Lock per Ref-Delete entfernt; Worktree sauber; Folge-Run besteht Clean-Input-Guard (AC-5) Release-Fehler = HARD-FAIL; Lock nie hängend
KANONISCHES_LOG Run-Historie schreiben wiki/log.md nur vertragskonforme fachliche Änderungen + notwendige Koordinationsereignisse; Build-/Review-/Story-/Sandbox-Historie außerhalb (AC-6) Verstoß = textuell benannt (NFR-4)
KILLPUNKT_VOR_MUTATION vor erster Mutation Zustand == Baseline; keine Zwischenstände (AC-7) konsistenter Endzustand, Determinismus
KILLPUNKT_NACH_MUTATION nach Mutation Zustand == valider Zwischenstand (geplanter Plan-Freeze); kein Ghost-Diff außerhalb erlaubter Menge (AC-7) §5.9-Pkt.-5-Ghost-Diff-Rollback
KILLPUNKT_VOR_COMMIT nach Staging, vor Commit nur erlaubte Pfad-Menge staged; kein Teilzustand committet (AC-7) Commit-Boundary = Mutation-Boundary
KILLPUNKT_NACH_COMMIT nach Commit Bundle == valide committeter Zustand; anschließbar an Clean-Input-Guard (AC-7) kein hängender Lock, sauberer Worktree

Code Map

  • schema/compiler.mdprimär mutiert (D-3): neue Sektion §5.18 „Lease-Lifecycle & transaktionaler Commit-Abschluss (Story 3.12)" (nach §5.17 Z. 415424, vor §6 Z. 441; Pkt. 17, Z. 426439); §7-Bullet-Erweiterung (Story-3.12-Verankerung im Leasing-Bullet, Z. 495; §7 bei Z. 486); §8-Revisionslog Revision 3.7 (Z. 543; §8 bei Z. 501, Revisionslog ab Z. 512). Bestehende §5.11 (Z. 304321)/§5.12 (Z. 323342)/§5.13 (Z. 344363)/§5.17 (Z. 415424) bleiben textuell unverändert (Fugen-Identität; §5.17-Pkt.-1-Z. 419 „Lifecycle-Regie Story 3.12" und Pkt.-6-Z. 424 „bleibt Story 3.12" sind die Anschluss-Sutur).
  • _bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.shneu (re-executierbar, Muster sandbox-3-11/run-sandbox.sh 543 Z., Exit 0): Lifecycle-Szenarien L-1..L-9 (12 Matrix-Zeilen als harte Assertionen, Kill-Punkte 1:1 in L-9). Übernahme der 3-11/3-5/3-6-Mechanik (Ableitung, nicht Zeilen-Identität): 3-11-Bausteine (isolate(), scopelock_acquire() create-only, scopelock_release() mit Ownership-Prüfung, scopelock_content() — in 3-12 erweitert um scopelock_healthy()/LOCK_READ_ERROR-Propagation, Loop-2-P1 — und scopelock_takeover() als atomarer Ownership-CAS, Loop-1-PATCH 1; assert_frontmatter(), runlabel/pass/fail), 3-5-Mechanik (Abort-/Protect-Zustandsmaschine aus sandbox-3-5-L4-Inline: Preflight via git status --porcelain inline statt db_check-Helfer, Stash/Scratch-Sicherung, byte-identischer Restore), 3-6-Mechanik (Registry/Gen/Liveness: reg_gen/reg_hold_mark/reg_stale_mark/reg_bump/lease_stale/lease_liveness_stale; free_lease aus 3-6 wird nicht übernommen — Release läuft durch scopelock_release (Ref-Delete, §5.17-Pkt.-1-Modell), reg_write real geübt in L-1), Baseline-Rollback Index+Worktree (via §5.13-Pkt.-3 „Post-Rollback-Diff gg. Baseline leer"), Kill-Point-Tests (4 Konsistenz-Assertions + Ghost-Diff-Probe via inv_viol/assert_invariant, Loop-2-P4), Clean-Input-Guard (Worktree-Sauberkeitsprüfung nach Release). Kein Zugriff auf reales Bundle/raw/.
  • _bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.shread-only Vorbild (Ableitungs-Pflicht: scopelock_release-Ownership, isolate-Ref-Reset, A-8-Relase-erneut Z. 501523; Defer „scopelock_header_banner" Z. 166/175 → Home 3.12).
  • _bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.shread-only Quelle der Dirty-Tree-Mechanik (L4 Z. 379434: db_check Z. 223234, UNCOMMITTED_INPUT-Abbruch Z. 395415, Stash/Scratch Z. 416421, Restore Z. 422425, NIE-gelöscht Z. 426428).
  • _bmad-output/implementation-artifacts/sandbox-3-6/run-sandbox.shread-only Quelle der Registry/Stale-/Recovery-Mechanik (Registry Z. 216245, Gen Z. 219224/246256, lease_stale Z. 277283, Stale-Mark/Übernahme Z. 257264/346478, raw/-Recovery STALE-4 Z. 451478, assert_no_wallclock Z. 294300).
  • _bmad-output/implementation-artifacts/sprint-status.yamlmutiert: Key 3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen backlogreview (Implementierungs-Commit; finaler done-Flip im Step-05-Status-Sync nach konvergiertem Review-Loop); last_updated (Format MM-DD-YYYY HH:MM).
  • wiki/log.mdappend (Vertrag §5): Story-3.12-Eintrag (Verankerung §5.18, Sandbox L-1..L-9, Status-Flip, Validator-Verdikt) — nur vertragskonforme fachliche + Koordinationsereignisse (AC-6). AC-6-Grenz-Klärung (Loop 2, D1): die dokumentierten Run-Nachweise (Sandbox-Zählung, Validator-Verdikt, Status-Flip, Artefakt-Pfadszitate) sind notwendige Koordinationsereignisse im Sinne von Vertrag §5 — die verbotene Kategorie ist Build-/Review-/Story-/Sandbox-Historie (Kategorie-benennende Einträge, z. B. „Sandbox-Protokoll", „Build-Historie"); die L-8-Grep ist entsprechend angepasst (Kategorie-Hyphenate; Artefakt- und Review-Kennzeichnungen im Fließtext bleiben zulässig, 3.10/3.11-Praxis unverändert).
  • _bmad-output/implementation-artifacts/deferred-work.mdappend: Story-3.12-relevante Defers aus Review-Loop-1-Story-3.11 als aufgegriffen markieren („Sandbox-3.5/-3.6-check-then-act-Abgleich", „Banner-/I-O-Matrix-Kosmetik", „scopelock_header_banner"-Platzhalter) bzw. benannte Home-Zuordnung.
  • _bmad-output/implementation-artifacts/epic-3-context.mdmutiert („Edit freely"): Technical Decision Z. 43 „Transaktionaler Lifecycle" von „Zielzustand… nicht verankert" auf Ist-Zustand (§5.18) aktualisieren.

Read-only evidence (AD-3): schema/validator.md (Rev 9 — prüft keine Lease-/Koordinationszustände, Z. 194/195 nur stale_after-Lebenszyklus-WARN; Validator-Erweiterung nicht Teil dieser Story), schema/wiki-compiler.md, adapters/, raw/ (z. B. raw/prd/…, raw/epics/…). schema/canonical-terms.md append-only unangetastet.

Tasks & Acceptance

Execution:

  • schema/compiler.md — §5.18 einfügen (nach §5.17, vor §6): Pkt. 17 gemäß Intent; §7-Bullet und §8-Revisionslog Revision 3.7 nachführen; bestehende §5.11/§5.12/§5.13/§5.17 textuell unverändert (Fugen-Identität)
  • _bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh — L-1..L-9 (Lifecycle, Abort-/Protect-Zustandsmaschine, Baseline-Rollback Index+Worktree, Kill-Point-Tests, Clean-Input-Guard), harte PASS/FAIL, Exit 0, /tmp-Baum, nie realer Ist-Baum
  • _bmad-output/implementation-artifacts/sprint-status.yaml — Key 3-12 → review (Impl-Commit; finaler done-Flip Step-05); last_updated aktualisieren
  • wiki/log.md — Story-3.12-Eintrag (Verankerung, Sandbox, Status-Flip, Validator-Verdikt) — nur vertragskonforme Inhalte (AC-6)
  • _bmad-output/implementation-artifacts/deferred-work.md — relevante Story-3.12-Home-Defers als aufgegriffen markieren/zuordnen
  • _bmad-output/implementation-artifacts/epic-3-context.md — Technical Decision Z. 43 auf Ist-Zustand (§5.18) aktualisieren

Acceptance Criteria:

  • Given einen lebenden Lease-Halter, when eine höhere Generation sichtbar wird, then bleibt seine Lease aktiv; Staleness verlangt bestätigten Abbruch oder abgelaufene Liveness sowie atomare Ownership-Prüfung (AC-1).
  • Given eine nachweislich stale Lease, when sie übernommen wird, then gelingt die Übernahme genau einmal, nennt die ersetzte Holder-ID und hinterlässt genau eine aktive Root-Lease (AC-2).
  • Given getrackte oder ungetrackte fremde Änderungen im Mutationsbereich, when der Preflight läuft, then folgt er einer eindeutigen Abort-/Protect-Zustandsmaschine und stellt geschützte Bytes nach dem Run vollständig wieder her (AC-3).
  • Given einen Fehler nach Mutation oder Staging, when Rollback läuft, then restauriert er explizit aus dem bezeichneten Baseline-Commit sowohl Index als auch Worktree; der Post-Rollback-Diff gegen die Baseline ist leer (AC-4).
  • Given einen erfolgreichen Run, when er freigegeben wird, then sind Mutation, zulässiger Log-/Koordinationsnachweis und Release dauerhaft, der aktive Lock ist entfernt, der Worktree ist sauber und der unmittelbar folgende Run besteht den Clean-Input-Guard (AC-5).
  • Given wiki/log.md, when ein Run protokolliert wird, then enthält das kanonische Knowledge Log nur vertragskonforme fachliche Änderungen und notwendige Koordinationsereignisse; Build-, Review-, Story- und Sandbox-Historie liegt außerhalb des Knowledge Bundle (AC-6).
  • Given ein Lifecycle, when Kill-Point-Tests vor Mutation, nach Mutation, vor Commit und nach Commit laufen, then beweisen sie den jeweils konsistenten Endzustand (AC-7).

Design Notes

Der Lifecycle ist der geschlossene transaktionale Rahmen der Koordinations-Dimension: Akquise (§5.11/§5.17) → Preflight/Protect (§5.11 Pkt. 3) → Mutation (§5.9/§5.10/§5.16) → Rollback (§5.13) → durable Release (§5.11 Pkt. 1/§5.17 Pkt. 1 Ref-Delete) → Clean-Input-Guard (Nachfolger-Bedingung). §5.18 ordnet die bestehenden Mechaniken in eine Zustandsmaschine und ergänzt nur die fehlenden Klammern (Liveness/Ownership, Abort-/Protect-Zustandsmaschine, Index+Worktree-Rollback, durable Release + Clean-Input-Guard, kanonisches Log, Kill-Point-Tests).

Kernprinzipien:

  • Keine Wanduhr-TTL: Staleness folgt nie aus Kalenderzeit (A0-20), sondern aus committeten Zuständen (Gen-Registry, §5.12) plus bestätigtem Abbruch / abgelaufener Liveness (deterministisch belegt, z. B. Halter-Branch-Verlust/Registry-Status) — Liveness ist ein beobachtbarer, kein zeitlicher Zustand.
  • Ownership-Prägung: Akquise (create-only-Existenz, §5.17), Übernahme (atomare Ownership-Prüfung: Inhaber-Run-ID muss Lock-Inhalt tragen) und Release (Ref-Delete nur durch Inhaber) sind einheitlich ownership-gebunden.
  • Rollback = Baseline-Punkt: Index + Worktree werden aus <Baseline-Commit> restauriert (git reset --hard <Baseline-Commit> ist zulässiges Beispiel — deterministisch, ohne Wanduhr); Post-Rollback-Diff leer (§5.13 Pkt. 3 Zustands-Restaurations-Invariante).
  • Clean-Input-Guard: Nach Release muss ein Folge-Run ohne INPUT_UNCOMMITTED-Abbruch starten — d. h. sauberer Worktree, kein hängender Lock, geschützte Fremd-Bytes sind restauriert. Kill-Punkt „nach Commit" antizipiert genau diesen Zustand.

Verification

Commands:

  • bash _bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh -- expected: L-1..L-9 harte PASS, Exit 0, kein Zugriff auf reales Bundle/raw/.
  • grep -n "## 5.18" schema/compiler.md und grep -n "Revision 3.7" schema/compiler.md -- expected: §5.18-Überschrift und §8-Revisionslogeintrag vorhanden; bestehende §5.11/§5.12/§5.13/§5.17-Texte unverändert (diff prüft nur additive/berichtigte Zeilen).
  • git diff --stat (Repo-Root) -- expected: nur Story-3.12-Touched-Files (compiler.md, sandbox-3-12, spec, log.md, sprint-status.yaml, deferred-work.md, epic-3-context.md); schema/validator.md/schema/wiki-compiler.md/adapters//raw/ ohne Diff (AD-3); git status --porcelain -- wiki/ zeigt nur wiki/log.md.

Manual checks (if no CLI):

  • Keine Beschreibung nötig — sämtliche Nachweise laufen über die Sandbox (Exit-Code) und additive Diffs.

Suggested Review Order

Normative Verankerung (Einstieg)

  • §5.18 als transaktionaler Lifecycle der Koordinations-Dimension; Pkt. 2 verlangt atomare Ownership-Prüfung (Anschluss an §5.17 Sutur). compiler.md:426

  • Liveness/Ownership (AC-1), stale-Übernahme genau einmal mit CAS (AC-2), Durable Release + Clean-Input-Guard (AC-5). compiler.md:430

  • Abort-/Protect-Zustandsmaschine (AC-3), Baseline-Rollback Index+Worktree (AC-4), kanonisches Log (AC-6), Kill-Point-Tests (AC-7). compiler.md:432

Lifecycle-Mechanik (Sandbox)

  • Atomarer Ownership-CAS im Takeover (Review-Patch Loop 1): der entscheidende Guard ist der Old-Value-Write git update-ref <ref> <neu> <oldblob>; Loop 2 ergänzt scopelock_healthy/LOCK_READ_ERROR-Propagation (P1). run-sandbox.sh:153

  • Stale-Übernahme L-2: positiver Exactly-once-CAS plus negative atomare Abweisung (falscher Old-Value → kein Clobber) plus Takeover-Exactly-once am Takeover-Pfad (Loop 2 P5); genau eine aktive Root-Lease, ersetzte Holder-ID benannt. run-sandbox.sh:367

  • Abort-/Protect-Zustandsmaschine L-3/L-4 (getrackt/ungetrackt, byte-identischer Restore, Loop 2 P3-Backup-Checks) und Baseline-Rollback L-5/L-6 (Index+Worktree, Post-Rollback-Diff leer, L-6 „valide committet" hart verifiziert, Loop 2 P2). run-sandbox.sh:442

  • Durable Release L-7 (Lock per Ref-Delete, Clean-Input-Guard des Folge-Runs, Release-ohne-Ownership negativ geübt, Loop 2 P2) und Kill-Point-Tests L-9 (KP1KP4, Ghost-Diff-Probe via assert_invariant, Loop 2 P4). run-sandbox.sh:648

  • Kanonische Log-Grenze L-8 (nur vertragskonforme Fach-/Koordinationsereignisse; Kategorie-Check an Praxis angepasst + Negativ-Kontrolle, Loop 2 D1). run-sandbox.sh:700

Status- & Nachweissynchronisation (peripher)

  • Story-3.12-Eintrag im kanonischen Knowledge Log (Vertrag §5; Verankerung §5.18, Sandbox L-1..L-9). log.md

  • Transaktionaler Lifecycle-Zielzustand auf Ist-Zustand (§5.18) nachgeführt. epic-3-context.md:43

  • A-2-/I-O-Matrix-/Banner-Defers als aufgegriffen markiert; weiterreichende Defers (echte Zwei-Worktree-Übernahme → Story 3.13) benannt. deferred-work.md:606

  • Key 3-12 auf review geflippt (finaler done-Flip nach konvergiertem Review-Loop). sprint-status.yaml:65

Review Findings

Bmad-code-review Loop 1 (2026-08-21), 4 Layer (blind-hunter/edge-case-hunter/verification-gap/acceptance-auditor). Triage: konvergiert — kein intent_gap, kein bad_spec; 4 Patch-Kategorien auto-fixiert, 1 Defer, Rest begründet abgewiesen. Siehe ## Spec Change Log unten für die vollständige Triage-Struktur.

Bmad-code-review Loop 2 (2026-08-22), 4 Layer, Diff 80480af..HEAD. Triage: 1 decision-needed, 7 patch, 2 defer, 6 dismissed; kein intent_gap, kein bad_spec.

  • [Review][Decision] D1: AC-6/§5.18-Pkt.-6-Grenze widerspricht dem eigenen Artifact (wiki/log.md-Eintrag + Code-Map-Vorgabe) — Der reale wiki/log.md-Story-3.12-Eintrag benennt _bmad-output/…/sandbox-3-12/run-sandbox.sh, „bmad-code-review", „Review-Loop-1", die L-1..L-9-Szenario-Historie, „Sandbox-Nachweis 9/9 harte PASS", „Validator-Verdikt" und den Status-Flip — exakt die Build-/Review-/Story-/Sandbox-Historie, die §5.18 Pkt. 6/AC-6 außerhalb des Knowledge Bundle verlangt. Die eigene L-8-Kategorie-Grep der Sandbox (_bmad-output|run-sandbox|sandbox-3-12) würde auf diesem Eintrag HARD-FAIL auslösen; zudem instruiert die Code Map dieser Spec (Code-Map-Zeile „Sandbox L-1..L-9, Status-Flip, Validator-Verdikt") genau diesen Inhalt — innere Spec-Kontradiktion zwischen AC-6, Sandbox-L-8 und Code-Map.
  • [Review][Patch] P1: LOCK_READ_ERROR stirbt nur im Subshell — korrupter Lock wird en-bloc-stale klassifiziert (AC-1-Gate) [run-sandbox.sh:127, 223] — scopelock_content-exit 1 in $(…)-Substitution wird geschluckt (Eltern-Shell fährt mit leerem Wert fort); lease_liveness_stale interpretiert dann leer ≠ Holder-Run-ID als „Halter hält Lock nicht mehr" → lebende Lease mit korruptem Lock-Blob wird stale → Übernahme einer möglicherweise lebenden Lease. Der harter-LOCK_READ_ERROR-Zweig (PATCH 4c) ist praktisch wirkungslos, wo immer die Funktion per Kommandosubstitution aufgerufen wird.
  • [Review][Patch] P2: Release-Fehler-Pfad (HARD-FAIL, Lock nie hängend) und „Fehler nach Commit" nie negativ geübt [run-sandbox.sh:542-576] — Matrix-Zellen „Release-Fehler = HARD-FAIL; Lock nie hängend" (RELEASE_DURABLE) und „Fehler nach Commit" (ROLLBACK_NACH_COMMIT_VOR_RELEASE) sind nur im Erfolgszweig belegt; scopelock_release-Ownership-/Ref-Delete-Fehlschlag (Lock hängt) wird nirgends negativ demonstriert. Loop-1-REJECT begründet Commit-Immutabilität (AD-17f), deckt die Release-Fehler-Lücke aber nicht ab.
  • [Review][Patch] P3: Setup-Robustheit (keine Exit-Checks) vergiftet alle Szenarien bei Teilversagen [run-sandbox.sh:37-93, 410-411, 468-469] — mktemp -d/mkdir/cd/git init/git commit -qm "Baseline" ungeprüft (nur set -u); $BASE nie verifiziert (leerer/falscher Wert vergiftet alle $BASE-Vergleiche in L-1..L-9 und den isolate()-Fallback); L-3/L-4-Backup-cp ungeprüft, bevor git checkout --/git clean -qfd fremde Bytes verwerfen (stille AD-17e-Löschung; spätere sha256-Prüfung verschleiert die Ursache).
  • [Review][Patch] P4: AC-7-Kill-Punkt-Ghost-Diff-Probe fehlt in L-9; reg_write-Helfer tot [run-sandbox.sh:674-712, 156-167] — L-9 KP2/KP3 asserten nur Staged-Menge und HEAD; unstagede Ghost-Dateien im Worktree (Matrix „kein Ghost-Diff außerhalb erlaubter Menge") werden nicht geprüft — die definierten Helfer inv_viol/assert_invariant werden in L-9 nie aufgerufen; reg_write (Z. 156) definiert, aber nie aufgerufen (toter Code; Code-Map-Übernahme-Behauptung ungenau).
  • [Review][Patch] P5: AC-1-Ownership-Stale-Zweig nie positiv getestet; „keine Doppel-Übernahme" prüft falsches Primitiv [run-sandbox.sh:223-225, 375-377] — lease_liveness_stale-Zweig „Halter hält Lock nicht mehr" (Ownership-Quelle, §5.18 Pkt. 1 Bedingung (ii)) wird nie positiv ausgeübt (L-1: Gen allein; L-2: Registry-Marker-Zweig); L-2-Zweitversuch via scopelock_acquire beweist Create-only-Exklusivität, nicht Takeover-Exactly-once (Loop-1-Negativ-CAS deckt nur den falschen-Old-Value-Fall).
  • [Review][Patch] S1: Status-/Sync-/Spec-Struktur inkonsistent [spec-Frontmatter, Z. 87, Z. 12, sprint-status.yaml, wiki/log.md] — Frontmatter review_loop_iteration: 0 trotz dokumentiertem konvergiertem Loop 1 (Präzedenz 3.11: 0 → 1); Frontmatter status: done bei Sprint-Key review (finaler done-Flip gehört in Step 05 — der im Abschluss-Commit „Status-Sync" beanspruchte Sync fehlt im Diff); doppelte ## Spec Change Log-Überschrift (leere Z. 87); fehlendes </frozen-after-approval>-Schließtag (Präzedenz spec-3-11 schließt); last_updated 08-21-2026 20:45 (log.md-Nachweis) vs. 21:24 (sprint-status.yaml Istdiff).
  • [Review][Patch] S2: Anker-/Zählungs-Drift in Suggested Review Order, Code Map und deferred-work [spec-SRO run-sandbox.sh:365/416, Code Map Z. 57-58, deferred-work.md Z. 613/620] — SRO-Anker zeigen falsche Szenarien (Ist: L-3=Z. 392, L-4=Z. 447, L-7=Z. 584, L-9=Z. 670; beworbene 365 liegt in L-2, 416 in L-3-Frontmatter); „13 I/O-Matrix-Zeilen" (Ist 12 Datenzeilen); scopelock_header_banner „Z. 178-180" (Ist 280-282); Code Map „sandbox-3-11 544 Z." (Ist 543) und Übernahme-Behauptung db_check/free_lease/reg_write (tatsächlich: Preflight inline via git status --porcelain, scopelock_release statt free_lease, reg_write tot).
  • [Review][Defer] DF1: AC-3-git stash push-Variante und kombiniertes AC-5 „Fremd-Bytes restauriert" nie geübt [run-sandbox.sh:433-434 (Spec §5.18 Pkt. 3), 584-621] — §5.18 Pkt. 3 benennt git stash push -- <Pfad>/stash push -u als zulässige native Alternative; L-3/L-4 üben ausschließlich die Scratch-Zweige (kein Coverage/Guard für den Stash-Ast). AC-5-Clean-Input-Guard „geschützte Fremd-Bytes sind restauriert" wird nur isoliert in L-3/L-4 bewiesen, nie kombiniert mit Release + Folge-Run. — deferred, pre-existing (Variante-Abdeckung, kein Kernpfad-Defizit)
  • [Review][Defer] DF2: assert_no_wallclock überbreit — Anwendung auf log.md strukturell unmöglich [run-sandbox.sh:228-234, 314-315] — Regex 20[0-9]{2}-[0-9]{2}-[0-9]{2}[T ] trifft jedes Jahr-Zeichenmuster inkl. der legitimen ### YYYY-MM-DD-Datumsgruppen des log.md (Konventionsdaten, keine Wanduhr-Steuerung); der Check wird daher nur auf registry/wiki angewandt, L-1-Kommentar „kein Zeitstempel in Lock/Registry" behauptet aber mehr Coverage. — deferred, pre-existing (A0-20-Steuerung greift korrekt nur auf Registry/Lock)

Spec Change Log

  • 2026-08-21, Loop 1, Triage & Patches (kein Loopback — keine intent_gap/bad_spec):
    • PATCH (Kern, Verification-Gap V1): scopelock_takeover in sandbox-3-12 Z. 129146 auf atomaren Ownership-CAS umgestellt (git update-ref <ref> <neu> <oldblob> statt read-then-write ohne Old-Value) — §5.18 Pkt. 2 („Ersetzung als Ref-Schreibvorgang … nach atomarer Ownership-Prüfung") correct realisiert; L-2 übt jetzt die negative atomare Abweisung (falscher Old-Value-Blob → Ref-Write schlägt atomar fehl, Lock und genau-eine-aktive-Ref unverändert, kein Clobber) plus positiven Exactly-once-CAS.
    • PATCH: §5.18 Pkt. 2 Z. 431 Tippfehler AK-2:AC-2:.
    • PATCH (Härtung, Edge-Case-Hunter E2/E3/E4/E5): scopelock_acquire lehnt leere Run-ID ab; lease_liveness_stale lehnt leeres holder_runid ab (keine vacuous-stale-Klassifikation); scopelock_content unterscheidet korrupten/fehlenden Blob (harter LOCK_READ_ERROR) von „Ref nicht vorhanden"; L-8-Kanonikalitätsprüfung auf verboțene Kategorie-Marker + Artefakt-Pfade präzisiert (kein false-HARD-FAIL auf legitime Fließtext-Wörter) mit Positiv-Kontrolle.
    • DEFER: echte Zwei-Worktree-/Zwei-Prozess-Übernahme mit Synchronisations-Barriere bleibt Story 3.13-Abnahme (deferred-work.md-Append mit source_spec:-Format).
    • REJECT (begründet): L-6-„Rollback nach Commit" (Commit immutabel per AD-17f; Matrix-„oder"-Semantik Baseline-oder-valide-committet korrekt erfüllt, L-5 übt den echten Rollback); in-review-Flip ist Workflow-Folge; banner in sandbox-3-12 ersetzt (sandbox-3-11 unverändert korrekt); generated-Staleness-Konvention; baseline_commit korrekt = Vor-Implementierungs-HEAD; generated.at-Wanduhr-Gap §5.14 Pkt. 3 dokumentiert; Review-Findings-Sektion leer weil Loop 1 eben läuft; ein-Worktree-Sandbox bewusst (Defer Zwei-Worktree→3.13); epic-3-context kein Doppelsatz (geprüft); „12-vs-13-I/O-Matrix-Zeilen" Missverständnis (Story-3.11-Matrix 4-vs-8, nicht Story-3.12-12-Zeilen).
    • Nachweis: Sandbox-3-12 re-executiert nach Patches: L-1..L-9, 9/9 harte PASS, Exit 0; grep -n "AK-2" schema/compiler.md leer; AD-3-Files ohne Diff.
  • 2026-08-22, Loop 2, Triage & Patches (konvergiert — kein intent_gap, kein bad_spec; 1 decision-needed D-3.12-1, 7 patch, 2 defer, 6 dismissed):
    • DECISION D-3.12-1 (Nutzer-Entscheidung: Option 1 — Regel an Praxis angleichen): AC-6/§5.18-Pkt.-6-Grenze vs. eigener wiki/log.md-Eintrag (Sandbox-/Review-/Validator-Nachweise, Status-Flip, Artefakt-Pfadszitate; L-8-Grep würde darauf HARD-FAIL; Code Map verlangt genau diesen Inhalt). Entscheidung: dokumentierte Run-Nachweise zählen als notwendige Koordinationsereignisse (Vertrag §5; 3.10/3.11-Praxis bestätigt); die L-8-Kategorie-Grep schärft auf Kategorie-Hyphenate ((Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht)) + Negativ-Kontrolle (verbotene Form auf Probe-Datei ausserhalb wiki/ muss den Guard auslösen). §5.18 Pkt. 6 und AC-6 bleiben textuell unverändert; Code-Map wiki/log.md-Zeile um die Grenz-Klärung ergänzt.
    • PATCH (Kern, P1): scopelock_content/lease_liveness_stale/scopelock_release/scopelock_takeover — LOCK_READ_ERROR-Propagation: neuer Helfer scopelock_healthy() (Ref fehlt ODER lesbar; korrupter Blob → harter LOCK_READ_ERROR-Return vor jeder Liveness-/Release-/Takeover-Entscheidung); ein korrupter Lock wird nie mehr als „Halter hält nicht mehr" klassifiziert (AC-1-Gate bleibt geschlossen).
    • PATCH (Härtung, P2): Release-Fehler negativ geübt (L-7: scopelock_release mit falscher Inhaber-Run-ID in Subshell → harter Fehlschlag, Lock unverändert); L-6 „valide committet" hart verifiziert (HEAD ≠ Baseline + Frontmatter im Commit + Commit-Betreff) — Matrix-Zellen „Release-Fehler = HARD-FAIL; Lock nie hängend" und „Fehler nach Commit" damit belegt (AD-17f-„oder"-Semantik im L-6-Kommentar benannt).
    • PATCH (Härtung, P3): Setup-Robustheit — Exit-Checks auf mktemp/mkdir/cd/git init, verifizierter $BASE-Baseline-Commit (git cat-file -e), L-3/L-4-Backup-cp vor checkout/clean byte-identisch verifiziert (AD-17e-Stille-Löschung-Pfad geschlossen); bewusst kein set -e (negatives Assertion-Idiom cmd && fail), dokumentiert im Skriptkopf.
    • PATCH (Härtung, P4): L-9-Kill-Punkte KP2/KP3 um Ghost-Diff-Probe (assert_invariant via inv_viol) — Index und Worktree gegen erlaubte Menge (Matrix „kein Ghost-Diff außerhalb erlaubter Menge" vollständig belegt); reg_write real geübt in L-1 (kein toter Code); Code-Map-Übernahme-Behauptung präzisiert (Preflight inline statt db_check, free_lease nicht übernommen → scopelock_release-Modell).
    • PATCH (Härtung, P5): AC-1-Ownership-Stale-Zweig positiv getestet (L-1-Ende: nach Release + Gen-Ablauf klassifiziert die Liveness stale über die Ownership-Quelle); L-2 um Takeover-Exactly-once direkt am Takeover-Pfad (zweiter update-ref-CAS mit altem Old-Value schlägt atomar fehl, kein Clobber).
    • PATCH (S1): Spec-Frontmatter review_loop_iteration: 0 → 1, status: 'review' (finaler done-Flip Step 05); doppelte ## Spec Change Log (leere Instanz) entfernt; </frozen-after-approval>-Schließtag ergänzt (Präzedenz spec-3-11: Schließung vor Code Map); wiki/log.md last_updated-Nachweis (20:45) und sprint-status.yaml last_updated (21:24) im Step-05-Sync vereinheitlicht.
    • PATCH (S2): Suggested-Review-Order-Anker auf Ist-Zustand neu gesetzt (takeover Z. 153; L-2 Z. 367; L-3 Z. 442; L-7 Z. 648; L-8 Z. 700); Code Map „544 Z." → 543; „13 I/O-Matrix-Zeilen" → 12 in deferred-work.md berichtigt; Banner-Zeilenangabe „Z. 178-180" → Z. 310.
    • DEFER (2, → deferred-work.md „Deferred from: code review of spec-3-12 …" 2026-08-22): DF1 AC-3-git stash push-Variante + kombiniertes AC-5 „Fremd-Bytes restauriert" (Home: Sandbox-Härtung/Story 3.13); DF2 assert_no_wallclock überbreit/Kommentarschärfe (Home: Sandbox-Kosmetik).
    • REJECT (begründet, 6): BH7 UNCOMMITTED_INPUT-vs-Protect (Zustandsmaschine §5.18 Pkt. 3 explizit: Preflight → benannter Abbruch → Schutz-Überführung, kein Widerspruch); BH8 L-3/L-4-Release mit uncommittetem log.md (Protect-/Abort-Szenarien, nicht durable Release — das üben L-6/L-7/L-9); AA12 --short --porcelain-Doppel-Flag (funktional, --short--porcelain); AA13 isolate()-Szenario-Parameter dekorativ (Harness-Reset-Konvention, git reset --hard $BASE ist der operative Reset); BH14 AD-17e-Orphan „von isolate() gelöscht" (isolate() = Sandbox-Harness-Reset, kein Produktions-Release-Pfad; Pkt. 2 verlangt Erhaltung im Run-Endzustand, nicht über Harness-Reset hinweg); AA14 Sandbox-Synthetik-log.md nicht datumsgruppiert (Demo-Treue; das reale wiki/log.md ist datumsgruppiert).
    • Nachweis: Sandbox-3-12 re-executiert nach Loop-2-Patches: L-1..L-9, 9/9 harte PASS, Exit 0; AD-3-Files (schema/validator.md/schema/wiki-compiler.md/adapters//raw/) ohne Diff; §5.11/§5.12/§5.13/§5.17 textuell unverändert (Fugen-Identität).