fix: Story 3.12 Review-Loop-2-Abschluss (bmad-code-review 4 Layer, konvergiert; D-3.12-1 Option 1, 7 Patches, 2 Defer, 6 dismissed; Sandbox L-1..L-9 9/9 harte PASS/Exit 0)
- D-3.12-1 (Nutzer, Option 1): AC-6/§5.18-Pkt.-6-Grenze an log.md-Praxis — dokumentierte Run-Nachweise = notwendige Koordinationsereignisse; §5.18/AC-6 textuell unverändert; L-8-Guard auf Kategorie-Hyphenate + Negativ-Kontrolle geschärft - P1: scopelock_healthy() + LOCK_READ_ERROR-Propagation (korrupter Lock nie en-bloc-stale) - P2: Release-Fehler negativ geübt (L-7), L-6 "valide committet" hart verifiziert - P3: Setup-Robustheit (Exit-Checks, verifizierter $BASE, Backup-cp byte-identisch) - P4: L-9 Ghost-Diff-Probe (Index+Worktree), reg_write real geübt - P5: AC-1-Ownership-Stale positiv getestet, L-2 Takeover-Exactly-once am CAS - S1: Spec-Struktur (review_loop_iteration 0->1, </frozen-after-approval>, doppelte Change-Log-Überschrift entfernt), Status-Sync vereinheitlicht - S2: SRO-/Code-Map-/deferred-work-Anker auf Ist-Zeilen (takeover Z. 153, L-2 Z. 367, L-3 Z. 442, L-7 Z. 648, L-8 Z. 700; §5.18 Z. 426-439, §6 Z. 441, Rev 3.7 Z. 543) - Defer: DF1 (AC-3-stash-Variante + AC-5 kombiniert, Home 3.13), DF2 (assert_no_wallclock) - Status: Spec status done, sprint-status Key 3-12 -> done, last_updated 08-22-2026 07:44; wiki/log.md Loop-2-Abschlusseintrag (## 2026-08-22) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -33,12 +33,16 @@
|
||||
# ownership-gebundener Ref-Delete), die §5.12-Registry/Gen/Liveness- und §5.11-Pkt.-3-
|
||||
# Schutzmechanik und prueft die Lifecycle-Klammer inkl. KillPoint-Tests + Clean-Input-Guard.
|
||||
# Ubuntu-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale wiki/- oder raw/-Baum.
|
||||
# set -u: unbestimmte Variable = Fehler. Kein set -e: die Sandbox uebt NEGATIVE
|
||||
# Assertionen im Idiom `cmd && fail "..."` (erwartetes Scheitern = korrekte Semantik) —
|
||||
# set -e wuerde an genau diesen Stellen das Skript stoeren. Stattdessen: gezielte
|
||||
# Exit-Checks an den Setup-/Isolations-/Backup-Punkten (Loop-2-P3).
|
||||
set -u
|
||||
ROOT=$(mktemp -d /tmp/sb312-XXXXXX)
|
||||
ROOT=$(mktemp -d /tmp/sb312-XXXXXX) || { echo "HARD-FAIL: mktemp fehlgeschlagen (Sandbox-Setup nicht moeglich)" >&2; exit 1; }
|
||||
SB="$ROOT/sb"
|
||||
mkdir -p "$SB/wiki" "$SB/raw" "$SB/scratch"
|
||||
cd "$SB"
|
||||
git init -q
|
||||
mkdir -p "$SB/wiki" "$SB/raw" "$SB/scratch" || { echo "HARD-FAIL: Sandbox-Baum-Aufbau fehlgeschlagen" >&2; exit 1; }
|
||||
cd "$SB" || { echo "HARD-FAIL: cd in Sandbox fehlgeschlagen (Aufrufer-Baum waere kontaminiert)" >&2; exit 1; }
|
||||
git init -q || { echo "HARD-FAIL: git init fehlgeschlagen" >&2; exit 1; }
|
||||
# Determinismus vs. Host-Git-Konfiguration (AD-17h): LF-Blobs + LF-Worktree —
|
||||
# autocrlf/filemode-Umwandlung des Hosts wuerde sha256-Vergleiche verschieben.
|
||||
git config core.autocrlf false
|
||||
@@ -91,6 +95,10 @@ EOF
|
||||
git add -A
|
||||
git commit -qm "Baseline"
|
||||
BASE=$(git rev-parse HEAD)
|
||||
# Loop-2-P3: Baseline verifiziert — ein leerer/falscher $BASE-Wert wuerde alle
|
||||
# $BASE-Vergleiche in L-1..L-9 und den isolate()-Fallback vergiften.
|
||||
[ -n "$BASE" ] && git cat-file -e "$BASE^{commit}" 2>/dev/null \
|
||||
|| { echo "HARD-FAIL: Baseline-Commit nicht verifiziert (leer/kein Commit-Objekt)" >&2; exit 1; }
|
||||
echo "BASELINE-COMMIT (Merge-Base, eindeutiger Commit-Object-Wert): $BASE"
|
||||
echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)"
|
||||
echo
|
||||
@@ -115,16 +123,29 @@ scopelock_acquire() { # $1 = Run-ID (Lock-Inhalt; PRODUCER sichtbar) — create-
|
||||
{ git update-ref "$SCOPELOCK" "$val" "$ZERO"; } 2>/dev/null
|
||||
}
|
||||
scopelock_release() { # $1 = erwartete Inhaber-Run-ID (Ownership-Pruefung)
|
||||
scopelock_healthy || { echo "HARD-FAIL (LOCK_READ_ERROR): Release abgebrochen, Lock-Zustand unvertraeulich (Loop-2-P1)" >&2; exit 1; }
|
||||
[ "$(scopelock_content)" = "${1:-}" ] \
|
||||
|| { echo "HARD-FAIL: Release ohne Ownership (Inhaber: '$(scopelock_content)', Aufrufer: '${1:-}')" >&2; exit 1; }
|
||||
git update-ref -d "$SCOPELOCK" || { echo "HARD-FAIL: Release fehlgeschlagen" >&2; exit 1; }
|
||||
}
|
||||
scopelock_content() {
|
||||
# Leer ist NUR noch "Ref nicht vorhanden" (PATCH 4c-Grundvertrag). Ein korrupter
|
||||
# Blob wird NICHT hier per `exit 1` beendet — dieser Aufruf laeuft nahezuausschliesslich
|
||||
# in Kommandosubstitution, wo `exit 1` nur den Subshell toetete und der Eltern-Shell
|
||||
# ein leerer Wert erscheinen wuerde (=> falsche "Halter haelt nicht mehr"-
|
||||
# Klassifikation, Loop-2-P1). Stattdessen pruefen die Aufrufer VORHER
|
||||
# `scopelock_healthy` und werten einen korrupten Blob hart als LOCK_READ_ERROR.
|
||||
local val
|
||||
val=$(git rev-parse -q --verify "$SCOPELOCK" 2>/dev/null) || { echo ""; return 0; }
|
||||
# PATCH 4c: Ref existiert, aber cat-file scheitert = korrupter/fehlender Blob -> harter
|
||||
# LOCK_READ_ERROR statt stiller leerer Rueckgabe (leer ist nur "Ref nicht vorhanden").
|
||||
git cat-file -p "$val" 2>/dev/null || { echo "HARD-FAIL (LOCK_READ_ERROR): Lock-Ref '$SCOPELOCK' zeigt auf '$val', aber Blob nicht lesbar (korrupt/fehlend)" >&2; exit 1; }
|
||||
git cat-file -p "$val" 2>/dev/null || { echo "" ; return 0; }
|
||||
}
|
||||
# Loop-2-P1 (PATCH 4c propagiert): gesund = Ref fehlt (leer erlaubt) ODER Ref existiert
|
||||
# UND ist lesbar. Return 1 = korrupter/fehlender Blob (LOCK_READ_ERROR).
|
||||
scopelock_healthy() {
|
||||
local val
|
||||
val=$(git rev-parse -q --verify "$SCOPELOCK" 2>/dev/null) || return 0
|
||||
git cat-file -e "$val" 2>/dev/null || { echo "HARD-FAIL (LOCK_READ_ERROR): Lock-Ref '$SCOPELOCK' zeigt auf '$val', aber Blob nicht lesbar (korrupt/fehlend)" >&2; return 1; }
|
||||
return 0
|
||||
}
|
||||
# Ownership-CAS: Uebernahme nur, wenn der Lock (noch) vom erwarteten Inhaber gehalten wird
|
||||
# (atomare Ownership-Pruefung, §5.18 Pkt. 1/2). Die alte Inhaber-Run-ID im Lock-Inhalt ist
|
||||
@@ -135,6 +156,7 @@ scopelock_takeover() { # $1 = erwartete alte Run-ID (Lock-Inhalt) $2 = neue Run
|
||||
# HARD-FAIL. Der entscheidende Guard ist danach der ATOMARE Old-Value-Write (CAS) — die
|
||||
# atomare Abweisung selbst wird im negativen L-2-Test durch direkten atomaren Ref-Write
|
||||
# geprueft (PATCH 2), der schnelle Diagnose-Zweig bleibt fuer echte Aufrufer fatal.
|
||||
scopelock_healthy || { echo "HARD-FAIL (LOCK_READ_ERROR): Takeover abgebrochen, Lock-Zustand unvertraeulich (Loop-2-P1)" >&2; exit 1; }
|
||||
[ "$(scopelock_content)" = "$old" ] \
|
||||
|| { echo "HARD-FAIL (Ownership): Lock-Inhalt '$old' erwartet, tatsaechlich '$(scopelock_content)'" >&2; exit 1; }
|
||||
newval=$(printf '%s' "$new" | git hash-object -w --stdin) || return 2
|
||||
@@ -211,6 +233,14 @@ lease_stale() { # $1=area $2=id $3=erzeugungs_gen: true (0) wenn Erzeugungs-Ge
|
||||
lease_liveness_stale() {
|
||||
local area="$1" id="$2" gen="$3" holder_runid="$4"
|
||||
[ -n "${4:-}" ] || return 1 # PATCH 4b: leere holder_runid -> keine vacuous-stale-Klassifikation
|
||||
# Loop-2-P1: korrupter Lock-Blob ist KENNE Liveness-Quelle — weder "haelt" noch
|
||||
# "haelt nicht mehr". Ohne harte LOCK_READ_ERROR-Pruefung wuerde ein leer lesender
|
||||
# Subshell den Lock als "Halter haelt nicht mehr" klassifizieren und eine moeglich-
|
||||
# weise LEBENDE Lease en bloc stale markieren (AC-1-Gate ausgehebelt).
|
||||
if ! scopelock_healthy; then
|
||||
echo "HARD-FAIL (LOCK_READ_ERROR): Liveness-Bewertung abgebrochen, Lock-Zustand unvertraeulich (keine Stale-Klassifikation moeglich)" >&2
|
||||
return 2
|
||||
fi
|
||||
if ! lease_stale "$area" "$id" "$gen"; then
|
||||
return 1 # nicht generationen-abgelaufen -> nicht stale
|
||||
fi
|
||||
@@ -294,8 +324,11 @@ fail() { echo "HARD-FAIL: $1" >&2; exit 1; }
|
||||
runlabel "L-1: LIVENESS_AKTIV (AC-1) — hoehere Gen-Hoehe macht lebende Lease nicht stale"
|
||||
isolate l1
|
||||
# Producer erwirbt den Root-Scope (Run-ID als Lock-Inhalt) und registriert die Lease
|
||||
# (Registry, Erzeugungs-Gen 1).
|
||||
# (Registry, Erzeugungs-Gen 1): reg_write legt die Registry mit der Erzeugungs-Generation
|
||||
# an (Loop-2-P4: reg_write wird hier real geuebt — kein toter Code), reg_hold_mark markiert
|
||||
# den aktiven Hold.
|
||||
scopelock_acquire "RUN-L1-holder" || fail "L-1: Root-Scope-Akquise schlug fehl"
|
||||
reg_write wiki run-l1 "RUN-L1-holder" 1
|
||||
reg_hold_mark wiki run-l1 1
|
||||
scopelock_header_banner "RUN-L1-holder"
|
||||
# Probe: die Lease ist bei Reg-Gen 1 NICHT stale (Erzeugungs-Gen == aktueller Reg-Gen).
|
||||
@@ -316,7 +349,14 @@ assert_no_wallclock registry/wiki
|
||||
# Release des Halter (Ownership), dann ist der Clean-Input-Guard-Zustand wieder leer.
|
||||
scopelock_release "RUN-L1-holder"
|
||||
[ -z "$(scopelock_content)" ] || fail "L-1: Lock nach Release nicht leer"
|
||||
echo "RESULT: PASS — L-1: LIVENESS_AKTIV — hoehere Generation macht lebende Lease NICHT stale; Liveness ist Zustand (bestaetigter Abbruch/abgelaufene Liveness + Ownership-Pruefung), kein Wanduhr-/Gen-Hoehen-Effekt (AC-1, A0-20)"
|
||||
# Loop-2-P5: AC-1-Ownership-Stale-Zweig POSITIV getestet — nach dem Release haelt der
|
||||
# Halter den Lock NICHT mehr (Inhalt leer != Halter-Run-ID), der Gen-Check ist abgelaufen
|
||||
# (Erzeugungs-Gen 1 < Reg-Gen 2) und es fehlt ein Registry-Stale-Marker -> die Liveness
|
||||
# klassifiziert die Lease stale ueber die Ownership-Quelle (Pkt. 1 Bedingung (ii),
|
||||
# "Halter haelt Lock nicht mehr") — NICHT ueber einen Wanduhr-Effekt.
|
||||
lease_liveness_stale wiki run-l1 1 "RUN-L1-holder" \
|
||||
|| fail "L-1-P5: Ownership-Stale-Zweig (Halter haelt Lock nicht mehr) klassifizierte NICHT stale (AC-1 Bedingung ii)"
|
||||
echo "RESULT: PASS — L-1: LIVENESS_AKTIV — hoehere Generation macht lebende Lease NICHT stale; Liveness ist Zustand (bestaetigter Abbruch/abgelaufene Liveness + Ownership-Pruefung), kein Wanduhr-/Gen-Hoehen-Effekt; Ownership-Stale-Zweig positiv belegt (AC-1, A0-20)"
|
||||
pass
|
||||
|
||||
# =====================================================================
|
||||
@@ -370,12 +410,22 @@ printf '\n### 2026-08-21 — Lease-Uebernahme: wiki/run-l2; Baseline %s; alte Ho
|
||||
grep -qF "alte Holder-ID RUN-L2-alt" wiki/log.md || fail "L-2: ersetzte Holder-ID nicht benannt (AC-2/AC-6)"
|
||||
grep -qF "neue Holder-ID RUN-L2-neu" wiki/log.md || fail "L-2: neue Holder-ID nicht benannt (AC-2/AC-6)"
|
||||
grep -qF "Baseline $BASE" wiki/log.md || fail "L-2: Baseline-Commit fehlt im Uebernahme-Eintrag (Vertrag §5)"
|
||||
# Kein Doppel-Uebernehmer: eine zweite (sequentielle) Uebernahme derselben stale id schlaegt
|
||||
# fehl — der Lock wird nur einmal ersetzt (genau einmal-Uebernahme, AC-2).
|
||||
# Kein Doppel-Uebernehmer: eine zweite (sequentielle) AKQUISE derselben stale id schlaegt
|
||||
# fehl (create-only, Ref existiert) — der Lock wird nur einmal ersetzt (genau einmal-Uebernahme, AC-2).
|
||||
if scopelock_acquire "RUN-L2-zweiter"; then
|
||||
fail "L-2: zweite Uebernahme gelang (AC-2: genau einmal verletzt)"
|
||||
fi
|
||||
[ "$(scopelock_content)" = "RUN-L2-neu" ] || fail "L-2: Lock-Inhalt nach zweitem Uebernahme-Versuch veraendert"
|
||||
# Loop-2-P5: TAKEOVER-Exactly-once direkt am Takeover-Pfad (nicht nur am create-only-Akquise-
|
||||
# pfad): ein zweiter scopelock_takeover-Versuch mit ALTEM Old-Value (RUN-L2-alt, Inhaber ist
|
||||
# jetzt RUN-L2-neu) muss ATOMAR FEHLSCHLAGEN (Ownership-CAS: Lock traegt nicht mehr den
|
||||
# erwarteten Old-Value) und den Lock UNVERAENDERT lassen.
|
||||
oldblob2=$(printf '%s' 'RUN-L2-alt' | git hash-object -w --stdin) || fail "L-2-P5: oldblob2 nicht erzeugt"
|
||||
neu2blob=$(printf '%s' 'RUN-L2-doppelt' | git hash-object -w --stdin) || fail "L-2-P5: neu2blob nicht erzeugt"
|
||||
if git update-ref "$SCOPELOCK" "$neu2blob" "$oldblob2" 2>/dev/null; then
|
||||
fail "L-2-P5: zweiter Takeover-CAS mit altem Old-Value gelang (AC-2: Takeover genau einmal verletzt)"
|
||||
fi
|
||||
[ "$(scopelock_content)" = "RUN-L2-neu" ] || fail "L-2-P5: zweiter Takeover-Versuch hat den Lock veraendert (Clobber)"
|
||||
# Die verwaiste Registry-Zeile bleibt erhalten (nie still geloescht, AD-17e):
|
||||
grep -qF "hold: run-l2 (Gen 1)" registry/wiki || fail "L-2: Registry-Zeile run-l2 still geloescht (AD-17e)"
|
||||
scopelock_release "RUN-L2-neu"
|
||||
@@ -407,7 +457,10 @@ ALPHA_ONLY=$({ git diff --name-only "$BASE" -- wiki/ ; git status --porcelain --
|
||||
# ABORT-/PROTECT-ZUSTANDSMASCHINE (getrackt): SCHUETZEN — Sicherung in Scratch-Zone
|
||||
# (ausserhalb wiki/, deterministisch benannt), dann Arbeitssatz bereinigt.
|
||||
mkdir -p scratch/l3
|
||||
cp wiki/alpha.md "scratch/l3/alpha.md.stash"
|
||||
cp wiki/alpha.md "scratch/l3/alpha.md.stash" || fail "L-3: Backup fehlgeschlagen — Fremdbearbeitung NICHT verworfen (AD-17e, Loop-2-P3)"
|
||||
# Loop-2-P3: Backup VOR der Bereinigung verifiziert — schlaege es still fehl, wuerde
|
||||
# `git checkout --` die fremde Aenderung still loeschen (AD-17e-Verletzung).
|
||||
[ "$(sha256sum "scratch/l3/alpha.md.stash" | cut -d' ' -f1)" = "$FRANK_MD5" ] || fail "L-3: Backup nicht byte-identisch vor Bereinigung (Loop-2-P3, AD-17e)"
|
||||
git checkout -q -- wiki/alpha.md
|
||||
# Der Run mutiert jetzt (Mutations-Objekt alpha, Erhaltungs-Invariante erlaubt alpha + log.md):
|
||||
cat > wiki/alpha.md <<'EOF'
|
||||
@@ -465,7 +518,10 @@ F_UNTRACK_MD5=$(sha256sum wiki/inoffiziell.md | cut -d' ' -f1)
|
||||
git status --porcelain -- wiki/inoffiziell.md | grep -qE '^\?\? ' || fail "L-4: ungetrackte Fremd-Datei nicht als '??' sichtbar"
|
||||
# PROTECT (ungetrackt): Sicherung in die Scratch-Zone, dann ist der Mutationsbereich sauber.
|
||||
mkdir -p scratch/l4
|
||||
cp wiki/inoffiziell.md "scratch/l4/inoffiziell.md.stash"
|
||||
cp wiki/inoffiziell.md "scratch/l4/inoffiziell.md.stash" || fail "L-4: Backup fehlgeschlagen — Fremd-Datei NICHT verorfen (AD-17e, Loop-2-P3)"
|
||||
# Loop-2-P3: Backup VOR `git clean` verifiziert — ein still fehlgeschlagener `cp` wuerde
|
||||
# die fremde ungetrackte Datei still loeschen (AD-17e-Verletzung).
|
||||
[ "$(sha256sum "scratch/l4/inoffiziell.md.stash" | cut -d' ' -f1)" = "$F_UNTRACK_MD5" ] || fail "L-4: Backup nicht byte-identisch vor Clean (Loop-2-P3, AD-17e)"
|
||||
git clean -qfd wiki/inoffiziell.md
|
||||
# Der Run mutiert alpha (Kill-Punkt vor Mutation/Nach-Mutation, konsistenter Zwischenstand):
|
||||
cat > wiki/alpha.md <<'EOF'
|
||||
@@ -560,14 +616,22 @@ assert_frontmatter wiki/alpha.md
|
||||
printf '\n### 2026-08-21 — Story-3.12-L6: committeter Mutations-Nachweis (Baseline %s)\n' "$BASE" >> wiki/log.md
|
||||
git add wiki/alpha.md wiki/log.md
|
||||
git commit -qm "L6: committeter Run (Mutation + log.md-Nachweis)"
|
||||
# Loop-2-P2: Matrix-Zelle ROLLBACK_NACH_COMMIT_VOR_RELEASE "Fehler nach Commit, vor Release"
|
||||
# benannt und belegt: nach Commit ist der Zustand entweder == Baseline (nicht hier) ODER
|
||||
# VALID COMMITTET — ein Rollback NACH Commit ist per AD-17f nicht vorgesehen (Commit ist
|
||||
# unveraenderlich; die Matrix-"oder"-Semantik gilt). Der Fehler-Nachlauf loest sich in
|
||||
# genau diesem Endzustand auf. "Valide committet" wird hier HART verifiziert:
|
||||
[ "$(git rev-parse HEAD)" != "$BASE" ] || fail "L-6-P2: nach Commit HEAD == Baseline (Commit fehlgeschlagen — kein valide-committeter Zustand)"
|
||||
git show -q HEAD:wiki/alpha.md | grep -q '^type: concept$' \
|
||||
|| fail "L-6-P2: committeter Zustand nicht valide (Frontmatter im Commit verletzt)"
|
||||
git show --format=%s -s HEAD | grep -q "L6: committeter Run" || fail "L-6-P2: Commit-Betreff nicht valide"
|
||||
# Kill-Punkt VOR RELEASE: Commit ist erfolgt, aber der Lock ist noch NICHT freigegeben (kein
|
||||
# haengender Lock — der Lock wird noch vom Run gehalten, kein Teilzustand veroeffentlicht).
|
||||
git status --porcelain -- wiki/ | grep -q '^??' && fail "L-6: ungetrackte Reste nach Commit (Clean-Input-Guard-Vorfeld)"
|
||||
[ "$(scopelock_content)" = "RUN-L6" ] || fail "L-6: Lock vor Release nicht gehalten (Kill-Punkt vor Release)"
|
||||
# Fehler-Nachlauf vor Release wird sauber aufgeloest: entweder Rollback auf Baseline (valide)
|
||||
# oder der committete Zustand wird beibehalten und der Lock freigegeben (Zustand == Baseline
|
||||
# oder valide committet, nie ein Teilzustand — AD-17f). Hier: committeter Zustand ist valide,
|
||||
# der Run gibt durativ frei.
|
||||
# Fehler-Nachlauf vor Release wird sauber aufgeloest: Zustand == Baseline ODER valide
|
||||
# committet (hier: valide committet, P2-verified) — der Run gibt durativ frei; ein
|
||||
# Teilzustand wird nie veroeffentlicht (AD-17f).
|
||||
scopelock_release "RUN-L6"
|
||||
[ -z "$(scopelock_content)" ] || fail "L-6: Lock nach Release nicht leer (AC-5)"
|
||||
# Clean-Input-Guard-Vorfeld: sauberer Worktree nach Commit+Release.
|
||||
@@ -602,6 +666,14 @@ assert_frontmatter wiki/alpha.md
|
||||
printf '\n### 2026-08-21 — Story-3.12-L7: durativer Run, Freigabe per Ref-Delete (Baseline %s)\n' "$BASE" >> wiki/log.md
|
||||
git add wiki/alpha.md wiki/log.md
|
||||
git commit -qm "L7: durativer Run (Mutation + Log-Nachweis)"
|
||||
# Loop-2-P2: RELEASE-Fehler negativ geuebt (Matrix RELEASE_DURABLE "Release-Fehler =
|
||||
# HARD-FAIL; Lock nie haengend"): ein Release mit FALSCHER Inhaber-Run-ID muss hart
|
||||
# FEHLSCHLAGEN (Ownership-Pruefung) und den Lock UNVERAENDERT lassen — in einem Subshell,
|
||||
# damit die erwartete HARD-FAIL-Beendigung das Skript selbst nicht toetet.
|
||||
if ( scopelock_release "RUN-L7-fremd" ) 2>/dev/null; then
|
||||
fail "L-7-P2: Release OHNE Ownership gelang (HARD-FAIL-Pfad nicht wirksam, AC-5)"
|
||||
fi
|
||||
[ "$(scopelock_content)" = "RUN-L7" ] || fail "L-7-P2: fehlgeschlagenes Release hat den Lock veraendert (Lock haengt/verfalscht, AC-5)"
|
||||
# Release per Ref-Delete (nur durch Inhaber, Ownership-Pruefung):
|
||||
scopelock_release "RUN-L7"
|
||||
# Lock ist entfernt (ref-delete):
|
||||
@@ -639,14 +711,25 @@ printf '\n### 2026-08-21 — Freigabe: wiki Root-Scope durch RUN-L8 (Ref-Delete,
|
||||
mkdir -p registry
|
||||
echo "gen: 1" > registry/wiki
|
||||
echo "hold: run-l8 (Gen 1)" >> registry/wiki
|
||||
# KERN (AC-6): log.md traegt KEINE Build-/Review-/Story-/Sandbox-Historie — weder als
|
||||
# Kategorie-benennende Eintraege (z. B. 'Build-Historie', 'Sandbox-Protokoll', 'Story-Log')
|
||||
# noch als Sandbox-Artefakt-/Pfad-Referenz (_bmad-output, run-sandbox, sandbox-3-12);
|
||||
# legitime Fach-/Koordinationswoerter im Fliesstext (z. B. einzelnes 'Build'/'Review' ohne
|
||||
# Kategorie-Hyphenat; Story-Nummern wie 'Story-3.12-L6' ohne '-Historie') werden NICHT
|
||||
# getroffen (PATCH 4d — Edge-Case-Hunter).
|
||||
grep -qiE '(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht|Nachweis)|_bmad-output|run-sandbox|sandbox-3-12' wiki/log.md \
|
||||
&& fail "L-8: log.md traegt Build-/Review-/Story-/Sandbox-Historie (AC-6 verletzt; PATCH 4d)"
|
||||
# KERN (AC-6): log.md traegt KEINE Build-/Review-/Story-/Sandbox-Historie als
|
||||
# KATEGORIE-benennende Eintraege (z. B. 'Build-Historie', 'Sandbox-Protokoll',
|
||||
# 'Story-Log', 'Review-Bericht'). Legitime Fach-/Koordinationswoerter im Fliesstext —
|
||||
# inkl. der von der eigenen Code-Map und der 3.10/3.11-Praxis getragenen Nachweis-
|
||||
# Formen (Sandbox-/Review-/Validator-Nachweis-Kennzeichnungen, Artefakt-Pfadszitate,
|
||||
# 'bmad-code-review', Story-Nummern ohne Kategorie-Endung) — werden NICHT getroffen:
|
||||
# sie sind notwendige Koordinationsereignisse im Sinne von Vertrag §5, keine verbotene
|
||||
# Historie (PATCH 4d, Loop-2-D1: Regel an die dokumentierte log.md-Praxis angegleichen
|
||||
# — die Code-Map VORGIBT diese Zitate im Story-Log-Eintrag; ein Guard, der sie traf,
|
||||
# wuerde die eigene Vorgabe verletzen).
|
||||
grep -qiE '(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht)' wiki/log.md \
|
||||
&& fail "L-8: log.md traegt Build-/Review-/Story-/Sandbox-Historie (AC-6 verletzt; PATCH 4d, Loop-2-D1)"
|
||||
# Loop-2-D1 NEGATIV-KONTROLLE: die verbotene Form (Kategorie-Hyphenat) muss den Guard
|
||||
# AUSLOESEN — auf einer Probe-Datei ausserhalb wiki/, damit das konforme log.md nicht
|
||||
# beruehrt wird und bewiesen ist, dass die Regel zündet:
|
||||
printf '### 2026-08-21 — Sandbox-Protokoll: Build-Historie und Story-Log (Review-Bericht)\n' > /tmp/l8-probe-$$
|
||||
grep -qiE '(Build|Review|Story|Sandbox)-(Histor|Log|Protokoll|Bericht)' /tmp/l8-probe-$$ \
|
||||
|| fail "L-8-D1: Negativ-Kontrolle — Guard hat verbotene Kategorie-Form NICHT erkannt (Regel wirkungslos)"
|
||||
rm -f /tmp/l8-probe-$$
|
||||
# Positiv-Kontrolle (PATCH 4d): die beiden vertragskonformen Koordinations-Eintraege sind
|
||||
# vorhanden und loesen den Kategorie-Check NICHT aus — kein false-HARD-FAIL auf legitime
|
||||
# Koordinations-Eintraege im Fliesstext.
|
||||
@@ -693,12 +776,20 @@ git add wiki/alpha.md
|
||||
# Erlaubte Pfad-Menge nach Mutation: alpha (Kill-Punkt-Zwischenstand). Staging nur alpha.
|
||||
staged=$(git diff --cached --name-only | sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u)
|
||||
[ "$staged" = "alpha" ] || fail "L-9/KP2: nach Mutation sind nur erlaubte Pfade staged, tatsaechlich '$staged'"
|
||||
echo " KP2 (nach Mutation): valider Zwischenstand (nur alpha staged), kein Ghost — PASS"
|
||||
# Loop-2-P4: Ghost-Diff-Probe (Matrix KILLPUNKT_NACH_MUTATION "kein Ghost-Diff ausserhalb
|
||||
# erlaubter Menge"): Index UND Worktree ueber die §5.9-P5-Helfer gegen die erlaubte Menge —
|
||||
# unstagede Ghost-Dateien wuerden hier hart fehlschlagen.
|
||||
assert_invariant "alpha"
|
||||
echo " KP2 (nach Mutation): valider Zwischenstand (nur alpha staged), kein Ghost-Diff ausserhalb erlaubter Menge — PASS"
|
||||
# KILLPUNKT 3 — VOR COMMIT: nur erlaubte Pfad-Menge staged, kein Teilzustand committet.
|
||||
[ "$(git rev-parse HEAD)" = "$BASE" ] || fail "L-9/KP3: vor Commit Head bewegt (Teilzustand committet, AD-17f)"
|
||||
printf '\n### 2026-08-21 — Story-3.12-L9: Kill-Punkt-Test (Baseline %s)\n' "$BASE" >> wiki/log.md
|
||||
git add wiki/log.md
|
||||
echo " KP3 (vor Commit): nur alpha + log staged, kein Commit, HEAD == Baseline — PASS"
|
||||
[ "$(git diff --cached --name-only | sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u | paste -sd' ' -)" = "alpha log" ] \
|
||||
|| fail "L-9/KP3: vor Commit sind nicht exakt alpha+log staged (Teilzustand, AD-17f)"
|
||||
# Loop-2-P4: Ghost-Diff-Probe an KP3 (nur erlaubte Pfad-Menge staged, Worktree frei von Ghosts):
|
||||
assert_invariant "alpha log"
|
||||
echo " KP3 (vor Commit): nur alpha + log staged, kein Commit, HEAD == Baseline, kein Ghost — PASS"
|
||||
# KILLPUNKT 4 — NACH COMMIT: Bundle == valide committeter Zustand, anschliessbar an den
|
||||
# Clean-Input-Guard (kein haengender Lock, sauberer Worktree).
|
||||
git commit -qm "L9: Kill-Punkt-nach-Commit (Mutation + log.md)"
|
||||
|
||||
Reference in New Issue
Block a user