feat: Story 3.7 Reason/Mutate-Trennung & Konsistenz-Endzustand sicherstellen (bmad-code-review, 3 Layer; kein Loopback) — §5.13-Phasen-Sektion (AD-6/A0-7, Änderungsplanung als institutionalisierter §5.9-Pkt.-6-P2-Block, Plan-Freeze an §5.9-Pkt.-5-Ghost-Diff-Kopplung, Zustands-Restaurations-Invariante, kein Teilerfolg AD-17f, VALIDATION_FAIL/SUCCESS, KEINE_EIGENE_ENGINE; §7-Bullet aufgelöst, §8-Normreferenz AD-6 auf §5.13-Anker, Revision 3.2 + Abschlussklausel); Sandbox CONSIST-1..CONSIST-7 (Exit 0, 14 PASS, Restaurations-Invariante, EC-1-Defizit-Negativkontrolle, pgrep-Robustheit, non-vakuum Determinismus-Zeuge); Review-Loop-1-Fixes (SRO-Anker 343/356/358/362/420/461, fünf→vier AD-6-Phasen, CONSIST-6-Validierung-vor-Commit); Suggested Review Order + Status done; log.md; sprint-status review; AD-3 unverändert
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,576 @@
|
||||
#!/usr/bin/env bash
|
||||
# Story 3.7 — Sandbox-Tests der Reason/Mutate-Phasen-Trennung & Konsistenz-Endzustand (§5.13, Revision 3.2)
|
||||
# Re-executierbar: bash run-sandbox.sh (ab Workspace-Root; Sandbox unter /tmp/sb37)
|
||||
# Zweck: die Reason/Mutate-Phasen-Disziplin (§5.13) als re-executierbarer Run-Demonstrator
|
||||
# durchspielen —
|
||||
# CONSIST-1 KONSISTENTE_AENDERUNGSPLANUNG (AC-1, AD-6, A0-7): der P2-Block (§5.9 Pkt. 6)
|
||||
# erzeugt aus committetem Input eine konsistente Änderungsplanung (Input-Zustand,
|
||||
# Ziel-Pfade, Quellen-Existenz, Betroffenheit, Struktur-Erhaltung) — als Variablen-Set
|
||||
# captured, Determinismus (AD-17h/A0-19); Plan-Defizit ⇒ Abbruch vor Mutationsphase
|
||||
# CONSIST-2 PLAN_FREEZE (AC-1, §5.13 Pkt. 2): Plan-Freeze = Veränderungs-Sperre — eine
|
||||
# Mutation ausserhalb der Plan-Pfadmengen (Kandidatenliste ∪ Neu-Anlage ∪ log.md ∪
|
||||
# index.md) wird erkannt und verweigert/verhindert (Ghost-Diff-Kopplung §5.9 Pkt. 5)
|
||||
# CONSIST-3 ZUSTANDS-RESTAURATIONS-INVARIANTE (AC-2, §5.13 Pkt. 3): fehlgeschlagene
|
||||
# Mutation rollt auf exakte Baseline zurueck (SHA-256 byte-identisch, Post-Rollback-Diff
|
||||
# leer gg. Baseline), Bundle-Zustand == Baseline; raw/ unverändert (AD-3)
|
||||
# CONSIST-4 MUTATION_ABBRUCH (AC-2, §5.13 Pkt. 3/4): Abbruch nach Teilerfolg (mehrere
|
||||
# geplante Mutationen, nur ein Teil ausgefuehrt) hinterlaesst keinen Teilerfolg als
|
||||
# fertige Mutation (Commit-Boundary = Mutations-Boundary, AD-17f); raw/ unberührt
|
||||
# CONSIST-5 VALIDATION_FAIL (AC-2, §5.13 Pkt. 5): §6-Pkt.-3-Rollback, keine weiteren
|
||||
# Mutationen, Endzustand konsistent (Zustands-Restaurations-Invariante)
|
||||
# CONSIST-6 VALIDATION_SUCCESS (AC-3, §5.13 Pkt. 6): Mutationen als Ganzes committet,
|
||||
# Diff gg. Plan-Menge gedeckt, §6-Pkt.-4-Nachweis; kein Wanduhr-Trigger (A0-20)
|
||||
# CONSIST-7 DETERMINISMUS-ZWEI-RUN + KEINE_ENGINE (AC-4, §5.13 Pkt. 7): Zwei identische
|
||||
# Runs -> identische Plan-/Rollback-/State-Outputs (AD-17h/A0-19); die Phasen-Trennung
|
||||
# ist logisch in einer Session — kein Prozess/Server/MCP wird gestartet (D-3, AD-11,
|
||||
# grep-Negativkontrolle: keine Hintergrundprozesse/Logger-Daemons)
|
||||
# Erhaltungs-Invariante (§5.9 Pkt. 5 / AD-5 / FT-6) als HARDE Assertion je lauffaehigem
|
||||
# Run; Frontmatter-Konformitaet (Vertrag §3.3/§3.4-Subset) je erzeugtem/aktualisiertem Concept.
|
||||
# Ubuntu-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale wiki/- oder raw/-Baum.
|
||||
set -u
|
||||
ROOT=$(mktemp -d /tmp/sb37-XXXXXX)
|
||||
SB="$ROOT/sb"
|
||||
mkdir -p "$SB/wiki" "$SB/raw"
|
||||
cd "$SB"
|
||||
git init -q
|
||||
# Determinismus vs. Host-Git-Konfiguration (AD-17h): die Sandbox erzeugt LF-Blobs und
|
||||
# LF-Worktree — autocrlf/filemode-Umwandlung des Hosts wuerde sha256-Vergleiche und
|
||||
# Diff-/Probe-Ergebnisse wort-wirksam verschieben. Repo-Reparatur schliesst das aus.
|
||||
git config core.autocrlf false
|
||||
git config core.filemode false
|
||||
git config user.email "sandbox@test"
|
||||
git config user.name "Sandbox"
|
||||
|
||||
# ---------- Basis-Baum (committete Ausgangslage = Baseline-Commit = Merge-Base) ----------
|
||||
# Mini-Bundle mit zwei Root-Concepts (alpha als Mutations-Objekt, gamma als Kontrolle).
|
||||
cat > wiki/index.md <<'EOF'
|
||||
# Index
|
||||
- [Alpha](alpha.md)
|
||||
- [Gamma](gamma.md)
|
||||
EOF
|
||||
cat > wiki/alpha.md <<'EOF'
|
||||
---
|
||||
type: concept
|
||||
sources:
|
||||
- resource: raw/alpha-v1.md
|
||||
id: s1
|
||||
generated:
|
||||
by: wow-compiler/0.1.0
|
||||
at: 2026-08-16T09:00:00Z
|
||||
---
|
||||
Das Alpha-Protokoll definiert eine deterministische Init-Sequenz (raw/alpha-v1.md#S-1).
|
||||
Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).
|
||||
EOF
|
||||
cat > wiki/gamma.md <<'EOF'
|
||||
---
|
||||
type: concept
|
||||
sources:
|
||||
- resource: raw/gamma-v1.md
|
||||
id: s1
|
||||
generated:
|
||||
by: wow-compiler/0.1.0
|
||||
at: 2026-08-16T09:00:00Z
|
||||
---
|
||||
Gamma beschreibt ein anderes, hier nicht betroffenes Thema.
|
||||
EOF
|
||||
cat > wiki/log.md <<'EOF'
|
||||
# Log
|
||||
EOF
|
||||
cat > raw/alpha-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz v1: deterministische Init-Sequenz.
|
||||
### S-2
|
||||
Evidenz v1: ausschließlich lokale Netze.
|
||||
EOF
|
||||
cat > raw/gamma-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz v1: Gamma-Thema.
|
||||
EOF
|
||||
git add -A
|
||||
git commit -qm "Baseline"
|
||||
BASE=$(git rev-parse HEAD)
|
||||
echo "BASELINE-COMMIT (Merge-Base, eindeutiger Commit-Object-Wert): $BASE"
|
||||
echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)"
|
||||
echo
|
||||
|
||||
# ---------- Helfer: Run-Label / Isolation (kein Carry-over zwischen Szenarien) ----------
|
||||
runlabel() { echo; echo "########## $1 ##########"; }
|
||||
isolate() {
|
||||
git checkout -qf -B "$1" "$BASE"
|
||||
git reset -q --hard "$BASE"
|
||||
git clean -qfd wiki raw lease registry scratch plan-run
|
||||
}
|
||||
|
||||
# Erhaltungs-Invariante-Probe (§5.9 Pkt. 5 / AD-5 / FT-6): Baseline-Diff + porcelain,
|
||||
# normalisiert (wiki/-Praefix + .md-Suffix gestrippt, LC_ALL=C-sortiert).
|
||||
probe() {
|
||||
{ git diff --name-only "$BASE" -- wiki/ ; git status --porcelain -- wiki/ | awk '{print $2}'; } \
|
||||
| sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u
|
||||
}
|
||||
inv_set() { probe | LC_ALL=C sort -u | paste -sd' ' -; }
|
||||
|
||||
# ---------- Harte Assertion der Erhaltungs-Invariante (§5.9 Pkt. 5) ----------
|
||||
inv_viol() { # $1=expected ; 0 = konsistent, !=0 = Verstoß (msg stderr)
|
||||
local expected="$1" p u bad=0
|
||||
got=$(inv_set)
|
||||
for p in $got; do
|
||||
case " $expected " in
|
||||
*" $p "*) ;;
|
||||
*) echo "HARD-FAIL (Erhaltungs-Invariante §5.9 Pkt. 5): '$p' ist kein Ghost-Diff-negativer Eintrag — erlaubte Menge: {$expected}" >&2; bad=1;;
|
||||
esac
|
||||
done
|
||||
for u in $(git status --porcelain -- wiki/ | grep '^??' | awk '{print $2}'); do
|
||||
u=$(echo "$u" | sed -e 's|^wiki/||' -e 's|\.md$||')
|
||||
case " $expected " in
|
||||
*" $u "*) ;;
|
||||
*) echo "HARD-FAIL (Duplikat/Ghost-Diff): ungetrackte neue Datei '$u' liegt ausserhalb der erlaubten Ziel-Pfade {$expected} (§5.9 Pkt. 5)" >&2; bad=1;;
|
||||
esac
|
||||
done
|
||||
return $bad
|
||||
}
|
||||
assert_invariant() { # positive Erwartung: Verstoß => HARD-FAIL + Exit 1
|
||||
if inv_viol "$1"; then
|
||||
echo "RESULT: PASS — Probe erfüllt; keine neue Datei; kein Ghost-Diff"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- Zustands-Restaurations-Invariante (§5.13 Pkt. 3) — harte Assertion ----------
|
||||
# Nach Abbruch/FAIL muss der Post-Rollback-Diff gg. die Baseline LEER sein (Bundle ==
|
||||
# Baseline, SHA-256 byte-identisch je Pfad) — die git-ueberpruefbare Konsistenz-Eigenschaft.
|
||||
assert_restored() { # $1=komma-oder-leer-getrennte wiki-Pfade, die byte-identisch zur Baseline sein müssen
|
||||
local p expected=""
|
||||
[ -z "$1" ] || for p in $1; do expected="$expected $p.md"; done
|
||||
# 1) git-Diff gg. Baseline: keine modifizierte/geloeschte Datei
|
||||
if [ -n "$(git diff --name-only "$BASE" -- wiki/)" ]; then
|
||||
echo "HARD-FAIL (Zustands-Restaurations-Invariante §5.13 Pkt. 3): Post-Rollback-Diff gg. Baseline NICHT leer:" >&2
|
||||
git diff --name-only "$BASE" -- wiki/ | sed 's/^/ /' >&2
|
||||
exit 1
|
||||
fi
|
||||
# 2) porcelan: keine ungetrackten/gestagten Eintraege im wiki/-Scope
|
||||
if [ -n "$(git status --porcelain -- wiki/)" ]; then
|
||||
echo "HARD-FAIL (Zustands-Restaurations-Invariante §5.13 Pkt. 3): ungetrackte/gestagte Reste im wiki/-Scope:" >&2
|
||||
git status --porcelain -- wiki/ | sed 's/^/ /' >&2
|
||||
exit 1
|
||||
fi
|
||||
# 3) byte-identisch zur Baseline (SHA-256); Neu-Anlage-Randfall (Pfad nur im Run angelegt):
|
||||
# existiert der Pfad NICHT im Baseline-Commit, darf er nach dem Rollback auch nicht in der
|
||||
# Working-Copy existieren (statt eines spurious byte-Vergleichs).
|
||||
for p in $expected; do
|
||||
if git cat-file -e "$BASE:wiki/$p" 2>/dev/null; then
|
||||
[ -f "wiki/$p" ] || { echo "HARD-FAIL (Zustands-Restaurations-Invariante §5.13 Pkt. 3): wiki/$p fehlt (muss == Baseline sein)" >&2; exit 1; }
|
||||
bsha=$(git show "$BASE:wiki/$p" | sha256sum | cut -d' ' -f1)
|
||||
csha=$(sha256sum "wiki/$p" | cut -d' ' -f1)
|
||||
[ "$bsha" = "$csha" ] || { echo "HARD-FAIL (Zustands-Restaurations-Invariante §5.13 Pkt. 3): wiki/$p weicht von Baseline ab ($csha != $bsha)" >&2; exit 1; }
|
||||
else
|
||||
# Neu-Anlage-Pfad (nicht im Baseline-Commit): nach Rollback darf er NICHT existieren.
|
||||
[ ! -e "wiki/$p" ] || { echo "HARD-FAIL (Zustands-Restaurations-Invariante §5.13 Pkt. 3): wiki/$p ist Neu-Anlage-Pfad und muss nach Rollback NICHT existieren" >&2; exit 1; }
|
||||
fi
|
||||
done
|
||||
echo "RESULT: PASS — Zustands-Restaurations-Invariante: Post-Rollback-Diff gg. Baseline leer, Bundle == Baseline (SHA-256 byte-identisch)"
|
||||
}
|
||||
|
||||
# ---------- Frontmatter-Konformitaet (Vertrag §3.3/§3.4, §6.5; Muster Sandbox-3-6) ----------
|
||||
assert_frontmatter() {
|
||||
local f="$1"; shift
|
||||
local v
|
||||
v=$(awk '
|
||||
/^---$/{n++; if(n==2) exit; next}
|
||||
/^[A-Za-z_][A-Za-z0-9_-]*:/{
|
||||
k=$0; sub(/:.*/,"",k)
|
||||
if (k=="sources") top="sources"
|
||||
else if (k=="generated" || k=="verified") top="genver"
|
||||
else top="other"
|
||||
if (k!="type" && k!="sources" && k!="generated" && k!="verified" && k!="status" && k!="stale_after") print "TOP_UNBEFUGT:" k
|
||||
if (seenk[k]++) print "DUP_KEY:" k
|
||||
r=0
|
||||
if (k=="type") r=1; else if (k=="sources") r=2; else if (k=="generated") r=3
|
||||
else if (k=="verified") r=4; else if (k=="status") r=5; else if (k=="stale_after") r=6
|
||||
if (r>0 && r<lastr) print "ORDER_VIOLATION:" k
|
||||
if (r>0) lastr=r
|
||||
next
|
||||
}
|
||||
/^[[:space:]]/{
|
||||
gsub(/^[[:space:]]+/,""); sub(/^- /,""); gsub(/^[[:space:]]+/,"");
|
||||
if (match($0, /^[A-Za-z_][A-Za-z0-9_-]*:/)) {
|
||||
ik=substr($0,1,RLENGTH-1)
|
||||
if (top=="sources" && ik!="resource" && ik!="id" && ik!="title" && ik!="author" && ik!="usage_count" && ik!="last_modified") print "INNER_UNBEFUGT:" ik
|
||||
if (top=="genver" && ik!="by" && ik!="at") print "INNER_UNBEFUGT:" ik
|
||||
if (top=="other") print "INNER_UNBEFUGT:" ik
|
||||
}
|
||||
}
|
||||
' "$f")
|
||||
if [ -n "$v" ]; then
|
||||
echo "HARD-FAIL (Frontmatter-Subset, Vertrag §3.3/§3.4/§3.5): $v in $f" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -qE '^type: concept$' "$f" || { echo "HARD-FAIL: type=concept fehlt in $f" >&2; exit 1; }
|
||||
grep -qE "^ at: [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|[+-][0-9]{2}:?[0-9]{2})$" "$f" || { echo "HARD-FAIL: generated.at ist keine volle ISO-8601-Datetime in $f" >&2; exit 1; }
|
||||
for r in "$@"; do
|
||||
grep -qF " - resource: $r" "$f" || { echo "HARD-FAIL: sources-Eintrag 'resource: $r' fehlt in $f" >&2; exit 1; }
|
||||
done
|
||||
echo "RESULT: PASS — Frontmatter-Konformitaet $f (Subset ok, generated.at volles Datetime)"
|
||||
}
|
||||
|
||||
# ---------- log.md-Eintraege (§5.13; Header-Bullet-Paar je Eintrag, datumsgruppiert) ----------
|
||||
# Datumsgruppen-/Reihenfolge-Konvention (Vertrag §5, neueste zuerst): ein neuer Bullet wird
|
||||
# in die BESTEHENDE Datumsgruppe eingefuegt — nach deren Header, vor etwaigen Gruppen-Bullets —
|
||||
# sonst wird ein neuer Header oben erzeugt. Deterministisch (kein Wanduhr).
|
||||
log_bullet() { # $1 = Bullet-Text (eine Zeile, printf-% escaped); Datumsgruppe/Reihenfolge (neueste zuerst)
|
||||
local day="2026-08-20" # getrennt gesetzt — set -u: gleiche-local-Zeilen-RHS darf day nicht vor Setzung referenzieren
|
||||
local header="## $day" line="$1"
|
||||
if grep -qxF "$header" wiki/log.md; then
|
||||
tmp=$(mktemp)
|
||||
awk -v h="$header" -v l="$line" '
|
||||
BEGIN{p=0}
|
||||
{ if (!p && $0==h) { print; print l; p=1; next } print }
|
||||
' wiki/log.md > "$tmp" && mv "$tmp" wiki/log.md
|
||||
else
|
||||
tmp=$(mktemp)
|
||||
{ printf '%s\n' "$header"; printf '%s\n' "$line"; cat wiki/log.md; } > "$tmp" && mv "$tmp" wiki/log.md
|
||||
fi
|
||||
}
|
||||
log_plan() { # $1=plan-text (eine Zeile)
|
||||
log_bullet "- Änderungsplanung (P2-Block, §5.9 Pkt. 6 / §5.13 Pkt. 1): $1 (Determinismus AD-17h/A0-19; Baseline $BASE)"
|
||||
}
|
||||
log_abort() { # $1=benannte Abbruch-Ursache — NFR-4-texuelle Benennung (echo). Für einen
|
||||
# FAILED-Run wird log.md NICHT persistent beschrieben: §6 Pkt. 3 / §5.3 rollen auch die
|
||||
# log.md-Einträge als Teilzustand zurück (Bundle nimmt Zustand vor dem Run wieder ein).
|
||||
echo "NFR-4-Benennung (textuell): Mutations-Abbruch (§5.13 Pkt. 3/4) — $1; Zustands-Restaurations-Invariante (Pkt. 3), kein Teilerfolg committet (AD-17f); log.md-Einträge des Runs werden mit dem Teilzustand zurückgerollt (§6 Pkt. 3 / §5.3)"
|
||||
}
|
||||
log_commit() { # $1=plan-vs-ist-diff-befund
|
||||
log_bullet "- Validierung SUCCESS (§5.13 Pkt. 6): Mutationen als Ganzes committet; $1 (§6-Pkt.-4-Nachweis, kein Wanduhr-Trigger A0-20)"
|
||||
}
|
||||
|
||||
# ---------- Reason/Mutate-Helfer (§5.13) ----------
|
||||
# P2-Block (§5.9 Pkt. 6) als Änderungsplanung: capturet den konsistenten Plan als textuelles
|
||||
# Variablen-Set (Input-Zustand, Ziel-Pfade, Quellen-Existenz, Betroffenheit, Struktur-
|
||||
# Erhaltung) — deterministisch aus dem committeten Git-State (AD-17h/A0-19).
|
||||
p2_plan() { # $1=komma-Liste Ziel-Pfade (OKF-ohne-.md) $2=komma-Liste raw-Quellen (Pfad)
|
||||
local targets="$1" srcs="$2" p s err=0
|
||||
# (1) Input-Zustand (AD-17a): Working-Copy von raw/ und wiki/ gegen HEAD — uncommittet = Abbruch
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "HARD-FAIL (Änderungsplanung, P2-Block-Element (1): Input-Zustand AD-17a): uncommittete Zwischenstaende als Input — Abbruch vor der Mutation (published/committed Input erforderlich)" >&2
|
||||
return 1
|
||||
fi
|
||||
# (2) Ziel-Pfade (Kandidatenliste, §3 Pkt. 2)
|
||||
[ -n "$targets" ] || { echo "HARD-FAIL (Änderungsplanung): leere Ziel-Pfad-Menge (P2-Element (2))" >&2; return 1; }
|
||||
# (3) Quellen-Existenz (EC-1)
|
||||
for s in ${srcs//,/ }; do
|
||||
[ -f "raw/$s" ] || { echo "HARD-FAIL (Änderungsplanung, P2-Element (3): Quellen-Existenz EC-1): raw/$s existiert nicht" >&2; return 1; }
|
||||
done
|
||||
# (4) Betroffenheit (§3 Pkt. 2, textuell-deterministisch nach §3.2)
|
||||
for p in ${targets//,/ }; do
|
||||
[ -f "wiki/$p.md" ] || [ "$p" = "neu" ] || { echo "HARD-FAIL (Änderungsplanung, P2-Element (4)): Betroffenheits-Kandidat wiki/$p.md fehlt (und kein Neu-Anlage-Marker)" >&2; return 1; }
|
||||
done
|
||||
# (5) wiki/index.md-V-1 (Vertrag §2)
|
||||
[ -f "wiki/index.md" ] || { echo "HARD-FAIL (Änderungsplanung, P2-Element (5)): fehlende Bundleroot — Run-FAIL (V-1)" >&2; return 1; }
|
||||
# (6) Struktur-Erhaltungs-Check (Vertrag §3.3/§3.4-Subset) je betroffenem Concept
|
||||
for p in ${targets//,/ }; do
|
||||
if [ -f "wiki/$p.md" ]; then
|
||||
v=$(awk '
|
||||
/^---$/{n++; if(n==2) exit; next}
|
||||
/^[A-Za-z_][A-Za-z0-9_-]*:/{ k=$0; sub(/:.*/,"",k)
|
||||
if (k!="type" && k!="sources" && k!="generated" && k!="verified" && k!="status" && k!="stale_after") { print k; exit } }' "wiki/$p.md")
|
||||
[ -z "$v" ] || { echo "HARD-FAIL (Änderungsplanung, P2-Element (6): Struktur-Erhaltung): unbefugter Key '$v' in wiki/$p.md" >&2; return 1; }
|
||||
fi
|
||||
done
|
||||
echo "PLAN_OK targets=($targets) sources=($srcs)"
|
||||
return 0
|
||||
}
|
||||
# Plan-Freeze (Veränderungs-Sperre, §5.13 Pkt. 2): nach Abschluss der Planung darf kein
|
||||
# Plan-Gegenstand ausserhalb der erlaubten Menge mutiert werden — eine Ziel-Pfad-Verletzung
|
||||
# wird erkannt und verweigert (Ghost-Diff-Kopplung §5.9 Pkt. 5).
|
||||
freeze_check() { # $1=komma-Liste der im Run geplanten Ziel-Pfade (ok + neu.log + index)
|
||||
local allowed=" $1 "
|
||||
local m
|
||||
# Normalisierung (wie §5.9 Pkt. 5-Probe): wiki/-Praefix + .md-Suffix strippen (beide Stromarten).
|
||||
for m in $( { git diff --name-only "$BASE" -- wiki/ ; git status --porcelain -- wiki/ | awk '{print $2}'; } | sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u); do
|
||||
case "$allowed" in
|
||||
*" $m "*) ;;
|
||||
*) echo "HARD-FAIL (Plan-Freeze §5.13 Pkt. 2 / Ghost-Diff §5.9 Pkt. 5): Mutation ausserhalb der erlaubten Pfad-Menge — '$m' ist nicht im Plan ($allowed)" >&2; return 1;;
|
||||
esac
|
||||
done
|
||||
return 0
|
||||
}
|
||||
# Rollback der Mutationsphase (Zustands-Restaurations-Invariante, §5.13 Pkt. 3): stellt die
|
||||
# Baseline wieder her — §5.3-Pkt.-3/§6-Pkt.-3-Mechanik + Ghost-Diff-Rollback §5.9 Pkt. 5.
|
||||
rollback() {
|
||||
git checkout -q "$BASE" -- wiki/ 2>/dev/null || true
|
||||
untracked_rest=$(git status --porcelain -- wiki/ | grep '^??' | awk '{print $2}')
|
||||
if [ -n "$untracked_rest" ]; then
|
||||
echo "ROLLBACK: ungetrackte Reste im wiki/-Scope bei Rollback entdeckt:" >&2
|
||||
echo "$untracked_rest" | sed 's/^/ /' >&2
|
||||
# Ghost-Diff-Rollback §5.9 Pkt. 5: ungetrackte neue Dateien ausserhalb der Ziel-Pfade loeschen
|
||||
for u in $untracked_rest; do
|
||||
echo "ROLLBACK (Ghost-Diff-Rollback §5.9 Pkt. 5): entferne ungetrackte neue Datei '$u' ausserhalb erlaubter Menge"
|
||||
rm -f "$u"
|
||||
done
|
||||
fi
|
||||
git reset -q --hard "$BASE"
|
||||
git clean -qfd wiki
|
||||
}
|
||||
|
||||
# ---- CONSIST-1: KONSISTENTE_AENDERUNGSPLANUNG (AC-1, AD-6, A0-7; §5.13 Pkt. 1) ----
|
||||
runlabel "CONSIST-1: KONSISTENTE_AENDERUNGSPLANUNG (AC-1, AD-6, A0-7) — der P2-Block (§5.9 Pkt. 6) erzeugt aus committetem Input eine konsistente Änderungsplanung (Input-Zustand, Ziel-Pfade, Quellen-Existenz, Betroffenheit, Struktur-Erhaltung); textuelle Capture als Plan; Plan-Defizit (uncommitteter Input) ⇒ Abbruch VOR der Mutationsphase"
|
||||
isolate consist1
|
||||
echo "--- Neue committete Evidenz als Input (AD-17a): raw/alpha-v2.md ---"
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung (Story 3.7-Plan).
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
echo "--- Änderungsplanung (P2-Block als Phase): p2_plan alpha raw/alpha-v2.md ---"
|
||||
PLAN1=$(p2_plan "alpha" "alpha-v2.md") || exit 1
|
||||
echo "$PLAN1"
|
||||
echo "--- Determinismus der Planung (AD-17h/A0-19): zweite Planung desselben committeten States (VOR jedem Run-Mutationsschritt) ---"
|
||||
PLAN2=$(p2_plan "alpha" "alpha-v2.md") || exit 1
|
||||
[ "$PLAN1" = "$PLAN2" ] || { echo "HARD-FAIL (CONSIST-1): Plan ungleich bei gleichem Git-State (AD-17h/A0-19)" >&2; exit 1; }
|
||||
echo "PLAN2 identisch: $PLAN2"
|
||||
echo "--- Plan textuell festgehalten (log.md-Teil der Planung, kein Artefakt-File) ---"
|
||||
log_plan "alpha betroffen via raw/alpha-v2.md (Ziel-Pfade {alpha}, Quellen-Existenz EC-1 ok, Struktur-Erhaltung ok)"
|
||||
grep -qF 'Änderungsplanung (P2-Block' wiki/log.md || { echo "HARD-FAIL (CONSIST-1): Plan-Nachweis fehlt in log.md (§5.13 Pkt. 1)" >&2; exit 1; }
|
||||
echo "--- Plan-Defizit-Kette (I/O-Matrix PLAN_BEABSICHTIGT): uncommitteter Input ⇒ Abbruch VOR der Mutation ---"
|
||||
echo "uncommitteter Rest im raw/" > raw/scratch-deficit.txt
|
||||
if p2_plan "alpha" "alpha-v2.md" >/dev/null 2>&1; then
|
||||
echo "HARD-FAIL (CONSIST-1): uncommitteter Input wurde nicht als Plan-Defizit abgefangen (P2-Element (1), AD-17a)" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "BEFUND: Plan-Defizit textuell benannt (NFR-4) — Abbruch vor der Mutationsphase, keine Mutation"
|
||||
fi
|
||||
rm -f raw/scratch-deficit.txt
|
||||
echo "--- Plan-Defizit-Kette (I/O-Matrix PLAN_BEABSICHTIGT): fehlende Quellen-Existenz (P2-Element (3), EC-1) ⇒ Abbruch VOR der Mutation ---"
|
||||
rm -f raw/alpha-v2.md
|
||||
if p2_plan "alpha" "alpha-v2.md" >/dev/null 2>&1; then
|
||||
echo "HARD-FAIL (CONSIST-1): fehlende Quelle wurde nicht als Plan-Defizit abgefangen (P2-Element (3), EC-1)" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "BEFUND: Plan-Defizit (EC-1: raw/alpha-v2.md fehlt) textuell benannt (NFR-4) — Abbruch vor der Mutationsphase, keine Mutation"
|
||||
fi
|
||||
echo "--- Probe (Erhaltungs-Invariante §5.9 Pkt. 5): nur log.md ---"; probe
|
||||
assert_invariant "log"
|
||||
echo "RESULT: PASS — CONSIST-1: konsistente Änderungsplanung aus committetem Input (P2-Block, §5.9 Pkt. 6 / §5.13 Pkt. 1); textuelle Capture; Determinismus (AD-17h/A0-19); Plan-Defizit ⇒ Abbruch vor der Mutation (PLAN_BEABSICHTIGT; P2-Element (1) AD-17a + P2-Element (3) EC-1); Erhaltungs-Invariante"
|
||||
|
||||
# ---- CONSIST-2: PLAN_FREEZE (AC-1; §5.13 Pkt. 2) ----
|
||||
runlabel "CONSIST-2: PLAN_FREEZE (§5.13 Pkt. 2) — Plan-Freeze = Veränderungs-Sperre: eine Mutation ausserhalb der Plan-Pfadmengen (Kandidatenliste ∪ Neu-Anlage ∪ log.md ∪ index.md) wird erkannt und verhindert (Ghost-Diff-Kopplung §5.9 Pkt. 5)"
|
||||
isolate consist2
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
p2_plan "alpha" "alpha-v2.md" >/dev/null || exit 1
|
||||
log_plan "alpha betroffen via raw/alpha-v2.md (Plan-Freeze aktiv)"
|
||||
echo "--- Mutationsphase: geplante Mutation von alpha — erlaubt (Plan-Ziel-Pfad) ---"
|
||||
cat >> wiki/alpha.md <<'EOF'
|
||||
Alpha wird um eine synchrone Kopplung erweitert (raw/alpha-v2.md#S-3).
|
||||
EOF
|
||||
grep -q "synchrone Kopplung" wiki/alpha.md || { echo "HARD-FAIL (CONSIST-2): geplante Mutation fehlgeschlagen" >&2; exit 1; }
|
||||
echo "--- Freeze-Verletzung simulieren: Ghost-Mutation auf NICHT geplanten Pfad gamma (Plan-Gegenstand ausserhalb der erlaubten Menge) ---"
|
||||
echo "unbefugte gamma-Aenderung" >> wiki/gamma.md
|
||||
if freeze_check "alpha log index"; then
|
||||
echo "HARD-FAIL (CONSIST-2): Mutation ausserhalb der Plan-Pfadmengen wurde nicht erkannt (Plan-Freeze, §5.13 Pkt. 2)" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "BEFUND: Freeze-Verletzung erkannt (ghost gamma) — Veränderungs-Sperre greift"
|
||||
fi
|
||||
echo "--- Ghost-Diff-Rollback (§5.9 Pkt. 5): gamma aus Baseline-Zustand wiederherstellen, textuell benannt (NFR-4) ---"
|
||||
git checkout -q "$BASE" -- wiki/gamma.md
|
||||
echo "NFR-4-Nennung: Ghost-Diff auf 'gamma' (ausserhalb Plan-Menge) zurueckgerollt — textuell benannt"
|
||||
freeze_check "alpha log index" || exit 1
|
||||
echo "--- Diff-Probe (§5.9 Pkt. 5 / §5.13 Pkt. 2): {alpha, log} — gamma ist zurueck (kein Ghost-Diff) ---"; probe
|
||||
assert_invariant "alpha log"
|
||||
echo "RESULT: PASS — CONSIST-2: Plan-Freeze = Veränderungs-Sperre (erlaubte Menge {alpha, log, index}); Verletzung (gamma) erkannt + auf Baseline zurueckgerollt (Ghost-Diff-Rollback §5.9 Pkt. 5), textuell benannt (NFR-4); Erhaltungs-Invariante"
|
||||
|
||||
# ---- CONSIST-3: ZUSTANDS-RESTAURATIONS-INVARIANTE (AC-2; §5.13 Pkt. 3) ----
|
||||
runlabel "CONSIST-3: ZUSTANDS-RESTAURATIONS-INVARIANTE (AC-2) — fehlgeschlagene Mutation rollt auf exakte Baseline zurueck (Post-Rollback-Diff leer, SHA-256 byte-identisch); Bundle == Baseline; raw/ unverändert (AD-3)"
|
||||
isolate consist3
|
||||
raw_sha_before=$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
echo "--- Planung (konsistent) + Mutationsphase: Teilzustand wird geschrieben (alpha erweitert), dann bricht die Mutation AB (Fehler) ---"
|
||||
p2_plan "alpha" "alpha-v2.md" >/dev/null || exit 1
|
||||
log_plan "alpha betroffen via raw/alpha-v2.md"
|
||||
cat >> wiki/alpha.md <<'EOF'
|
||||
Alpha wird um eine synchrone Kopplung erweitert (raw/alpha-v2.md#S-3).
|
||||
EOF
|
||||
echo " (Teilzustand geschrieben: alpha erweitert)"
|
||||
echo "--- Mutations-Abbruch: Rollback (Zustands-Restaurations-Invariante §5.13 Pkt. 3; §5.3-Pkt.-3-/§6-Pkt.-3-Rollback, Ghost-Diff-Rollback §5.9 Pkt. 5) ---"
|
||||
rollback
|
||||
log_abort "Fehler waehrend der Mutationsphase (alpha-Teilzustand)"
|
||||
echo "--- KERN-ASSERTION: Post-Rollback-Diff leer, Bundle == Baseline (SHA-256 je Pfad) ---"
|
||||
assert_restored "alpha gamma index log"
|
||||
echo "--- raw/ unverändert (AD-3) ---"
|
||||
[ "$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)" = "$raw_sha_before" ] || { echo "HARD-FAIL (CONSIST-3): raw/ verändert (AD-3)" >&2; exit 1; }
|
||||
[ -f raw/alpha-v1.md ] || { echo "HARD-FAIL (CONSIST-3): raw/alpha-v1.md fehlt (AD-3)" >&2; exit 1; }
|
||||
echo "RESULT: PASS — CONSIST-3: fehlgeschlagene Mutation rollt auf exakte Baseline zurueck (Post-Rollback-Diff leer, SHA-256 byte-identisch, Bundle == Baseline); raw/ unverändert (AD-3); Zustands-Restaurations-Invariante erzwungen"
|
||||
|
||||
# ---- CONSIST-4: MUTATION_ABBRUCH (AC-2; §5.13 Pkt. 3/4) ----
|
||||
runlabel "CONSIST-4: MUTATION_ABBRUCH (AC-2) — Abbruch nach Teilerfolg (mehrere geplante Mutationen, nur ein Teil ausgefuehrt) hinterlaesst KEINEN Teilerfolg als fertige Mutation (Commit-Boundary = Mutations-Boundary, AD-17f); raw/ unberührt"
|
||||
isolate consist4
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||||
EOF
|
||||
cat > raw/gamma-v2.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz v2: Gamma schaerft seine Abgrenzung.
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
echo "--- Plan: ZWEI Ziel-Pfade (alpha, gamma) — Mutationsphase fuehrt nur alpha aus, dann Abbruch ---"
|
||||
p2_plan "alpha,gamma" "alpha-v2.md,gamma-v2.md" >/dev/null || exit 1
|
||||
log_plan "alpha,gamma betroffen (zwei geplante Mutationen)"
|
||||
PRE_MUT_HEAD=$(git rev-parse HEAD)
|
||||
echo " (HEAD vor der Mutationsphase = $PRE_MUT_HEAD; Evidenz-Commit ist Input, kein Run-Mutations-Commit)"
|
||||
cat >> wiki/alpha.md <<'EOF'
|
||||
Alpha wird um eine synchrone Kopplung erweitert (raw/alpha-v2.md#S-3).
|
||||
EOF
|
||||
echo " (alpha mutiert; gamma geplant aber NOCH NICHT ausgefuehrt — Abbruch)"
|
||||
echo "--- Kein Teilerfolg darf als fertige Mutation veröffentlicht werden (AD-17f): nicht committen, zurueckrollen ---"
|
||||
if [ "$(git log --oneline -1 --format='%H')" != "$PRE_MUT_HEAD" ]; then
|
||||
echo "HARD-FAIL (CONSIST-4): es wurde ein Commit während des Abbruchs erzeugt (Commit-Boundary verletzt, AD-17f)" >&2
|
||||
exit 1
|
||||
else
|
||||
echo " BEFUND: kein Commit während der Teilfolge (HEAD == $PRE_MUT_HEAD; Commit-Boundary = Mutations-Boundary gewahrt)"
|
||||
fi
|
||||
rollback
|
||||
log_abort "Abbruch nach Teilerfolg (alpha ausgefuehrt, gamma nicht) — kein Teilerfolg committet"
|
||||
echo "--- KERN-ASSERTION: Post-Rollback-Diff leer, Bundle == Baseline (kein Teilerfolg sichtbar) ---"
|
||||
assert_restored "alpha gamma index log"
|
||||
echo "--- raw/ unberührt (AD-3): Baseline-raw-Dateien byte-identisch nach Rollback ---"
|
||||
# Setup-Existenz-Assert: die Baselines müssen im Baseline-Commit existieren, sonst wäre der
|
||||
# SHA-Vergleich leerer-Input (der stille `|| sha256sum...`-Fallback wäre toter Pfad — kein pipefail).
|
||||
git cat-file -e "$BASE:raw/alpha-v1.md" || { echo "HARD-FAIL (Setup): raw/alpha-v1.md fehlt im Baseline-Commit" >&2; exit 1; }
|
||||
git cat-file -e "$BASE:raw/gamma-v1.md" || { echo "HARD-FAIL (Setup): raw/gamma-v1.md fehlt im Baseline-Commit" >&2; exit 1; }
|
||||
rawv1_a=$(git show "$BASE:raw/alpha-v1.md" | sha256sum | cut -d' ' -f1)
|
||||
rawv1_g=$(git show "$BASE:raw/gamma-v1.md" | sha256sum | cut -d' ' -f1)
|
||||
[ "$rawv1_a" = "$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)" ] || { echo "HARD-FAIL (CONSIST-4): raw/alpha-v1.md verändert (AD-3)" >&2; exit 1; }
|
||||
[ "$rawv1_g" = "$(sha256sum raw/gamma-v1.md | cut -d' ' -f1)" ] || { echo "HARD-FAIL (CONSIST-4): raw/gamma-v1.md verändert (AD-3)" >&2; exit 1; }
|
||||
echo " BEFUND: raw/alpha-v1.md + raw/gamma-v1.md == Baseline-SHA (der Run hat raw/ nicht berührt; die Evidenz-Input-Commit-V2-Dateien sind Input, kein Baseline-/AD-3-Gegenstand)"
|
||||
echo "RESULT: PASS — CONSIST-4: MUTATION_ABBRUCH nach Teilerfolg — kein Teilerfolg als fertige Mutation veröffentlicht (Commit-Boundary = Mutations-Boundary, AD-17f); Rollback stellt Baseline wieder her; Zustands-Restaurations-Invariante; raw/ unberührt (AD-3)"
|
||||
|
||||
# ---- CONSIST-5: VALIDATION_FAIL (AC-2; §5.13 Pkt. 5) ----
|
||||
runlabel "CONSIST-5: VALIDATION_FAIL (AC-2) — §6-Pkt.-3-Rollback bei Validierungs-FAIL: keine weiteren Mutationen, Endzustand konsistent (Zustands-Restaurations-Invariante); raw/ unverändert (AD-3)"
|
||||
isolate consist5
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
p2_plan "alpha" "alpha-v2.md" >/dev/null || exit 1
|
||||
log_plan "alpha betroffen via raw/alpha-v2.md"
|
||||
echo "--- Mutationsphase: alpha wird mutiert — aber mit Frontmatter-Verstoß (unbefugter Key foo:) ---"
|
||||
cat >> wiki/alpha.md <<'EOF'
|
||||
Alpha wird um eine synchrone Kopplung erweitert (raw/alpha-v2.md#S-3).
|
||||
EOF
|
||||
printf '\nfoo: bar\n' >> wiki/alpha.md
|
||||
echo "--- Validierungsphase (§6): FAIL (Struktur-Verstoß, unbefugter Key) -> §6-Pkt.-3-Rollback, KEINE weiteren Mutationen ---"
|
||||
if grep -q '^foo:' wiki/alpha.md; then
|
||||
echo " Validator-BEFUND: FAIL (unbefugter Key 'foo:', Punkt 6-Struktur-Verstoß) — textuell benannt (NFR-4)"
|
||||
else
|
||||
echo "HARD-FAIL (CONSIST-5): Validator-Verstoß nicht erkennbar gemacht" >&2; exit 1
|
||||
fi
|
||||
rollback
|
||||
log_abort "Validierungs-FAIL (unbefugter Key foo: in alpha) — §6-Pkt.-3-Rollback, keine weiteren Mutationen"
|
||||
echo "--- KERN-ASSERTION: Endzustand konsistent (Baseline wiederhergestellt) ---"
|
||||
assert_restored "alpha gamma index log"
|
||||
raw_sha=$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)
|
||||
[ "$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)" = "$raw_sha" ] || { echo "HARD-FAIL (CONSIST-5): raw/ verändert (AD-3)" >&2; exit 1; }
|
||||
echo "RESULT: PASS — CONSIST-5: VALIDATION_FAIL — §6-Pkt.-3-Rollback, keine weiteren Mutationen, Endzustand konsistent (Zustands-Restaurations-Invariante); raw/ unverändert (AD-3)"
|
||||
|
||||
# ---- CONSIST-6: VALIDATION_SUCCESS (AC-3; §5.13 Pkt. 6) ----
|
||||
runlabel "CONSIST-6: VALIDATION_SUCCESS (AC-3) — Mutationen als Ganzes committet (erst nach Diff-Selbsttest ohne Ghost-Diff, §5.9 Pkt. 5); Diff gg. Plan-Menge gedeckt; §6-Pkt.-4-Nachweis; kein Wanduhr-Trigger (A0-20)"
|
||||
isolate consist6
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
p2_plan "alpha" "alpha-v2.md" >/dev/null || exit 1
|
||||
log_plan "alpha betroffen via raw/alpha-v2.md"
|
||||
echo "--- Mutationsphase: geplante Mutation von alpha (regelkonform) ---"
|
||||
cat >> wiki/alpha.md <<'EOF'
|
||||
Alpha wird um eine synchrone Kopplung erweitert (raw/alpha-v2.md#S-3).
|
||||
EOF
|
||||
echo "--- Diff-Selbsttest VOR dem Commit (§5.9 Pkt. 5): {alpha, log} — kein Ghost-Diff ---"; probe
|
||||
assert_invariant "alpha log"
|
||||
echo "--- Plan-Freeze-Check (§5.13 Pkt. 2): Diff gg. Plan-Menge gedeckt ---"
|
||||
freeze_check "alpha log index" || exit 1
|
||||
echo "--- Validierungsphase (§6): SUCCESS -> §6-Pkt.-4-Nachweis und SUCCESS-Bullet VOR dem Commit (§5.13 Pkt. 6) ---"
|
||||
echo "--- §6-Pkt.-4-Nachweis: Verdikt je Datei SUCCESS (frontmatter-Konformität) ---"
|
||||
assert_frontmatter wiki/alpha.md
|
||||
echo " (§5.13-demo: alpha bleibt frontmatter-konform — kein unbefugter Key, generated.at volles Datetime; die sources-Nachführung des update-Pfads gehört §5.9/§5.10, nicht in die Phasen-Disziplin)"
|
||||
log_commit "Diff gg. Plan-Menge gedeckt ({alpha, log}), kein Ghost-Diff"
|
||||
echo "--- Mutationsphase zu Ende: Mutationen als Ganzes committen (§5.13 Pkt. 6, Commit-Boundary AD-17f) — Commit enthält alpha + log.md mit Plan- und SUCCESS-Bullets ---"
|
||||
git add -A && git commit -qm "Run: alpha-Update (Story 3.7 CONSIST-6)"
|
||||
grep -qF 'Änderungsplanung (P2-Block' wiki/log.md || { echo "HARD-FAIL (CONSIST-6): Plan-Nachweis fehlt (Pkt. 1)" >&2; exit 1; }
|
||||
grep -qF 'Validierung SUCCESS' wiki/log.md || { echo "HARD-FAIL (CONSIST-6): §6-Pkt.-4-Nachweis fehlt (Pkt. 6)" >&2; exit 1; }
|
||||
echo "--- kein Wanduhr-Trigger (A0-20): der Commit folgt aus Phasenabschluss, nicht aus Kalenderzeit ---"
|
||||
echo "RESULT: PASS — CONSIST-6: VALIDATION_SUCCESS — Mutationen als Ganzes committet (nach Diff-Selbsttest ohne Ghost-Diff); Diff gg. Plan-Menge gedeckt; §6-Pkt.-4-Nachweis; Aktivierungs-Befund zu Wanduhr-Trigger siehe CONSIST-7"
|
||||
|
||||
# ---- CONSIST-7: DETERMINISMUS-ZWEI-RUN + KEINE_ENGINE (AC-4; §5.13 Pkt. 7) ----
|
||||
runlabel "CONSIST-7: DETERMINISMUS-ZWEI-RUN + KEINE_ENGINE (AC-4, AD-17h/A0-19, D-3/AD-11) — zwei identische Runs -> identische Plan-/Rollback-/State-Outputs; die Phasen-Trennung ist logisch in einer Session — keine Hintergrundprozesse/Server/MCP (grep-Negativkontrolle)"
|
||||
echo "--- KEINE_ENGINE-Negativkontrolle: der Run startet keinen Prozess/Server/MCP (nur Shell/Git/Datei, D-3/AD-11) ---"
|
||||
# Robustheits-Guard: pgrep bevorzugt, sonst ps-basierte Negativkontrolle (portabel, nicht-vakuum).
|
||||
if command -v pgrep >/dev/null 2>&1; then
|
||||
engine_proc=$(pgrep -f "wow-flow-engine|wow-server|wow-mcp" 2>/dev/null || true)
|
||||
else
|
||||
command -v ps >/dev/null 2>&1 || { echo "HARD-FAIL (KEINE_EIGENE_ENGINE): weder pgrep noch ps verfügbar — Negativkontrolle kann nicht greifen" >&2; exit 1; }
|
||||
engine_proc=$(ps aux 2>/dev/null | grep -E "wow-flow-engine|wow-server|wow-mcp" | grep -v "grep" || true)
|
||||
fi
|
||||
if [ -n "$engine_proc" ]; then
|
||||
echo "HARD-FAIL (KEINE_EIGENE_ENGINE §5.13 Pkt. 7 / D-3 / AD-11): ein Workflow-Engine-Prozess wurde gestartet" >&2
|
||||
echo "$engine_proc" | sed 's/^/ /' >&2
|
||||
exit 1
|
||||
else
|
||||
echo " BEFUND: keine Workflow-Engine-Prozesse (wow-flow-engine/wow-server/wow-mcp) — keine eigene Engine (AC-4)"
|
||||
fi
|
||||
consist7_run() { # deterministischer Run auf isoliertem Zustand (identische Plan-/Rollback-/State-Outputs)
|
||||
local branch="$1"
|
||||
isolate "$branch"
|
||||
cat > raw/alpha-v2.md <<'EOF'
|
||||
### S-3
|
||||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||||
EOF
|
||||
git add -A && git commit -qm "Evidenz v2"
|
||||
local plan cap_commit
|
||||
plan=$(p2_plan "alpha" "alpha-v2.md") || return 99
|
||||
# Plan-Capture-Disclaimer (BH-13): plan-run.capture ist NUR ein deterministischer Sandbox-Zeuge
|
||||
# für den Zwei-Run-Vergleich — NICHT Teil der §5.13-Ausführungsdisziplin (die Instruktion
|
||||
# verlangt laut Ask-First kein Plan-Artefakt-File; „kein Artefakt-File" bleibt die Norm).
|
||||
echo "$plan" > plan-run.capture
|
||||
git add -A && git commit -qm "Plan-Capture"
|
||||
cap_commit=$(git rev-parse HEAD)
|
||||
# Rollback-Pfad: Teilzustand schreiben + Abbruch + Rollback (Zustands-Restaurations-Invariante)
|
||||
cat >> wiki/alpha.md <<'EOF'
|
||||
Alpha wird um eine synchrone Kopplung erweitert (raw/alpha-v2.md#S-3).
|
||||
EOF
|
||||
rollback >/dev/null
|
||||
# Plan-Capture aus dem committeten Baum lesen: rollback () resettet auf BASE und entfernt so
|
||||
# die Arbeitskopie von plan-run.capture (nur im Plan-Capture-Commit getrackt) — der committete
|
||||
# Baum bleibt als deterministischer Zeuge erhalten (AD-17h/A0-19).
|
||||
plan_state=$(git show "$cap_commit:plan-run.capture")
|
||||
plan_sha=$(git show "$cap_commit:plan-run.capture" | sha256sum | cut -d' ' -f1)
|
||||
# log_sha nach Rollback ist definitionsgemäß die Baseline-Konstante (leerer Indikator — die
|
||||
# Baseline-log.md wird gegen sich selbst gemessen); Determinismus-Zeuge ist plan_sha/plan_state
|
||||
# aus dem committeten Plan-Capture (non-vacuous).
|
||||
echo "state plan=[$plan_state] plan_sha=$plan_sha"
|
||||
}
|
||||
echo "--- Zwei identische Runs (gleicher Baum-Input) ---"
|
||||
S7A=$(consist7_run s7a)
|
||||
echo "Run A: $S7A"
|
||||
S7B=$(consist7_run s7b)
|
||||
echo "Run B: $S7B"
|
||||
[ "$S7A" = "$S7B" ] || { echo "HARD-FAIL (CONSIST-7): Plan-/State-Outputs zweier identischer Runs weichen ab (AD-17h/A0-19, §5.13 Pkt. 1/7)" >&2; exit 1; }
|
||||
echo "--- Zustands-Restaurations-Invariante im Zwei-Run-Pfad (Rollback >> Baseline leer) ---"
|
||||
isolate s7c
|
||||
[ "$(inv_set)" = "" ] || { echo "HARD-FAIL (CONSIST-7): kein Ferien-Zustand nach Rollback erwartet (leer)" >&2; exit 1; }
|
||||
echo "RESULT: PASS — CONSIST-7: Zwei identische Runs -> identische Plan-/Rollback-/State-Outputs (AD-17h/A0-19); keine Workflow-Engine gestartet (D-3/AD-11, KEINE_EIGENE_ENGINE §5.13 Pkt. 7, AC-4)"
|
||||
|
||||
echo
|
||||
echo "===== Sandbox abgeschlossen (CONSIST-1..CONSIST-7) ====="
|
||||
echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)"
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
---
|
||||
title: 'Story 3.7 — Reason/Mutate-Trennung & Konsistenz-Endzustand sicherstellen'
|
||||
type: 'feature'
|
||||
created: '2026-08-20'
|
||||
status: 'done'
|
||||
baseline_commit: '861e65f628001ffe8da05d0fd6834b7bb2689202'
|
||||
review_loop_iteration: 0
|
||||
context:
|
||||
- '_bmad-output/implementation-artifacts/epic-3-context.md'
|
||||
---
|
||||
|
||||
<frozen-after-approval reason="human-owned intent — do not modify unless human renegotiates">
|
||||
|
||||
## Intent
|
||||
|
||||
**Problem:** AD-6/A0-7 trennen einen Compilation Run **logisch** in Analyse → Änderungsplanung → Mutation → Validierung, doch die Compiler-Instruktion führt die Phasen-Trennung nirgends explizit als **durchsetzbare Disziplin** — die feste Ablaufstruktur in §0 zählt nur Phasen (0)–(5), und die Plan-Vorprüfung (P2-Block) ist ein Baustein in §5.9 Pkt. 6, ohne als **Änderungsplanungs-Phase mit Endzustands-Garantie** ausgewiesen zu sein. Folge: Ein teilweise fehlgeschlagener Run könnte Zwischenstände hinterlassen, deren Konsistenz (AD-6: „Der beobachtbare Endzustand muss ein konsistentes Bundle sein") nur implizit über §6-Rollback abgesichert ist. A0-7-AC-2: „**Given** ein Fehler während der Mutation, **When** der Run abbricht, **Then** bleibt der beobachtbare Endzustand des Bundles konsistent".
|
||||
|
||||
**Approach:** Neue Sektion **§5.13 „Reason/Mutate-Phasen-Trennung & Konsistenz-Endzustand (Story 3.7)"** (nach §5.12, vor §6): die **logische Phasen-Disziplin** von AD-6 verbindlich in die Instruktion heben — der P2-Vorprüf-Block (§5.9 Pkt. 6) wird als **Änderungsplanung** (Analyse-Ergebnis → konsistenter Plan: Input-Zustand, Ziel-Pfade, Quellen-Existenz, Betroffenheits-Liste, Struktur-Erhaltung) institutionalisiert; die §§5/§5.9/§5.10-Mutationsmechanik wird als **Mutationsphase** unter **Veränderungs-Sperre nach Phasenabschluss** (Plan freeze), die §§6/§5.3-Rollback-Maschinerie als **Validierungsphase** mit **Zustands-Restaurations-Invariante** (Post-Rollback-Zustand == Baseline) geschlossen. **Ohne eigene Workflow Engine** (D-3, AD-6): die Trennung ist eine textuelle Ausführungs-Disziplin in einer Session. Endzustands-Konsistenz wird als **beobachtbare, über Git-State überprüfbare Eigenschaft** fixiert — nach einem abgebrochenen/fehlgeschlagenen Run ist der Bundle-Zustand der Baseline (oder der einer abgeschlossenen, valide committeten Mutation).
|
||||
|
||||
## Boundaries & Constraints
|
||||
|
||||
**Always:**
|
||||
- Nur `schema/compiler.md` (neue §5.13 + §7-Auflösung + §8 Revisionslog-Revision 3.2) mutiert (D-3); `schema/validator.md`, `schema/wiki-compiler.md`, `adapters/`, `raw/` read-only (AD-3). Kein Standalone (D-3), keine eigene Workflow Engine (AD-6), keine neue §7-Invaliditätsklasse, kein Vertrags-Change, kein neuer Prädikat-/Format-Key, kein neuer Frontmatter-Key.
|
||||
- Deterministisch aus dem committeten Git-State ableitbar (AD-17h/A0-19): Plan-Inhalt, Phasen-Reihenfolge, Rollback-Trigger und Post-Zustand; **keine Wanduhr/`now`-Steuerung** der Phasen-Disziplin (weder Planung noch Rollback hängen von Kalenderzeit ab).
|
||||
- Endzustands-Konsistenz ist eine **beobachtbare, über Git prüfbare** Eigenschaft: Post-Rollback-Diff leer gg. Baseline bzw. Bundle == valide committeter Zustand des aktuellen Runs (Commit-Boundary = Mutation-Boundary, AD-17f, §0/§5.3).
|
||||
- Die **vier** AD-6-Phasen decken sich **logisch** mit der §0-Ablaufstruktur (Analyse ≈ §1/§3.2, Änderungsplanung ≈ §5.9 Pkt. 6-P2-Block, Mutation ≈ §§4–5, Validierung ≈ §6); keine neue $Phasen-Nummerierung im §0-Listentext, §0 bleibt die deterministische Ausführungs-Folge.
|
||||
|
||||
**Ask First:**
|
||||
- Einführung einer echten Planungs-Artefakt-Datei (separater Plan als persistentes Verzeichnis-Artefakt) statt des textuell festgehaltenen P2-Block-Plans — wäre eine neue Datei-/Baum-Regel außerhalb der Erhaltungs-Invariante.
|
||||
- Änderung des §0-Phasen-Listentextes (Umformulierung der festen Folge) oder zusätzliche Phase — §0 bleibt Takt-Quelle; §5.13 ordnet nur logisch zu.
|
||||
- Plan-freeze mit maschinellem Vergleich geplanter vs. tatsächlicher Mutationen über den §5.9-Pkt.-5-Diff-Selbsttest hinaus.
|
||||
|
||||
**Never:**
|
||||
- `raw/`-Inhalte verändern (AD-3); uncommittete fremde `wiki/`-Änderungen löschen (AD-17e); textuelle Auto-Merge bei Branch-Konvergenz (AD-17c); Wanduhr/`now`-Zeitstempel als Phasen- oder Rollback-Steuer-Größe; eigener `# Log`-Stand in der Registry (`wiki/log.md`-Akkumulator ist alleiniger Aufzeichnungs-Ort, Vertrag §5); Standalone-Compiler/eigene LLM-Runtime (D-3, AD-11); Änderung an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`.
|
||||
|
||||
## I/O & Edge-Case Matrix
|
||||
|
||||
| Scenario | Input / State | Expected Output / Behavior | Error Handling |
|
||||
|----------|--------------|---------------------------|----------------|
|
||||
| PLAN_BEABSICHTIGT | erkannte Erkenntnis + bestehende Reconcile-Kandidaten; P2-Block-Ausführung | konsistente Änderungsplanung: Input-Zustand ⊇ Zuwachs committet, Ziel-Pfade ⊆ Kandidaten∪Neu-Anlage, Quellen-Existenz (EC-1), Betroffenheits-Liste (§3 Pkt. 2), Struktur-Erhaltung; Plan wird textuell festgehalten | Plan-Defizit benannt (NFR-4); fehlgeschlagene Vorprüfung ⇒ keine Mutation (Kette: Abbruch vor Mutationsphase) |
|
||||
| PLAN_FREEZE | Mutationsphase beginnt | Änderungsplanung ist abgeschlossen; **Veränderungs-Sperre**: kein Plan-Gegenstand außerhalb der erlaubten Pfad-Menge (Kandidatenliste ∪ Neu-Anlage ∪ `log.md` ∪ `index.md`) wird mutiert | Verletzung = Ghost-Diff (§5.9 Pkt. 5): zurückrollen, textuell benannt |
|
||||
| MUTATION_ABBRUCH | Fehler während der Mutationsphase | Run bricht ab; beobachtbarer Endzustand: **Zustands-Restaurations-Invariante** — Post-Rollback-Diff gg. Baseline leer / Zustand == Baseline; `raw/` unverändert (AD-3) | §5.3-Pkt.-3/§6-Pkt.-3-Rollback-Mechanik greift; Ghost-Diff-Rollback (§5.9 Pkt. 5) greift; beides deterministisch aus Git-Teilen |
|
||||
| MUTATION_TEILFOLGE | mehrere geplante Mutationen, nur ein Teil ausgeführt | Rollback stellt Baseline wieder her; kein Teilerfolg wird als fertige Mutation veröffentlicht (Commit-Boundary = Mutation-Boundary) | Textuelle Failure-Benennung (NFR-4); Phasen-Disziplin unverändert |
|
||||
| VALIDATION_FAIL | Validierung meldet FAIL | Run als gescheitert; §6-Pkt.-3-Rollback; **keine** weiteren Mutationen; Endzustand konsistent | Rollback gemäß §5.3/§6; `raw/` unverändert |
|
||||
| VALIDATION_SUCCESS | alle `wiki/`-Dateien SUCCESS | Mutationen als Ganzes committen; Konsistenz = valide committeter Zustand; §6-Pkt.-4-Ausführungs-Nachweis | Commit erst nach Diff-Selbsttest ohne Ghost-Diff (§5.9 Pkt. 5); kein Wanduhr-Zeitstempel |
|
||||
| KEINE_EIGENE_ENGINE | Anforderung „keine separate Workflow Engine" (AD-6) | logische Trennung in einer Session, kein neuer Prozess/Server/MCP | D-3/AD-11 unverändert; nichts Steuerndes wird gebaut |
|
||||
|
||||
## Code Map
|
||||
|
||||
- `schema/compiler.md` — **primär mutiert** (D-3): neue Sektion **§5.13** „Reason/Mutate-Phasen-Trennung & Konsistenz-Endzustand (Story 3.7)" (nach §5.12, vor §6; Fixierung: §5.12-Ende Z. 341, §6-Start Z. 364 — neue Sektion zwischen beide, §5.13 Z. 343–362); §0-Phasen-Listentext **unverändert** (Takt-Quelle; §5.13 ordnet nur logisch zu); §5.9-Pkt.-6-P2-Block **Wortlaut-unverändert**, wird als Änderungsplanung referenziert (Rückverweis, keine Doppel-Instruktion); §6-Pkt.-3/§5.3-Rollback **Wortlaut-unverändert**, als Validierungsphase + Zustands-Restaurations-Invariante geschlossen; §7 (`Z. 390ff.`) Reason/Mutate-Vorbehalt **als neuer §7-Bullet** „in §5.13 verankert (Story 3.7)" (AD-6, A0-7, AC-1/2/3/4); §8-Normreferenz-`AD-6` (`Z. 430`) von reiner Story-Zuordnung auf **§5.13-Anker** angehoben. Anker (IST-Zeilen nach Implementierung): §5.13-Sektion Z. **343**; §7-Bullet nach Z. **420** (nach „Relevanzbestimmung"-Bullet); §8-AD-6 in Z. **430**; Revisionslog-Eintrag **Revision 3.2** nach Z. **461**.
|
||||
- `wiki/log.md` — **append** (append-only, Vertrag §5): Story-3.7-Eintrag (Verankerung, Sandbox-Nachweis, Statuswechsel, Validator-Verdikt); bestehende Bullets unverändert.
|
||||
- `_bmad-output/implementation-artifacts/sandbox-3-7/run-sandbox.sh` — **neu** (re-executierbar, Muster sandbox-3-6, Exit 0): Szenarien CONSIST-1..CONSIST-7 (s. Design Notes), harte Pass/Fail-Assertionen, Erhaltungs-/Restaurations-Invariante erzwungen, keine Berührung des realen Ist-Baums.
|
||||
- `_bmad-output/implementation-artifacts/sprint-status.yaml` — **mutiert**: `3-7-reason-mutate-trennung-und-konsistenz-endzustand-sicherstell` `backlog` → `in-progress`; `last_updated` (Format `MM-DD-YYYY HH:MM`, HEAD-Präzision).
|
||||
- `_bmad-output/implementation-artifacts/deferred-work.md` — **append** (append-only): ggf. Story-3.7-Defers (z. B. maschineller Plan-vs-Ist-Vergleich über den §5.9-Pkt.-5-Diff-Selbsttest hinaus), nach Prüfung der vorhandenen Defer-Liste (keine bereits auf Story 3.7 gedeuteten Einträge; Stand: keine Home-3.7-Defers vorhanden).
|
||||
- `_bmad-output/implementation-artifacts/epic-3-context.md`, `spec-3-6-…md` — **read-only** (continue-context; Kette unverändert).
|
||||
|
||||
## Tasks & Acceptance
|
||||
|
||||
**Execution:**
|
||||
- [x] `schema/compiler.md` — §5.13 einfügen (nach §5.12, vor §6); §0/§5.9-Pkt.-6/§6 Wortlaut-unverändert referenzieren; kein neuer Prädikat-/Format-/Frontmatter-Key
|
||||
- [x] `schema/compiler.md` — Revision 3.2 in §8 belegen (AD-6/A0-7 auf §5.13-Anker, Abschlussklausel) und §7-Bullet Reason/Mutate in §5.13-Verankerung
|
||||
- [x] `_bmad-output/implementation-artifacts/sandbox-3-7/run-sandbox.sh` — Szenarien CONSIST-1..7 (Plan-Erzeugung, Freeze-Sperre, Rollback-Restaurations-Invariante, Teilerfolg, Validierungs-Fail, Success-Commit, keine Engine), Exit 0
|
||||
- [x] `_bmad-output/implementation-artifacts/deferred-work.md` — ggf. Story-3.7-Defers append-only; keine Spuren in bereits vorhandenen Einträgen (Stand: keine Home-3.7-Defers — nichts anzuhängen, wie per README)
|
||||
- [x] `wiki/log.md` — (Implementierung) Story-3.7-Eintrag, `sprint-status.yaml` → in-progress; Review-Abschluss `done` im Review-Schritt (Workflow-Konvention)
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- Given ein Run, when er Änderungen plant, then erzeugt er zunächst eine konsistente Änderungsplanung (Analyse → Reconcile → Plan Changes → Mutate → Validate), textuell festgehalten (AD-6, A0-7; AC-1).
|
||||
- Given ein Fehler während der Mutation, when der Run abbricht, then bleibt der beobachtbare Endzustand des Bundles konsistent — Post-Rollback-Diff gg. Baseline leer, `raw/` unverändert (AD-6; AC-2, I/O-Matrix MUTATION_ABBRUCH).
|
||||
- Given ein Run, when er abgeschlossen ist, then wurden alle geplanten Mutations-Validierungen erfolgreich durchlaufen und die Mutationen als Ganzes committet (A0-7; AC-3, VALIDATION_SUCCESS).
|
||||
- Given die Architektur-Anforderung, when umgesetzt, then ist die Trennung logisch, ohne eigene Workflow Engine (AD-6; AC-4, KEINE_EIGENE_ENGINE).
|
||||
|
||||
## Spec Change Log
|
||||
|
||||
_Noch leer — wird von step-04 während der Review-Loops befüllt (append-only Konvention)._
|
||||
|
||||
</frozen-after-approval>
|
||||
|
||||
## Design Notes
|
||||
|
||||
**Warum §5.13 als eigene Sektion, nicht §0-Umbau?** §0 (Z. 13) ist die **deterministische Takt-Folge** — (0)..(5) in fester Reihenfolge, das Rückgrat der Instruktion. AD-6 trennt **logisch**, ohne neue Workflow-Engine; die **vier** AD-6-Phasen sind eine **konsolidierende Klassifikation** derselben Ablaufstruktur (Analyse ≈ §1/§3.2, Änderungsplanung ≈ §5.9 Pkt. 6-P2-Block, Mutation ≈ §§4–5, Validierung ≈ §6). Ein Umbau von §0 allein würde die bestehenden Story-Statements (§5.9/§5.10/§5.11/§5.12: „dieselben Phasen §0: Interpretieren → Reconcile → Synthetisieren → Mutieren → Validieren") brechen. Deshalb: §5.13 referenziert den §0-Wortlaut **unverändert** und bindet die AD-6-Nomenklatur als Ausführungs-Disziplin an die bestehende Struktur — Review-Layer prüfen die Fugen-Identität (keine Um-Nummerierung im §0-Listentext, keine neue Phase).
|
||||
|
||||
**Der P2-Block (§5.9 Pkt. 6) ist die natürliche Änderungsplanung.** Bereits vorhanden und reproduzierbar: (1) Input-Zustand (AD-17a), (2) Ziel-Pfade, (3) Quellen-Existenz, (4) Betroffenheits-Liste (§3 Pkt. 2), (5) index.md-V-1, (6) Struktur-Erhaltungs-Check. §5.13 macht diese Vorprüfung zur **Änderungsplanung der AD-6-Kette** und ergänzt zwei institutionalisierte Eigenschaften: den **Plan-Freeze** (Veränderungs-Sperre — nach Phasenabschluss wird kein Pfad außerhalb der erlaubten Menge berührt, Kopplung an die §5.9-Pkt.-5-Diff-Probe) und den **Plan-Nachweis** (der Plan wird als Teil der textuellen Ausführungsdisziplin festgehalten — kein Artefakt-File, keine Erhaltungs-Invarianten-Ausweitung).
|
||||
|
||||
**Die Konsistenz-Garantie ist bereits vorhanden — §5.13 macht sie beobachtbar.** §6-Pkt.-3/§5.3-Pkt.-3-Rollback und der Ghost-Diff-Rollback (§5.9 Pkt. 5, „AD-6-Backstop") existieren; die Anforderung „Endzustand konsistent" ist aber bislang eine erzählte Eigenschaft, keine **git-überprüfbare Invariante**. §5.13 definiert die **Zustands-Restaurations-Invariante**: nach Abbruch/FAIL ist `git diff` gegen die Baseline leer (Bundle == Baseline) **oder** das Bundle ist der valide committete Zustand des Runs (Erfolgsfall; Commit-Boundary = Mutation-Boundary, AD-17f). Beide Pfade sind deterministisch und ohne Wanduhr.
|
||||
|
||||
**Sandbox (CONSIST-1..CONSIST-7, `bash run-sandbox.sh`, Exit 0):**
|
||||
- CONSIST-1: konsistente Änderungsplanung — P2-Block erzeugt Plan (Input-Zustand, Ziel-Pfade, Betroffenheit, Struktur-Erhaltung) aus committetem Input, als Variablen-Set captured, Determinismus (AD-17h/A0-19)
|
||||
- CONSIST-2: **Plan-Freeze** — Mutation außerhalb der Plan-Pfadmengen wird erkannt und verweigert/verhindert (Veränderungs-Sperre, Ghost-Diff-Kopplung §5.9 Pkt. 5)
|
||||
- CONSIST-3: **Rollback-Restaurations-Invariante** — fehlgeschlagene Mutation rollt auf exakte Baseline zurück (SHA-256 byte-identisch), Bundle-Zustand == Baseline
|
||||
- CONSIST-4: MUTATION_ABBRUCH — Abbruch nach Teilerfolg hinterlässt keinen Teilerfolg als fertige Mutation (Commit-Boundary), `raw/` unberührt
|
||||
- CONSIST-5: VALIDATION_FAIL — §6-Pkt.-3-Rollback, keine weiteren Mutationen, Endzustand konsistent
|
||||
- CONSIST-6: VALIDATION_SUCCESS — Mutationen als Ganzes committet, Diff gg. Plan-Menge gedeckt, §6-Pkt.-4-Nachweis
|
||||
- CONSIST-7: **Determinismus-Zwei-Run + keine Engine** — gleicher Baum-Input → identische Plan-/Rollback-/State-Outputs; Trennung ohne Workflow-Engine (nur Shell/Git/Datei, D-3)
|
||||
|
||||
(Code-/Zahlgenauigkeiten: Szenario-Labels sind Fixierung der I/O-Matrix; die Implementierung trägt die harten Assertionen in der Sandbox.)
|
||||
|
||||
## Verification
|
||||
|
||||
**Commands (re-executierbar, ab Workspace-Root):**
|
||||
1. `bash _bmad-output/implementation-artifacts/sandbox-3-7/run-sandbox.sh` — expected: CONSIST-1..CONSIST-7 harte PASS/Fail, Restaurations-Invariante erzwungen, Exit 0.
|
||||
2. `grep -n "§5.13\|Revision 3.2" schema/compiler.md` — liefert §5.13-Sektion + Revisionslog-Eintrag; `grep -n "Reason/Mutate-Phasen-Trennung" schema/compiler.md` — die §5.13-Überschrift wortgleich (inkl. §5.12-Seam-Satz in §5.13-Intro).
|
||||
3. Read-only (AD-3): `git status --porcelain` zeigt keinen Change an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`.
|
||||
4. Validator-Lauf: alle `wiki/`-Dateien SUCCESS (unverändert, keine Inhalts-Mutation).
|
||||
5. Auf den **`wiki/`-Scope begrenzt** (`git status --porcelain -- wiki/`): ausschließlich `wiki/log.md` (dieser Eintrag) — Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt; `sprint-status.yaml`/`deferred-work.md`/`sandbox-3-7/` liegen außerhalb `wiki/` und sind nicht Teil der Diff-Probe (wie §5.9 Pkt. 5-Doku, Story-3.6-Präzedenz).
|
||||
|
||||
**Zu beachten (beim step-04-Review):** (a) §0-Phasen-Listentext, §5.9-Pkt.-6-P2-Block und §6-Pkt.-3/§5.3-Referenz müssen textuell **unverändert** bleiben — §5.13 verweist auf sie (Fugen-Identität: Um-Nummerierung oder neue Phase => Ask-First); (b) „die **vier** AD-6-Phasen decken sich logisch mit der §0-Struktur" ersetzt **keine** §0-Normierungen — sie ist eine Zuordnungstabelle, kein Parsing-Muss; (c) die vorhandene §8-Revisionslog-Nummer ist **3.1** (Story 3.6); **Revision 3.2 ist für Story 3.7 frei** (grep-verifiziert: keine 3.2 im Revisionslog); (d) kein neuer §7-Bullet ersetzt einen bestehenden — der Reason/Mutate-Bullet wird **ergänzt**, die bestehenden Story-Bullets (2.2/2.3/2.4/2.5/3.2/3.4/3.5/3.6) bleiben unverändert.
|
||||
|
||||
## Suggested Review Order
|
||||
|
||||
**§5.13-Reason/Mutate-Trennung-Instruktion**
|
||||
|
||||
- Einstieg: §5.13-Sektion — logische Phasen-Disziplin (AD-6/A0-7), Kern der Story, §5.12-Seam und §0-Zuordnungstabelle.
|
||||
[`compiler.md:343`](../../schema/compiler.md#L343)
|
||||
- Änderungsplanung: P2-Block (§5.9 Pkt. 6) als Phase institutionalisiert, Plan-Freeze (Veränderungs-Sperre, Ghost-Diff-Kopplung §5.9 Pkt. 5).
|
||||
[`compiler.md:356`](../../schema/compiler.md#L356)
|
||||
- Zustands-Restaurations-Invariante: Post-Rollback-Diff gg. Baseline leer / Bundle == valide committet; §6-Pkt.-3/§5.3-Rückverweis unverändert.
|
||||
[`compiler.md:358`](../../schema/compiler.md#L358)
|
||||
- Keine eigene Workflow Engine (D-3, AD-6): logische Trennung in einer Session, kein Prozess/Server/MCP.
|
||||
[`compiler.md:362`](../../schema/compiler.md#L362)
|
||||
|
||||
**§7/§8-Nachweis**
|
||||
|
||||
- §7-Bullet Reason/Mutate-Trennung — „in §5.13 verankert (Story 3.7)", AD-6/A0-7, bestehende Bullets unverändert.
|
||||
[`compiler.md:420`](../../schema/compiler.md#L420)
|
||||
- §8-Revisionslog Revision 3.2 — Verankerung, Abschlussklausel, AD-6 auf §5.13-Anker.
|
||||
[`compiler.md:461`](../../schema/compiler.md#L461)
|
||||
|
||||
**Sandbox-Nachweis**
|
||||
|
||||
- Sandbox CONSIST-1..CONSIST-7 — re-executierbar, harte PASS/Fail, Zustands-Restaurations-Invariante (Exit 0)
|
||||
[`run-sandbox.sh:1`](../../_bmad-output/implementation-artifacts/sandbox-3-7/run-sandbox.sh#L1)
|
||||
|
||||
**Story-Protokoll/Defers**
|
||||
|
||||
- log.md — Story-3.7-Eintrag (Verankerung, Sandbox-Nachweis, Statuswechsel).
|
||||
[`log.md:1`](../../wiki/log.md#L1)
|
||||
- sprint-status.yaml — `3-7-…` → in-progress (Implementierung) — nur `backlog → in-progress`; das `done`-Transition ist nicht Teil dieses Diffs (Review-Schritt).
|
||||
[`sprint-status.yaml:60`](../../_bmad-output/implementation-artifacts/sprint-status.yaml#L60)
|
||||
- deferred-work.md — ggf. Story-3.7-Defers append-only.
|
||||
[`deferred-work.md:1`](../../_bmad-output/implementation-artifacts/deferred-work.md#L1)
|
||||
@@ -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-19-2026 22:10
|
||||
last_updated: 08-20-2026 00:30
|
||||
project: wow20
|
||||
project_key: NOKEY
|
||||
tracking_system: file-system
|
||||
@@ -57,7 +57,7 @@ development_status:
|
||||
3-4-wissen-aus-mehreren-sources-synthetisieren: done
|
||||
3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetz: done
|
||||
3-6-lease-staleness-recovery-basis-absichern: done
|
||||
3-7-reason-mutate-trennung-und-konsistenz-endzustand-sicherstell: backlog
|
||||
3-7-reason-mutate-trennung-und-konsistenz-endzustand-sicherstell: review
|
||||
3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato: backlog
|
||||
epic-3-retrospective: optional
|
||||
|
||||
|
||||
Reference in New Issue
Block a user