From c234fc361e006043c3c972cc03211b52998c2ddb Mon Sep 17 00:00:00 2001 From: Michael Tamse Date: Sat, 22 Aug 2026 08:14:56 +0200 Subject: [PATCH] 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) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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, , 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 --- .../implementation-artifacts/deferred-work.md | 9 +- .../sandbox-3-12/run-sandbox.sh | 145 ++++++++++++++---- ...mmit-abschluss-transaktional-schliessen.md | 57 +++++-- .../sprint-status.yaml | 4 +- wiki/log.md | 3 + 5 files changed, 171 insertions(+), 47 deletions(-) diff --git a/_bmad-output/implementation-artifacts/deferred-work.md b/_bmad-output/implementation-artifacts/deferred-work.md index 5b19d32..225b19d 100644 --- a/_bmad-output/implementation-artifacts/deferred-work.md +++ b/_bmad-output/implementation-artifacts/deferred-work.md @@ -613,17 +613,22 @@ Noch nicht adressierte, aber real erkannte Arbeit — gesammelt aus Reviews. Ein ### Aufgegriffen: Banner-/I-O-Matrix-Kosmetik (Story-3.11-Defer, Home Story 3.12) — Story 3.12, 2026-08-21 - Bezug: Defer `Die I/O-Matrix (frozen) listet 4 Szenarien, die Sandbox übt 8 … dazu der leere scopelock_header_banner()-Platzhalter` (Defer-Block „Deferred from: code review of spec-3-11 …", Eintrag der Z. 602-603; Home: Matrix-Nachführung (Append außerhalb frozen Blocks über den Spec-Change-Log) / Story-3.12). -- Umsetzung: Die Story-3.12-Sandbox führt die Banner-Konvention ein (nicht-leerer `scopelock_header_banner()` je Lifecycle-Run, Z. 178-180) und deckt die 13 I/O-Matrix-Zeilen der Story-3.12-Spec als harte Assertionen L-1..L-9 ab (LIVENESS_AKTIV, STALE_UEBERNAHME, DIRTY_GETRACKT, DIRTY_UNGETRACKT, ROLLBACK_NACH_MUTATION, ROLLBACK_NACH_COMMIT_VOR_RELEASE, RELEASE_DURABLE, KANONISCHES_LOG, KILLPUNKT_VOR_MUTATION, KILLPUNKT_NACH_MUTATION, KILLPUNKT_VOR_COMMIT, KILLPUNKT_NACH_COMMIT); die Matrix-Kosmetik-Nachführung der Story-3.11-Spec-Diskrepanz (4 vs. 8 Szenarien) bleibt als Append über den Story-3.11-Spec-Change-Log benannt. +- Umsetzung: Die Story-3.12-Sandbox führt die Banner-Konvention ein (nicht-leerer `scopelock_header_banner()` je Lifecycle-Run, Z. 310-312) und deckt die 12 I/O-Matrix-Zeilen der Story-3.12-Spec als harte Assertionen L-1..L-9 ab (LIVENESS_AKTIV, STALE_UEBERNAHME, DIRTY_GETRACKT, DIRTY_UNGETRACKT, ROLLBACK_NACH_MUTATION, ROLLBACK_NACH_COMMIT_VOR_RELEASE, RELEASE_DURABLE, KANONISCHES_LOG, KILLPUNKT_VOR_MUTATION, KILLPUNKT_NACH_MUTATION, KILLPUNKT_VOR_COMMIT, KILLPUNKT_NACH_COMMIT); die Matrix-Kosmetik-Nachführung der Story-3.11-Spec-Diskrepanz (4 vs. 8 Szenarien) bleibt als Append über den Story-3.11-Spec-Change-Log benannt. - Sandbox-Nachweis: `_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh` L-1..L-9 (jede Matrix-Zeile als Szenario) — Exit 0. - status: aufgegriffen (Banner-Konvention umgesetzt in sandbox-3-12; restliche Story-3.11-Matrix-Kosmetik bleibt benannter Defer) ### Aufgegriffen: `scopelock_header_banner()`-Platzhalter (Story-3.11-Defer, Home Story 3.12) — Story 3.12, 2026-08-21 - Bezug: Defer `Die Helfer-Funktion scopelock_header_banner() { :; } in der Sandbox-3.11 ist ein leerer Platzhalter` (Defer-Block „Deferred from: code review of spec-3-11 …", Eintrag der Z. 590-591; Home: Story-3.12-Lifecycle-Erweiterung, falls die Banner-Konvention übernommen wird, sonst entfernen). -- Umsetzung: Die Story-3.12-Sandbox übernimmt die Banner-Konvention und ersetzt den leeren Platzhalter durch eine dokumentierende Funktion (`scopelock_header_banner() { echo "--- Lifecycle-Run: $1 (Root-Scope wiki/, Lock refs/leases/wiki) ---"; }`, Z. 178-180) — je Lifecycle-Szenario wird der Banner als Run-Kopf ausgegeben (L-1, L-3..L-9). Die Story-3.11-Sandbox selbst bleibt — wo es keinen Platzhalter-Aufruf gibt — unverändert (Fugen-Identität). +- Umsetzung: Die Story-3.12-Sandbox übernimmt die Banner-Konvention und ersetzt den leeren Platzhalter durch eine dokumentierende Funktion (`scopelock_header_banner() { echo "--- Lifecycle-Run: $1 (Root-Scope wiki/, Lock refs/leases/wiki) ---"; }`, Z. 310-312) — je Lifecycle-Szenario wird der Banner als Run-Kopf ausgegeben (L-1, L-3..L-9). Die Story-3.11-Sandbox selbst bleibt — wo es keinen Platzhalter-Aufruf gibt — unverändert (Fugen-Identität). - Sandbox-Nachweis: `_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh` L-1/L-3..L-9 (Banner-Ausgabe je Run) — Exit 0. - status: aufgegriffen (Home erledigt in sandbox-3-12, Banner-Konvention umgesetzt) - source_spec: `_bmad-output/implementation-artifacts/spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen.md` summary: Echte Zwei-Worktree-/Zwei-Prozess-Übernahme des Root-Scope-Locks mit Synchronisations-Barriere üben — die §5.18-Pkt.-2-Takeover-Atomarität (AC-2) ist in sandbox-3-12 nur sequenziell (ein Worktree) geprüft. evidence: Verification-Gap-Review Story 3.12 (Loop 1): sandbox-3-12 läuft komplett in einem `git init`-Worktree; die §5.17-geteilte-Ref-Namespace-Sichtbarkeit und die Echt-Überlappung (Zwei Producer gleichzeitig, eine Entscheidung) ist nicht beobachtet; die vorhandene Rest-Vertiefung in der Story-3.11-Aufgegriffen-Notiz (Home §5.18 Pkt. 1/2/5) und der deferred-work-Eintrag zur Zwei-Worktree-Barriere (Sandbox-Härtung / Story-3.13-Abnahme) scopen dasselbe Restziel. + +## Deferred from: code review of spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen (2026-08-22) + +- DF1 — AC-3-`git stash push`-Variante und kombiniertes AC-5 „Fremd-Bytes restauriert" nie geübt: §5.18 Pkt. 3 benennt `git stash push -- ` bzw. `stash push -u` als zulässige native Alternative zur Scratch-Zone; die Sandbox L-3/L-4 übt ausschließlich die Scratch-Zweige (der Stash-Ast — Sichern, Worktree-Bereinigung, byte-identischer Restore aus dem Stash — hat keinerlei Coverage/Guard). Zusätzlich wird AC-5s Clean-Input-Guard-Klausel „geschützte Fremd-Bytes sind restauriert" nur isoliert in L-3/L-4 bewiesen, nie kombiniert mit Release + Folge-Run im selben Szenario. Home: Sandbox-Härtung (Story-3.13-Abnahme-Gate deckt native-Varianten-Abdeckung über echte Bäume). +- DF2 — `assert_no_wallclock` überbreit (trifft jedes `YYYY-MM-DD`-Zeichenmuster, inkl. legitimer `### YYYY-MM-DD`-Datumsgruppen des `wiki/log.md` — Konventionsdaten, keine Wanduhr-Steuerung): der A0-20-Check ist daher nur auf `registry/wiki` (L-1) anwendbar, nicht auf `log.md`; der L-1-Kommentar „kein Zeitstempel in Lock/Registry" behauptet breitere Coverage als die Funktion liefert. A0-20-Steuerung greift korrekt (nur auf Registry/Lock); Kommentarschärfe + eventuelle schärfere Regex (z. B. `T[0-9]{2}`-Pflicht) = Kosmetik. Home: Sandbox-Kosmetik (nächste Sandbox-Härtung). diff --git a/_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh b/_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh index bc99555..594a7ca 100644 --- a/_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh +++ b/_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh @@ -33,12 +33,16 @@ # ownership-gebundener Ref-Delete), die §5.12-Registry/Gen/Liveness- und §5.11-Pkt.-3- # Schutzmechanik und prueft die Lifecycle-Klammer inkl. KillPoint-Tests + Clean-Input-Guard. # Ubuntu-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale wiki/- oder raw/-Baum. +# set -u: unbestimmte Variable = Fehler. Kein set -e: die Sandbox uebt NEGATIVE +# Assertionen im Idiom `cmd && fail "..."` (erwartetes Scheitern = korrekte Semantik) — +# set -e wuerde an genau diesen Stellen das Skript stoeren. Stattdessen: gezielte +# Exit-Checks an den Setup-/Isolations-/Backup-Punkten (Loop-2-P3). set -u -ROOT=$(mktemp -d /tmp/sb312-XXXXXX) +ROOT=$(mktemp -d /tmp/sb312-XXXXXX) || { echo "HARD-FAIL: mktemp fehlgeschlagen (Sandbox-Setup nicht moeglich)" >&2; exit 1; } SB="$ROOT/sb" -mkdir -p "$SB/wiki" "$SB/raw" "$SB/scratch" -cd "$SB" -git init -q +mkdir -p "$SB/wiki" "$SB/raw" "$SB/scratch" || { echo "HARD-FAIL: Sandbox-Baum-Aufbau fehlgeschlagen" >&2; exit 1; } +cd "$SB" || { echo "HARD-FAIL: cd in Sandbox fehlgeschlagen (Aufrufer-Baum waere kontaminiert)" >&2; exit 1; } +git init -q || { echo "HARD-FAIL: git init fehlgeschlagen" >&2; exit 1; } # Determinismus vs. Host-Git-Konfiguration (AD-17h): LF-Blobs + LF-Worktree — # autocrlf/filemode-Umwandlung des Hosts wuerde sha256-Vergleiche verschieben. git config core.autocrlf false @@ -91,6 +95,10 @@ EOF git add -A git commit -qm "Baseline" BASE=$(git rev-parse HEAD) +# Loop-2-P3: Baseline verifiziert — ein leerer/falscher $BASE-Wert wuerde alle +# $BASE-Vergleiche in L-1..L-9 und den isolate()-Fallback vergiften. +[ -n "$BASE" ] && git cat-file -e "$BASE^{commit}" 2>/dev/null \ + || { echo "HARD-FAIL: Baseline-Commit nicht verifiziert (leer/kein Commit-Objekt)" >&2; exit 1; } echo "BASELINE-COMMIT (Merge-Base, eindeutiger Commit-Object-Wert): $BASE" echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)" echo @@ -115,16 +123,29 @@ scopelock_acquire() { # $1 = Run-ID (Lock-Inhalt; PRODUCER sichtbar) — create- { git update-ref "$SCOPELOCK" "$val" "$ZERO"; } 2>/dev/null } scopelock_release() { # $1 = erwartete Inhaber-Run-ID (Ownership-Pruefung) + scopelock_healthy || { echo "HARD-FAIL (LOCK_READ_ERROR): Release abgebrochen, Lock-Zustand unvertraeulich (Loop-2-P1)" >&2; exit 1; } [ "$(scopelock_content)" = "${1:-}" ] \ || { echo "HARD-FAIL: Release ohne Ownership (Inhaber: '$(scopelock_content)', Aufrufer: '${1:-}')" >&2; exit 1; } git update-ref -d "$SCOPELOCK" || { echo "HARD-FAIL: Release fehlgeschlagen" >&2; exit 1; } } scopelock_content() { + # Leer ist NUR noch "Ref nicht vorhanden" (PATCH 4c-Grundvertrag). Ein korrupter + # Blob wird NICHT hier per `exit 1` beendet — dieser Aufruf laeuft nahezuausschliesslich + # in Kommandosubstitution, wo `exit 1` nur den Subshell toetete und der Eltern-Shell + # ein leerer Wert erscheinen wuerde (=> falsche "Halter haelt nicht mehr"- + # Klassifikation, Loop-2-P1). Stattdessen pruefen die Aufrufer VORHER + # `scopelock_healthy` und werten einen korrupten Blob hart als LOCK_READ_ERROR. local val val=$(git rev-parse -q --verify "$SCOPELOCK" 2>/dev/null) || { echo ""; return 0; } - # PATCH 4c: Ref existiert, aber cat-file scheitert = korrupter/fehlender Blob -> harter - # LOCK_READ_ERROR statt stiller leerer Rueckgabe (leer ist nur "Ref nicht vorhanden"). - git cat-file -p "$val" 2>/dev/null || { echo "HARD-FAIL (LOCK_READ_ERROR): Lock-Ref '$SCOPELOCK' zeigt auf '$val', aber Blob nicht lesbar (korrupt/fehlend)" >&2; exit 1; } + git cat-file -p "$val" 2>/dev/null || { echo "" ; return 0; } +} +# Loop-2-P1 (PATCH 4c propagiert): gesund = Ref fehlt (leer erlaubt) ODER Ref existiert +# UND ist lesbar. Return 1 = korrupter/fehlender Blob (LOCK_READ_ERROR). +scopelock_healthy() { + local val + val=$(git rev-parse -q --verify "$SCOPELOCK" 2>/dev/null) || return 0 + git cat-file -e "$val" 2>/dev/null || { echo "HARD-FAIL (LOCK_READ_ERROR): Lock-Ref '$SCOPELOCK' zeigt auf '$val', aber Blob nicht lesbar (korrupt/fehlend)" >&2; return 1; } + return 0 } # Ownership-CAS: Uebernahme nur, wenn der Lock (noch) vom erwarteten Inhaber gehalten wird # (atomare Ownership-Pruefung, §5.18 Pkt. 1/2). Die alte Inhaber-Run-ID im Lock-Inhalt ist @@ -135,6 +156,7 @@ scopelock_takeover() { # $1 = erwartete alte Run-ID (Lock-Inhalt) $2 = neue Run # HARD-FAIL. Der entscheidende Guard ist danach der ATOMARE Old-Value-Write (CAS) — die # atomare Abweisung selbst wird im negativen L-2-Test durch direkten atomaren Ref-Write # geprueft (PATCH 2), der schnelle Diagnose-Zweig bleibt fuer echte Aufrufer fatal. + scopelock_healthy || { echo "HARD-FAIL (LOCK_READ_ERROR): Takeover abgebrochen, Lock-Zustand unvertraeulich (Loop-2-P1)" >&2; exit 1; } [ "$(scopelock_content)" = "$old" ] \ || { echo "HARD-FAIL (Ownership): Lock-Inhalt '$old' erwartet, tatsaechlich '$(scopelock_content)'" >&2; exit 1; } newval=$(printf '%s' "$new" | git hash-object -w --stdin) || return 2 @@ -211,6 +233,14 @@ lease_stale() { # $1=area $2=id $3=erzeugungs_gen: true (0) wenn Erzeugungs-Ge lease_liveness_stale() { local area="$1" id="$2" gen="$3" holder_runid="$4" [ -n "${4:-}" ] || return 1 # PATCH 4b: leere holder_runid -> keine vacuous-stale-Klassifikation + # Loop-2-P1: korrupter Lock-Blob ist KENNE Liveness-Quelle — weder "haelt" noch + # "haelt nicht mehr". Ohne harte LOCK_READ_ERROR-Pruefung wuerde ein leer lesender + # Subshell den Lock als "Halter haelt nicht mehr" klassifizieren und eine moeglich- + # weise LEBENDE Lease en bloc stale markieren (AC-1-Gate ausgehebelt). + if ! scopelock_healthy; then + echo "HARD-FAIL (LOCK_READ_ERROR): Liveness-Bewertung abgebrochen, Lock-Zustand unvertraeulich (keine Stale-Klassifikation moeglich)" >&2 + return 2 + fi if ! lease_stale "$area" "$id" "$gen"; then return 1 # nicht generationen-abgelaufen -> nicht stale fi @@ -294,8 +324,11 @@ fail() { echo "HARD-FAIL: $1" >&2; exit 1; } runlabel "L-1: LIVENESS_AKTIV (AC-1) — hoehere Gen-Hoehe macht lebende Lease nicht stale" isolate l1 # Producer erwirbt den Root-Scope (Run-ID als Lock-Inhalt) und registriert die Lease -# (Registry, Erzeugungs-Gen 1). +# (Registry, Erzeugungs-Gen 1): reg_write legt die Registry mit der Erzeugungs-Generation +# an (Loop-2-P4: reg_write wird hier real geuebt — kein toter Code), reg_hold_mark markiert +# den aktiven Hold. scopelock_acquire "RUN-L1-holder" || fail "L-1: Root-Scope-Akquise schlug fehl" +reg_write wiki run-l1 "RUN-L1-holder" 1 reg_hold_mark wiki run-l1 1 scopelock_header_banner "RUN-L1-holder" # Probe: die Lease ist bei Reg-Gen 1 NICHT stale (Erzeugungs-Gen == aktueller Reg-Gen). @@ -316,7 +349,14 @@ assert_no_wallclock registry/wiki # Release des Halter (Ownership), dann ist der Clean-Input-Guard-Zustand wieder leer. scopelock_release "RUN-L1-holder" [ -z "$(scopelock_content)" ] || fail "L-1: Lock nach Release nicht leer" -echo "RESULT: PASS — L-1: LIVENESS_AKTIV — hoehere Generation macht lebende Lease NICHT stale; Liveness ist Zustand (bestaetigter Abbruch/abgelaufene Liveness + Ownership-Pruefung), kein Wanduhr-/Gen-Hoehen-Effekt (AC-1, A0-20)" +# Loop-2-P5: AC-1-Ownership-Stale-Zweig POSITIV getestet — nach dem Release haelt der +# Halter den Lock NICHT mehr (Inhalt leer != Halter-Run-ID), der Gen-Check ist abgelaufen +# (Erzeugungs-Gen 1 < Reg-Gen 2) und es fehlt ein Registry-Stale-Marker -> die Liveness +# klassifiziert die Lease stale ueber die Ownership-Quelle (Pkt. 1 Bedingung (ii), +# "Halter haelt Lock nicht mehr") — NICHT ueber einen Wanduhr-Effekt. +lease_liveness_stale wiki run-l1 1 "RUN-L1-holder" \ + || fail "L-1-P5: Ownership-Stale-Zweig (Halter haelt Lock nicht mehr) klassifizierte NICHT stale (AC-1 Bedingung ii)" +echo "RESULT: PASS — L-1: LIVENESS_AKTIV — hoehere Generation macht lebende Lease NICHT stale; Liveness ist Zustand (bestaetigter Abbruch/abgelaufene Liveness + Ownership-Pruefung), kein Wanduhr-/Gen-Hoehen-Effekt; Ownership-Stale-Zweig positiv belegt (AC-1, A0-20)" pass # ===================================================================== @@ -370,12 +410,22 @@ printf '\n### 2026-08-21 — Lease-Uebernahme: wiki/run-l2; Baseline %s; alte Ho grep -qF "alte Holder-ID RUN-L2-alt" wiki/log.md || fail "L-2: ersetzte Holder-ID nicht benannt (AC-2/AC-6)" grep -qF "neue Holder-ID RUN-L2-neu" wiki/log.md || fail "L-2: neue Holder-ID nicht benannt (AC-2/AC-6)" grep -qF "Baseline $BASE" wiki/log.md || fail "L-2: Baseline-Commit fehlt im Uebernahme-Eintrag (Vertrag §5)" -# Kein Doppel-Uebernehmer: eine zweite (sequentielle) Uebernahme derselben stale id schlaegt -# fehl — der Lock wird nur einmal ersetzt (genau einmal-Uebernahme, AC-2). +# Kein Doppel-Uebernehmer: eine zweite (sequentielle) AKQUISE derselben stale id schlaegt +# fehl (create-only, Ref existiert) — der Lock wird nur einmal ersetzt (genau einmal-Uebernahme, AC-2). if scopelock_acquire "RUN-L2-zweiter"; then fail "L-2: zweite Uebernahme gelang (AC-2: genau einmal verletzt)" fi [ "$(scopelock_content)" = "RUN-L2-neu" ] || fail "L-2: Lock-Inhalt nach zweitem Uebernahme-Versuch veraendert" +# Loop-2-P5: TAKEOVER-Exactly-once direkt am Takeover-Pfad (nicht nur am create-only-Akquise- +# pfad): ein zweiter scopelock_takeover-Versuch mit ALTEM Old-Value (RUN-L2-alt, Inhaber ist +# jetzt RUN-L2-neu) muss ATOMAR FEHLSCHLAGEN (Ownership-CAS: Lock traegt nicht mehr den +# erwarteten Old-Value) und den Lock UNVERAENDERT lassen. +oldblob2=$(printf '%s' 'RUN-L2-alt' | git hash-object -w --stdin) || fail "L-2-P5: oldblob2 nicht erzeugt" +neu2blob=$(printf '%s' 'RUN-L2-doppelt' | git hash-object -w --stdin) || fail "L-2-P5: neu2blob nicht erzeugt" +if git update-ref "$SCOPELOCK" "$neu2blob" "$oldblob2" 2>/dev/null; then + fail "L-2-P5: zweiter Takeover-CAS mit altem Old-Value gelang (AC-2: Takeover genau einmal verletzt)" +fi +[ "$(scopelock_content)" = "RUN-L2-neu" ] || fail "L-2-P5: zweiter Takeover-Versuch hat den Lock veraendert (Clobber)" # Die verwaiste Registry-Zeile bleibt erhalten (nie still geloescht, AD-17e): grep -qF "hold: run-l2 (Gen 1)" registry/wiki || fail "L-2: Registry-Zeile run-l2 still geloescht (AD-17e)" scopelock_release "RUN-L2-neu" @@ -407,7 +457,10 @@ ALPHA_ONLY=$({ git diff --name-only "$BASE" -- wiki/ ; git status --porcelain -- # ABORT-/PROTECT-ZUSTANDSMASCHINE (getrackt): SCHUETZEN — Sicherung in Scratch-Zone # (ausserhalb wiki/, deterministisch benannt), dann Arbeitssatz bereinigt. mkdir -p scratch/l3 -cp wiki/alpha.md "scratch/l3/alpha.md.stash" +cp wiki/alpha.md "scratch/l3/alpha.md.stash" || fail "L-3: Backup fehlgeschlagen — Fremdbearbeitung NICHT verworfen (AD-17e, Loop-2-P3)" +# Loop-2-P3: Backup VOR der Bereinigung verifiziert — schlaege es still fehl, wuerde +# `git checkout --` die fremde Aenderung still loeschen (AD-17e-Verletzung). +[ "$(sha256sum "scratch/l3/alpha.md.stash" | cut -d' ' -f1)" = "$FRANK_MD5" ] || fail "L-3: Backup nicht byte-identisch vor Bereinigung (Loop-2-P3, AD-17e)" git checkout -q -- wiki/alpha.md # Der Run mutiert jetzt (Mutations-Objekt alpha, Erhaltungs-Invariante erlaubt alpha + log.md): cat > wiki/alpha.md <<'EOF' @@ -465,7 +518,10 @@ F_UNTRACK_MD5=$(sha256sum wiki/inoffiziell.md | cut -d' ' -f1) git status --porcelain -- wiki/inoffiziell.md | grep -qE '^\?\? ' || fail "L-4: ungetrackte Fremd-Datei nicht als '??' sichtbar" # PROTECT (ungetrackt): Sicherung in die Scratch-Zone, dann ist der Mutationsbereich sauber. mkdir -p scratch/l4 -cp wiki/inoffiziell.md "scratch/l4/inoffiziell.md.stash" +cp wiki/inoffiziell.md "scratch/l4/inoffiziell.md.stash" || fail "L-4: Backup fehlgeschlagen — Fremd-Datei NICHT verorfen (AD-17e, Loop-2-P3)" +# Loop-2-P3: Backup VOR `git clean` verifiziert — ein still fehlgeschlagener `cp` wuerde +# die fremde ungetrackte Datei still loeschen (AD-17e-Verletzung). +[ "$(sha256sum "scratch/l4/inoffiziell.md.stash" | cut -d' ' -f1)" = "$F_UNTRACK_MD5" ] || fail "L-4: Backup nicht byte-identisch vor Clean (Loop-2-P3, AD-17e)" git clean -qfd wiki/inoffiziell.md # Der Run mutiert alpha (Kill-Punkt vor Mutation/Nach-Mutation, konsistenter Zwischenstand): cat > wiki/alpha.md <<'EOF' @@ -560,14 +616,22 @@ assert_frontmatter wiki/alpha.md printf '\n### 2026-08-21 — Story-3.12-L6: committeter Mutations-Nachweis (Baseline %s)\n' "$BASE" >> wiki/log.md git add wiki/alpha.md wiki/log.md git commit -qm "L6: committeter Run (Mutation + log.md-Nachweis)" +# Loop-2-P2: Matrix-Zelle ROLLBACK_NACH_COMMIT_VOR_RELEASE "Fehler nach Commit, vor Release" +# benannt und belegt: nach Commit ist der Zustand entweder == Baseline (nicht hier) ODER +# VALID COMMITTET — ein Rollback NACH Commit ist per AD-17f nicht vorgesehen (Commit ist +# unveraenderlich; die Matrix-"oder"-Semantik gilt). Der Fehler-Nachlauf loest sich in +# genau diesem Endzustand auf. "Valide committet" wird hier HART verifiziert: +[ "$(git rev-parse HEAD)" != "$BASE" ] || fail "L-6-P2: nach Commit HEAD == Baseline (Commit fehlgeschlagen — kein valide-committeter Zustand)" +git show -q HEAD:wiki/alpha.md | grep -q '^type: concept$' \ + || fail "L-6-P2: committeter Zustand nicht valide (Frontmatter im Commit verletzt)" +git show --format=%s -s HEAD | grep -q "L6: committeter Run" || fail "L-6-P2: Commit-Betreff nicht valide" # Kill-Punkt VOR RELEASE: Commit ist erfolgt, aber der Lock ist noch NICHT freigegeben (kein # haengender Lock — der Lock wird noch vom Run gehalten, kein Teilzustand veroeffentlicht). git status --porcelain -- wiki/ | grep -q '^??' && fail "L-6: ungetrackte Reste nach Commit (Clean-Input-Guard-Vorfeld)" [ "$(scopelock_content)" = "RUN-L6" ] || fail "L-6: Lock vor Release nicht gehalten (Kill-Punkt vor Release)" -# Fehler-Nachlauf vor Release wird sauber aufgeloest: entweder Rollback auf Baseline (valide) -# oder der committete Zustand wird beibehalten und der Lock freigegeben (Zustand == Baseline -# oder valide committet, nie ein Teilzustand — AD-17f). Hier: committeter Zustand ist valide, -# der Run gibt durativ frei. +# Fehler-Nachlauf vor Release wird sauber aufgeloest: Zustand == Baseline ODER valide +# committet (hier: valide committet, P2-verified) — der Run gibt durativ frei; ein +# Teilzustand wird nie veroeffentlicht (AD-17f). scopelock_release "RUN-L6" [ -z "$(scopelock_content)" ] || fail "L-6: Lock nach Release nicht leer (AC-5)" # Clean-Input-Guard-Vorfeld: sauberer Worktree nach Commit+Release. @@ -602,6 +666,14 @@ assert_frontmatter wiki/alpha.md printf '\n### 2026-08-21 — Story-3.12-L7: durativer Run, Freigabe per Ref-Delete (Baseline %s)\n' "$BASE" >> wiki/log.md git add wiki/alpha.md wiki/log.md git commit -qm "L7: durativer Run (Mutation + Log-Nachweis)" +# Loop-2-P2: RELEASE-Fehler negativ geuebt (Matrix RELEASE_DURABLE "Release-Fehler = +# HARD-FAIL; Lock nie haengend"): ein Release mit FALSCHER Inhaber-Run-ID muss hart +# FEHLSCHLAGEN (Ownership-Pruefung) und den Lock UNVERAENDERT lassen — in einem Subshell, +# damit die erwartete HARD-FAIL-Beendigung das Skript selbst nicht toetet. +if ( scopelock_release "RUN-L7-fremd" ) 2>/dev/null; then + fail "L-7-P2: Release OHNE Ownership gelang (HARD-FAIL-Pfad nicht wirksam, AC-5)" +fi +[ "$(scopelock_content)" = "RUN-L7" ] || fail "L-7-P2: fehlgeschlagenes Release hat den Lock veraendert (Lock haengt/verfalscht, AC-5)" # Release per Ref-Delete (nur durch Inhaber, Ownership-Pruefung): scopelock_release "RUN-L7" # Lock ist entfernt (ref-delete): @@ -639,14 +711,25 @@ printf '\n### 2026-08-21 — Freigabe: wiki Root-Scope durch RUN-L8 (Ref-Delete, mkdir -p registry echo "gen: 1" > registry/wiki echo "hold: run-l8 (Gen 1)" >> registry/wiki -# KERN (AC-6): log.md traegt KEINE Build-/Review-/Story-/Sandbox-Historie — weder als -# Kategorie-benennende Eintraege (z. B. 'Build-Historie', 'Sandbox-Protokoll', 'Story-Log') -# noch als Sandbox-Artefakt-/Pfad-Referenz (_bmad-output, run-sandbox, sandbox-3-12); -# legitime Fach-/Koordinationswoerter im Fliesstext (z. B. einzelnes 'Build'/'Review' ohne -# Kategorie-Hyphenat; Story-Nummern wie 'Story-3.12-L6' ohne '-Historie') werden NICHT -# getroffen (PATCH 4d — Edge-Case-Hunter). -grep -qiE '(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht|Nachweis)|_bmad-output|run-sandbox|sandbox-3-12' wiki/log.md \ - && fail "L-8: log.md traegt Build-/Review-/Story-/Sandbox-Historie (AC-6 verletzt; PATCH 4d)" +# KERN (AC-6): log.md traegt KEINE Build-/Review-/Story-/Sandbox-Historie als +# KATEGORIE-benennende Eintraege (z. B. 'Build-Historie', 'Sandbox-Protokoll', +# 'Story-Log', 'Review-Bericht'). Legitime Fach-/Koordinationswoerter im Fliesstext — +# inkl. der von der eigenen Code-Map und der 3.10/3.11-Praxis getragenen Nachweis- +# Formen (Sandbox-/Review-/Validator-Nachweis-Kennzeichnungen, Artefakt-Pfadszitate, +# 'bmad-code-review', Story-Nummern ohne Kategorie-Endung) — werden NICHT getroffen: +# sie sind notwendige Koordinationsereignisse im Sinne von Vertrag §5, keine verbotene +# Historie (PATCH 4d, Loop-2-D1: Regel an die dokumentierte log.md-Praxis angegleichen +# — die Code-Map VORGIBT diese Zitate im Story-Log-Eintrag; ein Guard, der sie traf, +# wuerde die eigene Vorgabe verletzen). +grep -qiE '(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht)' wiki/log.md \ + && fail "L-8: log.md traegt Build-/Review-/Story-/Sandbox-Historie (AC-6 verletzt; PATCH 4d, Loop-2-D1)" +# Loop-2-D1 NEGATIV-KONTROLLE: die verbotene Form (Kategorie-Hyphenat) muss den Guard +# AUSLOESEN — auf einer Probe-Datei ausserhalb wiki/, damit das konforme log.md nicht +# beruehrt wird und bewiesen ist, dass die Regel zündet: +printf '### 2026-08-21 — Sandbox-Protokoll: Build-Historie und Story-Log (Review-Bericht)\n' > /tmp/l8-probe-$$ +grep -qiE '(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht)' /tmp/l8-probe-$$ \ + || fail "L-8-D1: Negativ-Kontrolle — Guard hat verbotene Kategorie-Form NICHT erkannt (Regel wirkungslos)" +rm -f /tmp/l8-probe-$$ # Positiv-Kontrolle (PATCH 4d): die beiden vertragskonformen Koordinations-Eintraege sind # vorhanden und loesen den Kategorie-Check NICHT aus — kein false-HARD-FAIL auf legitime # Koordinations-Eintraege im Fliesstext. @@ -693,12 +776,20 @@ git add wiki/alpha.md # Erlaubte Pfad-Menge nach Mutation: alpha (Kill-Punkt-Zwischenstand). Staging nur alpha. staged=$(git diff --cached --name-only | sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u) [ "$staged" = "alpha" ] || fail "L-9/KP2: nach Mutation sind nur erlaubte Pfade staged, tatsaechlich '$staged'" -echo " KP2 (nach Mutation): valider Zwischenstand (nur alpha staged), kein Ghost — PASS" +# Loop-2-P4: Ghost-Diff-Probe (Matrix KILLPUNKT_NACH_MUTATION "kein Ghost-Diff ausserhalb +# erlaubter Menge"): Index UND Worktree ueber die §5.9-P5-Helfer gegen die erlaubte Menge — +# unstagede Ghost-Dateien wuerden hier hart fehlschlagen. +assert_invariant "alpha" +echo " KP2 (nach Mutation): valider Zwischenstand (nur alpha staged), kein Ghost-Diff ausserhalb erlaubter Menge — PASS" # KILLPUNKT 3 — VOR COMMIT: nur erlaubte Pfad-Menge staged, kein Teilzustand committet. [ "$(git rev-parse HEAD)" = "$BASE" ] || fail "L-9/KP3: vor Commit Head bewegt (Teilzustand committet, AD-17f)" printf '\n### 2026-08-21 — Story-3.12-L9: Kill-Punkt-Test (Baseline %s)\n' "$BASE" >> wiki/log.md git add wiki/log.md -echo " KP3 (vor Commit): nur alpha + log staged, kein Commit, HEAD == Baseline — PASS" +[ "$(git diff --cached --name-only | sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u | paste -sd' ' -)" = "alpha log" ] \ + || fail "L-9/KP3: vor Commit sind nicht exakt alpha+log staged (Teilzustand, AD-17f)" +# Loop-2-P4: Ghost-Diff-Probe an KP3 (nur erlaubte Pfad-Menge staged, Worktree frei von Ghosts): +assert_invariant "alpha log" +echo " KP3 (vor Commit): nur alpha + log staged, kein Commit, HEAD == Baseline, kein Ghost — PASS" # KILLPUNKT 4 — NACH COMMIT: Bundle == valide committeter Zustand, anschliessbar an den # Clean-Input-Guard (kein haengender Lock, sauberer Worktree). git commit -qm "L9: Kill-Punkt-nach-Commit (Mutation + log.md)" diff --git a/_bmad-output/implementation-artifacts/spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen.md b/_bmad-output/implementation-artifacts/spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen.md index 5b778f8..e78d26a 100644 --- a/_bmad-output/implementation-artifacts/spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen.md +++ b/_bmad-output/implementation-artifacts/spec-3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen.md @@ -4,7 +4,7 @@ type: 'feature' created: '2026-08-21' status: 'done' baseline_commit: '80480af3ec910b6a00d10f4fe820131bbf79c6a5' -review_loop_iteration: 0 +review_loop_iteration: 1 context: - '_bmad-output/implementation-artifacts/epic-3-context.md' --- @@ -51,15 +51,17 @@ context: | 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.md` — **primär mutiert** (D-3): neue Sektion **§5.18 „Lease-Lifecycle & transaktionaler Commit-Abschluss (Story 3.12)"** (nach §5.17 Z. 415–424, vor §6 Z. 426; Pkt. 1–7); **§7-Bullet-Erweiterung** (Story-3.12-Verankerung analog §5.17-/§5.15-Ergänzung bei Z. 471ff); **§8-Revisionslog Revision 3.7** (Z. 486ff, nach Z. 527). Bestehende §5.11 (Z. 304–321)/§5.12 (Z. 323–342)/§5.13 (Z. 344–363)/§5.17 (Z. 415–424) 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.sh` — **neu** (re-executierbar, Muster `sandbox-3-11/run-sandbox.sh` 544 Z., Exit 0): Lifecycle-Szenarien L-1..L-9 (Matrix-Zeilen als harte Assertionen); übernimmt die 3-11-Bausteine (`isolate()` Z. 99–109, `scopelock_acquire()` Z. 124–131, `scopelock_release()` Z. 132–141 mit Ownership-Prüfung, `scopelock_content()` Z. 142–148, `assert_frontmatter()` Z. 164–173, `runlabel`/`pass`/`fail` Z. 98/179–180) und ergänzt: **Abort-/Protect-Zustandsmaschine** (aus sandbox-3-5-L4-Inline Z. 379–434: `db_check` Z. 223–234, Stash/Scratch Z. 416–421, Restore Z. 422–425), **Registry/Gen/Liveness** (aus sandbox-3-6: `reg_gen` Z. 219–224, `lease_stale` Z. 277–283, `reg_write`/`reg_bump` Z. 233–256, `reg_stale_mark` Z. 257–264, `free_lease` Z. 338–343), **Baseline-Rollback Index+Worktree** (via §5.13-Pkt.-3 Z. 359 „Post-Rollback-Diff gg. Baseline leer"), **Kill-Point-Tests** (4 Konsistenz-Assertions), **Clean-Input-Guard** (Worktree-Sauberkeitsprüfung nach Release). Kein Zugriff auf reales Bundle/`raw/`. +- `schema/compiler.md` — **primär mutiert** (D-3): neue Sektion **§5.18 „Lease-Lifecycle & transaktionaler Commit-Abschluss (Story 3.12)"** (nach §5.17 Z. 415–424, vor §6 Z. 441; Pkt. 1–7, Z. 426–439); **§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. 304–321)/§5.12 (Z. 323–342)/§5.13 (Z. 344–363)/§5.17 (Z. 415–424) 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.sh` — **neu** (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.sh` — **read-only Vorbild** (Ableitungs-Pflicht: `scopelock_release`-Ownership, `isolate`-Ref-Reset, A-8-Relase-erneut Z. 501–523; Defer „scopelock_header_banner" Z. 166/175 → Home 3.12). - `_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh` — **read-only Quelle** der Dirty-Tree-Mechanik (L4 Z. 379–434: `db_check` Z. 223–234, UNCOMMITTED_INPUT-Abbruch Z. 395–415, Stash/Scratch Z. 416–421, Restore Z. 422–425, NIE-gelöscht Z. 426–428). - `_bmad-output/implementation-artifacts/sandbox-3-6/run-sandbox.sh` — **read-only Quelle** der Registry/Stale-/Recovery-Mechanik (Registry Z. 216–245, Gen Z. 219–224/246–256, `lease_stale` Z. 277–283, Stale-Mark/Übernahme Z. 257–264/346–478, `raw/`-Recovery STALE-4 Z. 451–478, `assert_no_wallclock` Z. 294–300). - `_bmad-output/implementation-artifacts/sprint-status.yaml` — **mutiert**: Key `3-12-lease-lifecycle-und-commit-abschluss-transaktional-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`). -- `wiki/log.md` — **append** (Vertrag §5): Story-3.12-Eintrag (Verankerung §5.18, Sandbox L-1..L-9, Status-Flip, Validator-Verdikt) — **nur** vertragskonforme fachliche + Koordinationsereignisse (AC-6). +- `wiki/log.md` — **append** (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.md` — **append**: 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.md` — **mutiert** („Edit freely"): Technical Decision Z. 43 „Transaktionaler Lifecycle" von „Zielzustand… nicht verankert" auf Ist-Zustand (§5.18) aktualisieren. @@ -84,8 +86,6 @@ context: - 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). -## Spec Change Log - ## 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). @@ -121,20 +121,20 @@ Der Lifecycle ist der **geschlossene transaktionale Rahmen** der Koordinations-D **Lifecycle-Mechanik (Sandbox)** -- Atomarer Ownership-CAS im Takeover (Review-Patch Loop 1): der entscheidende Guard ist der Old-Value-Write `git update-ref `. - [`run-sandbox.sh:132`](./sandbox-3-12/run-sandbox.sh#L132) +- Atomarer Ownership-CAS im Takeover (Review-Patch Loop 1): der entscheidende Guard ist der Old-Value-Write `git update-ref `; Loop 2 ergänzt `scopelock_healthy`/LOCK_READ_ERROR-Propagation (P1). + [`run-sandbox.sh:153`](./sandbox-3-12/run-sandbox.sh#L153) -- Stale-Übernahme L-2: positiver Exactly-once-CAS plus negative atomare Abweisung (falscher Old-Value → kein Clobber, genau eine aktive Root-Lease, ersetzte Holder-ID benannt). - [`run-sandbox.sh:343`](./sandbox-3-12/run-sandbox.sh#L343) +- 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`](./sandbox-3-12/run-sandbox.sh#L367) -- Abort-/Protect-Zustandsmaschine L-3/L-4 (getrackt/ungetrackt, byte-identischer Restore) und Baseline-Rollback L-5/L-6 (Index+Worktree, Post-Rollback-Diff leer). - [`run-sandbox.sh:365`](./sandbox-3-12/run-sandbox.sh#L365) +- 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`](./sandbox-3-12/run-sandbox.sh#L442) -- Durable Release L-7 (Lock per Ref-Delete, Clean-Input-Guard des Folge-Runs) und Kill-Point-Tests L-9 (KP1–KP4). - [`run-sandbox.sh:416`](./sandbox-3-12/run-sandbox.sh#L416) +- 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 (KP1–KP4, Ghost-Diff-Probe via `assert_invariant`, Loop 2 P4). + [`run-sandbox.sh:648`](./sandbox-3-12/run-sandbox.sh#L648) -- Kanonische Log-Grenze L-8 (nur vertragskonforme Fach-/Koordinationsereignisse; präzisierter Kategorie-Check PATCH 4d). - [`run-sandbox.sh:646`](./sandbox-3-12/run-sandbox.sh#L646) +- Kanonische Log-Grenze L-8 (nur vertragskonforme Fach-/Koordinationsereignisse; Kategorie-Check an Praxis angepasst + Negativ-Kontrolle, Loop 2 D1). + [`run-sandbox.sh:700`](./sandbox-3-12/run-sandbox.sh#L700) **Status- & Nachweissynchronisation (peripher)** @@ -154,6 +154,19 @@ Der Lifecycle ist der **geschlossene transaktionale Rahmen** der Koordinations-D _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._ + +- [x] [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. +- [x] [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. +- [x] [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. +- [x] [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). +- [x] [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). +- [x] [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). +- [x] [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 ``-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). +- [x] [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). +- [x] [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 -- `/`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) +- [x] [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):** @@ -163,4 +176,16 @@ _Bmad-code-review Loop 1 (2026-08-21), 4 Layer (blind-hunter/edge-case-hunter/ve - **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; ``-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). diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index 7b35938..4891467 100644 --- a/_bmad-output/implementation-artifacts/sprint-status.yaml +++ b/_bmad-output/implementation-artifacts/sprint-status.yaml @@ -29,7 +29,7 @@ # - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended) # - Retrospective appends its action items to action_items; the status view surfaces open ones generated: 08-14-2026 00:00 -last_updated: 08-21-2026 21:24 +last_updated: 08-22-2026 07:44 project: wow20 project_key: NOKEY tracking_system: file-system @@ -62,7 +62,7 @@ development_status: 3-9-deterministische-relevanz-und-reconcile-routing-schliessen: done # Review-Loop-3-Abschluss 2026-08-21 (bmad-code-review, 4 Layer; D-3.9-1/2/3 = 1/1/2 — empfohlene Optionen; kein Loopback). Hinweis: der finale `done`-Flip ist der Step-05-Status-Sync nach konvergiertem Review-Loop (Präzedenz Story 3.7/3.8); die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). 3-10-inkrementelle-update-und-synthese-erhaltung-absichern: done # Story 3.10 Abschluss 2026-08-21 (bmad-code-review, 3 Layer; Patch-Kaskade, keine intent_gap/bad_spec — Sandbox E-1..E-9 nach Härtung 9/9 harte PASS/Exit 0, §5.16 Rev 3.5). Hinweis: die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). 3-11-root-scope-leasing-atomar-akquirieren: done # Story 3.11 Review-Loop-1-Abschluss 2026-08-21 (bmad-code-review, 4 Layer; D-3.11-1 „Konstruktiv + härten", D-3.11-2 „Intentionalen Mutationsversuch bauen"; 20 Patches angewendet — A-2-Sampler wirksam, A-4 Worktree-Beobachtung, A-7 MERGE_OK hart abgewiesen + Post-Merge-State + Baseline im Hold-Eintrag, §5.17 Pkt. 1/4/5-Berichtigungen; Sandbox A-1..A-8 8/8 harte PASS/Exit 0 re-executiert). Hinweis: der finale `done`-Flip ist der Step-05-Status-Sync nach konvergiertem Review-Loop (Präzedenz Story 3.7/3.8/3.9); die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). - 3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen: review # Story 3.12 Abschluss 2026-08-21 (bmad-code-review, 4 Layer; Review-Loop-1 konvergiert: atomarer Ownership-CAS im Takeover, AK-2->AC-2, L-2-Negativ-CAS, Sandbox-Härtung; §5.18 Revision 3.7, Sandbox L-1..L-9 9/9 harte PASS/Exit 0 re-executiert). Hinweis: der finale `done`-Flip ist der Step-05-Status-Sync nach konvergiertem Review-Loop (Präzedenz Story 3.7/3.8/3.9/3.10/3.11); die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). + 3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen: done # Story 3.12 Review-Loop-2-Abschluss 2026-08-22 (bmad-code-review, 4 Layer; D-3.12-1 Option 1 — AC-6-Grenze an log.md-Praxis, L-8-Kategorie-Hyphenate + Negativ-Kontrolle; 7 Patches — P1 scopelock_healthy()/LOCK_READ_ERROR-Propagation, P2 Release-Fehler-negativ + L-6 hart, P3 Setup-Robustheit, P4 Ghost-Diff-Probe + reg_write real, P5 Ownership-Stale + Takeover-Exactly-once, S1/S2 Sync- & Anker-Berichtigung; Sandbox L-1..L-9 9/9 harte PASS/Exit 0 re-executiert; Loop 1: atomarer Ownership-CAS im Takeover, AK-2->AC-2; §5.18 Revision 3.7). Hinweis: der finale `done`-Flip ist der Step-05-Status-Sync nach konvergiertem Review-Loop (Präzedenz Story 3.7/3.8/3.9/3.10/3.11); die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). 3-13-epic-3-verifikations-und-abnahmegate: backlog epic-3-retrospective: optional diff --git a/wiki/log.md b/wiki/log.md index 10e3408..5adefdb 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -1,5 +1,8 @@ # Log +## 2026-08-22 +- **Story 3.12 → Review-Loop-2-Abschluss + `done` (Lease-Lifecycle und Commit-Abschluss transaktional schließen, bmad-code-review 4 Layer — blind-hunter / edge-case-hunter / verification-gap / acceptance-auditor, Diff `80480af..HEAD`, 2026-08-22):** Re-Review der konvergierten Loop-1-Implementierung (Diffform `80480af..HEAD`, 4 Dateien); **Triage:** 1 decision-needed / 7 patch / 2 defer / 6 dismissed; **keine intent_gap/bad_spec (kein Loopback).** **Nutzer-Entscheidung:** D-3.12-1 = **Option 1 (empfohlene Option)** — AC-6/§5.18-Pkt.-6-Grenze an die eigene `wiki/log.md`-Praxis angeglichen: dokumentierte Run-/Review-/Sandbox-Nachweise sind **notwendige Koordinationsereignisse** (Vertrag §5; 3.10/3.11-Praxis); die verbotene Kategorie ist Build-/Review-/Story-/Sandbox-**Historie**; §5.18 Pkt. 6 und AC-6 bleiben textuell unverändert; L-8-Kategorie-Grep schärft auf Kategorie-Hyphenate `(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht)` + Negativ-Kontrolle (verbotene Form auf Probe-Datei außerhalb `wiki/` muss den Guard auslösen). **Patches (7, angewendet):** Sandbox — P1 `scopelock_healthy()`-Helfer + LOCK_READ_ERROR-Propagation vor jeder Liveness-/Release-/Takeover-Entscheidung (ein korrupter Lock wird nie mehr als „Halter hält nicht mehr" klassifiziert, AC-1-Gate bleibt geschlossen), P2 Release-Fehler negativ geübt (L-7: `scopelock_release` mit falscher Inhaber-Run-ID → harter Fehlschlag, Lock unverändert) + L-6 „valide committet" hart verifiziert (HEAD ≠ Baseline, Frontmatter im Commit, Commit-Betreff), P3 Setup-Robustheit (Exit-Checks `mktemp`/`mkdir`/`cd`/`git init`, verifizierter `$BASE`-Baseline-Commit, L-3/L-4-Backup-`cp` byte-identisch vor `checkout`/`clean`; bewusst kein `set -e` — negatives Assertion-Idiom), P4 L-9-KP2/KP3 Ghost-Diff-Probe (`assert_invariant` via `inv_viol`, Index **und** Worktree) + `reg_write` real geübt in L-1, P5 AC-1-Ownership-Stale-Zweig positiv getestet (L-1-Ende) + L-2 Takeover-Exactly-once direkt am Takeover-Pfad (zweiter CAS mit altem Old-Value schlägt atomar fehl, kein Clobber); Spec/Sync — S1 Frontmatter `review_loop_iteration: 0 → 1`, doppelte `## Spec Change Log` entfernt, ``-Schließtag ergänzt, Status-Sync vereinheitlicht (dieser Eintrag); S2 SRO-/Code-Map-/deferred-work-Anker auf Ist-Zeilen neu gesetzt. **Defer (2, → deferred-work.md append-only, Block „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). **Sandbox re-executiert:** `bash _bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh` (Windows/Git-Bash, `/tmp`-Baum, nie der reale `wiki/`-/`raw/`-Baum) → **L-1..L-9, 9/9 harte PASS, Exit 0**. **Abschlussklausel:** keine Änderung an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` (AD-3); keine neue §7-Invaliditätsklasse; kein neuer Frontmatter-/Format-Key; kein Standalone (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut, §5.12-, §5.13- und §5.17-Anker textuell unverändert (additive Klammer, Fugen-Identität); keine Wanduhr-/Systemzeitsteuerung (A0-20). **Validator-Verdikt** (human-mechanisch, `schema/validator.md` Rev 9, D-3 — kein CLI; keine Concept-Inhalts-Mutation): alle `wiki/`-Dateien **SUCCESS**. `sprint-status.yaml`-Key `3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen` → **`done`** (finaler Step-05-Flip nach konvergiertem Review-Loop-2, Präzedenz Story 3.7/3.8/3.9/3.10/3.11), `last_updated` → 08-22-2026 07:44. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag); AD-3 read-only (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert); kein Standalone (D-3), keine neue §7-Invaliditätsklasse, keine Vertragsänderung; Epic-3-Abnahme (Story 3.13) bleibt offen (epic-3 in-progress); Staleness-Nachfolge bleibt offen. + ## 2026-08-21 - **Story 3.12 → `review` (Lease-Lifecycle und Commit-Abschluss transaktional schließen, Verankerung §5.18 + Revision 3.7, 2026-08-21):** `schema/compiler.md` **Revision 3.7** — neue Sektion **§5.18 „Lease-Lifecycle & transaktionaler Commit-Abschluss (Story 3.12)“** (nach §5.17, vor §6): die Koordinations-Dimensionen aus §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) werden zur **transaktionalen Lifecycle-Klammer** geschlossen (additive Klammer, Fugen-Identität; D-3; keine Wanduhr-/Systemzeitsteuerung A0-20; kein neuer Regel-Operand). **Punkte 1–7:** (1) **Liveness & Ownership (AC-1):** eine höhere Generation allein macht eine lebende Lease **nicht** stale; Staleness verlangt bestätigten Abbruch oder abgelaufene Liveness **plus** atomare Ownership-Prüfung (generationeller §5.12-Staleness-Check ist notwendig, nicht hinreichend — die Liveness wird am Scope-Lock-Inhalt bestätigt, keine Wanduhr-TTL A0-20), (2) **stale-Übernahme genau einmal (AC-2):** ownership-gebunden über den §5.17-Scope-Lock (`refs/leases/wiki`), ersetzte Holder-ID benannt im `log.md`, genau eine aktive Root-Lease, nie stiller Verlust (AD-17e), (3) **eindeutige Abort-/Protect-Zustandsmaschine (AC-3):** getrackte fremde Änderung → Scratch-Zone `scratch//` bzw. `git stash push`; ungetrackte fremde Datei → Protect (sichern + byte-identischer Restore, keine stillen Löschungen AD-17e); `UNCOMMITTED_INPUT`-Abbruch abgestimmt mit §5.11 Pkt. 3, (4) **Baseline-Rollback (AC-4):** `git reset --hard ` stellt Index **+** Worktree aus dem bezeichneten Baseline-Commit wieder her, Post-Rollback-Diff leer (§5.13 Pkt. 3; Kill-Punkt nach Mutation/Staging), (5) **durable Release (AC-5):** Mutation + zulässiger Log-/Koordinationsnachweis committet, Lock per Ref-Delete nur durch den Inhaber (Ownership) entfernt, Worktree sauber, der unmittelbar folgende Run besteht den **Clean-Input-Guard**, (6) **kanonisches Log (AC-6):** `wiki/log.md` enthält nur vertragskonforme fachliche Änderungen + notwendige Koordinationsereignisse; Build-/Review-/Story-/Sandbox-Historie außerhalb, (7) **Kill-Point-Tests (AC-7):** vor Mutation, nach Mutation, vor Commit, nach Commit — je konsistenter Endzustand (§5.13-Pkt.-3-Zustands-Restaurations-Invariante). **§7:** Leasing-Bullet um die Story-3.12-Verankerung erweitert (originaler Wortlaut textuell unverändert); **§8:** Revisionslog-Addendum 3.7 (Abschlussklausel AD-3). **Sandbox-Nachweis** (`_bmad-output/implementation-artifacts/sandbox-3-12/run-sandbox.sh`, `/tmp`-Baum, nie der reale Ist-Baum; re-executierbar): **L-1..L-9, 9/9 harte PASS, Exit 0** — L-1 LIVENESS_AKTIV (Gen-Bump ohne bestätigten Abbruch macht eine lebende Lease nicht stale; Lock-Inhalt = Liveness-Bestätigung), L-2 STALE_UEBERNAHME **genau einmal** (Takeover als Ownership-CAS, ersetzte Holder-ID benannt im `log.md`, genau eine aktive Root-Lease), L-3 DIRTY_GETRACKT (Scratch-Sicherung + byte-identischer Restore + `UNCOMMITTED_INPUT`-Abbruch), L-4 DIRTY_UNGETRACKT (Protect: sichern + Restore, nie gelöscht), L-5 ROLLBACK_NACH_MUTATION (`git reset --hard ` — Index **+** Worktree, leerer Post-Rollback-Diff), L-6 ROLLBACK_NACH_COMMIT_VOR_RELEASE (Kill-Punkt nach Commit, Konsistenz-Endzustand), L-7 RELEASE_DURABLE (Mutation + Nachweis committet, Lock per Ref-Delete entfernt, Worktree sauber, Folge-Run besteht Clean-Input-Guard), L-8 KANONISCHES_LOG (nur vertragskonforme fachliche + Koordinationsereignisse; Sandbox-/Review-/Build-Historie textuell zurückgewiesen), L-9 KILLPUNKT_TESTS (vier Kill-Punkte je konsistenter Endzustand). **Defer-Aufgriffe:** `deferred-work.md` append — drei Story-3.12-Home-Defers → **`aufgegriffen`** (Sandbox-3.5/-3.6-check-then-act-Abgleich mit dem §5.17-Scope-Lock — Home §5.18 Pkt. 1/2/5; Banner-/I-O-Matrix-Kosmetik und `scopelock_header_banner`-Platzhalter via Banner-Konvention der Sandbox L-1..L-9). **Abschlussklausel:** keine Änderung an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` (AD-3); keine neue §7-Invaliditätsklasse; kein neuer Frontmatter-/Format-Key; kein Standalone (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut, §5.12-, §5.13- und §5.17-Anker textuell unverändert (additive Klammer, Fugen-Identität); kein textueller Auto-Merge (AD-17c); Kollisions-/Klassifikations-Semantik bleibt AD-16/Epic 4; keine Wanduhr-/Systemzeitsteuerung (A0-20). `sprint-status.yaml`-Key `3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen` → **`review`** (Implementierungs-Flip, HEAD-Stand 08-21-2026; finaler `done`-Flip im Step-05-Status-Sync nach konvergiertem Review-Loop, Präzedenz Story 3.7/3.8/3.9/3.10/3.11), `last_updated` → 08-21-2026 20:45. **Validator-Verdikt** (human-mechanisch, `schema/validator.md` Rev 9, D-3 — kein CLI; keine Concept-Inhalts-Mutation): alle `wiki/`-Dateien **SUCCESS**. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag); AD-3 read-only (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert); kein Standalone (D-3), keine neue §7-Invaliditätsklasse, keine Vertragsänderung; Epic-3-Abnahme (Story 3.13) bleibt offen (epic-3 in-progress); Staleness-Nachfolge bleibt offen. - **Story 3.11 → Review-Loop-1-Abschluss + `done` (Root-Scope-Leasing atomar und worktree-übergreifend akquirieren, bmad-code-review 4 Layer — blind-hunter / edge-case-hunter / verification-gap / acceptance-auditor, 2026-08-21):** Re-Review der Implementierung (Diffform `a8b486d..e02cf84`, 7 Dateien); **Triage:** 2 decision-needed / 20 patch / 5 defer / 5 dismissed; **keine intent_gap/bad_spec (kein Loopback).** **Nutzer-Entscheidungen:** D-3.11-1 AC-d-Beweisart = **Konstruktiv + härten** („niemals zwei aktive Root-Leases“ konstruktiv belegt — eine scope-bezogene Ref + atomarer create-only-Write —, A-2-Sampler gehärtet, Nachweis um „konstruktiv“ qualifiziert); D-3.11-2 A-4-Mutations-Regime = **Intentionalen Mutationsversuch bauen** (Worktree-Beobachtung des Arbeitsbaums statt invarianter Baseline-Blob-Selbstvergleich). **Patches (20, angewendet):** Sandbox — A-2-Sampler **wirksam** (Ref-Kardinalität + Wert-Evidenz im Überlappungs-Fenster; `TWO_LOCKS_AT_ONCE`/`TWO_VALUES_IN_WINDOW`-Marker per stdout ins Capture, statt strukturell tot per `>&2` + nie >1), A-4 **Worktree-Beobachtung** (Arbeitsbaum sauber, `wiki/alpha.md`/`log.md` byte-gleich, keine Commits über Baseline; D-3.11-2), A-7 **`MERGE_OK` hart abgewiesen** (stiller textueller Auto-Merge = AD-17c/AC-e-Verletzung; statt `MERGE_CONFLICT|MERGE_OK`-Durchlass) + stale-Kommentar-Korrektur + tautologische `hold_msg`-Variablen-Case entfernt + **Post-Merge-State-Assertions** auf `branch-y`-HEAD/Body + **`baseline=$BASE`** im `log.md`-Hold-Eintrag (Hold-Mechanik-Form §5.16-Pkt.-8), **`assert_frontmatter`-Aufrufe** an den A-7-Varianten (tote Funktion wird ausgeführt), A-3-Kommentar-Korrektur (sequentiell, echte Überlappung liegt in A-2) + **exakter Identitäts-Fall** `RUN-A3` geübt, A-1 toter `run_a1`-Blob entfernt, A-8 Commit-Zähl-Check **nach** erstem Release (vorher vor dem Release = wirkungslos), finale **No-op-Schlusskontrolle → echte Arbeitsbaum-Sauberkeits-Assertion** + Worktree-Abbau (`git worktree remove`, A-2/A-4), **`scopelock_release()`-Ownership-Prüfung + Exit-Code-Kopplung** (Inhaber-Run-ID muss Lock-Inhalt tragen; Release-Fehler = HARD-FAIL), `isolate()`-Ref-Namespace-Raum (hänge­nde Scope-Locks kontaminieren keine Folgeszenarien), **Release-Ende-Leereprüfung je Szenario vereinheitlicht** (A-1/A-2/A-3/A-4/A-5/A-6/A-8). compiler.md §5.17 — Pkt. 1 **Ref-Objekttyp** (Ref verweist auf geschriebenen Blob-Inhalt, kein Commit-Objekt; endet per Ref-Delete), Pkt. 4 **Determinismus-Grenze** (sequentielle Versuche deterministisch; überlappende Producer → Gewinnerwahl Scheduling-abhängig, Invariante bleibt genau-ein-Gewinner), Pkt. 5 **Grammatik-Korrektur + Ablage-Stelle** (datumsgruppierte `log.md`-Eintrag als normatives Hold-Ziel benannt), §8-Revision-3.6 + log-Nachweis um **„konstruktiv“** qualifiziert. Spec — Frontmatter `context:` um `epic-3-context.md` (Präzedenz 3.10), `review_loop_iteration: 0 → 1`, **Verification-Kommandos berichtigt** (ungültiges `git -C ` entfernt, gezielte `grep -n "Revision 3.6"`/`## 5.17`), **Suggested-Review-Order-Anker neu gesetzt** (compiler.md:424 Abgrenzung, log.md:4, deferred-work.md:578; compiler.md:415 verifiziert korrekter §5.17-Überschrift-Anker). **Defer (5, → deferred-work.md append-only):** AC-d-Token-Statussynchronisation (Home Epic 4), Sandbox-3.5/-3.6-check-then-act-Abgleich (Home 3.12/3.13), A-2-garantierte-Überlappung (Home Sandbox-Härtung/3.13), Status-Kontraktion 3.9-Präzedenz (kein Defekt, hier aufgelöst), Banner-/I/O-Matrix-Kosmetik (Home 3.12) — inkl. **KORREKTUR-Teileintrag** (vorheriger Zeilen-Drift-Defer „§5.11/§5.12-Anker veraltet“ **widerlegt**: §5.11 weiterhin Z. 304, §5.12 Z. 323, Fugen-Identität verifiziert). **Sandbox re-executiert:** `bash _bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh` (Windows/Git-Bash) → **A-1..A-8, 8/8 harte PASS, Exit 0**, kein Zugriff auf reales Bundle/`raw/` (AD-3); Ask-First-Pflicht **nicht ausgelöst** (create-only-Primitiv zuverlässig atomar belegbar). **Validator-Verdikt (human-mechanisch, `schema/validator.md` Rev 9, D-3 — kein CLI; keine Concept-Inhalts-Mutation):** alle `wiki/`-Dateien SUCCESS. `sprint-status.yaml`-Key `3-11-root-scope-leasing-atomar-akquirieren` → **`done`** (finaler Step-05-Flip nach konvergiertem Loop-1; D-3.9-2-Präzedenz: Impl-Commit-`review` maßgeblich, finaler `done`-Flip hier), `last_updated` → 08-21-2026. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag); AD-3 read-only (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert); kein Standalone (D-3), keine neue §7-Invaliditätsklasse, keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker textuell unverändert (Fugen-Identität); Epic-3-Abnahme (Story 3.13) bleibt offen (epic-3 in-progress); Lease-Lifecycle (Story 3.12) und Staleness-Nachfolge bleiben offen.