220 lines
9.5 KiB
Bash
220 lines
9.5 KiB
Bash
#!/usr/bin/env bash
|
|
# Story 3.1 — Sandbox-Edge-Tests der I/O-Matrix (fünf Szenarien) + D-3-Abbruch-Kontrolle
|
|
# Re-executierbar: bash run-sandbox.sh (ab Workspace-Root; Sandbox unter /tmp/sb31)
|
|
# Review-Loop-2-Härtung (Story 3.13, D/Patch P-1): harte Assertions mit Exit-Pfaden —
|
|
# jede Erwartung wird geassertet (Abweichung = Non-Zero-Exit), konsistent mit 3-2..3-12.
|
|
set -u
|
|
ROOT=$(mktemp -d /tmp/sb31-XXXXXX)
|
|
SB="$ROOT/sb"
|
|
mkdir -p "$SB/wiki" "$SB/raw"
|
|
cd "$SB"
|
|
git init -q
|
|
git config user.email "sandbox@test"
|
|
git config user.name "Sandbox"
|
|
FAILED=0
|
|
PASS_COUNT=0
|
|
pass() { PASS_COUNT=$((PASS_COUNT+1)); echo "PASS: $1"; }
|
|
fail() { FAILED=$((FAILED+1)); echo "FAIL: $1" >&2; }
|
|
# hardfail: Setup-/Infrastrukturfehler brchen sofort ab (kein Szenario-Exit).
|
|
hardfail() { echo "HARD-FAIL: $1" >&2; exit 1; }
|
|
|
|
# ---------- Basis-Baum (committete Ausgangslage = Baseline-Commit) ----------
|
|
cat > wiki/index.md <<'EOF'
|
|
# Index
|
|
- [Alpha](alpha.md)
|
|
- [Beta](beta.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 verwendet quanten-protocol-schlüssel für die Authentifizierung.
|
|
EOF
|
|
cat > wiki/beta.md <<'EOF'
|
|
---
|
|
type: concept
|
|
sources:
|
|
- resource: raw/beta-v1.md
|
|
id: s1
|
|
generated:
|
|
by: wow-compiler/0.1.0
|
|
at: 2026-08-16T09:00:00Z
|
|
---
|
|
Beta beschreibt ein anderes, hier nicht betroffenes Thema.
|
|
EOF
|
|
cat > wiki/log.md <<'EOF'
|
|
# Log
|
|
EOF
|
|
cat > raw/alpha-v1.md <<'EOF'
|
|
Evidenz v1: quanten-protocol-schlüssel (Stelle S-1).
|
|
EOF
|
|
cat > raw/beta-v1.md <<'EOF'
|
|
Evidenz v1: Beta-Thema (Stelle S-1).
|
|
EOF
|
|
git add -A
|
|
git commit -qm "Baseline" || hardfail "Baseline-Commit fehlgeschlagen"
|
|
BASE=$(git rev-parse HEAD)
|
|
[ -n "$BASE" ] || hardfail "Baseline-Commit nicht auflösbar"
|
|
echo "BASELINE-COMMIT: $BASE"
|
|
echo
|
|
runlabel() { echo; echo "########## $1 ##########"; }
|
|
RG() { if command -v rg >/dev/null; then rg "$@"; else grep -rln "$@"; fi; }
|
|
# Isolation: Worktree auf BASE zuruecksetzen (kein Carry-over ueber Szenarien)
|
|
isolate() { git checkout -q -b "$1" "$BASE" 2>/dev/null || git checkout -q "$1"; git reset -q --hard "$BASE"; git clean -qfd wiki raw; }
|
|
probe() { # Pkt. 5-Probe (D-1-Form): Baseline-Diff + porcelain, normalisiert (wiki/-Praefix + .md gestrippt)
|
|
{ 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
|
|
}
|
|
# expect_eq: $1=Beschreibung, $2=erwartet, $3=ist (jeweils mehrzeilig)
|
|
expect_eq() {
|
|
if [ "$2" = "$3" ]; then pass "$1"; else
|
|
fail "$1 — erwartet: [$2], ist: [$3]"
|
|
fi
|
|
}
|
|
|
|
# =====================================================================
|
|
runlabel "S1: HAPPY_PATH_UPDATE (bestehendes Concept wird im bestehenden Pfad aktualisiert)"
|
|
# Zuwachs: neue committierte Evidenz mit Term-Ueberschneidung
|
|
cat > raw/alpha-v2.md <<'EOF'
|
|
Evidenz v2: quanten-protocol-schlüssel erfaehrt eine Rotation (Stelle S-2).
|
|
EOF
|
|
git add -A; git commit -qm "Zuwachs raw/alpha-v2.md" || hardfail "Zuwachs-Commit fehlgeschlagen"
|
|
# Reconcile: Kandidatenliste (textuell-deterministisch, AD-13)
|
|
echo "--- Kandidaten-Erhebung: rg -l 'quanten-protocol-schlüssel' wiki/ ---"
|
|
RG -l 'quanten-protocol-schlüssel' wiki/ || true
|
|
# Update-Pfad: Mutation im BESTEHENDEN Pfad (Erweitern) + log.md
|
|
cat >> wiki/alpha.md <<'EOF'
|
|
Seit der Rotation (raw/alpha-v2.md#S-2) gelten die Schlüssel neu.
|
|
EOF
|
|
cat >> wiki/log.md <<EOF
|
|
## 2026-08-19
|
|
- Story 3.1-Update: alpha (raw/alpha-v2.md; Baseline $BASE)
|
|
EOF
|
|
echo "--- Probe (git diff --name-only <BASE> -- wiki/ + git status --porcelain -- wiki/, normalisiert) ---"
|
|
S1_PROBE=$(probe)
|
|
echo "$S1_PROBE"
|
|
expect_eq "S1 Probe: genau alpha + log betroffen, beta NICHT" "$(printf 'alpha\nlog')" "$S1_PROBE"
|
|
# Keine neue Datei (Duplikat-Kontrolle): kein ?? unter wiki/
|
|
S1_UNTRACKED=$(git status --porcelain -- wiki/ | grep -c '^??' || true)
|
|
[ "$S1_UNTRACKED" -eq 0 ] && pass "S1 keine neue Datei unter wiki/ (kein Duplikat)" \
|
|
|| fail "S1 unerwartete untracked wiki/-Datei(en): $S1_UNTRACKED"
|
|
# alpha.md existiert exakt 1x
|
|
S1_ALPHA_COUNT=$(git ls-files wiki/alpha.md | wc -l | tr -d ' ')
|
|
[ "$S1_ALPHA_COUNT" -eq 1 ] && pass "S1 alpha.md ist exakt 1x getrackt" \
|
|
|| fail "S1 alpha.md getrackt: $S1_ALPHA_COUNT (erwartet 1)"
|
|
|
|
# =====================================================================
|
|
runlabel "S2: UNTOUCHED_CONCEPT (neue Evidenz betrifft kein bestehendes Concept)"
|
|
isolate s2
|
|
cat > raw/gamma.md <<'EOF'
|
|
Evidenz: vollstaendig neues gamma-observatorium-thema (Stelle S-1).
|
|
EOF
|
|
git add -A; git commit -qm "Zuwachs raw/gamma.md"
|
|
echo "--- Kandidaten-Erhebung: rg -l 'gamma-observatorium-thema' wiki/ ---"
|
|
RG -l 'gamma-observatorium-thema' wiki/ || echo "(leer — kein Kandidat)"
|
|
# Folge: keine Mutation, kein log.md-Zusatz (UNTOUCHED_CONCEPT)
|
|
S2_PROBE=$(probe)
|
|
echo "--- Probe: [$S2_PROBE] ---"
|
|
expect_eq "S2 Probe: leer (kein Ghost-Diff, UNTOUCHED_CONCEPT)" "" "$S2_PROBE"
|
|
S2_LOG_DIFF=$(git diff "$BASE" -- wiki/log.md | wc -l | tr -d ' ')
|
|
[ "$S2_LOG_DIFF" -eq 0 ] && pass "S2 log.md unverändert (kein Eintrag ohne Kandidat)" \
|
|
|| fail "S2 log.md mutierte ohne Kandidat (S2_LOG_DIFF=$S2_LOG_DIFF)"
|
|
|
|
# =====================================================================
|
|
runlabel "S3: CONCEPT_COLLISION_BESTEHEND (Zielpfad belegt -> Update-Routing, kein Duplikat)"
|
|
isolate s3
|
|
cat > raw/alpha-v2.md <<'EOF'
|
|
Evidenz v2: quanten-protocol-schlüssel (Stelle S-2, ergaenzend).
|
|
EOF
|
|
git add -A; git commit -qm "Zuwachs"
|
|
echo "--- Vor-Mutation-Check: Ziel-Pfad wiki/alpha.md belegt? ---"
|
|
test -f wiki/alpha.md && echo "JA — Update-Routing (kein Duplikat, kein stummer Ueberschreiben)" \
|
|
|| fail "S3 Zielpfad wiki/alpha.md nicht belegt (Szenario-Setup verletzt)"
|
|
echo "--- Vor-Mutation-Zustand (muss leer sein) ---"
|
|
S3_PRE=$(git status --porcelain -- wiki/)
|
|
echo "$S3_PRE"
|
|
[ -z "$S3_PRE" ] && pass "S3 Vor-Mutation-Zustand leer" || fail "S3 Vor-Mutation-Zustand nicht leer: $S3_PRE"
|
|
# Mutation im bestehenden Pfad (Update)
|
|
echo "Ergaenzung (raw/alpha-v2.md#S-2)." >> wiki/alpha.md
|
|
echo "## 2026-08-19" >> wiki/log.md; echo "- Story 3.1-Update: alpha (raw/alpha-v2.md)" >> wiki/log.md
|
|
echo "--- Nach-Mutation: nur M-Eintraege, KEIN ?? (keine neue Datei = kein Duplikat) ---"
|
|
S3_PORC=$(git status --porcelain -- wiki/)
|
|
echo "$S3_PORC"
|
|
S3_UNTRACKED=$(echo "$S3_PORC" | grep -c '^??' || true)
|
|
[ "$S3_UNTRACKED" -eq 0 ] && pass "S3 keine ??-Einträge (kein Duplikat)" \
|
|
|| fail "S3 unerwartete ??-Einträge: $S3_PORC"
|
|
S3_ONLY_M=$(echo "$S3_PORC" | grep -cv '^ M ' || true)
|
|
[ -n "$S3_PORC" ] && [ "$S3_ONLY_M" -eq 0 ] && pass "S3 nur M-Einträge (Update im bestehenden Pfad)" \
|
|
|| fail "S3 Porcelain enthält Einträge außerhalb ' M ' (nur-$S3_ONLY_M-Andere)"
|
|
S3_PROBE=$(probe)
|
|
expect_eq "S3 Probe: genau alpha + log" "$(printf 'alpha\nlog')" "$S3_PROBE"
|
|
|
|
# =====================================================================
|
|
runlabel "S4: CHANGE_DETECTION (R-1: nur der Zuwachs wird als Evidenz interpretiert)"
|
|
isolate s4
|
|
cat > raw/alpha-v2.md <<'EOF'
|
|
Evidenz v2: nur diese Datei ist neu (Stelle S-2).
|
|
EOF
|
|
git add -A; git commit -qm "Zuwachs"
|
|
echo "--- git diff --name-only <BASE> -- raw/ ---"
|
|
S4_ADD=$(git diff --name-only "$BASE" -- raw/)
|
|
echo "$S4_ADD"
|
|
expect_eq "S4 Zuwachs: ausschließlich raw/alpha-v2.md" "raw/alpha-v2.md" "$S4_ADD"
|
|
echo "--- SHA-256-Abgleich (Sekundaer-Fingerprint, D-2): alpha-v1 unveraendert? ---"
|
|
S4_SHA_NOW=$(sha256sum raw/alpha-v1.md | cut -d' ' -f1)
|
|
S4_SHA_BASE=$(git show "$BASE:raw/alpha-v1.md" | sha256sum | cut -d' ' -f1)
|
|
echo "$S4_SHA_NOW / $S4_SHA_BASE"
|
|
[ -n "$S4_SHA_NOW" ] && [ "$S4_SHA_NOW" = "$S4_SHA_BASE" ] \
|
|
&& pass "S4 raw/alpha-v1.md byte-identisch zur Baseline (Immutabilität)" \
|
|
|| fail "S4 raw/alpha-v1.md weicht von der Baseline ab ($S4_SHA_NOW != $S4_SHA_BASE)"
|
|
|
|
# =====================================================================
|
|
runlabel "S5: PRE_RUN_RECONCILE (Check-Block vor Mutation; fehlende Bundleroot -> Run-FAIL V-1)"
|
|
isolate s5
|
|
rm wiki/index.md # Szenario-Setup: Bundleroot fehlt (simuliert, kein Run-Zustand)
|
|
echo "--- Check-Block: (4) wiki/index.md-V-1-Vorbedingung ---"
|
|
if [ -f wiki/index.md ]; then
|
|
echo "OK"
|
|
fail "S5 V-1-Vorbedingung: wiki/index.md fehlt nicht — Szenario-Setup verletzt"
|
|
else
|
|
echo "Run-FAIL (V-1, Vertrag §2): wiki/index.md fehlt — keine Mutation darf erfolgen"
|
|
pass "S5 V-1-Check löst Run-FAIL (fehlende Bundleroot)"
|
|
fi
|
|
git checkout -q "$BASE" -- wiki/index.md # Setup-Rueckstellung (kein Run-Zustand)
|
|
echo "--- Zustand nach Abbruch + Rueckstellung (muss leer sein — der Run selbst mutierte nichts) ---"
|
|
S5_PORC=$(git status --porcelain -- wiki/)
|
|
echo "$S5_PORC"
|
|
[ -z "$S5_PORC" ] && pass "S5 Zustand nach Abbruch leer (keine Mutation erfolgt)" \
|
|
|| fail "S5 Zustand nach Abbruch nicht leer: $S5_PORC"
|
|
|
|
# =====================================================================
|
|
runlabel "S6: INPUT_UNCOMMITTED (D-3: Working-Copy vs. HEAD-Check -> benannter Abbruch)"
|
|
isolate s6
|
|
echo "uncommittete Zwischenstunde" >> raw/alpha-v1.md # simuliert Dirty-Tree
|
|
echo "--- Check-Block: Working-Copy vs. HEAD fuer raw/ + wiki/ ---"
|
|
DIRTY=$(git status --porcelain -- raw/ wiki/)
|
|
if [ -z "$DIRTY" ]; then
|
|
echo "OK — published/committed Input"
|
|
fail "S6 Dirty-Tree nicht erkannt (Abbruch hätte greifen müssen)"
|
|
else
|
|
echo "Abbruch: published/committed Input erforderlich (AD-17a) — ungepublishter Zustand:"
|
|
echo "$DIRTY"
|
|
pass "S6 INPUT_UNCOMMITTED-Abbruch greift (benannter Abbruch, keine Mutation)"
|
|
fi
|
|
|
|
echo
|
|
echo "########## EMBEDDED-EXIT ##########"
|
|
echo "FAILED=$FAILED PASS_COUNT=$PASS_COUNT"
|
|
if [ "$FAILED" -eq 0 ]; then
|
|
echo "SANDBOX-3-1-OK"
|
|
exit 0
|
|
else
|
|
echo "SANDBOX-3-1-FAILED" >&2
|
|
exit 1
|
|
fi
|