Files

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