#!/usr/bin/env bash # Story 3.3 — Sandbox-Tests der operationellen Update-Formen (§5.9 Pkt. 2, Revision 2.8) # Re-executierbar: bash run-sandbox.sh (ab Workspace-Root; Sandbox unter /tmp/sb33) # Zweck: alle drei Update-Formen (Erweitern + Präzisieren + Korrigieren) + No-Op # durchspielen; die Erhaltungs-Invariante (§5.9 Pkt. 5) als HARDE Assertion # erzwingen (Diff nach Normalisierung ⊆ {betroffener Concept-Pfad, log}; keine # neue Datei; kein Ghost-Diff); Zwei-Run-Identität (AD-17h/A0-19); # Frontmatter-Konformität je mutiertem Concept (Vertrag §3.3/§3.4-Subset). # Linux-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale wiki/-Baum. set -u ROOT=$(mktemp -d /tmp/sb33-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" # ---------- Basis-Baum (committete Ausgangslage = Baseline-Commit) ---------- # Concept alpha mit drei belegten Aussagen; Aussagen 1/2 sind fachlich korrekt, # Aussage 3 ist fehlerhaft (Korrigieren-Ziel des Szenarios U3). beta ist ein # nicht-betroffenes Kontroll-Concept (Ghost-Diff-Kontrolle, U5). 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 deterministische-init-sequenz für den Abgleich (raw/alpha-v1.md#S-1). Alpha läuft ausschließlich auf isolierten Netzen (raw/alpha-v1.md#S-3). Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2). 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' ### S-1 Evidenz v1: deterministische-init-sequenz für den Abgleich. ### S-2 Evidenz v1: keine Rotation der Schlüssel. ### S-3 Evidenz v1: Alpha läuft auf isolierten Netzen. EOF cat > raw/beta-v1.md <<'EOF' ### S-1 Evidenz v1: Beta-Thema. EOF git add -A git commit -qm "Baseline" BASE=$(git rev-parse HEAD) echo "BASELINE-COMMIT: $BASE" echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)" echo runlabel() { echo; echo "########## $1 ##########"; } # 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; } # Pkt.-5-Probe (D-1-Form): Baseline-Diff + porcelain, normalisiert # (wiki/-Praefix + .md-Suffix gestrippt, LC_ALL=C-sortiert; deterministisch, AD-17h) 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) ---------- # Erwartete erlaubte Menge = Space-getrennte normalisierte Pfade # (z. B. "alpha log"). Jeder Proben-Eintrag MUSS in der erlaubten Menge liegen — # sonst Ghost-Diff (nicht betroffener Pfad) → HARD-FAIL, Exit 1 (NFR-4/FT-6). assert_invariant() { local expected="$1" got p bad=0 rcs=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 # Keine neue Datei (Duplikat-Kontrolle: die ??-Sicht fehlt git diff allein) rcs=$(git status --porcelain -- wiki/ | grep -c '^??' || true) [ "$rcs" -eq 0 ] || { echo "HARD-FAIL (keine neue Datei): $rcs ungetrackte neue Datei(en) unter wiki/ (Duplikat/Ghost-Diff)" >&2; bad=1; } if [ "$bad" -eq 0 ]; then echo "RESULT: PASS — Probe {$got} ⊆ erlaubte Menge {$expected}; keine neue Datei; kein Ghost-Diff" else exit 1 fi } # ---------- Frontmatter-Konformitaet je mutiertem Concept (Vertrag §3.3/§3.4, §6.5) ---------- # $1=Datei; $2...=erwartete sources[].resource-Werte. Prueft: Top-Level-Key-Subset # {type,sources,generated,verified,status,stale_after}, sources-Eintrag-Key-Subset # (Vertrag §3.3-Innen-Ebene), type=concept, generated.at = volle ISO-8601-Datetime # (die erlaubten Key-Mengen sind inline im awk-Subset-Vergleich hartkodiert). assert_frontmatter() { local f="$1"; shift local r bad=0 # Kontextuelle Validierung ueber awk: Top-Level-Subset {type,sources,generated, # verified,status,stale_after}; Innen-Ebenen je Sektion — sources: Vertrag §3.3- # Subset {resource,id,title,author,usage_count,last_modified}; generated/verified: # {by,at} (Vertrag §3.4/§3.5). Jeder andere Key = unbefugt (Punkt 6, §6.5). 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 # Duplikat-Prohibition: jeder Top-Level-Key hoechstens einmal (Punkt 13). if (seenk[k]++) print "DUP_KEY:" k # Canonische Reihenfolge (Vertrag §3.x Normalform: type, sources, generated, # verified, status, stale_after): jeder neue Key-Kandidat muss der canonichen # Ordnung folgen — Verstoß via Ordnungs-Rang erkannt (ORDER_VIOLATION). 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 && r0) 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)" } # ---------- Update-Helfer (deterministisch; at gepinnt fuer Zwei-Run-Identitaet) ---------- AT_NEW="2026-08-19T12:00:00Z" bump_at() { sed -i "s|^ at: .*| at: $AT_NEW|" "$1"; } add_source() { # $1=Datei $2=resource $3=id (Eintrag vor der generated:-Zeile einfuegen) sed -i "s|^generated:| - resource: $2\n id: $3\ngenerated:|" "$1" } log_update() { # $1=Concept-Pfad $2=raw-Datei printf '\n## 2026-08-19\n- Story 3.1-Update: %s (%s; Baseline %s)\n' "$1" "$2" "$BASE" >> wiki/log.md } # ===================================================================== runlabel "U1: ERWEITERN — neue belegte Aussage, bestehender Pfad wird erweitert (AC-1/FR-6)" isolate u1 cat > raw/alpha-v2.md <<'EOF' ### S-4 Evidenz v2 (neue Aussage): Alpha-Replikation traegt einen zusaetzlichen Schluessel-Rotationszyklus. EOF git add -A; git commit -qm "Zuwachs raw/alpha-v2.md" echo "--- Kandidaten-Erhebung: rg -l 'schluessel-rotationszyklus' wiki/ ---" if command -v rg >/dev/null 2>&1; then rg -l 'schluessel-rotationszyklus' -g '!log.md' wiki/ || true else grep -rl 'schluessel-rotationszyklus' --exclude=log.md wiki/ || true; fi echo "--- UPDATE: neue Aussage als Absatz angefuegt (§5.5-Inline-Beleg), sources-Zuwachs s2, at-Bump ---" cat >> wiki/alpha.md <<'EOF' Alpha führt für die Replikation einen zusätzlichen Schlüssel-Rotationszyklus (raw/alpha-v2.md#S-4). EOF add_source wiki/alpha.md raw/alpha-v2.md s2 bump_at wiki/alpha.md log_update alpha raw/alpha-v2.md echo "--- Struktur-Erhaltung: bestehende drei Aussagen byte-identisch erhalten? ---" grep -qF 'Das Alpha-Protokoll verwendet deterministische-init-sequenz für den Abgleich (raw/alpha-v1.md#S-1).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 1 wurde beim Erweitern umgeschrieben" >&2; exit 1; } grep -qF 'Alpha läuft ausschließlich auf isolierten Netzen (raw/alpha-v1.md#S-3).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 2 (Netze) wurde beim Erweitern umgeschrieben" >&2; exit 1; } grep -qF 'Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 3 wurde beim Erweitern umgeschrieben" >&2; exit 1; } echo "RESULT: PASS — bestehende belegte Aussagen unveraendert (Struktur-Erhaltungsregel Erweitern)" echo "--- Probe (Pkt. 5, vor dem Commit) ---"; probe assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md # ===================================================================== runlabel "U2: PRAEZISIEREN — bestehende Aussage wird an ihr selbst geschaerft (AC-2/FR-6)" isolate u2 cat > raw/alpha-v2.md <<'EOF' ### S-1 Evidenz v2 (Praezisierung): die deterministische-init-sequenz wird nach der initialen Synchronisation zusaetzlich rotiert. EOF git add -A; git commit -qm "Zuwachs raw/alpha-v2.md" echo "--- UPDATE: Aussage 1 an Position geschaerft, Beleg nachgefuehrt (Multi-Beleg §5.5); kein Satz-Umbau ---" sed -i 's|^Das Alpha-Protokoll verwendet deterministische-init-sequenz für den Abgleich (raw/alpha-v1.md#S-1)\.|Das Alpha-Protokoll verwendet deterministische-init-sequenz für den Abgleich und rotiert sie nach der initialen Synchronisation zusätzlich (raw/alpha-v1.md#S-1; raw/alpha-v2.md#S-1).|' wiki/alpha.md add_source wiki/alpha.md raw/alpha-v2.md s2 bump_at wiki/alpha.md log_update alpha raw/alpha-v2.md echo "--- Struktur-Erhaltung: Aussagen 2/3 unveraendert, geschaerfte Aussage 1 an Position? ---" grep -qF 'Das Alpha-Protokoll verwendet deterministische-init-sequenz für den Abgleich und rotiert sie nach der initialen Synchronisation zusätzlich (raw/alpha-v1.md#S-1; raw/alpha-v2.md#S-1).' wiki/alpha.md || { echo "HARD-FAIL: geschaerfte Aussage fehlt" >&2; exit 1; } grep -qF 'Alpha läuft ausschließlich auf isolierten Netzen (raw/alpha-v1.md#S-3).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 2 wurde beim Praezisieren veraendert" >&2; exit 1; } grep -qF 'Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 3 wurde beim Praezisieren veraendert" >&2; exit 1; } echo "RESULT: PASS — Schaerfung an der Aussage selbst, Position/Struktur erhalten, kein Satz-Umbau" echo "--- Probe ---"; probe assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md # ===================================================================== runlabel "U3: KORRIGIEREN — fehlerhafte Aussage abgeloest, nicht still geloescht (AC-2, AD-16-Default)" isolate u3 cat > raw/alpha-v2.md <<'EOF' ### S-2 Evidenz v2 (Korrektur): Alpha rotiert seine Schluessel bei jeder Sitzung. EOF git add -A; git commit -qm "Zuwachs raw/alpha-v2.md" echo "--- UPDATE: Aussage 3 wird explizit abgeloest + Ersetzungsbeleg; keine stille Loeschung ---" sed -i 's|^Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2)\.|Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2) — überholt durch: Alpha rotiert seine Schlüssel bei jeder Sitzung (raw/alpha-v2.md#S-2).|' wiki/alpha.md add_source wiki/alpha.md raw/alpha-v2.md s2 bump_at wiki/alpha.md log_update alpha raw/alpha-v2.md echo "--- AD-16-Default: alte Aussagen 1/2 textuell erhalten (keine stille Loeschung, keine flankierende Umschreibung)? ---" grep -qF 'Das Alpha-Protokoll verwendet deterministische-init-sequenz für den Abgleich (raw/alpha-v1.md#S-1).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 1 wurde beim Korrigieren flankierend umgeschrieben" >&2; exit 1; } grep -qF 'Alpha läuft ausschließlich auf isolierten Netzen (raw/alpha-v1.md#S-3).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 2 wurde beim Korrigieren flankierend umgeschrieben" >&2; exit 1; } grep -qF 'Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2)' wiki/alpha.md || { echo "HARD-FAIL: alte Aussage wurde still geloescht oder ihr Wortlaut verändert (AD-16, Struktur-Erhaltungsregel Korrigieren)" >&2; exit 1; } grep -qF 'rotiert seine Schlüssel bei jeder Sitzung (raw/alpha-v2.md#S-2)' wiki/alpha.md || { echo "HARD-FAIL: Ersetzungsbeleg fehlt" >&2; exit 1; } echo "RESULT: PASS — Abloesung mit Ersetzungsbeleg, Provenienz erhalten (AD-16-Default Erhaltung)" echo "--- Probe ---"; probe assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md # ===================================================================== runlabel "U4: NO_OP — Evidenz ist bereits vollstaendig im Body (engere Auslegung, Pkt. 2)" isolate u4 cat > raw/alpha-v2.md <<'EOF' Evidenz v2 (Redundanz): deterministische-init-sequenz fuer den Abgleich; Alpha rotiert seine Schluessel nie. EOF git add -A; git commit -qm "Zuwachs raw/alpha-v2.md" echo "--- Kandidaten-Erhebung: Terme treffen alpha; die Evidenz ist bereits vollstaendig enthalten ---" echo "--- UPDATE: KEINE Body-Mutation, KEIN at-Bump, KEIN sources-Zusatz, KEIN log.md-Eintrag (byte-identisch) ---" if git status --porcelain -- wiki/ | grep -q .; then echo "HARD-FAIL (No-Op): Wiki-Baum ist nicht byte-identisch" >&2 git status --porcelain -- wiki/ exit 1 fi echo "RESULT: PASS — No-Op: keine Mutation, kein at-Bump, kein sources-Zusatz, kein log.md-Eintrag (byte-identisch)" echo "--- Probe (leer = Ghost-Diff-negativ, leere Menge ist Teilmenge jeder erlaubten Menge) ---"; probe assert_invariant "" # ===================================================================== runlabel "U5: NEGATIV-KONTROLLE — Assertions-Mechanik erkennt einen Ghost-Diff (nicht vacuous)" isolate u5 echo "unbefugte Mutation auf nicht-betroffenem beta" >> wiki/beta.md # simulierter Ghost-Diff echo "--- Probe (erwartet: beta ausserhalb der erlaubten Menge {alpha log}) ---"; probe if ( assert_invariant "alpha log" ) >/dev/null 2>&1; then echo "HARD-FAIL (Assertions-Mechanik): Ghost-Diff auf beta wurde NICHT erkannt" >&2 exit 1 else echo "RESULT: PASS — Ghost-Diff auf beta wurde erkannt (Assertions-Mechanik loest verlaesslich HARD-FAIL aus, kein Ghost-Diff kommt durch)" fi # ===================================================================== runlabel "U6: ZWEI-RUN-IDENTITAET (AD-17h/A0-19) — gleicher Git-State + gleiches Eingabeset -> identischer Update-Vorgang" # Zwei unabhaengige Runs ueber dieselbe Evidenz (Erweitern); die Ergebnisse # (mutierter Body + Frontmatter + Status) muessen byte-identisch sein. run_erweitern() { # $1 = Branchname; mutiert Worktree, dann git add -A (Staging) isolate "$1" cat > raw/alpha-v2.md <<'EOF' ### S-4 Evidenz v2 (neue Aussage): Alpha-Replikation traegt einen zusaetzlichen Schluessel-Rotationszyklus. EOF git add -A; git commit -qm "Zuwachs raw/alpha-v2.md" cat >> wiki/alpha.md <<'EOF' Alpha führt für die Replikation einen zusätzlichen Schlüssel-Rotationszyklus (raw/alpha-v2.md#S-4). EOF add_source wiki/alpha.md raw/alpha-v2.md s2 bump_at wiki/alpha.md log_update alpha raw/alpha-v2.md git add -A # Staging — die Mutationen sind Teil des Runs (Commit-Boundary = Mutations-Boundary) } run_erweitern u6a A_ALPHA=$(sha256sum wiki/alpha.md | cut -d' ' -f1) # Worktree-Inhalt = staged-Inhalt (git add) A_LOG=$(sha256sum wiki/log.md | cut -d' ' -f1) git commit -qm "Run A (Erweitern)" A_ALPHA_COM=$(git show HEAD:wiki/alpha.md | sha256sum | cut -d' ' -f1) run_erweitern u6b B_ALPHA=$(sha256sum wiki/alpha.md | cut -d' ' -f1) B_LOG=$(sha256sum wiki/log.md | cut -d' ' -f1) git commit -qm "Run B (Erweitern)" B_ALPHA_COM=$(git show HEAD:wiki/alpha.md | sha256sum | cut -d' ' -f1) echo "Run A (alpha.md): $A_ALPHA" echo "Run B (alpha.md): $B_ALPHA" echo "Run A (log.md): $A_LOG" echo "Run B (log.md): $B_LOG" echo "Run A commit (alpha.md): $A_ALPHA_COM ; Run B commit (alpha.md): $B_ALPHA_COM" if [ "$A_ALPHA" = "$B_ALPHA" ] && [ "$A_LOG" = "$B_LOG" ] && [ "$A_ALPHA_COM" = "$B_ALPHA_COM" ]; then echo "RESULT: PASS — zwei unabhaengige Runs ueber dieselbe Evidenz -> identischer Update-Vorgang (AD-17h/A0-19)" else echo "HARD-FAIL (Determinismus-Vertrag): Run A und Run B weichen ab" >&2 exit 1 fi # ===================================================================== runlabel "U7: MEHRFACH_TREFFER — zwei Neuevidenzen desselben Runs treffen denselben Concept-Pfad (Konsolidierung, I/O-Matrix)" # Matrix-Zeile MEHRFACH_TREFFER: mehrere neue Wissenseinheiten desselben Runs auf # denselben Pfad -> EIN konsolidiertes Update (eine Body-Mutation, EIN log.md-Eintrag, # EIN konsolidierter sources-Zuwachs, EIN generated.at). Reihenfolge = Zuwachs-Sicht # (Ankunftsreihenfolge der Belege); lexikografischer Tie-Break bei identischem Ort # (Body-Ende) -> alpha-v2.md vor alpha-v3.md. isolate u7 cat > raw/alpha-v2.md <<'EOF' ### S-4 Evidenz v2 (neue Aussage): Alpha-Replikation nutzt Quorum-Bestaetigung. EOF cat > raw/alpha-v3.md <<'EOF' ### S-4 Evidenz v3 (neue Aussage): Alpha-Replikation waechst linear zum Cluster. EOF git add -A; git commit -qm "Zwei Einheiten, ein Run (raw/alpha-v2.md + raw/alpha-v3.md)" echo "--- Kandidaten-Erhebung: beide Terme treffen denselben Pfad alpha ---" echo "--- KONSOLIDIERTES UPDATE: beide Aussagen als Absaetze angehaengt (Zuwachs-Sicht: v2 vor v3), EIN log-Eintrag, sources-Zuwachs s2+s3, EIN at ---" cat >> wiki/alpha.md <<'EOF' Alpha-Replikation nutzt Quorum-Bestaetigung (raw/alpha-v2.md#S-4). Alpha-Replikation waechst linear zum Cluster (raw/alpha-v3.md#S-4). EOF add_source wiki/alpha.md raw/alpha-v2.md s2 add_source wiki/alpha.md raw/alpha-v3.md s3 bump_at wiki/alpha.md log_update alpha "raw/alpha-v2.md + raw/alpha-v3.md" echo "--- Konsolidierung: genau EIN log.md-Eintrag und EIN generated.at trotz zweier Einheiten? ---" [ "$(grep -c 'Story 3.1-Update: alpha' wiki/log.md)" -eq 1 ] || { echo "HARD-FAIL: Mehrfach-Treffer erzeugte nicht exakt einen log.md-Eintrag (Konsolidierung oder Eintragspflicht Pkt. 4 verletzt)" >&2; exit 1; } grep -qF 'raw/alpha-v2.md' wiki/log.md || { echo "HARD-FAIL: konsolidierter log.md-Eintrag verlinkt raw/alpha-v2.md nicht (Pkt. 4, genutzte raw/-Quellen)" >&2; exit 1; } grep -qF 'raw/alpha-v3.md' wiki/log.md || { echo "HARD-FAIL: konsolidierter log.md-Eintrag verlinkt raw/alpha-v3.md nicht (Pkt. 4, genutzte raw/-Quellen)" >&2; exit 1; } [ "$(grep -c '^ at:' wiki/alpha.md)" -eq 1 ] || { echo "HARD-FAIL: Mehrfach-Treffer erzeugte mehrere generated.at" >&2; exit 1; } echo "--- Struktur-Erhaltung: alte Aussagen byte-identisch, beide neuen Aussagen vorhanden, Zuwachs-Sicht-Ordnung v2-vor-v3 ---" grep -qF 'Das Alpha-Protokoll verwendet deterministische-init-sequenz für den Abgleich (raw/alpha-v1.md#S-1).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 1 wurde beim konsolidierten Update umgeschrieben" >&2; exit 1; } grep -qF 'Alpha läuft ausschließlich auf isolierten Netzen (raw/alpha-v1.md#S-3).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 2 wurde beim konsolidierten Update umgeschrieben" >&2; exit 1; } grep -qF 'Alpha rotiert seine Schlüssel nie (raw/alpha-v1.md#S-2).' wiki/alpha.md || { echo "HARD-FAIL: Aussage 3 wurde beim konsolidierten Update umgeschrieben" >&2; exit 1; } grep -qF 'Quorum-Bestaetigung (raw/alpha-v2.md#S-4)' wiki/alpha.md || { echo "HARD-FAIL: neue Aussage aus v2 fehlt" >&2; exit 1; } grep -qF 'waechst linear zum Cluster (raw/alpha-v3.md#S-4)' wiki/alpha.md || { echo "HARD-FAIL: neue Aussage aus v3 fehlt" >&2; exit 1; } v2pos=$(grep -n 'Quorum-Bestaetigung' wiki/alpha.md | cut -d: -f1); v3pos=$(grep -n 'waechst linear' wiki/alpha.md | cut -d: -f1) [ "$v2pos" -lt "$v3pos" ] || { echo "HARD-FAIL: Zuwachs-Sicht-Ordnung verletzt (v3 vor v2)" >&2; exit 1; } echo "RESULT: PASS — ein konsolidiertes Update (eine Body-Aenderung, ein log-Eintrag, ein sources-Zuwachs s2+s3, ein at); Zuwachs-Sicht-Ordnung v2-vor-v3" echo "--- Probe ---"; probe assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md raw/alpha-v3.md # ===================================================================== runlabel "U8: STRUKTUR-VERLETZUNG — unbefugter Frontmatter-Key wird erkannt (Pkt. 5 Struktur-Ebene, P2-Check-Element (6))" isolate u8 echo "--- simulierter Verstoß gegen die Struktur-Erhaltung: unbefugter Frontmatter-Key 'foo' im YAML-Block ---" awk '/^type: concept$/{print; print "foo: bar"; next} {print}' wiki/alpha.md > /tmp/sb33-fm && mv /tmp/sb33-fm wiki/alpha.md echo "--- Probe + Frontmatter-Konformität (erwartet: HARD-FAIL, Verstoß textuell benannt, NFR-4) ---"; probe if ( assert_invariant "alpha log" && assert_frontmatter wiki/alpha.md ) >/dev/null 2>&1; then echo "HARD-FAIL (Struktur-Ebene): unbefugter Frontmatter-Key wurde NICHT erkannt (Pkt. 5/Pkt. 6-Element (6))" >&2 exit 1 else echo "RESULT: PASS — unbefugter Frontmatter-Key wird als Struktur-Verstoß erkannt (Frontmatter-Subset-HARD-FAIL ausgelöst)" fi # ===================================================================== runlabel "U9: NEUE-DATEI — ungetrackte neue Datei unter wiki/ wird erkannt (??-Sicht, Duplikat-Kontrolle)" isolate u9 echo "--- simulierter Ghost-Diff: ungetrackte neue Datei wiki/neu.md (Duplikat, ??-Sicht) ---" echo "unbefugte neue Concept-Datei" > wiki/neu.md echo "--- Probe (erwartet: neu ausserhalb erlaubter Menge + ??-Sicht-HARD-FAIL) ---"; probe if ( assert_invariant "alpha log" ) >/dev/null 2>&1; then echo "HARD-FAIL (Keine-neue-Datei): ungetrackte neue Datei wiki/neu.md wurde NICHT erkannt (??-Sicht, Duplikat-Kontrolle)" >&2 exit 1 else echo "RESULT: PASS — ungetrackte neue Datei unter wiki/ wird über die ??-Sicht erkannt (Duplikat/Ghost-Diff, keine neue Datei)" fi echo echo "===== Sandbox abgeschlossen (alle 9 Tests U1-U9) =====" echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)"