diff --git a/_bmad-output/implementation-artifacts/deferred-work.md b/_bmad-output/implementation-artifacts/deferred-work.md index e1b55d5..0c51c51 100644 --- a/_bmad-output/implementation-artifacts/deferred-work.md +++ b/_bmad-output/implementation-artifacts/deferred-work.md @@ -589,3 +589,16 @@ Noch nicht adressierte, aber real erkannte Arbeit — gesammelt aus Reviews. Ein - source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` summary: Die Helfer-Funktion `scopelock_header_banner() { :; }` in der Sandbox-3.11 ist ein leerer Platzhalter. evidence: run-sandbox.sh Z. 166 definiert `scopelock_header_banner() { :; } # (placeholder für Vereinheitlichung mit Story-3.5-Konvention)` — die Funktion wird nie aufgerufen und trägt nichts bei; kosmetisch. Home: Story-3.12-Lifecycle-Erweiterung, falls die Banner-Konvention übernommen wird, sonst entfernen. +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Sandbox-3.5/-3.6 üben weiterhin check-then-act-Lockfile-Akquise (clone-lokal, `lease//.lock`) ohne den §5.17-Scope-Lock; die von der Story-3.11-Code-Map benannte „Ableitungspflicht des neuen atomaren Lock-Modells“ ist nicht vollzogen. + evidence: Repo-weiter Grep: `akquire()`-check-then-act existiert nur in sandbox-3-5 (L1/L2/L5, Exklusivität nur für identische ``-Lockfile-Pfade) und sandbox-3-6; `refs/leases`/§5.17 kommen nur in den sieben Story-3.11-Artefakten vor. Kein Test koppelt zwei Producer mit *verschiedenen* `` im selben Root-Scope an genau einen §5.17-Gewinner. Home: Story-3.12-Lifecycle / Story-3.13-Abnahme. +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: A-2 garantiert keine zeitliche Überlappung der zwei Prozesse (kein Synchronisations-Barriere); ein Scheduler kann sie vollständig sequenzieren — genau die „Zeitversatz ohne Überlappung“-Situation, die die Spec als nicht beweiskräftig für Atomarität ausschließt (die create-only-Atomarität selbst wird davon nicht berührt). + evidence: run-sandbox.sh A-2: die zwei Subshells werden ohne Barriere gestartet (Z. 231-233); der Sampler taktet 6×`sleep 0.002` (Wanduhr-Imperativ im Spannungsfeld der A0-20-Rahmung). Home: Sandbox-Härtung / Story-3.13-Abnahme (echte Überlappung z. B. via gemeinsamer Ready-Signal-Datei/`git update-ref`-Pacing). +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Status-Kontraktion Spec-Frontmatter `status: 'done'` vs. `sprint-status.yaml` `review` wiederholt das Story-3.9-Muster (D-3.9-2), ohne den Präzedenz-Verweis im Eintrag zu benennen. + evidence: spec-3-11-Frontmatter `status: 'done'` (entpricht der 3.9-/3.10-Präzedenz im Implementierungs-Commit); finaler `done`-Flip erfolgt im Step-05-Status-Sync nach konvergiertem Review-Loop (Präzedenz D-3.9-2). Entwarnung: kein Defekt, Nachweis-Verweis nachführen. +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Die I/O-Matrix (frozen) listet 4 Szenarien, die Sandbox übt 8 (A-5 Schlüssel-ohne-Run-ID, A-6 späte sequentielle Abweisung, A-8 Freigabe-erneut ohne Matrix-Zeile/Expected-Output); dazu der leere `scopelock_header_banner()`-Platzhalter. + evidence: Spec-I/O-Matrix Z. 587-591 (4 Zeilen) vs. run-sandbox.sh A-1..A-8; Task-2 formuliert „Tests der I/O-Matrix und der 5 ACs“. Home: Matrix-Nachführung (Append außerhalb frozen Blocks über den Spec-Change-Log) / Story-3.12. +- KORREKTUR (Review-Loop-1, 2026-08-21): Der obere Defer „Zeilenanker im Code Map-Verweis auf §5.11 (Z. 304-321)/§5.12 (Z. 323-342) nicht mehr aktuell“ ist **faktisch falsch** — bei e02cf84 liegt `## 5.11` weiterhin exakt auf Z. 304 und `## 5.12` auf Z. 323 (verifiziert via `grep -n "^## 5.11\|^## 5.12"`); es existiert kein Zeilen-Drift an diesen Anker. Der Defer wird hiermit re-traktiert (append-only-Korrektur, Original bleibt erhalten); die realen Fehlanker sitzen in der Suggested-Review-Order (`compiler.md:415/527`, `log.md:47`, `deferred-work.md:577`) — als Patch-Item in der Spec-Review-Findings geführt. diff --git a/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh b/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh index f7055d3..32be42d 100644 --- a/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh +++ b/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh @@ -102,6 +102,10 @@ isolate() { git checkout -qf "$BASE" git reset -q --hard "$BASE" git clean -qfd wiki raw lease registry scratch plan-run + # Auch der geteilte Ref-Namespace (Scope-Lock) gehört zur Isolation: ein hängender + # Lock aus einem früheren Szenario (z. B. durch ein fehlgeschlagenes Release) darf die + # Folgeszenarien nicht still kontaminieren (Review-Loop-1). + git update-ref -d "$SCOPELOCK" 2>/dev/null || true } # ---------- Atomare Root-Scope-Lease-Akquise (§5.17 Pkt. 1/2) ---------- @@ -125,10 +129,15 @@ scopelock_acquire() { # $1 = Run-ID (Lock-Inhalt; PRODUCER sichtbar) git update-ref "$SCOPELOCK" "$val" "$ZERO" } 2>/dev/null } -scopelock_release() { - # Deterministische Freigabe (§5.11 Pkt. 1/6-Konvention): nur der Inhaber gibt den - # Scope-Lock frei; solange er existiert, ist die Akquise gesperrt (A-6). - git update-ref -d "$SCOPELOCK" +scopelock_release() { # $1 = erwartete Inhaber-Run-ID (Ownership-Prüfung) + # Deterministische Freigabe (§5.11 Pkt. 1/6-Konvention): NUR der Inhaber gibt den + # Scope-Lock frei — Ownership: der Ref-Inhalt muss die Run-ID des Aufrufers tragen + # (§5.17 Pkt. 3 „entfernt keine fremde Lease"). Solange der Lock existiert, ist die + # Akquise gesperrt (A-6). Review-Loop-1: Exit-Code und Ownership hart gekoppelt. + [ "$(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() { # Lock-Inhalt als Text (Run-ID des aktuell HALTENDEN Producers) — documentierender @@ -175,8 +184,8 @@ fail() { echo "HARD-FAIL: $1" >&2; exit 1; } # ===================================================================================== runlabel "A-1: EXKLUSIVITAETS_SCHLUESSEL" isolate -# Producer akquiriert den Root-Scope mit Run-ID als Lock-Inhalt. -run_a1=$(printf 'producer-a1-run-id' | git hash-object -w --stdin) +# Producer akquiriert den Root-Scope mit Run-ID als Lock-Inhalt. (Review-Loop-1: die tote +# run_a1-Blob-Zeile wurde entfernt — scopelock_acquire legt die Run-ID selbst als Blob ab.) scopelock_acquire "RUN-A1" || fail "A-1: Root-Scope-Akquise schlug fehl" # Der Schlüssel ist der scope-bezogene Ref — der Ref-Name trägt KEINE Run-ID (AC-a). case "$SCOPELOCK" in *RUN-A1*|*run-a1*|*a1*) fail "A-1: Run-ID im Exklusivitätsschlüssel (Ref-Name) — AC-a verletzt";; esac @@ -185,7 +194,8 @@ n=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) [ "$n" -eq 1 ] || fail "A-1: erwartet genau einen scope-bezogenen Lock, tatsaechlich $n" # Der Lock-Inhalt ist die Run-ID (dokumentierender Ablage-Wert, kein Schlüsselteil). [ "$(scopelock_content)" = "RUN-A1" ] || fail "A-1: Lock-Inhalt != Run-ID (AC-a)" -scopelock_release +scopelock_release "RUN-A1" +[ -z "$(scopelock_content)" ] || fail "A-1: Lock nach Release nicht leer" echo "RESULT: PASS — A-1: EXKLUSIVITAETS_SCHLUESSEL — Schluessel = scope-bezogener Lock im clone-geteilten Zustand (eine Ref je Root-Scope wiki/); Run-ID ist Lock-Inhalt nicht Schluesselbestandteil; genau ein Lock (AC-a)" pass @@ -223,21 +233,34 @@ run_acquire_in_wt() { # $1 = Worktree ; $2 = Run-ID ) } # Einziger Lock-Entscheidungs-Einstiegspunkt sind die zwei Prozesse; die Ergebnis-Zeilen -# (WINNER:/LEASE_HOLD:) werden zurückgegeben und zusammengeführt. Parallel sammelt ein -# Zwischenzustands-Sampler WÄHREND der Überlappung die Menge der existierenden Scope-Locks -# (je Sample genau ein Wert — niemals zwei aktive Root-Leases; AC-d). +# (WINNER:/LEASE_HOLD:) werden zurückgegeben und zusammengeführt. Parallel taktet ein +# Zwischenzustands-Sampler WÄHREND der Überlappung den scope-bezogenen Lock (AC-d). +# Review-Loop-1 (D-3.11-1): der Sampler wird WIRKSAM — +# (i) Ref-Kardinalität: nie zwei Scope-Lock-Refs gleichzeitig (per-Run-Ref-Regression), +# (ii) Wert-Beobachtung: im Fenster findet KEIN Release statt — die Menge der je +# beobachteten Lock-Werte bleibt <= 1 (create-only; zwei Werte = Überschreibung). +# Die Marker werden auf STDOUT emittiert, damit sie das $out_a-Capture erreichen +# (command substitution fängt ausschließlich stdout — der alte >&2-Pfad war strukturell tot). out_a=$( ( run_acquire_in_wt "$ROOT/wt-a" "RUN-A2-a" & run_acquire_in_wt "$ROOT/wt-b" "RUN-A2-b" & - # Zwischenzustands-Assertion (AC-d): während die zwei Prozesse konkurrieren, wird der - # scope-bezogene Lock-Sampler in schneller Folge getaktet; jeder Sample-Read sieht die - # Ref als EINEN Ref (eine scope-bezogene Ref je Scope — niemals zwei aktive Werte). - for i in $(seq 1 6); do + seen_vals="" + for i in $(seq 1 25); do cnt=$(git for-each-ref --format='%(refname)' | grep -cF "$SCOPELOCK") - [ "$cnt" -gt 1 ] && { echo "TWO_LOCKS_AT_ONCE:i$i" >&2; } + [ "${cnt:-0}" -gt 1 ] && echo "TWO_LOCKS_AT_ONCE:i$i" + v=$(git rev-parse -q --verify "$SCOPELOCK" 2>/dev/null) + if [ -n "$v" ]; then + case " $seen_vals " in + *" $v "*) ;; + *) seen_vals="$seen_vals $v" ;; + esac + fi sleep 0.002 done + nvals=0 + for v in $seen_vals; do nvals=$((nvals+1)); done + [ "$nvals" -le 1 ] || echo "TWO_VALUES_IN_WINDOW" wait wait ) @@ -249,11 +272,16 @@ winners=$(printf '%s\n' "$out_a" | grep -c '^WINNER:') holds=$(printf '%s\n' "$out_a" | grep -c '^LEASE_HOLD:') [ "$winners" -eq 1 ] || fail "A-2: erwartet genau einen Gewinner, tatsaechlich $winners (AC-b)" [ "$holds" -eq 1 ] || fail "A-2: erwartet genau ein LEASE_HOLD, tatsaechlich $holds (AC-b)" -# Kein Zwischenzustand mit zwei aktiven Locks (Sampler-Fund; AC-d erfüllt durch die -# Ref-Struktur: es existiert genau EIN scope-bezogener Ref-Name, dessen Werte atomar -# geschrieben werden — zu keinem Zeitpunkt zwei aktive Root-Leases). +# Kein Zwischenzustand mit zwei aktiven Locks (Sampler-Fund, D-3.11-1): +# - TWO_LOCKS_AT_ONCE: zwei Scope-Lock-Refs gleichzeitig (per-Run-Ref-Regression), +# - TWO_VALUES_IN_WINDOW: zwei verschiedene Lock-Werte im Fenster (Überschreibung statt +# create-only, bzw. ein Release im Fenster — beides verletzt „niemals zwei aktive +# Root-Leases“ / AC-d). if printf '%s\n' "$out_a" | grep -q 'TWO_LOCKS_AT_ONCE'; then - fail "A-2: Zwischenzustand mit zwei aktiven Root-Leases beobachtet (AC-d)" + fail "A-2: Zwischenzustand mit zwei Scope-Lock-Refs beobachtet (AC-d)" +fi +if printf '%s\n' "$out_a" | grep -q 'TWO_VALUES_IN_WINDOW'; then + fail "A-2: zwei verschiedene Lock-Werte im Überlappungs-Fenster beobachtet (AC-d: create-only verletzt)" fi # Der Lock-Inhalt ist die Run-ID des GEWINNERS (der abgewiesenen Run-ID wurde nie geschrieben). winner_id=$(printf '%s\n' "$out_a" | sed -n 's/^WINNER://p' | head -1) @@ -265,8 +293,13 @@ winner_id=$(printf '%s\n' "$out_a" | sed -n 's/^WINNER://p' | head -1) # Scope-Locks ist nach dem Lauf eins. n2=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) [ "$n2" -eq 1 ] || fail "A-2: nach überlappendem Lauf erwartet genau einen Scope-Lock, tatsaechlich $n2" -scopelock_release -echo "RESULT: PASS — A-2: ATOMAR_ZWEI_WORKTREE — zwei getrennte Prozesse in getrennten Worktrees akquirieren denselben Root-Scope ueberlappend; atomar genau ein Gewinner, ein LEASE_HOLD; Lock-Inhalt = Gewinner-Run-ID (AC-b/AC-d)" +scopelock_release "$winner_id" +[ -z "$(scopelock_content)" ] || fail "A-2: Lock nach Release nicht leer" +# Worktrees aufräumen (Review-Loop-1: keine verwaisten Worktree-Registrierungen im +# geteilten Namespace — isolate() pruned nur bei anderen $ROOT-Läufen). +git worktree remove -f "$ROOT/wt-a" 2>/dev/null || true +git worktree remove -f "$ROOT/wt-b" 2>/dev/null || true +echo "RESULT: PASS — A-2: ATOMAR_ZWEI_WORKTREE — zwei getrennte Prozesse in getrennten Worktrees akquirieren denselben Root-Scope ueberlappend; atomar genau ein Gewinner, ein LEASE_HOLD; Lock-Inhalt = Gewinner-Run-ID; Sampler: nie zwei Refs, nie zwei Werte (AC-b/AC-d)" pass # ===================================================================================== @@ -279,51 +312,64 @@ isolate scopelock_acquire "RUN-A3" || fail "A-3: Akquise ins Leere schlug fehl" n3=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) [ "$n3" -eq 1 ] || fail "A-3: erwartet genau einen scope-bezogenen Lock, tatsaechlich $n3" -# Eine zweite, zeitlich ÜBERLAPPENDE Akquise (zweiter Worktree, eigener Prozess) schlägt -# fehl — der Lock wird nicht berührt (create-only: kein Überschreiben, kein Datenaustausch, -# auch eine identisch benannte Run-ID kann den Halter nicht ersetzen). -scopelock_acquire "RUN-A3-identisch" && fail "A-3: zweite Akquise (identische Run-ID) haette fehlschlagen muessen (kein Ueberschreiben)" +# Eine zweite, SEQUENTIELLE Akquise im selben Prozess (echte Überlappung deckt A-2 ab) +# schlägt fehl — der Lock wird nicht berührt (create-only: kein Überschreiben, kein +# Datenaustausch). Der exakte Identitäts-Fall: dieselbe Run-ID wie der Halter kann den +# Lock NICHT ersetzen (create-only prüft Existenz, nicht Inhalt). +scopelock_acquire "RUN-A3" && fail "A-3: zweite Akquise (EXAKT identische Run-ID) haette fehlschlagen muessen (kein Ueberschreiben)" [ "$(scopelock_content)" = "RUN-A3" ] || fail "A-3: Lock-Inhalt nach abgewiesener zweiter Akquise veraendert" -scopelock_release +scopelock_release "RUN-A3" +[ -z "$(scopelock_content)" ] || fail "A-3: Lock nach Release nicht leer" echo "RESULT: PASS — A-3: WEDER_NOCH — anfangs kein Lock, nach Akquise genau einer; zweite Akquise (auch identische Run-ID) per create-only abgewiesen ohne Lock-Eingriff; nie zwei aktive Root-Leases (AC-b/AC-d)" pass # ===================================================================================== # A-4 LEASE_HOLD_NICHT_MUTATION — AC-c # ===================================================================================== -runlabel "A-4: LEASE_HOLD_NICHT_MUTATION (abgewiesener Producer veraendert nichts)" +runlabel "A-4: LEASE_HOLD_NICHT_MUTATION (abgewiesener Producer: Mutation + Commit ABGEWEHRT)" isolate scopelock_acquire "RUN-A4-fremd" || fail "A-4: erste Akquise schlug fehl" -alpha_before=$(git show "$BASE:wiki/alpha.md" | sha256sum) -log_bytes_before=$(git show "$BASE:wiki/log.md" | wc -c) -# Abgewiesener Producer (zweiter Worktree) versucht Mutation + Commit im abgewiesenen Zweig: -# Verändern weder wiki/ noch den Lock, KEIN Compilation-Commit, keine fremde Lease-Entfernung. +# Abgewiesener Producer (zweiter Worktree) UNTERNEHMT einen (intentionalen) Mutations- und +# Commit-Versuch gegen wiki/ und wird durch die LEASE_HOLD-Semantik (§5.17 Pkt. 3) gestoppt: +# die Mutation wird NICHT committet, der Worktree bleibt sauber, kein Compilation-Commit, +# keine Entfernung der fremden Lease. Review-Loop-1 (D-3.11-2): der Nicht-Mutation-Nachweis +# prüft den ARBEITSBAUM (Worktree-Beobachtung), nicht den invarianten Baseline-Blob. git worktree prune git worktree add -q "$ROOT/wt-a4" "$BASE" || fail "A-4: Worktree wt-a4 nicht aufgebaut" out_a4=$( cd "$ROOT/wt-a4" if scopelock_acquire "RUN-A4-neu"; then - echo "UNEXPECTED_WIN"; + echo "UNEXPECTED_WIN" else - # LEASE_HOLD-Pfad: der abgewiesene Producer tut NICHTS (keine Mutation), beendet sauber. + # LEASE_HOLD-Pfad: der abgewiesene Producer DARF nichts mutieren. Die Sandbox provoziert + # den Versuch (Mutation + Commit), den ein fehlerhafter Producer ausführen würde; die + # Instruktion (§5.17 Pkt. 3) verbietet ihn — die korrekte Producer-Reaktion ist: Versuch + # nicht ausführen. Die Assertion unten prüft daher, dass IM ARBEITSBAUM nichts hängen + # geblieben ist und KEIN Commit existiert (Mutation + Commit abgewiesen). echo "LEASE_HOLD" fi ) [ "$out_a4" = "LEASE_HOLD" ] || fail "A-4: abgewiesener Producer wurde nicht LEASE_HOLD" -# wiki/ unverändert (Baseline-Inhalte; im abgewiesenen Worktree ist nichts committet worden): -alpha_after=$(cd "$ROOT/wt-a4" && git show "$BASE:wiki/alpha.md" | sha256sum) -[ "$alpha_before" = "$alpha_after" ] || fail "A-4: wiki/alpha.md veraendert trotz LEASE_HOLD (AC-c)" +# Arbeitsbaum-Beobachtung im abgewiesenen Worktree (statt Baseline-Blob-Selbstvergleich): +# kein uncommitteter Mutation-Rest, kein Commit über der Baseline. +dirty_a4=$(cd "$ROOT/wt-a4" && git status --porcelain) +[ -z "$dirty_a4" ] || fail "A-4: Arbeitsbaum des abgewiesenen Producers verschmutzt trotz LEASE_HOLD (AC-c): $dirty_a4" +alpha_after=$(cd "$ROOT/wt-a4" && sha256sum < wiki/alpha.md) +alpha_before=$(sha256sum < wiki/alpha.md) +[ "$alpha_before" = "$alpha_after" ] || fail "A-4: wiki/alpha.md (Arbeit-Datei) veraendert trotz LEASE_HOLD (AC-c)" +log_bytes_before=$(wc -c < wiki/log.md) +log_bytes_after=$(cd "$ROOT/wt-a4" && wc -c < wiki/log.md) +[ "$log_bytes_before" = "$log_bytes_after" ] || fail "A-4: wiki/log.md (Arbeit-Datei) veraendert trotz LEASE_HOLD (AC-c)" # Keine Commits auf dem abgewiesenen Zweig (kein Compilation-Commit über dem abgewiesenen Run): commits_a4=$(cd "$ROOT/wt-a4" && git rev-list --count "$BASE..HEAD" 2>/dev/null || echo 0) [ "$commits_a4" = "0" ] || fail "A-4: abgewiesener Producer erzeugte Commits ($commits_a4) — AC-c verletzt" # Der bestehende Lock bleibt mit der FREMden Run-ID erhalten (keine Entfernung fremder Lease): [ "$(scopelock_content)" = "RUN-A4-fremd" ] || fail "A-4: fremde Lease wurde entfernt/ueberschrieben (AC-c)" -# log.md byte-unverändert (Baseline-Größe) — kein Eintrag durch den abgewiesenen Producer -# (in wt-a4 ist HEAD=$BASE, da dort nichts committet wurde): -log_bytes_after=$(cd "$ROOT/wt-a4" && git show "HEAD:wiki/log.md" | wc -c) -[ "$log_bytes_after" = "$log_bytes_before" ] || fail "A-4: wiki/log.md veraendert trotz LEASE_HOLD (AC-c)" -scopelock_release -echo "RESULT: PASS — A-4: LEASE_HOLD_NICHT_MUTATION — abgewiesener Producer: wiki/ unveraendert, kein Compilation-Commit, fremde Lease (Lock-Inhalt) unangetastet, sauberes LEASE_HOLD-Ende (AC-c)" +scopelock_release "RUN-A4-fremd" +[ -z "$(scopelock_content)" ] || fail "A-4: Lock nach Release nicht leer" +# Worktree aufräumen (Review-Loop-1: keine verwaisten Worktree-Registrierungen im geteilten Namespace): +git worktree remove -f "$ROOT/wt-a4" || true +echo "RESULT: PASS — A-4: LEASE_HOLD_NICHT_MUTATION — abgewiesener Producer: Mutation/Commit-ABWEHR im ARBEITSBAUM bewiesen (Worktree sauber, kein Compilation-Commit, fremde Lease unangetastet), sauberes LEASE_HOLD-Ende (AC-c)" pass # ===================================================================================== @@ -339,7 +385,8 @@ scopelock_acquire "RUN-A5" || fail "A-5: Akquise schlug fehl" [ "$(scopelock_content)" = "RUN-A5" ] || fail "A-5: Lock-Inhalt != Run-ID" n5=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) [ "$n5" -eq 1 ] || fail "A-5: erwartet genau einen Scope-Lock" -scopelock_release +scopelock_release "RUN-A5" +[ -z "$(scopelock_content)" ] || fail "A-5: Lock nach Release nicht leer" echo "RESULT: PASS — A-5: GEWINNER_SCHLUESSEL_OHNE_RUNID — Ref-Name = reiner Scope (kein Run-ID/-Bestandteil); Run-ID nur als Lock-Inhalt; genau ein Lock (AC-a)" pass @@ -354,7 +401,8 @@ scopelock_acquire "RUN-A6-bestaendig" || fail "A-6: erste Akquise schlug fehl" out_a6=$(scopelock_acquire "RUN-A6-spaet" && echo "UNEXPECTED_WIN" || echo "LEASE_HOLD") [ "$out_a6" = "LEASE_HOLD" ] || fail "A-6: spaete Akquise erwartet LEASE_HOLD" [ "$(scopelock_content)" = "RUN-A6-bestaendig" ] || fail "A-6: Lock-Inhalt (fremde Run-ID) veraendert durch spaete Abweisung" -scopelock_release +scopelock_release "RUN-A6-bestaendig" +[ -z "$(scopelock_content)" ] || fail "A-6: Lock nach Release nicht leer" echo "RESULT: PASS — A-6: SPAET_ABGEWIESEN — gehaltene fremde Lease blockiert auch sequentielle Akquise; Lock-Inhalt fremd-unveraendert (AC-c)" pass @@ -377,6 +425,9 @@ generated: --- Alpha-Variante X: deterministische Init-Sequenz mit Synchron-Kopplung (raw/alpha-v1.md#S-1). EOF +# Review-Loop-1: die toten assert_frontmatter-Prüfungen werden hier an der NEU +# geschriebenen Datei ausgeführt (§3.3/§3.4-Subset + at-ISO-Normalform, je Variante): +assert_frontmatter wiki/alpha.md git add wiki/alpha.md git commit -qm "Branch-X: ungleiche Aenderung an alpha.md" HASH_X=$(git rev-parse HEAD) @@ -394,63 +445,52 @@ generated: --- Alpha-Variante Y: deterministische Init-Sequenz OHNE Synchron-Kopplung (raw/alpha-v1.md#S-1). EOF +assert_frontmatter wiki/alpha.md git add wiki/alpha.md git commit -qm "Branch-Y: ungleiche Aenderung an alpha.md" HASH_Y=$(git rev-parse HEAD) -# Kein textueller Auto-Merge (AD-17c): drei Merge-Versuche (cherry-pick / merge ff / merge) -# muessen alle OHNE stille textuelle Konsolidierung enden — der Run erkennt die Kollision. -# (a) git merge auf branch-y == "ablösen von alpha.txt-loesungen" — der Befehl wird gar nicht -# erst ausgeführt, die Kollision ist durch gleichen Pfad + ungleiche Blobs EINDEUTIG -# erkennbar: kein Merge, kein Rebase — Text bleibt variantenrein (kein mischer). -merge_attempt() { - git checkout -q -f branch-y - if git merge --no-edit "$HASH_X" >/dev/null 2>&1; then - echo "MERGE_OK" - else - # Textuelle Kollision bleibt unaufgelöst: im Index steht kein gemischter Body. - echo "MERGE_CONFLICT" - fi -} -ma=$(merge_attempt) -# Ob der git-Merge-Versuch mit Konflikt endet (MERGE_CONFLICT) ODER — falls der Host-Branch -# denselben Pfad hält — der Merge nicht still textuell konsolidiert, ist die AD-17c-Aussage -# erfüllt: wir führen NIE ein $ git merge mit automatischer Text-Konsolidierung aus. Der -# strukturierte Hold ist die VERBINDLICHE Reaktion des Runs: -case "$ma" in - MERGE_CONFLICT|MERGE_OK) - # Verbindliche Run-Reaktion: strukturierter Kollisions-Hold mit beiden Commit-Hashes - # und Scope an Epic 4 (benannte Hold-Mechanik §5.16 Pkt. 8/§5.10 Pkt. 8, §5.17 Pkt. 5): - # kein Merge-Ergebnis wird committet; die beiden Varianten bleiben als Commits erhalten. - ;; - *) fail "A-7: unerwarteter Merge-Versuch-Zustand: $ma" ;; -esac -# Der Hold trägt BEIDE Commit-Hashes und den Scope (deterministisch auflösbar, AC-e): -hold_msg="KOLLISIONS_HOLD scope=wiki/alpha.md branch-x=$HASH_X branch-y=$HASH_Y" -case "$hold_msg" in - *"$HASH_X"*|*"$HASH_Y"*) ;; # beide Hashes geführt - *) fail "A-7: Hold trägt nicht beide Commit-Hashes" ;; -esac -case "$hold_msg" in - *"$HASH_X"*"$HASH_Y"*) ;; # BEIDE gefordert (nicht nur einer) - *) fail "A-7: Hold trägt nicht BEIDE Commit-Hashes (AC-e)" ;; -esac -# Textueller Auto-Merge ist verboten: der Body von branch-y bleibt byte-identisch zu seiner -# Variante (keine still gemergte Mischung aus X und Y eingespielt): -y_body=$(git show "$HASH_Y:wiki/alpha.md" | grep -c 'Alpha-Variante Y:') +# Kein textueller Auto-Merge (AD-17c): die Kollision wird durch gleichen Pfad + ungleiche +# Blobs an derselben Zeilenregion EINDEUTIG erkennbar. Der Merge-Versuch wird auf branch-y +# real ausgeführt und MUSS mit einem Konflikt enden: ein erfolgreicher (still textuell +# konsolidierender) Merge wäre genau der von AD-17c/AC-e verbotene Auto-Merge — Review-Loop-1: +# `MERGE_OK` wird daher HART abgewiesen und der Merge wieder abgebrochen. +git checkout -q -f branch-y +ma="MERGE_CONFLICT" +if git merge --no-edit "$HASH_X" >/dev/null 2>&1; then + ma="MERGE_OK" +fi +if [ "$ma" = "MERGE_OK" ]; then + # Ein stummer textueller Auto-Merge ist verboten (AD-17c) — Merge-Commit wieder entfernen, + # damit branch-y variantenrein bleibt, und hart fehlschlagen: + git merge --abort >/dev/null 2>&1 || git reset -q --hard "$HASH_Y" + fail "A-7: git merge endete CLEAN (still textueller Auto-Merge) — AD-17c/AC-e verletzt" +fi +# Kollisions-Zustand auflösen, ohne ein Merge-Ergebnis zu committen (branch-y variantenrein): +git reset -q --hard "$HASH_Y" +# Post-Merge-State-Assertion: branch-y steht WIEDER exakt auf seiner Variante — kein +# Merge-Commit, kein gemischter Body (statt des invarianten $HASH_X/$HASH_Y-Objekt-Vergleichs): +[ "$(git rev-parse branch-y)" = "$HASH_Y" ] || fail "A-7: branch-y-HEAD hat sich verschoben (Merge-Commit Spur)" +y_body=$(git show branch-y:wiki/alpha.md | grep -c 'Alpha-Variante Y:') [ "$y_body" -eq 1 ] || fail "A-7: branch-y-Body nicht variantenrein (Auto-Merge-Spur)" x_body=$(git show "$HASH_X:wiki/alpha.md" | grep -c 'Alpha-Variante X:') [ "$x_body" -eq 1 ] || fail "A-7: branch-x-Body nicht variantenrein (Auto-Merge-Spur)" -# Der log.md-Hold-Eintrag (zur Datumsgruppe, Vertrag §5) trägt Quell-Pfad + Baseline-Commit: +# Der Hold trägt BEIDE Commit-Hashes und den Scope (deterministisch auflösbar, AC-e): +hold_msg="KOLLISIONS_HOLD scope=wiki/alpha.md baseline=$BASE branch-x=$HASH_X branch-y=$HASH_Y" +# Der log.md-Hold-Eintrag (zur Datumsgruppe, Vertrag §5) trägt Quell-Pfad + Baseline-Commit +# + beide Varianten-Hashes (Hold-Mechanik §5.16 Pkt. 8/§5.10 Pkt. 8; Review-Loop-1: Baseline +# ist Teil der Hold-Form, nicht nur Quell-Pfad + Hashes): git checkout -q -f "$BASE" printf '\n### 2026-08-21 — %s\n' "$hold_msg" >> wiki/log.md 2>/dev/null || \ { echo "HARD-FAIL (A-7): log.md-Run-Eintrag nicht geschrieben" >&2; exit 1; } -# Hard aus der Datei assertieren (nicht aus der Quell-Variablen), dass beide Commit-Hashes -# + Scope wirklich im geschriebenen Eintrag landen (§5.16-Pkt.-8-/Vertrag-§5-Form): +# Hard aus der DATEI assertieren (nicht aus der Quell-Variablen), dass beide Commit-Hashes +# + Baseline + Scope wirklich im geschriebenen Eintrag landen (§5.16-Pkt.-8-/Vertrag-§5-Form): grep -Fq "$HASH_X" wiki/log.md && grep -Fq "$HASH_Y" wiki/log.md \ || { echo "HARD-FAIL (A-7): log.md-Hold-Eintrag traegt nicht beide Commit-Hashes" >&2; exit 1; } grep -Fq "scope=wiki/alpha.md" wiki/log.md \ || { echo "HARD-FAIL (A-7): log.md-Hold-Eintrag ohne Scope" >&2; exit 1; } +grep -Fq "baseline=$BASE" wiki/log.md \ + || { echo "HARD-FAIL (A-7): log.md-Hold-Eintrag ohne Baseline-Commit" >&2; exit 1; } echo " hold: $hold_msg" echo "RESULT: PASS — A-7: KOLLISIONS_HOLD — ungleiche Aenderungen am selben Concept-Pfad: kein textueller Auto-Merge; strukturierter Kollisions-Hold mit beiden Commit-Hashes + Scope an Epic 4; variantenreine Bodies (AC-e, AD-17c)" pass @@ -462,23 +502,24 @@ runlabel "A-8: FREIGABE_ERNEUT (nach Release wieder genau ein Lock)" isolate scopelock_acquire "RUN-A8-erster" || fail "A-8: erste Akquise schlug fehl" [ "$(scopelock_content)" = "RUN-A8-erster" ] || fail "A-8: Lock-Inhalt != erste Run-ID" -# Der Scope-Lock bedarf keiner Commits — ein nebenbei committender Release-Pfad wäre -# hiermit entdeckt (hart, vor dem ersten Release): +# Release mit Ownership (nur der Inhaber gibt frei) + sofortige Leere-Assertion: +scopelock_release "RUN-A8-erster" +[ -z "$(scopelock_content)" ] || fail "A-8: Lock nach erstem Release nicht leer" +# Commit-Zähl-Assert NACH dem ersten Release (Review-Loop-1: hier ist der Check erst +# aussagekräftig — der alte Check stand VOR dem Release und hätte nichts entdecken können): commits_a8=$(git rev-list --count "$BASE..HEAD" 2>/dev/null || echo 0) -[ "$commits_a8" = "0" ] || fail "A-8: Release erzeugte Commits ($commits_a8) — AC-c verletzt" -scopelock_release -[ -z "$(scopelock_content)" ] || fail "A-8: Lock nach Release nicht leer" +[ "$commits_a8" = "0" ] || fail "A-8: Akquise/Release erzeugte Commits ($commits_a8) — AC-c verletzt" # Nachfolgender Producer erwirbt denselben Root-Scope atomar erneut: scopelock_acquire "RUN-A8-zweiter" || fail "A-8: zweite Akquise nach Release schlug fehl" n8=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) [ "$n8" -eq 1 ] || fail "A-8: erwartet genau einen Scope-Lock nach erneuter Akquise" [ "$(scopelock_content)" = "RUN-A8-zweiter" ] || fail "A-8: Lock-Inhalt != zweite Run-ID" -# Release-Semantik bleibt deterministisch — nur der Inhaber gibt frei (der Inhalt ist bekannt). -# Commit-Zähl-Assert am Block-Ende (nach zweitem Release): der gesamte Akquise-/Release-Zyklus -# hat keine Commits erzeugt (AC-c; A-4-Konvention Z. 317): +# Zweites Release mit Ownership; Commit-Zähl-Assert am Block-Ende (nach zweitem Release): +# der gesamte Akquise-/Release-Zyklus hat keine Commits erzeugt (AC-c; A-4-Konvention): +scopelock_release "RUN-A8-zweiter" +[ -z "$(scopelock_content)" ] || fail "A-8: Lock nach zweitem Release nicht leer" commits_a8=$(git rev-list --count "$BASE..HEAD" 2>/dev/null || echo 0) -[ "$commits_a8" = "0" ] || fail "A-8: Release erzeugte Commits ($commits_a8) — AC-c verletzt" -scopelock_release +[ "$commits_a8" = "0" ] || fail "A-8: Akquise/Release-Zyklus erzeugte Commits ($commits_a8) — AC-c verletzt" echo "RESULT: PASS — A-8: FREIGABE_ERNEUT — deterministische Freigabe; nachfolgende Akquise desselben Root-Scope erneut atomar, genau ein Lock, keine Commits durch Akquise/Release (AC-c, Lifecycle-Nachfolge bleibt Story 3.12)" pass @@ -491,7 +532,11 @@ echo "Harte PASS-Assertions: $PASS_COUNT" [ "$PASS_COUNT" -ge 8 ] || { echo "HARD-FAIL: erwartet >= 8 harte PASS-Assertions, tatsaechlich $PASS_COUNT" >&2; exit 1; } # Kein Zugriff auf das reale Bundle/raw/ (AD-3): das Skript lebt ausschließlich auf dem # /tmp-Baum; der reale wiki//raw/-Baum wurde nicht berührt (Sandbox-Selbstbindung). -git status --short --porcelain >/dev/null 2>&1 || true +# Review-Loop-1: die finale Baumsauberkeits-Prüfung ist eine ECHTE Assertion (der alte +# no-op `|| true` hätte jeden Zustand still bestanden) — am Ende muss der Sandbox-Baum +# sauber sein (alle Szenarien haben gerefact/geräumt; kein Carry-over nach außen): +final_dirty=$(git status --short --porcelain) +[ -z "$final_dirty" ] || { echo "HARD-FAIL: Sandbox-Arbeitsbaum am Ende nicht sauber: $final_dirty" >&2; exit 1; } echo "Alle Szenarien A-1..A-8 harte PASS (Exit 0) — atomare Root-Scope-Lease-Akquise im" echo "clone-geteilten Zustand verifiziert (§5.17, Revision 3.6): kein Zugriff auf reales Bundle/raw/." echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)" diff --git a/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md b/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md index ab01d52..64858ab 100644 --- a/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md +++ b/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md @@ -4,8 +4,9 @@ type: 'feature' created: '2026-08-21' status: 'done' baseline_commit: 'a8b486d0f04b44344cdfa62e9cc32dfea0d49abd' -review_loop_iteration: 0 -context: [] +review_loop_iteration: 1 +context: + - '_bmad-output/implementation-artifacts/epic-3-context.md' --- @@ -82,8 +83,8 @@ Der Lock muss im clone-geteilten Zustand liegen, weil nur dieser Zustand von all **Commands:** - `bash _bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh` -- expected: alle Szenarien harte PASS (u.a. „niemals zwei aktive Root-Leases"-Assertion, `LEASE_HOLD`-Reihenfolge), Exit 0, kein Zugriff auf reales Bundle/`raw/`. -- `grep -n "3.11\|3.6" schema/compiler.md` und `grep -n "Revision 3.6"` -- expected: neuer Abschnitt und Revisionslogeintrag vorhanden; bestehende Pkt.-1/2-Texte unverändert (diff checkt nur additive Zeilen). -- `git -C _bmad-output diff` vs. `git -C schema/compiler.md diff` -- expected: nur additive Änderung an `schema/compiler.md`; `validator.md`/`wiki-compiler.md`/`adapters/`/`raw/` ohne Diff. +- `grep -n "Revision 3.6" schema/compiler.md` und `grep -n "## 5.17" schema/compiler.md` -- expected: §5.17-Überschrift und §8-Revisionslogeintrag vorhanden; bestehende Pkt.-1/2-Texte unverändert (diff checkt nur additive/berichtigte Zeilen). +- `git diff --stat` (Repo-Root) -- expected: nur die Review-Loop-1-Touched-Files (Sandbox, `schema/compiler.md` §5.17-Berichtigungen, Spec, log.md, deferred-work.md, sprint-status.yaml); `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` ohne Diff (AD-3). **Manual checks (if no CLI):** - Keine Beschreibung nötig — sämtliche Nachweise laufen über die Sandbox (Exit-Code) und additive Diffs. @@ -95,30 +96,71 @@ Der Lock muss im clone-geteilten Zustand liegen, weil nur dieser Zustand von all - Einstieg: die §5.17-Atomaritäts-Präzisierung — Exklusivitätsschlüssel im clone-geteilten Zustand, Run-ID als Lock-Inhalt, create-only-Akquise, LEASE_HOLD, Kollisions-Hold an Epic 4 (AC-a..e). [`compiler.md:415`](../../schema/compiler.md#L415) - Abgrenzungsklausel der Story-3.11-Verankerung — Fugen-Identität von §5.11-Pkt.-1/2 und §5.12 bleibt erhalten, keine neue §7-Klasse, kein Standalone. - [`compiler.md:527`](../../schema/compiler.md#L527) + [`compiler.md:424`](../../schema/compiler.md#L424) **Atomarer Lock im clone-geteilten Zustand** - Atomare create-only-Akquise (`git update-ref $ZERO_SHA`) — gits Ref-Sperre serialisiert Worktrees/Prozesse; deterministischer Blob-Inhalt. - [`run-sandbox.sh:120`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L120) -- Zwei-Prozess-Überlappung im Zwei-Worktree — Schlüssel-Beweis AC-b/AC-d (genau ein Gewinner, ein LEASE_HOLD, Zwischenzustands-Sampler). - [`run-sandbox.sh:207`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L207) + [`run-sandbox.sh:124`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L124) +- Zwei-Prozess-Überlappung im Zwei-Worktree — Schlüssel-Beweis AC-b/AC-d (genau ein Gewinner, ein LEASE_HOLD, gehärteter Zwischenzustands-Sampler: Ref-Kardinalität + Wert-Evidenz). + [`run-sandbox.sh:217`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L217) **Kollisions-Hold & Abweisung** -- LEASE_HOLD-Nicht-Mutation: abgewiesener Producer lässt `wiki/`/Lock/`log.md` unverändert, keine Commits, fremde Lease erhalten (AC-c) — inkl. gehärteter `log.md`-Assertion. - [`run-sandbox.sh:292`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L292) -- Kollisions-Hold mit beiden Commit-Hashes + Scope in `log.md` an Epic 4 (AC-e, AD-17c, kein textueller Auto-Merge) — Datei-Level-Attest nachgeschärft. - [`run-sandbox.sh:362`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L362) +- LEASE_HOLD-Nicht-Mutation: abgewiesener Producer lässt `wiki/`/Lock/`log.md` unverändert, keine Commits, fremde Lease erhalten (AC-c) — Worktree-Beobachtung des Arbeitsbaums (D-3.11-2). + [`run-sandbox.sh:339`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L339) +- Kollisions-Hold mit beiden Commit-Hashes + Scope + Baseline in `log.md` an Epic 4 (AC-e, AD-17c, kein textueller Auto-Merge) — `MERGE_OK` wird hart abgewiesen; Datei-Level-Attest auf den Post-Merge-State. + [`run-sandbox.sh:460`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L460) **Status- & Nachweissynchronisation (peripher)** - Revisionsnachweis Story 3.11 → `review` in der Laufzeitakte — Verankerung, Sandbox, Abschlussklausel, Erhaltungs-Invariante. - [`log.md:47`](../../wiki/log.md#L47) + [`log.md:4`](../../wiki/log.md#L4) - Planungsartefakt auf Ist-Zustand nachgeführt (epic-3-context Z. 41). [`epic-3-context.md:41`](../../_bmad-output/implementation-artifacts/epic-3-context.md#L41) **Härtung & Konsistenz-Funde (defer)** -- Konsistenz-, Drift- und Härtungs-Funde aus der Review in der Defer-Liste festgehalten (AC-d-Token, Zeilenanker, dynamische Negativ-Kontrolle, Platzhalter-Banner). - [`deferred-work.md:577`](../../_bmad-output/implementation-artifacts/deferred-work.md#L577) +- Konsistenz-, Drift- und Härtungs-Funde aus der Review in der Defer-Liste festgehalten (AC-d-Token, Zeilenanker, dynamische Negativ-Kontrolle, Platzhalter-Banner) inkl. KORREKTUR-Teileintrag (Zeilen-Drift-Defer widerlegt). + [`deferred-work.md:578`](../../_bmad-output/implementation-artifacts/deferred-work.md#L578) + +### Review Findings + +_Bmad-code-review Loop 1 (2026-08-21), 4 Layer (blind-hunter/edge-case-hunter/verification-gap/acceptance-auditor). Triage: 2 decision-needed, 20 patch, 5 defer, 5 dismissed. Sandbox re-executiert (Windows/Git-Bash): A-1..A-8 8/8 harte PASS, Exit 0, kein Zugriff auf reales Bundle/raw/._ + +#### Decision-Needed + +- [x] [Review][Decision] **D-3.11-1 AC-d-Beweisart (Zwischenzustands-Assertion)** — *Gelöst (Nutzer-Entscheidung 2026-08-21):* **Konstruktiv + härten** — AC-4 als konstruktiv erfüllt akzeptiert (eine scope-bezogene Ref + atomarer create-only-Write → zu keinem Zeitpunkt zwei aktive Root-Leases); A-2-Sampler zur lebendigen Wert-Evidenz gehärtet, §5.17-/log.md-Nachweis um „konstruktiv“ qualifiziert. Kein frozen-Block-Neuverhandeln. Hintergrund: der A-2-Sampler zählt die Ref-Kardinalität (`grep -cF "$SCOPELOCK"`, Z. 237, nie >1 bei einem Ref-Namen) und der `TWO_LOCKS_AT_ONCE`-Marker geht per `>&2` verloren, weil `out_a` nur stdout fängt (Z. 238 vs. Z. 255) — die Assertion war als *beobachtete* Evidenz strukturell tot. [run-sandbox.sh:237-257] +- [x] [Review][Decision] **D-3.11-2 A-4-Mutations-Regime (Nicht-Mutation des abgewiesenen Producers)** — *Gelöst (Nutzer-Entscheidung 2026-08-21):* **Intentionalen Mutationsversuch bauen** — in A-4 einen bewussten Mutations-/Commit-Versuch des abgewiesenen Producers in die Sandbox einbauen, dessen Ausbleiben/Ablehnung dann hart geprüft wird (deckt AC-c als Verhalten ab, nicht nur als Selbstvergleich). Hintergrund: der LEASE_HOLD-Pfad unternimmt heute keinen Mutationsversuch (nur `echo "LEASE_HOLD"`, Z. 309-311) und die AC-c-Assertions vergleichen `git show "$BASE:…"` mit sich selbst (invarianter Baseline-Blob, nie der Worktree; Z. 297/314/323) — uncommittete Arbeitsbaum-Mutationen des Abgewiesenen schifften unentdeckt durch. [run-sandbox.sh:297-324] + +#### Patch + +- [x] [Review][Patch] **A-7 `MERGE_OK`-Zweig akzeptiert den verbotenen textuellen Auto-Merge** — `case "$ma" in MERGE_CONFLICT|MERGE_OK)` lässt beide Outcomes durch; wäre `git merge --no-edit` clean gegangen, läge exakt der von AD-17c/AC-e verbotene stille Merge vor, der Test meldet dennoch PASS. `MERGE_OK` hart `fail`en (oder begründen, warum nur CONFLICT zulässig ist); dazu die Body-Assertions auf den **Post-Merge-HEAD von `branch-y`** (`git show branch-y:wiki/alpha.md`) statt auf die invarianten `$HASH_X/$HASH_Y`-Objekte ausrichten. [run-sandbox.sh:406-443] +- [x] [Review][Patch] **A-7 stale-Aussage-Kommentar widerspricht dem Code** — Kommentar „(a) … `git merge` … der Befehl wird gar nicht erst ausgeführt, … kein Merge“ (Z. 401-405) steht über `merge_attempt()`, das den Merge real ausführt; zudem unverstandener Rest „ablösen von alpha.txt-loesungen“. Kommentar an den tatsächlichen Ablauf korrigieren. [run-sandbox.sh:401-414] +- [x] [Review][Patch] **A-7 `hold_msg`-Variablen-Case ist tautologisch** — die zwei `case "$hold_msg"`-Checks (Z. 430-437) prüfen eine gerade konstruierte Zeichenkette gegen sich selbst (der erste `*"$HASH_X"*|*"$HASH_Y"*` bestünde sogar bei nur einem Hash); nur die Datei-Checks (Z. 450-453) sind real. Variablen-Case entfernen oder auf den geschriebenen `log.md`-Inhalt reduzieren. [run-sandbox.sh:430-437] +- [x] [Review][Patch] **A-7 `log.md`-Hold-Eintrag trägt keinen ``** — die zitierte Hold-Mechanik (§5.16 Pkt. 8/§5.10 Pkt. 8) verlangt „Quell-Pfad + ``“; der geschriebene Eintrag (Z. 447) hat Scope + beide Hashes, aber kein Baseline-Commit. Baseline-Komponente ergänzen oder begründen, warum sie beim Kollisions-Hold entfällt. [run-sandbox.sh:446-448] +- [x] [Review][Patch] **`assert_frontmatter()` ist tot — behauptete „at-Normalform je Szenario“ wird nicht ausgeführt** — die Funktion (Z. 155-164) prüft §3.3/§3.4-Frontmatter + `at`-ISO-Normalform, wird aber nirgendwo aufgerufen; `wiki/log.md`/Revision-3.6 attestiieren dennoch „Erhaltungs-Invariante + at-Normalform je Szenario“. Aufruf ergänzen (z. B. `assert_frontmatter wiki/alpha.md` nach A-7, wo `alpha.md` neu geschrieben wird) oder die Nachweis-Formulierung in log.md/Revision korrigieren. [run-sandbox.sh:155-164] +- [x] [Review][Patch] **A-3-Kommentar behauptet „zweiter Worktree, eigener Prozess“, ist aber sequentiell im Hauptprozess** — die zweite Akquise (Z. 285-286) ist ein direkter `scopelock_acquire`-Aufruf ohne `git worktree add`/Subshell; „zeitlich ÜBERLAPPEND“ ist hier falsch (echte Überlappung liegt in A-2). Kommentar entlarven/entschärfen. [run-sandbox.sh:282-286] +- [x] [Review][Patch] **A-3 Identitäts-Fall nicht geübt** — der Kommentar behauptet „auch eine identisch benannte Run-ID kann den Halter nicht ersetzen“, der zweite Versuch nutzt aber `RUN-A3-identisch` (andere ID); der exakte Identitäts-Fall `RUN-A3` wird nicht geübt. Entweder mit `RUN-A3` akquirieren oder den Kommentar korrigieren. [run-sandbox.sh:284-288] +- [x] [Review][Patch] **A-1 toter `run_a1`-Blob** — `run_a1=$(printf 'producer-a1-run-id' | git hash-object -w --stdin)` (Z. 179) wird nie verwendet (echter Lock-Inhalt ist `RUN-A1`); Dead Code, schreibt ein ungenutztes Objekt. Entfernen. [run-sandbox.sh:179] +- [x] [Review][Patch] **A-8 Commit-Zähler-Check am falschen Punkt** — der `git rev-list --count`-Check **vor** dem ersten `scopelock_release` (Z. 468-469) kann nur Akquise-Commits, keine Release-Commits nachweisen; der Check nach dem Release (Z. 479-480) ist der wirksame. Erster Check entfernen oder Kommentar korrigieren („hart, vor dem ersten Release“ trifft die eigene Aussage nicht). [run-sandbox.sh:466-480] +- [x] [Review][Patch] **Sandbox-Schlusskontrolle ist ein No-op** — `git status --short --porcelain >/dev/null 2>&1 || true` (Z. 494) verwirft Ausgabe und Exit-Code und attestiert nichts (weder Bundlesauberkeit noch „kein Zugriff auf reale Pfade“); dazu bleiben die in A-2/A-4 angelegten Worktrees (`$ROOT/wt-a/wt-b/wt-a4`) registriert und werden nicht abgeräumt. Ende-Assertion auf eine echte Prüfung umstellen (z. B. `git worktree list`-Prüfung gg. `$ROOT`) oder Worktrees aufräumen + No-op entfernen. [run-sandbox.sh:494] +- [x] [Review][Patch] **`scopelock_release()` ohne Ownership-/Exit-Code-Kopplung** — `git update-ref -d "$SCOPELOCK"` (Z. 132-134) läuft ohne `|| fail` und ohne Inhaber-Bindung (kein Abgleich des Ref-Inhalts mit der eigenen Run-ID); ein fehlgeschlagenes Release würde A-1/A-3/A-5/A-6 nicht bemerken. Release-Stellen hart koppeln; Ownership-Prüfung ergänzen oder explizit als Story-3.12-Home benennen. [run-sandbox.sh:132-134] +- [x] [Review][Patch] **`isolate()` räumt den geteilten Ref-Namespace nicht** — `reset --hard`/`git clean` betreffen nur Arbeitsbaum und HEAD; `refs/leases/wiki` überdauert Szenario-Grenzen und hängt an der impliziten Release-Disziplin. Expliziten Ref-Reset in `isolate()` ergänzen, damit ein fehlgeschlagenes Release die Folgeszenarien nicht still kontaminiert. [run-sandbox.sh:99-105] +- [x] [Review][Patch] **Asymmetrische Release-Ende-Leereprüfung** — A-8 prüft nach dem Release `[ -z "$(scopelock_content)" ]`, A-1/A-3/A-5/A-6 tun es nicht; ein hängender Lock wäre erst in einem späteren, nicht-attributierbaren Szenario auffindbar. Ende-Check je Szenario vereinheitlichen. [run-sandbox.sh:189-189, 288-288, 342-342, 359-359] +- [x] [Review][Patch] **§5.17 Pkt. 5 Grammatikbruch + fehlendes Ablage-Ziel** — „an Epic 4 übergeben — **der** benannten Hold-Mechanik“ (Anstelle von „an“); zudem benennt §5.17 Pkt. 5 nirgends, *wo* der Kollisions-Hold liegt (Run-Receipt? `log.md`?), während A-7 ihn in `wiki/log.md` schreibt. Wortlaut berichtigen + Ablage-Stelle normativ benennen. [compiler.md:423] +- [x] [Review][Patch] **§5.17 Pkt. 1: „committete Ref“ ist technisch inkorrekt** — eine Ref ist kein Commit-Objekt und nicht Teil eines Commits; die Sandbox realisiert es als Blob (`git hash-object -w`) plus Ref-Write. Für eine normative Sektion, aus der Story 3.12 den Lifecycle ableitet, unpräzise (Lebensdauer des Locks unklar). Auf „geschriebene/verwiesene Ref mit Blob-Inhalt“ berichtigen. [compiler.md:416] +- [x] [Review][Patch] **§5.17 Pkt. 4: Determinismus-Aussage gilt nicht im concurrenten Fall** — „gleicher Geteilter-Zustand + gleiche Eingabemenge → identische Gewinner-/Verlierer-Entscheidung“ trifft nur für sequentielle Versuche (A-3/A-6); bei überlappenden Producers hängt die Gewinnerwahl vom Scheduling ab, nicht allein vom geteilten Zustand. Pkt.-4-Aussage auf den deterministischen Kern (create-only-Existenzprüfung) eingrenzen oder den concurrenten Fall ausnehmen. [compiler.md:419] +- [x] [Review][Patch] **Suggested-Review-Order-Anker bei Commit-Zeit falsch** — `compiler.md:415` zeigt auf die Leerzeile vor dem §5.17-Intro; `compiler.md:527` auf die §8-Revision-3.6-Logzeile (die Abgrenzungsklausel Pkt. 6 liegt ≈ Z. 424); `log.md:47` auf eine Zeile unterhalb des 3.11-Eintrags (der liegt auf Z. 4); `deferred-work.md:577` auf die Leerzeile vor dem neuen „Deferred from“-Header (Z. 578). Anker neu setzen. [spec:642, 644, 663, 670] +- [x] [Review][Patch] **Defer-Evidence benennt die falsche Stelle** — der Zeilen-Drift-Defer in `deferred-work.md` verweist auf „die Spec (Code Map) und die Task-1-Rationale“, die konkreten Fehlancker sitzen aber in der Suggested-Review-Order; zudem ist die Aussage „§5.11 (Z. 304-321)/§5.12 (Z. 323-342) nicht mehr aktuell“ **falsch** — §5.11 liegt weiterhin auf Z. 304, §5.12 auf Z. 323 (verifiziert bei e02cf84). Evidence präzisieren; den Zeilen-Drift-Teileintrag berichtigen (es gibt keinen Defekt an diesen Anker). [deferred-work.md:580-585] +- [x] [Review][Patch] **Spec-Frontmatter `context: []` trägt die Code-Map-Abhängigkeit nicht** — die Code Map und Task 5 nennen `epic-3-context.md` (Z. 41) als nachgeführtes Planungsartefakt; die Präzedenz-Spec-3.10 listet dieselbe Datei im `context:`-Feld. `epic-3-context.md` in `context:` aufnehmen. [spec:8] +- [x] [Review][Patch] **Spec-Verification-Kommando ungültig** — `git -C schema/compiler.md diff` ist ungültig (`git -C` erwartet ein Verzeichnis, `schema/compiler.md` ist eine Datei); `grep -n "3.11\|3.6"` trifft zudem etliche „Story 3.6“-Erwähnungen in §5.11/§5.12 und taugt nicht als gezielte Revision-3.6-Prüfung. Kommandos berichtigen. [spec:631-632] + +#### Defer + +- [x] [Review][Defer] **AC-d-Token ohne normative Vorlagen-Definition** — der `AC-d`-Token (Sandbox A-2/A-3, §5.17, log.md) ist in der Vorlage epics.md A0-13/AD-17b nicht separat gelistet (AC-a..c, AC-e); er ist ein konsistenzerhaltender Behelf, kein neuer Anforderungskanon; Home: Epic-4-Statussynchronisation der Architecture-Spine (bereits in deferred-work.md, hier bestätigt). — deferred, pre-existing +- [x] [Review][Defer] **Sandbox-3.5/-3.6 üben weiterhin check-then-act-Lockfile-Akquise ohne §5.17-Scope-Lock** — die Code Map benennt die `akquire()` von 3.5/3.6 als „Ableitungspflicht des neuen atomaren Lock-Modells“; die Schwestern-Sandboxes demonstrieren weiterhin die clone-lokale check-then-act-Lockfile-Akquise (Exklusivität nur für identische ``). Ein Test, der zwei Producer mit *verschiedenen* `id` im selben Root-Scope unter §5.17 auf genau einen Gewinner prüft, fehlt. Home: Story-3.12-Lifecycle / Story-3.13-Abnahme. — deferred, pre-existing +- [x] [Review][Defer] **A-2 beweist keine garantierte zeitliche Überlappung** — die zwei Prozesse starten ohne Synchronisations-Barriere; ein Scheduler kann sie vollständig sequenzieren (genau die „Zeitversatz ohne Überlappung“-Situation, die die Spec als nicht beweiskräftig ausschließt). Die create-only-Atomarität wird davon nicht berührt, aber eine echte Überlappung wäre ein stärkerer Beleg. Home: Sandbox-Härtung / Story-3.13. — deferred, pre-existing +- [x] [Review][Defer] **Status-Kontraktion Spec-Frontmatter `status: done` vs. sprint-status `review`** — wiederholt das Story-3.9-Muster (D-3.9-2: maßgeblich `review`, Spec-`done` als Kontraktion); für 3.11 fehlt der explizite Präzedenz-Verweis. Entspricht aber der 3.9-/3.10-Präzedenz (`status: done` im Implementierungs-Commit, finaler `done`-Flip im Step-05-Sync) und wird im Step-05-Status-Sync aufgelöst. — deferred, pre-existing +- [x] [Review][Defer] **`scopelock_header_banner()` leerer Platzhalter + fehlende I/O-Matrix-Zeilen für A-5/A-6/A-8** — die ungenutzte Banner-Funktion (Z. 166) und die drei Sandbox-Szenarien ohne eigene I/O-Matrix-Zeile (Matrix listet 4 Szenarien, Sandbox übt 8) sind bekannter Kosmetik-/Dokumentations-Ausbau; Home: Story-3.12 / Matrix-Nachführung. — deferred, pre-existing + diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index ddb0155..e4e3d91 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 12:30 +last_updated: 08-21-2026 15:10 project: wow20 project_key: NOKEY tracking_system: file-system @@ -61,7 +61,7 @@ development_status: 3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato: done # Review-Loop-3-Abschluss 2026-08-20 (bmad-code-review; D-2-Entscheidung). Hinweis: die Abschluss-Reihenfolge „3.9 → 3.10 / 3.11 → 3.12 → 3.8 Abschluss → 3.13 Abnahme" des genehmigten Sprint-Change-Proposal 2026-08-20 betrifft das Epic-3-Abnahmegate (3.13) — die Story-3.8-Instruktionsverankerung ist abgeschlossen (done); die 3.9–3.12-Verankerungen und die 3.13-Abnahme bleiben offen (epic-3 remains in-progress). 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: review # Story 3.11 Review-Bereitschaft 2026-08-21 (§5.17 Verankerung, Revision 3.6; Sandbox A-1..A-8 8/8 harte PASS/Exit 0 — Zwei-Worktree-/Zwei-Prozess-Überlappung mit Zwischenzustands-Assertions „niemals zwei aktive Root-Leases", LEASE_HOLD-Nicht-Mutation, Kollisions-Hold mit beiden Commit-Hashes). 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: backlog 3-13-epic-3-verifikations-und-abnahmegate: backlog epic-3-retrospective: optional diff --git a/schema/compiler.md b/schema/compiler.md index b5dc96e..3b00475 100644 --- a/schema/compiler.md +++ b/schema/compiler.md @@ -416,11 +416,11 @@ Die Update-Formen-Wahl (§5.9, Story 3.1/3.3), die Synthese-Mechanik (§5.10, St Die §5.11-Lease-Akquise (Pkt. 1 — Lockfile `lease//.lock`, Merge-Base-Disziplin; Pkt. 2 — Root-Scope-Umfang) und die §5.12-Staleness-/Recovery-Dimension bleiben **textuell unverändert** — diese Sektion ist die **operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise** darüber (D-3, Story 3.11; AD-17a/b A0-12/A0-13; §5.11 Pkt. 1/2 und §5.12-Anker sind Fugen-Identität, Revision 3.6): sie ordnet unter die bestehende §5.11-Akquise die **atomare, create-only-Realisation im clone-geteilten Zustand** — dem geteilten Git-Ref-/Objektnamespace, den alle Worktrees und Prozesse eines Clones gemein sehen —, so dass die Akquise **nicht** mehr als nicht-atomare check-then-act-Operation auf einem Arbeitsbaum-Lockfile erfolgt und zwei Producer mit verschiedenen Run-IDs denselben Root-Scope nicht gleichzeitig „erwerben" können (TOCTOU-Race der bisherigen Lockfile-Lage geschlossen; AD-17b/A0-13 „genau ein scope-bezogener Lock im clone-geteilten Zustand"). Sie fügt **kein** Prädikat, **keine** neue §7-Invaliditätsklasse, **keinen** `schema/wiki-compiler.md`-/`schema/validator.md`-/`adapters/`-/`raw/`-Change hinzu (AD-3) und **keinen** Standalone (D-3); **kein neuer Frontmatter-Key für Lease-Metadaten** (Vertrag §3.1–§3.7 unverändert); **keine Wanduhr-/Systemzeit** in der Akquise (A0-20); **keine Staleness-/Recovery-Logik, keine Verwaist-/Stale-Behandlung und kein Lease-Branch-Lifecycle nach Übernahme** (bleibt Story 3.6/3.12). -1. **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand (AC-a):** Der Exklusivitätsschlüssel einer Root-Scope-Lease ist ein **einziger, scope-bezogener Lock im clone-geteilten Zustand** des Repos — der geteilte Git-Ref-/Objektnamespace ist der einzige Zustand, den alle Worktrees und Prozesse eines Clones **gemein sehen** (im Gegensatz zu einem clone-lokalen Arbeitsbaum-Lockfile, das zur nicht-atomaren check-then-act-Akquise einlädt). Der Lock wird als **eine deterministisch benannte, committete Ref je Root-Scope `wiki/`** realisiert (z. B. `refs/leases/wiki`; der Root-Scope-Umfang bleibt §5.11 Pkt. 2: `wiki/` inkl. `log.md`, `index.md` und aller Root-Dateien; kein Bereich jenseits `wiki/`). Die **Run-ID ist Lock-Inhalt und nicht Bestandteil des Exklusivitätsschlüssels**: sie steht als Wert im Lock (Ref-Inhalt); der Schlüssel ist allein der scope-bezogene Ref — der Ref-Name trägt **keine** Run-ID (sonst wäre der Schlüssel pro-Run und die Exklusivität wirkungslos). Die bisherige ``-Ablage (§5.11 Pkt. 1 — Branch-Form `lease//` und Lockfile `lease//.lock` mit Feld-Satz) bleibt als **per-Lease-Ablage** bestehen, trägt aber **keine Exklusivität mehr allein**: die Exklusivität hängt am scope-bezogenen Lock, der beim Gewinner die Freigabe-/Registrierungs-Information (inkl. der per-Lease-Referenz) im Inhalt trägt. +1. **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand (AC-a):** Der Exklusivitätsschlüssel einer Root-Scope-Lease ist ein **einziger, scope-bezogener Lock im clone-geteilten Zustand** des Repos — der geteilte Git-Ref-/Objektnamespace ist der einzige Zustand, den alle Worktrees und Prozesse eines Clones **gemein sehen** (im Gegensatz zu einem clone-lokalen Arbeitsbaum-Lockfile, das zur nicht-atomaren check-then-act-Akquise einlädt). Der Lock wird als **eine deterministisch benannte, geschriebene Ref je Root-Scope `wiki/`** realisiert (z. B. `refs/leases/wiki`; der Root-Scope-Umfang bleibt §5.11 Pkt. 2: `wiki/` inkl. `log.md`, `index.md` und aller Root-Dateien; kein Bereich jenseits `wiki/`). **Ref-Objekttyp:** die Ref verweist auf einen **geschriebenen Blob-Inhalt** (die Run-ID steht als Blob hinter der Ref) — die Ref ist kein Commit-Objekt und Teil keiner Commit-Historie; sie lebt ausschließlich im geteilten Ref-/Objektnamespace und endet per Ref-Delete (Release; Lifecycle-Regie Story 3.12). Die **Run-ID ist Lock-Inhalt und nicht Bestandteil des Exklusivitätsschlüssels**: sie steht als Wert im Lock (Ref-Inhalt); der Schlüssel ist allein der scope-bezogene Ref — der Ref-Name trägt **keine** Run-ID (sonst wäre der Schlüssel pro-Run und die Exklusivität wirkungslos). Die bisherige ``-Ablage (§5.11 Pkt. 1 — Branch-Form `lease//` und Lockfile `lease//.lock` mit Feld-Satz) bleibt als **per-Lease-Ablage** bestehen, trägt aber **keine Exklusivität mehr allein**: die Exklusivität hängt am scope-bezogenen Lock, der beim Gewinner die Freigabe-/Registrierungs-Information (inkl. der per-Lease-Referenz) im Inhalt trägt. 2. **Atomare Akquise (create-only) — genau ein Gewinner (AC-b):** Die Akquise erfolgt **atomar als create-only-Operation** auf den scope-bezogenen Lock im clone-geteilten Zustand: `git update-ref $ZERO_SHA` — create-only — die Operation **schlägt fehl, sobald der Ref bereits existiert**, und berührt einen existierenden Lock **nicht** (gits eigene Ref-Sperre serialisiert zwei Worktrees/Prozesse desselben Clones auf demselben Lock). Genau **ein** Producer erwirbt die Lease; jeder zweite, zeitlich überlappende Akquise-Versuch schlägt fehl. **Ask-First-Pflicht:** ist dieses create-only-Primitiv im geteilten Git-Refnamespace auf der Ziel-Plattform (Windows/Git-Bash) nicht zuverlässig atomar belegbar, **HALT** der Producer und legt eine alternative Primitiv-Auswahl zur Autorisierung vor (kein stiller Ausweich-Primitiv). 3. **`LEASE_HOLD`-Semantik (AC-c, §5.11 Pkt. 1 unverändert):** Schlägt die atomare Akquise fehl (der scope-bezogene Lock ist von einer anderen Run-ID bzw. einem anderen Worktree/Prozess gehalten), hält der abgewiesene Producer **`LEASE_HOLD`** und beendet sauber: er **überschreibt nichts** (kein Update des Locks, kein Inhalt-Austausch), **verändert weder `wiki/` noch den bestehenden Lock**, **erzeugt keinen Compilation Commit** und **entfernt keine fremde Lease**. Die Koordination geht wie bisher in den AD-16-Pfad (§5.11 Pkt. 4) über. -4. **Determinismus (AD-17h/A0-19):** Der clone-geteilte Zustand ist der einzige Zustand, den alle Worktrees/Prozesse eines Clones **gemein sehen** — die Akquise ist damit **deterministisch aus dem geteilten Git-State** entscheidbar (gleicher Geteilter-Zustand + gleiche Eingabemenge → identische Gewinner-/Verlierer-Entscheidung, AD-17h/A0-19). Der Lock-Inhalt (Run-ID) ist **dokumentierender Ablage-Wert, kein Schlüsselbestandteil** — die Exklusivität folgt allein aus Existenz/Abwesenheit des scope-bezogenen Locks. -5. **Kollisions-Hold an Epic 4 (AC-e, AD-17c/A0-14):** Zwei Branches mit **ungleichen Änderungen am selben Concept-Pfad** werden **nie textuell automatisch gemerged** (§5.11 Pkt. 4 bleibt textuell unverändert — kein textueller Auto-Merge, AD-17c). Erkennt der Run die Kollision, wird ein **strukturierter Kollisions-Hold mit beiden Commit-Hashes und dem Scope** an Epic 4 übergeben — der benannten Hold-Mechanik (§5.16 Pkt. 8/§5.10 Pkt. 8: datumsgruppierter `log.md`-Eintrag mit ``, keine Wissensmutation) statt eines automatischen Merges; **AD-16-Klassifikation und semantische Auflösung bleiben Epic 4 / Story 4.x**. Commit-Boundary = Mutations-Boundary (AD-17f, §0/§5.3/§5.11 Pkt. 5 unverändert); `log.md`-Eintragspflicht (Vertrag §5, §5.11 Pkt. 6 unverändert). +4. **Determinismus (AD-17h/A0-19):** Der clone-geteilte Zustand ist der einzige Zustand, den alle Worktrees/Prozesse eines Clones **gemein sehen** — die Akquise ist damit **deterministisch aus dem geteilten Git-State** entscheidbar (**sequentielle Versuche**: gleicher Geteilter-Zustand + gleiche Eingabemenge → identische Gewinner-/Verlierer-Entscheidung, AD-17h/A0-19). **Grenze (überlappende Producer):** bei zeitlich überlappenden Akquise-Versuchen entscheidet gits Ref-Serialisierung über den konkreten Gewinner — die Gewinner**wahl** ist Scheduling-abhängig, nicht allein aus dem geteilten Zustand ableitbar; invariant bleibt, dass **genau ein** Gewinner entsteht und jeder weitere Versuch abgewiesen wird (deterministischer Kern = die create-only-Existenzprüfung). Der Lock-Inhalt (Run-ID) ist **dokumentierender Ablage-Wert, kein Schlüsselbestandteil** — die Exklusivität folgt allein aus Existenz/Abwesenheit des scope-bezogenen Locks. +5. **Kollisions-Hold an Epic 4 (AC-e, AD-17c/A0-14):** Zwei Branches mit **ungleichen Änderungen am selben Concept-Pfad** werden **nie textuell automatisch gemerged** (§5.11 Pkt. 4 bleibt textuell unverändert — kein textueller Auto-Merge, AD-17c). Erkennt der Run die Kollision, wird ein **strukturierter Kollisions-Hold mit beiden Commit-Hashes und dem Scope** an Epic 4 übergeben — in die benannte Hold-Mechanik (§5.16 Pkt. 8/§5.10 Pkt. 8): **Ablage-Stelle ist der datumsgruppierte `log.md`-Eintrag** (Header `YYYY-MM-DD`, neueste zuerst — Vertrag §5; Form: Quell-Pfad + `` + beide Commit-Hashes + Scope, §5.10-Pkt.-8-Form) — **keine Wissensmutation** statt eines automatischen Merges; **AD-16-Klassifikation und semantische Auflösung bleiben Epic 4 / Story 4.x**. Commit-Boundary = Mutations-Boundary (AD-17f, §0/§5.3/§5.11 Pkt. 5 unverändert); `log.md`-Eintragspflicht (Vertrag §5, §5.11 Pkt. 6 unverändert). 6. **Abgrenzung (keine neue Dimension):** Keine Wanduhr-/Systemzeit in der Akquise (A0-20); keine Staleness-/TTL-/Recovery-Logik (bleibt §5.12/Story 3.6 und Story 3.12); keine Verwaist-/Stale-Behandlung und kein Lease-Branch-Lifecycle nach Übernahme (bleibt Story 3.12) — diese Sektion präzisiert ausschließlich die **Akquise-Atomarität** des Root-Scope im clone-geteilten Zustand; die §5.11-Pkt.-1-Formen (Branch, Lockfile, Merge-Base, Freigabe) und die §5.12-Dimension bleiben unverändert maßgeblich. ## 6. Validieren (mechanische Bestätigung) @@ -524,4 +524,4 @@ Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in A - **Revision 3.3 (2026-08-20, Story 3.8):** Neue Sektion **§5.14 „Determinismus-Vertrag & Agent-Instruktions-Validator (Story 3.8)"** eingefügt (nach §5.13, vor §6) — die **geschlossene, aus dem committeten Git-State ableitbare Bestätigungs-Mechanik des Determinismus-Vertrags** (AD-17h/FT-10/A0-19; §3.2/§5.9/§5.10/§5.11/§5.12/§5.13-Rückverweise verankern den Vertrag, §5.14 die Bestätigung): (1) **Bundle-State-Definition** (deterministische Projektion des committeten Git-States: committeter Baum unter `wiki/`/`raw/` gg. Baseline + Plan-/Kandidaten-/Reihenfolge-Outputs + Ausführungs-Entscheidungen; `generated.at`/`verified[].at` als benannte Ausnahme, A0-20 — einzig zulässige Differenz zwischen zwei Runs), (2) **Zwei-Run-Bestätigungs-Mechanik** (agent-Instruktions-basiert, D-3/Q-6: **zwei frische Agent-Kontexte in getrennt aufgebauten (sauberen) Worktrees** führen die Instruktion jeweils einmal über demselben committeten Git-State aus und die Bundle-States werden verglichen — **eine zweite Ausführung in derselben Session genügt nicht** (Q-6, A0-19); Vergleichs-Operandum = committeter Baum, **kanonisches Eingabemanifest** (Baseline-Commit, geordnete Sources, output-sichtbare Run-/Zeit-/Identitätswerte) + **Run-Receipt außerhalb des Bundles** (Candidates, Reihenfolge, Plan, Entscheidungen, Output-Hashes), re-executierbare diff-/hashbasierte Formeln, keine Wanduhr-Steuerung, keine hart codierten erwarteten Pläne/Concept-Bodies, keine pauschale `verified`-Maskierung; identische Plan-/Kandidaten-/Reihenfolge-Outputs, byte-identische mutierte Bestandteile; keine eigene Runtime/kein neues Werkzeug, AD-6/AD-11), (3) **Ausnahme-Menge** (allein der `generated.at`-Wanduhr-Gap; dokumentiert, kein stiller Ausschluss; alle übrigen Bestandteile byte-identisch), (4) **Abweichungs-Klassifikation** (jede Differenz außerhalb der Ausnahme = AD-16-Klassifikationsfehler, kein Rauschen; textuell benannt NFR-4, Run korrigiert/rollt zurück, Zustands-Restaurations-Invariante §5.13 Pkt. 3), (5) **Normalisierungs-/Match-/Orphan-Schließung** (§3.2-Pkt.-1b-Em-Dash-Kollaps-Klasse `[-–— _]`, Kollaps-Reichweite, Match-Scope Stufe a; §5.10-Pkt.-8-Reconcile-Orphan-Regel; Erhebungen vollständig pinbar). **§3.2:** die bekannten Determinismus-Lücken als append-only-Regel-Ergänzungen geschlossen (Em-Dash in der Kollaps-Klasse, Kollaps-Reichweite, Match-Scope der Stufe a) — bestehender §3.2-Wortlaut unverändert. **§5.10 Pkt. 8:** Orphan-Politik zur deterministischen **Reconcile-Orphan-Regel** präzisiert (unzugeordnet, datumsgruppierter `log.md`-Verwaist-Eintrag mit ``, kein Banner/keine stille Vorbearbeitung/keine eigenständige Anlage; AD-16-Default). **§5.13 Pkt. 7:** Home-Verweis des `generated.at`-Gaps auf die §5.14-Definition verlagert (Wortlaut des §5.13-Satzbaus semantisch unverändert; die Behandlung des Gaps ist jetzt in §5.14-Pkt.-3 definiert). **§7:** Determinismus-Vorbehalt der Relevanzbestimmung **aufgelöst** (Em-Dash-Lücke → „in §5.14 verankert (Story 3.8)"-Ergänzung; §3.2-/§5.10-/`at`-Gap-Schließung benannt; bestehende Story-Bullets unverändert — kein neuer Bullet ersetzt einen bestehenden). **§8:** Normreferenz **AD-17h** von reiner Story-Zuordnung auf **§5.14-Anker** angehoben (`AD-17h (Determinismus, §5.14 — Zwei-Run-Bestätigung mit benannter `generated.at`-Wanduhr-Gap-Ausnahme, A0-20/§5.9-Pkt.-2/§5.10-Pkt.-8)`). **Abschlussklausel:** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Prädikat-/Format-/Frontmatter-Key**; das `generated.at`-Verhalten selbst **unverändert** (nur seine Behandlung im Bundle-State-Vergleich; Verhaltenswechsel = Ask-First); keine Workflow-Engine/kein neuer Prozess/Server/MCP (AD-6, AD-11); §0-Phasen-Listentext, §5.13-Phasen-Disziplin und §6/§6.5 textuell **unverändert** (Fugen-Identität); Commit-Boundary-Regel unverändert; `schema/canonical-terms.md` unverändert (Em-Dash-/Kollaps-Schließung lebt als Regel in §3.2, nicht als Registry-Edits). **`sprint-status.yaml`:** Key `3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato` **`done`** (2026-08-20: Story-3.8-Instruktionsverankerung abgeschlossen — die Re-Open-/Abschluss-Reihenfolge „3.9 → 3.10/3.11 → 3.12 → 3.8-Abschluss → 3.13" des Sprint-Change-Proposals 2026-08-20 betrifft das Epic-3-**Abnahmegate**, nicht die Story-3.8-Inhaltsverankerung; die 3.9–3.12-Verankerungen bleiben offen, epic-3 bleibt in-progress). **Re-Open-Delta (2026-08-20, genehmigtes Sprint-Change-Proposal):** Zwei-Run-Mechanik auf getrennte Worktrees/frische Agent-Kontexte umgestellt (Q-6/A0-19), kanonisches Eingabemanifest + Run-Receipt außerhalb des Bundles, keine hart codierten erwarteten Pläne/Concept-Bodies, keine pauschale `verified`-Maskierung (nur `at`-Ausnahme). Sandbox-Nachweis (**DET-1..DET-8 + Erhaltungs-Invariante, Exit 0**; Zwei-Run-Identität nicht-vakuum, DET-2 in zwei getrennten Worktrees) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.8, Revision 3.3). - **Revision 3.4 (2026-08-20, Story 3.9):** Neue Sektion **§5.15 „Deterministische Relevanz- & Reconcile-Routing (Story 3.9)"** eingefügt (nach §5.14, vor §6) — die **geschlossene Routing-Ebene des Reconcile** (AD-17h/A0-19, Story 3.9; §5.14-Pkt.-5-/§7-„Story-3.9-ACs noch nicht verankert"-Vorbehalt aufgelöst): (1) **Termgewinnung** — geschlossener, geordneter Algorithmus aus der Zuwachs-Sicht (Dateiname→Term-Mapping, `source.md`-Sidecar-Exklusion, Status-Codes `A`/`M`/`D`/`R`/`C` via `--diff-filter=ACMR` mit der Akzeptanz-Regel A/C (akzeptiert) vs. M/D/R (Run-FAIL) aus Pkt. 4, §5.9-Pkt.-6-Diskrepanz-/Fallback-Kopplung, Diff↔Manifest-Äquivalenz, Mehrfach-Term-Vereinigung D-8 aufgegriffen; **eine** Kollaps-Definition §3.2-Pkt.-1b), (2) **symmetrische Normalisierung + literal-sichere Suche** (AC-2; `index.md`-Treffer → Traversal-Stufe, kein Konzept-Kandidat), (3) **eine exklusive Routing-Tabelle** (AC-3; UPDATE → CREATE → ORPHAN/HOLD → NO_OP; **NO_OP als Update-Unter-Entscheidung** — leere Candidate-Liste bei neuer Evidenz → Zellen 2/3, nie NO_OP; CREATE-vs-ORPHAN-Prädikat; Stufe-b-Zelle konsistent), (4) **Raw-Immutability-Guard** (AC-4; M/D/**R** → Run-FAIL vor jeder Mutation, A/C akzeptiert), (5) **reservierte Zielpfade** (AC-5; erschöpfende Liste `index`/`log`/`source`/`README`, Ist-Dateimenge via `git ls-tree`-Schnittmenge, deterministischer Hold), (6) **Zwei-Run-Identität** (AC-6; positive UND negative Fixtures, Zwei-Worktree-Vergleich, praktisch ausgeübte `at`-Exzeption — die einzige benannte Differenz). **§3.2:** der NO_MATCH-Anker (Pkt. 3d) als §5.15-Verweis-Anker nachgeführt (leere Candidate-Liste bei neuer Evidenz → Zellen 2/3, nicht NO_OP; `UNTOUCHED_CONCEPT` gilt für den Ghost-Diff-negativen Fall ohne Zuwachs). **§5.14 Pkt. 5:** Scope-Präzisierung nachgeführt (Story-3.9-ACs sind verankert). **§7:** Relevanzbestimmung-Bullet um die §5.15-Verankerung erweitert (Story-3.9-Vorbehalt aufgelöst; bestehende Story-Bullets unverändert). **§8:** AD-17h-/A0-19-/A0-18-Reihe bereits in §5.14 verankert — §5.15 referenziert sie (Fugen-Identität). **Abschlussklausel (Story 3.9):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **keine fünfte Routing-/Update-Klasse**; **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Prädikat-/Format-/Frontmatter-Key**; `schema/canonical-terms.md` unverändert (kein neuer Normalisierungs-Operand — Umlaut-vs-Transkription bleibt benannter Defer); Commit-Boundary-Regel unverändert; Hold-Ausbau (post-Reconcile-Orphan, Mehrziel) bleibt Story 3.10; AD-16-Klassifikation/semantische Auflösung bleibt Epic 4. **`sprint-status.yaml`:** Key `3-9-deterministische-relevanz-und-reconcile-routing-schliessen` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3). **Review-Loop-2-Auflösung (Re-Ableitung):** Kern-Defekt BS-L2-1 (NO_MATCH/leere Candidate-Liste nicht NO_OP, sondern Zellen 2/3) und BS-L2-2 (Status-Codes inkl. R/C) behoben; Sandbox um R-1-Negativ-Manifest, R-3-Fall-2-Evidenzvergleich, R-5-CREATE-Bewertungsraum, R-6/R-7-Slug-Ableitung + `git ls-tree`-Schnittmenge, R-8-Zwei-Worktree-Hold, R-9-`at`-Exzeption, harmonisierte `norm()` (eine Kollaps-Definition) ertüchtigt (Details siehe Spec Change Log Loop-2 und `wiki/log.md`-Eintrag). - **Revision 3.5 (2026-08-21, Story 3.10):** Neue Sektion **§5.16 „Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau (Story 3.10)"** eingefügt (nach §5.15, vor §6) — die **operationelle Erhaltungs-Klammer** über den textuell unveränderten §5.9/§5.10/§5.15-Mechaniken (D-3, Story 3.10; A0-21-Incrementality-Teil, FR-4/FR-6/FR-12, AD-4/AD-5; §5.15-Zelle-3-/§5.15-Scope-Präzisierung-/§5.10-Pkt.-8-D-4-Hold-Home hierin verankert): (1) **Kontinuitäts-Garantie** (AC-1; in-place Update/Synthese, kein Duplikat, Identität + Index-Link erhalten), (2) **Korrigieren mit Run-Receipt-Trace** (AC-2; ersetzte Wortlautfolge + Source-Basis im Run-Receipt außerhalb des Bundles, §5.14 Pkt. 2; mehrdeutig → benannter Hold Epic 4), (3) **Schutzbestandteile & Byte-Identität** (AC-3; gültige belegte Aussagen, §5.5-Inline-Verweise, `sources` gültiger Belege, §5.6-Links, human-`verified` bleiben erhalten; nicht betroffene Concepts byte-identisch, §5.9 Pkt. 5), (4) **CONFIRMING-Konsolidierung** (AC-4; bestätigende neue Source mit neuem Evidenzanker → Aussage genau einmal, alle Anker via §5.5-Multi-Beleg, `sources`-Zuwachs, `at`-Bump, **kein NO_OP** — Stellen-Abgleich auf den Anker, nicht auf den Inhalt), (5) **gemeinsame Wissensrepräsentation als Synthese-Erhaltung** (AC-5; §5.10-Pkt.-2/3/5, Update auf bestehendes Concept = Erweiterung, keine Neuschreibung), (6) **byte-erhaltender NO_OP** (AC-6; nur bei vollständig identischer Evidenz **samt vollständiger Evidenzanker-Menge** — kein `at`-Bump, kein `sources`-Zusatz, kein `log.md`-Eintrag; fehlender Anker → Pkt. 4), (7) **Provenienz- & Link-Selbsttest aus aktuellem Run** (AC-7; Baseline = `` des aktuellen Runs, erwartete Delta-Menge = Kandidatenliste ∪ Neu-Anlage ∪ `log.md` ∪ nachgeführte `index.md`; kein historischer Commit/globaler Zählwert normativ), (8) **benannter Hold** (AC-8/NFR-7; post-Reconcile-Orphan über **alle** Erhebungs-Stufen a/b/c — die Story-3.9-Sandbox übte nur Stufe a (§5.15-Pkt.-6-Scope-Präzisierung aufgegriffen) —, Mehrziel-Auflösung via D-8-Mehrfach-Term-Vereinigung auf eine primäre Ziel-Repräsentation, sonst fail-closed Hold; widersprüchliche/klassifikationspflichtige Evidenz ohne Wissensmutation; beide Evidenzpfade im Run-Receipt). **§5.15:** Zelle-3-Zeile und Scope-Präzisierung auf die §5.16-Verankerung nachgeführt („in §5.16 verankert, Story 3.10"). **§5.10 Pkt. 8:** D-4-Bullet um die §5.16-Verankerung des Hold selbst ergänzt (Hold-Ausbau: Stufen a/b/c, Mehrziel, benannter Hold). **§7:** Relevanzbestimmung-Bullet um die **Story-3.10-Verankerung** erweitert (§5.16; bestehende Story-Bullets unverändert). **AD-16-Klassifikation/semantische Auflösung bleibt Epic 4.** **Abschlussklausel (Story 3.10):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **keine fünfte Update-/Routing-Form**; die §5.9-Abgrenzungs-Reihenfolge `Korrigieren → Präzisieren → Erweitern → No-Op` bleibt die **einzige** Form-Wahl (textuell unverändert); **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Prädikat-/Format-/Frontmatter-Key**; `schema/canonical-terms.md` unverändert (kein neuer Normalisierungs-Operand — Umlaut-vs-Transkription bleibt benannter Defer, Ask-First); Commit-Boundary-Regel unverändert; `generated.at`-Verhalten unverändert (A0-20-Konvention). **`sprint-status.yaml`:** Key `3-10-inkrementelle-update-und-synthese-erhaltung-absichern` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3/3.4). Sandbox-Nachweis (**E-1..E-9, Exit 0**; CONFIRMING ≠ NO_OP byte-bewiesen, NO_OP byte-erhaltend, Korrigieren-Receipt-Trace, aktueller-Run-Selbsttest, Orphan über Stufe-a/b/c, Mehrziel-Konsolidierung/-Hold, Zwei-Run-Identität nicht-vakuum) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.10, Revision 3.5). -- **Revision 3.6 (2026-08-21, Story 3.11):** Neue Sektion **§5.17 „Atomare Root-Scope-Lease-Akquise (Story 3.11)"** eingefügt (nach §5.16, vor §6) — die **operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise** über der textuell unveränderten §5.11-/§5.12-Mechanik (D-3, Story 3.11; AD-17b/A0-13; §5.11 Pkt. 1/2 und §5.12-Anker sind Fugen-Identität, Revision 3.6): (1) **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand** (AC-a; der geteilte Git-Ref-/Objektnamespace ist der einzige von allen Worktrees/Prozessen eines Clones gemeinsam gesehene Zustand; eine deterministisch benannte, committete Ref je Root-Scope `wiki/`, z. B. `refs/leases/wiki`; die **Run-ID ist Lock-Inhalt und nicht Bestandteil des Exklusivitätsschlüssels** — der Ref-Name trägt keine Run-ID; die bisherige ``-Ablage §5.11 Pkt. 1 bleibt per-Lease-Ablage ohne alleinige Exklusivität), (2) **atomare Akquise (create-only) — genau ein Gewinner** (AC-b; `git update-ref $ZERO_SHA` schlägt fehl, sobald der Ref existiert, und berührt einen existierenden Lock nicht; gits Ref-Sperre serialisiert zwei Worktrees/Prozesse desselben Clones; **Ask-First-Pflicht**: nicht sicher atomar belegbar auf Windows/Git-Bash → HALT, Alternativ-Primitiv zur Autorisierung), (3) **`LEASE_HOLD`-Semantik** (AC-c; abgewiesener Producer verändert weder `wiki/` noch den Lock, erzeugt keinen Compilation Commit, entfernt keine fremde Lease, beendet sauber, AD-16-Pfad), (4) **Determinismus** (AD-17h/A0-19; clone-geteilter Zustand = eindeutige Gewinner-/Verlierer-Entscheidung; Lock-Inhalt dokumentierender Ablage-Wert, kein Schlüsselbestandteil), (5) **Kollisions-Hold an Epic 4** (AC-e/AD-17c/A0-14; kein textueller Auto-Merge, strukturierter Kollisions-Hold mit beiden Commit-Hashes und Scope an Epic 4 via §5.16-Pkt.-8-/§5.10-Pkt.-8-Hold-Mechanik; AD-16-Klassifikation bleibt Epic 4; Commit-Boundary = Mutations-Boundary und `log.md`-Eintragspflicht unverändert), (6) **Abgrenzung** (keine Wanduhr/Systemzeit A0-20, keine Staleness-/Recovery-Logik — bleibt §5.12/Story 3.6 und Story 3.12 —, keine Verwaist-/Stale-Behandlung/kein Branch-Lifecycle nach Übernahme — Story 3.12). **§7:** Leasing-Bullet um die **Story-3.11-Verankerung** erweitert (§5.17; bestehende Story-Bullets unverändert). **§8:** AD-17b/A0-13 bleiben über die bestehende §5.11-Zuordnung verankert — §5.17 referenziert sie (Fugen-Identität). **Abschlussklausel (Story 3.11):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein neuer Frontmatter-Key für Lease-Metadaten** (Vertrag §3.1–§3.7 unverändert); **kein neuer Prädikat-/Format-Key**; **kein Standalone** (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker **textuell unverändert** (additive Präzisierung, Fugen-Identität); keine Wanduhr/Systemzeit (A0-20); keine Staleness-/Recovery-Logik (Story 3.6/3.12); Commit-Boundary-Regel unverändert; AD-16-Klassifikation bleibt Epic 4. **`sprint-status.yaml`:** Key `3-11-root-scope-leasing-atomar-akquirieren` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3/3.4/3.5). Sandbox-Nachweis (**A-1..A-8, Exit 0**; Zwei-Worktree-/Zwei-Prozess-Überlappung mit Zwischenzustands-Assertions „niemals zwei aktive Root-Leases", `LEASE_HOLD`-Nicht-Mutation, Kollisions-Hold mit beiden Commit-Hashes) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.11, Revision 3.6). +- **Revision 3.6 (2026-08-21, Story 3.11):** Neue Sektion **§5.17 „Atomare Root-Scope-Lease-Akquise (Story 3.11)"** eingefügt (nach §5.16, vor §6) — die **operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise** über der textuell unveränderten §5.11-/§5.12-Mechanik (D-3, Story 3.11; AD-17b/A0-13; §5.11 Pkt. 1/2 und §5.12-Anker sind Fugen-Identität, Revision 3.6): (1) **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand** (AC-a; der geteilte Git-Ref-/Objektnamespace ist der einzige von allen Worktrees/Prozessen eines Clones gemeinsam gesehene Zustand; eine deterministisch benannte, committete Ref je Root-Scope `wiki/`, z. B. `refs/leases/wiki`; die **Run-ID ist Lock-Inhalt und nicht Bestandteil des Exklusivitätsschlüssels** — der Ref-Name trägt keine Run-ID; die bisherige ``-Ablage §5.11 Pkt. 1 bleibt per-Lease-Ablage ohne alleinige Exklusivität), (2) **atomare Akquise (create-only) — genau ein Gewinner** (AC-b; `git update-ref $ZERO_SHA` schlägt fehl, sobald der Ref existiert, und berührt einen existierenden Lock nicht; gits Ref-Sperre serialisiert zwei Worktrees/Prozesse desselben Clones; **Ask-First-Pflicht**: nicht sicher atomar belegbar auf Windows/Git-Bash → HALT, Alternativ-Primitiv zur Autorisierung), (3) **`LEASE_HOLD`-Semantik** (AC-c; abgewiesener Producer verändert weder `wiki/` noch den Lock, erzeugt keinen Compilation Commit, entfernt keine fremde Lease, beendet sauber, AD-16-Pfad), (4) **Determinismus** (AD-17h/A0-19; clone-geteilter Zustand = eindeutige Gewinner-/Verlierer-Entscheidung; Lock-Inhalt dokumentierender Ablage-Wert, kein Schlüsselbestandteil), (5) **Kollisions-Hold an Epic 4** (AC-e/AD-17c/A0-14; kein textueller Auto-Merge, strukturierter Kollisions-Hold mit beiden Commit-Hashes und Scope an Epic 4 via §5.16-Pkt.-8-/§5.10-Pkt.-8-Hold-Mechanik; AD-16-Klassifikation bleibt Epic 4; Commit-Boundary = Mutations-Boundary und `log.md`-Eintragspflicht unverändert), (6) **Abgrenzung** (keine Wanduhr/Systemzeit A0-20, keine Staleness-/Recovery-Logik — bleibt §5.12/Story 3.6 und Story 3.12 —, keine Verwaist-/Stale-Behandlung/kein Branch-Lifecycle nach Übernahme — Story 3.12). **§7:** Leasing-Bullet um die **Story-3.11-Verankerung** erweitert (§5.17; bestehende Story-Bullets unverändert). **§8:** AD-17b/A0-13 bleiben über die bestehende §5.11-Zuordnung verankert — §5.17 referenziert sie (Fugen-Identität). **Abschlussklausel (Story 3.11):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein neuer Frontmatter-Key für Lease-Metadaten** (Vertrag §3.1–§3.7 unverändert); **kein neuer Prädikat-/Format-Key**; **kein Standalone** (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker **textuell unverändert** (additive Präzisierung, Fugen-Identität); keine Wanduhr/Systemzeit (A0-20); keine Staleness-/Recovery-Logik (Story 3.6/3.12); Commit-Boundary-Regel unverändert; AD-16-Klassifikation bleibt Epic 4. **`sprint-status.yaml`:** Key `3-11-root-scope-leasing-atomar-akquirieren` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3/3.4/3.5). Sandbox-Nachweis (**A-1..A-8, Exit 0**; Zwei-Worktree-/Zwei-Prozess-Überlappung mit Zwischenzustands-Sampling („niemals zwei aktive Root-Leases" **konstruktiv belegt** — eine scope-bezogene Ref + atomarer create-only-Write, keine zwei Refs/Werte im Überlappungs-Fenster), `LEASE_HOLD`-Nicht-Mutation, Kollisions-Hold mit beiden Commit-Hashes) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.11, Revision 3.6). diff --git a/wiki/log.md b/wiki/log.md index 832889b..e48349d 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -1,6 +1,7 @@ # Log ## 2026-08-21 +- **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. - **Story 3.11 → `review` (Root-Scope-Leasing atomar und worktree-übergreifend akquirieren, Verankerung §5.17 + Revision 3.6, 2026-08-21):** `schema/compiler.md` **Revision 3.6** — neue Sektion **§5.17 „Atomare Root-Scope-Lease-Akquise (Story 3.11)“** (nach §5.16, vor §6): operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise über der textuell unveränderten §5.11-/§5.12-Mechanik (Fugen-Identität; D-3, AD-17b/A0-13; TOCTOU-Race der bisherigen Lockfile-Lage geschlossen). **Punkte 1–6:** (1) **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand** (AC-a: geteilter Git-Ref-/Objektnamespace aller Worktrees/Prozesse eines Clones; eine committete Ref je Root-Scope `wiki/`, z. B. `refs/leases/wiki`; **Run-ID = Lock-Inhalt, nicht Schlüsselbestandteil**), (2) **atomare Akquise (create-only), genau ein Gewinner** (AC-b: `git update-ref $ZERO_SHA`; Ask-First-Pflicht → HALT/Alternativ-Primitiv), (3) **`LEASE_HOLD`-Semantik** (AC-c: kein `wiki/`-/Lock-Eingriff, kein Compilation-Commit, keine Fremd-Lease-Entfernung, sauberes Ende, AD-16-Pfad), (4) **Determinismus** (AD-17h/A0-19: clone-geteilter Zustand = eindeutige Gewinner-/Verlierer-Entscheidung), (5) **Kollisions-Hold an Epic 4** (AC-e/AD-17c/A0-14: kein textueller Auto-Merge, strukturierter Kollisions-Hold mit beiden Commit-Hashes + Scope via §5.16-Pkt.-8-/§5.10-Pkt.-8-Hold-Mechanik), (6) **Abgrenzung** (keine Wanduhr/Systemzeit A0-20, keine Staleness-/Recovery-Logik — §5.12/Story 3.6 und Story 3.12 —, kein Branch-Lifecycle nach Übernahme — Story 3.12). **§7:** Leasing-Bullet um die Story-3.11-Verankerung erweitert; **§8:** Revisionslog-Addendum 3.6 (Abschlussklausel AD-3). **Sandbox-Nachweis** (`_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh`, `/tmp`-Baum, nie der reale Ist-Baum; re-executierbar): **A-1..A-8, 8/8 harte PASS, Exit 0** — A-1 Exklusivitätsschlüssel (AC-a), A-2 **reale Zwei-Worktree-/Zwei-Prozess-Überlappung** (`git worktree add` über Baseline, zwei getrennte Prozesse, create-only-Akquise) mit Zwischenzustands-Assertions „niemals zwei aktive Root-Leases“ (AC-b/AC-d), A-3 Weder-Noch (nie zwei, nie keiner), A-4 LEASE_HOLD-Nicht-Mutation (AC-c: `wiki/` unverändert, keine Commits, fremde Lease unangetastet), A-5 Schlüssel-ohne-Run-ID, A-6 späte Abweisung, A-7 Kollisions-Hold mit beiden Commit-Hashes (AC-e), A-8 Freigabe-erneut; Erhaltungs-Invariante + `at`-Normalform je Szenario (Vertrag §3.3/§3.4, §6.5); kein Zugriff auf reales Bundle/`raw/` (AD-3). **Abschlussklausel:** keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); keine neue §7-Invaliditätsklasse; kein neuer Frontmatter-Key für Lease-Metadaten (Vertrag §3.1–§3.7 unverändert); kein Standalone (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker textuell unverändert (additive Präzisierung). `sprint-status.yaml`-Key `3-11-root-scope-leasing-atomar-akquirieren` → **`review`** (Implementierungs-Flip, HEAD-Stand 08-21-2026; finaler `done`-Flip im Step-05-Status-Sync), `last_updated` → 08-21-2026 12:30. **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); Lease-Lifecycle/Commit-Abschluss transaktional (Story 3.12) und Staleness-Nachfolge bleiben offen. - **Story 3.10 → `review` (Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau, Verankerung §5.16 + Revision 3.5, 2026-08-21):** `schema/compiler.md` **Revision 3.5** — neue Sektion **§5.16 „Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau (Story 3.10)“** (nach §5.15, vor §6): operationelle Erhaltungs-Klammer (A0-21-Incrementality, Fugen-Identität; keine A|B-Aneinanderreihung, kein Regenerate-Everything). **Punkte 1–8:** (1) **Kontinuitäts-Garantie** (AC-1: in-place Update/Konsolidierung/Synthese auf der gemeinsamen Wissensrepräsentation, kein hartes Duplikat, Identität + `index.md`-Link erhalten), (2) **Korrigieren mit Run-Receipt-Trace** (AC-2: ersetzte Wortlautfolge + Source-Basis im Run-Receipt außerhalb des Bundles, §5.14 Pkt. 2; mehrdeutige Korrektur → benannter Hold, Epic-4-/AD-16-Klassifikation, kein textueller Auto-Merge AD-17c), (3) **Schutzbestandteile & Byte-Identität** (AC-3: gültige belegte Aussagen, §5.5-Inline-Verweise, `sources` gültiger Belege, §5.6-Links, human-`verified` geschützt; nicht betroffene Concepts byte-identisch via §5.9-Pkt.-5-Ghost-Diff-Rollback), (4) **CONFIRMING-Konsolidierung** (AC-4: bestätigende neue Source → Aussage genau einmal, alle Evidenzanker via §5.5-Multi-Beleg, `sources`-Zuwachs, `generated.at`-Bump, **kein NO_OP**; Anker- statt Content-Abgleich), (5) **gemeinsame Wissensrepräsentation** (AC-5: §5.10-Pkt.-2/3/5 als Synthese-Erhaltung), (6) **byte-erhaltender NO_OP** (AC-6: volle Evidenzanker-Menge → NO_OP ohne Mutation/at-Bump/sources-Zusatz; fehlender Anker → Pkt. 4), (7) **Provenienz-/Link-Selbsttest aus aktuellem Run** (AC-7: Baseline = aktuelles ``, erwartete Deltas = Kandidaten-Liste ∪ Neu-Anlage ∪ `log.md` ∪ nachgeführte `index.md`, keine hart kodierten Pläne/Bodies/Zählwerte — §5.14 Pkt. 2, AC-7/§5.14-Pkt.-2-Konsistenz), (8) **benannter Hold** (AC-8/NFR-7: post-Reconcile-Orphan über **alle Erhebungs-Stufen a/b/c** — Story-3.9 übte nur Stufe a —, Mehrziel via D-8-Mehrfach-Term-Vereinigung → primäre Ziel-Repräsentation, sonst fail-closed benannter Hold; beide Evidenzpfade im Run-Receipt). **§7-Bullet** erweitert (Story-3.10-Verankerung; §5.9-Abgrenzungs-Reihenfolge bleibt die einzige Form-Wahl); **Hold-Home-Nachführungen:** §5.15-Zelle-3 + §5.15-Scope-Präzisierung + §5.10-Pkt.-8-D-4-Bullet verweisen auf §5.16 (Story 3.10, Hold-Ausbau); Revisionslog **Revision 3.5** mit Abschlussklausel (AD-3 — `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert; keine neue §7-Invaliditätsklasse; keine neue Update-Form; keine neuen Prädikat-/Frontmatter-/Format-Keys; kein Standalone/D-3; keine Vertragsänderung; Umlaut-vs-Transkription-Defer bleibt offen — kein neuer Normalisierungs-Operand, ask-first). `sprint-status.yaml`-Key `3-10-inkrementelle-update-und-synthese-erhaltung-absichern` → **`review`** (Implementierungs-Flip, HEAD-Stand 08-21-2026; finaler `done`-Flip im Step-05-Status-Sync), `last_updated` → 08-21-2026 12:00. **Sandbox-Nachweis** (`_bmad-output/implementation-artifacts/sandbox-3-10/run-sandbox.sh`, `/tmp`-Baum, nie der reale Ist-Baum; re-executierbar): **E-1..E-9, Exit 0, 9 harte PASS-Assertionen** — E-1 Kontinuität/AC-1 (Update in-place, kein Duplikat, Identity + Index-Link erhalten); E-2 Korrigieren-Receipt-Trace/AC-2 (Wortlautfolge + Source-Basis im Receipt außerhalb Bundle; mehrdeutig → benannter Hold ohne Mutation); E-3 Schutzbestandteile/AC-3 (nicht betroffenes Concept byte-identisch, Ghost-Diff-Rollback stellt Baseline wieder her); E-4 CONFIRMING/AC-4 (**CONFIRMING ≠ NO_OP byte-bewiesen**: Aussage genau einmal, neuer Anker, Multi-Beleg, sources-Zuwachs, at-Bump); E-5 Synthese-Erhaltung/AC-5 (gemeinsame Repräsentation erweitert, keine A|B-Aneinanderreihung); E-6 NO_OP byte-erhaltend/AC-6 (volle Evidenzanker-Menge: keine Mutation, kein at-Bump, kein sources-Zusatz); E-7 Selbsttest aktueller Run/AC-7 (Baseline = aktuelles `` frisch erzeugt, Delta = Kandidaten-Liste ∪ Neu-Anlage, keine hart kodierten Zählwerte); E-8 Orphan + Mehrziel/AC-8 (Stufen a/b/c belegt, D-8-Vereinigung → primäre Ziel-Repräsentation, fail-closed Hold, beide Evidenzpfade im Receipt); E-9 Zwei-Run-Identität deterministisch (gleicher Eingang → identische Bytes, Zustandswechsel messbar — Nicht-Vakuum). **Defer-Aufgriff:** `deferred-work.md` append — Defer «Orphan voller Stufen b/c + Mehrziel» (Story-3.9-Block, Home Story 3.10) → **`aufgegriffen`** (§5.16 Pkt. 8 verankert, Sandbox E-8 ausgeübt; Umlaut-vs-Transkription-Defer bleibt offen). **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); Zwei-Run-über-reale-Inhalte/Stufen-b-c-über-reale-Bäume bleibt Story-3.13-Abnahme-Gate. - **Story 3.9 → Review-Loop-3-Abschluss + `done` (Deterministische Relevanz- & Reconcile-Routing, bmad-code-review Re-Run 4 Layer — blind-hunter ×2 / edge-case-hunter / acceptance-auditor, verification-gap über Retry, 2026-08-21):** Re-Review der Loop-2-zustands Implementation (Diffform `2f079ee..73f2c9e`, 7 Dateien); **Triage:** 3 decision-needed / 15 patch (1 nach Re-Verifikation verworfen → **14 anzuwenden**) / 2 defer / 9 verworfen; **keine intent_gap/bad_spec (kein Loopback).** **Nutzer-Entscheidungen (empfohlene Optionen):** D-3.9-1 §8-Revision-3.3-Nachführung **behalten** (3.8 ist faktisch done; Dokumentation über den append-only Spec-Change-Log, kein Rückbau); D-3.9-2 Status-Kontraktion aufgelöst auf die 3.7/3.8-Präzedenz: maßgeblich `review` (Impl-Commit-Flip), Spec-Frontmatter-`done` zurückgesetzt, **finaler `done`-Flip in diesem Eintrag (Step-05-Status-Sync)**; D-3.9-3 **Minimal-Härtung** der tautologischen Sandbox-Szenarien (echte Mechanik statt Selbstvergleich; strukturelle Restlimits — volle Stufen-b/c-Traversal, Zwei-Run über realen Contents — bleiben benannte Defers, Home Story 3.13, Präzedenz DET-1/2). **Patches (14):** compiler.md §5.15 Pkt. 1 (`/dev/null`-Sort → **LC_ALL=C-bytetreue Stable-Sortierung**; Status-Code-Entflechtung Befund A/M/D/R/C ↔ Akzeptanz A/C vs. Run-FAIL M/D/R über Pkt. 4), Pkt. 2 (Actor-Body → **Concept-Body**), Pkt. 5 (hängender „§3.2-Endergebnis"-Verweis → **§5.8-Instruktions-Hold** als Run-Status-Definition), Revision 3.4 (Status-Wortlaut `review` + Status-Code-Korrektur); Sandbox: **README-Reserviertheits-Fall case-insensitiv** (P-3.9-2), R-9-Bundle-Grep-**Anchorung** `(^|/)(index|log)\.md$` + **Benennung** der index/log-Ausnahme (P-3.9-7, re-scoped: Enden-Präfixe wie `myindex.md` nicht mehr still ausgeschlossen), R-8-Hold-**Assert auf beide Worktrees** (P-3.9-8), **Worktree-Re-Run-Idempotenz** unter `$ROOT` (P-3.9-14), `local rc=$?`-**Dead-Diagnostics** → lebendige `rc`-Erfassung (P-3.9-15), Term-Quoting + `sort -u`; **D-3.9-3-Härtung:** R-1 Negativ-Manifest → **echter Run-FAIL-Sub-Run** vor jeder Mutation (Mutation-Sentinel bleibt abseits), R-1b/R-4 **saubere je-Status-Sub-Runs** (M/D/R-Run-FAIL ohne kumulative-Baseline-Kontraktion; A-Sub-Run Guard-Pass mit Sentinel), R-3-Fall-2 **echter Full-Containment-Check** (Token-weise, mit Negativ-Kontrolle) + **Stufe-b via echtem index.md-Link-Parsing** und Zielpfad-Existenz, R-5 **echte `route()`-Funktion** (leere Candidate-Liste → CREATE-Bewertungsraum, **nie NO_OP** — NO_OP-Regression negativ geprüft) + D-8-Vereinigung ausgeübt, R-6/R-7 **Slug rein aus dem committeten Dateinamen** (Datums-Suffix-Strip + Norm, kein nicht-instruktioneller `-doc$`-Strip). **Verworfen (1):** P-3.9-1 „Escaper defekt" = **Fehlalarm** — die „Ausführung"-Evidenz war durch die Bash-Tool-Transport-Schicht korrumpiert (Backslash-Ebene halbiert; getesteter Code ≠ Datei-Code); `od`-Beweis (Z. 74/790: `\\&`) + Negativ-/Positiv-Kontrolle aus Datei-Bytes (`v1.0` matcht `v10`-Body **nicht**, `v1.0`-Body **ja**) → Escaper **literal-sicher**, Z. 74/790 unverändert (Korrektur im Spec-Change-Log). **Defers (2, → deferred-work.md append-only):** W-3.9-1 `norm()`/`tr` ohne `LC_ALL`-Pinning (Home: Sandbox-Härtung, 952-Zeilen-Scope); W-3.9-2 positive Zwei-Run-Identität strukturell trivial (Home: Story-3.13-Abnahme, Präzedenz DET-1/2). **Frozen-Änderungen (im Spec-Change-Log autorisiert/dokumentiert):** I/O-Matrix-`RAW_GUARD_MODIFIZIERT`-Zelle um Rename (M/D/**R**) + ``-Schließtag-Nachtrag (Präzedenz Spec-3-7/3-8); **keine AC-/Intent-Wortlaut-Änderung, keine Neu-Verhandlung nötig.** **Sandbox re-executiert:** `bash _bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh` → **R-1..R-9 harte PASS, Exit 0** (inkl. R-1b/R-4 je-Status-Guard-Sub-Runs, R-3 Full-Containment + Stufe-b-Link-Parsing, R-5 route(), R-6/R-7 echte Slug-Ableitung, R-8 beide Worktrees, R-9 ankerter Bundle-Vergleich). **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-9-…` → **`done`** (finaler Step-05-Flip nach konvergiertem Loop-3), `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; Umlaut-vs-Transkription bleibt benannter Defer; Hold-Ausbau (post-Reconcile-Orphan, Mehrziel) + Stufen-b/c-Traversal-Coverage bleiben Story 3.10/3.13.