626 lines
36 KiB
Bash
626 lines
36 KiB
Bash
#!/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) porcelain: 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-textuelle 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; Neu-Anlage = +name) $2=komma-Liste raw-Quellen (Pfad)
|
||
local targets="$1" srcs="$2" p s np err=0
|
||
# (1) Input-Zustand (AD-17a): Working-Copy von raw/ und wiki/ gegen HEAD — uncommittet = Abbruch
|
||
# (Scope exakt wie Instruktion §5.9 Pkt. 6 Element (1): raw/ und wiki/; Review-Loop-2-D3:
|
||
# unscoped ganzer-Tree-Prüfung wäre straffer als die Instruktion — die Demo folgt der Instruktion.)
|
||
if [ -n "$(git status --porcelain -- raw wiki)" ]; 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): bestehende Kandidaten
|
||
# oder geplante Neu-Anlage-Zielpfade (+Prefix; §5.13 Pkt. 2 "∪ Neu-Anlage") — Duplikat-Kontrolle:
|
||
# ein +Pfad, der bereits existiert, ist kein Neu-Anlage.
|
||
for p in ${targets//,/ }; do
|
||
case "$p" in
|
||
+*) np="${p#+}"
|
||
[ -f "wiki/$np.md" ] && { echo "HARD-FAIL (Änderungsplanung, P2-Element (4)): Neu-Anlage-Pfad wiki/$np.md existiert bereits (Duplikat — kein Neu-Anlage, §5.10 Pkt. 8)" >&2; return 1; } ;;
|
||
*) [ -f "wiki/$p.md" ] || { echo "HARD-FAIL (Änderungsplanung, P2-Element (4)): Betroffenheits-Kandidat wiki/$p.md fehlt (und kein Neu-Anlage-Zielpfad +name)" >&2; return 1; } ;;
|
||
esac
|
||
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.
|
||
# (Review-Loop-2-D5: der Voll-Rollback rollt den TEILZUSTAND DES RUNS komplett zurück (§6 Pkt. 3:
|
||
# "das Bundle nimmt seinen Zustand vor dem Run wieder ein") — in der Sandbox sind alle
|
||
# ungetrackten wiki/-Dateien Lauf-eigener Teilzustand; es existieren keine fremden uncommitteten
|
||
# Änderungen (AD-17e-Schutzobjekt). Ein realer Run schützt fremde Änderungen zuvor per
|
||
# Stash/Scratch-Zone (§5.11 Pkt. 3), bevor ein Rollback greift.)
|
||
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 ---"
|
||
# (Review-Loop-2-Patch: die Löschung wird COMMITTET — eine uncommittierte Löschung würde
|
||
# Element (1) (uncommitteter Input) zuerst feuern und die EC-1-Kontrolle nicht isolieren;
|
||
# im committeten Zustand ist Element (3) der einzige Trigger.)
|
||
git rm -q raw/alpha-v2.md && git commit -qm "Quelle entfernt"
|
||
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 isoliert [untracked Datei] + P2-Element (3) EC-1 isoliert [committete Löschung]); 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); Misch-Run (Update + Neu-Anlage): der geplante Neu-Anlage-Pfad ist erlaubter Teil der Plan-Menge (Review-Loop-2-Patch)"
|
||
isolate consist2
|
||
cat > raw/alpha-v2.md <<'EOF'
|
||
### S-3
|
||
Evidenz v2: Alpha erweitert um eine synchrone Kopplung.
|
||
### S-4
|
||
Evidenz v2: Delta-Thema — bisher nicht im Bundle repraesentiert.
|
||
EOF
|
||
git add -A && git commit -qm "Evidenz v2"
|
||
p2_plan "alpha,+delta" "alpha-v2.md" >/dev/null || exit 1
|
||
log_plan "alpha betroffen + delta neu angelegt via raw/alpha-v2.md (Plan-Freeze aktiv, Misch-Run)"
|
||
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 "--- Mutationsphase: geplante Neu-Anlage von delta — erlaubt (Neu-Anlage im Plan, §5.13 Pkt. 2) ---"
|
||
cat > wiki/delta.md <<'EOF'
|
||
---
|
||
type: concept
|
||
sources:
|
||
- resource: raw/alpha-v2.md
|
||
id: s1
|
||
generated:
|
||
by: wow-compiler/0.1.0
|
||
at: 2026-08-20T00:00:00Z
|
||
---
|
||
Delta-Thema (raw/alpha-v2.md#S-4).
|
||
EOF
|
||
[ -f wiki/delta.md ] || { echo "HARD-FAIL (CONSIST-2): geplante Neu-Anlage 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 delta 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 delta log index" || exit 1
|
||
echo "--- Voll-Rollback (Abbruch des Runs): Teilzustand {alpha, delta, log} wird komplett zurückgerollt (Zustands-Restaurations-Invariante) ---"
|
||
rollback
|
||
assert_restored "alpha gamma index log delta"
|
||
echo " BEFUND: Neu-Anlage-Pfad delta existiert nach Rollback NICHT (assert_restored-Neu-Anlage-Guard) — Misch-Run-Teilerfolg ist vollständig rückgerollt"
|
||
echo "RESULT: PASS — CONSIST-2: Plan-Freeze = Veränderungs-Sperre (erlaubte Menge {alpha, delta (Neu-Anlage), log, index}); Verletzung (gamma) erkannt + zurueckgerollt (Ghost-Diff-Rollback §5.9 Pkt. 5); Neu-Anlage-Pfad im Plan ist erlaubter Teil der Menge; Misch-Run-Voll-Rollback: Neu-Anlage nach Rollback nicht existent (Zustands-Restaurations-Invariante); 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"
|
||
# (Review-Loop-2-Patch: gg. den Baseline-Commit vergleichen — der Selbstvergleich wäre
|
||
# tautologisch und bewiese nichts; Muster CONSIST-4.)
|
||
rawv1_b=$(git show "$BASE:raw/alpha-v1.md" | sha256sum | cut -d' ' -f1)
|
||
[ "$rawv1_b" = "$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)" ] || { 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) — §5.9-Pkt.-2-Update-Form: Body-Erweiterung + sources-Zuwachs + generated.at-Bump ---"
|
||
cat > wiki/alpha.md <<'EOF'
|
||
---
|
||
type: concept
|
||
sources:
|
||
- resource: raw/alpha-v1.md
|
||
id: s1
|
||
- resource: raw/alpha-v2.md
|
||
id: s3
|
||
generated:
|
||
by: wow-compiler/0.1.0
|
||
at: 2026-08-20T00: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).
|
||
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 "raw/alpha-v1.md" "raw/alpha-v2.md"
|
||
echo " (§5.13-demo: der committete Zustand ist gültig — alpha frontmatter-konform (kein unbefugter Key, generated.at volles Datetime), sources-Nachführung der Update-Evidenz vollzogen (§5.9 Pkt. 2); der Body zitiert raw/alpha-v2.md#S-3 nur mit existierendem sources-Eintrag (EC-1/Punkt-3-konform))"
|
||
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 sauberer 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)"
|