#!/usr/bin/env bash # Story 3.5 — Sandbox-Tests der Leasing-/Dirty-Tree-Dimension (§5.11, Revision 3.0) # Re-executierbar: bash run-sandbox.sh (ab Workspace-Root; Sandbox unter /tmp/sb35) # Zweck: die Koordinations-Mechanik fuer konkurrierende Producer (§5.11) als # re-executierbarer Run-Demonstrator durchspielen — # L1 LEASE_AKQUISE (lease//-Branch, Lockfile, Merge-Base-Disziplin; # AC-1, AD-17a, A0-12), # L2 LEASE_HOLD (Lockfile existiert -> Lease-Hold, kein Ueberschreiben, keine # Mutation; I/O-Matrix LEASE_AKQUISE-Error-Handling), # L3 ROOT_SCOPE (wiki/ inkl. log.md, index.md, aller Root-Dateien; kein Bereich # jenseits wiki/; AC-2, AD-17b, A0-13), # L4 DIRTY_TREE_SCHUTZ (Pre-Mutation-Pruefung, Stash/Scratch-Zone, log.md- # Dokumentation; fremde uncommittete Aenderung wird NIE geloescht — # Negativ-Kontrolle; UNCOMMITTED_INPUT-Abbruch; AC-3, AD-17e/f, A0-16), # L5 NO_AUTO_MERGE (kein textueller Auto-Merge bei ungleichem Pfad-Inhalt; # compiler-vermittelter AD-16-Pfad mit log.md-Eintrag, Default Erhaltung; # Eskalation AD-17g; AC-4, AD-17c, A0-14), # L6 COMMIT_BOUNDARY (Commit-Boundary = Mutations-Boundary; Verletzung -> # HARD-FAIL-Detektion; Rollback §5.3), # N1 ??-GHOST-DIFF-Negativkontrolle (ungetrackte Nicht-Ziel-Datei unter wiki/), # D1 DETERMINISMUS (AD-17h/A0-19: Lockfile-Inhalt + Merge-Klassifikation # deterministisch aus dem committeten Git-State; Zwei-Run-Identitaet). # Erhaltungs-Invariante (§5.9 Pkt. 5 / AD-5 / FT-6) als HARDE Assertion je # Leasing-faehigem Run; Frontmatter-Konformitaet (Vertrag §3.3/§3.4-Subset, # P2-Element (6)) je erzeugtem/aktualisiertem Concept (Muster Story-3.4-Sandbox). # Linux-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale wiki/-Baum. set -u ROOT=$(mktemp -d /tmp/sb35-XXXXXX) SB="$ROOT/sb" mkdir -p "$SB/wiki" "$SB/raw" "$SB/lease" "$SB/scratch" cd "$SB" git init -q 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 + gamma als nicht-betroffene 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 runlabel() { echo; echo "########## $1 ##########"; } # Isolation: Worktree auf BASE zuruecksetzen (kein Carry-over ueber Szenarien); # jede Akquise startet von derselben Merge-Base aus (deterministisch, AD-17h). # Szenarien-lokale Leasing-/Tmp-Branches (lease/*, tmp/*) aus dem VORIGEN Szenario # werden entfernt, damit Branch-Namen wie lease/wiki/run-a szenarien-uebergreifend # wiederverwendbar sind (Determinismus: gleicher Startzustand je Szenario). # -f erzwingt den Checkout auch bei uncommitteten Resten aus dem Vorszenario # (z.B. nach einer abgebrochenen Merge-Simulation) — kein Fehlerpfad nach aussen. isolate() { git checkout -qf -B "$1" "$BASE" git for-each-ref --format='%(refname:short)' refs/heads/lease refs/heads/tmp 2>/dev/null | while read b; do git branch -D "$b" >/dev/null 2>&1 || true done git reset -q --hard "$BASE" git clean -qfd wiki raw lease scratch } # 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. 8)" >&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 } assert_frontmatter_ok() { ( assert_frontmatter "$@" ) >/dev/null 2>&1 } # ---------- Frontmatter-Konformitaet (Vertrag §3.3/§3.4, §6.5; Muster Story-3.4) ---------- assert_frontmatter() { local f="$1"; shift local r bad=0 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 && 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)" } # ---------- Leasing-Helfer (§5.11; deterministisch, AD-17h/A0-19) ---------- # Lockfile-Format (Pkt. 1: semantisch identisch in jedem Adapter, A0-12): # area: # id: # producer: # baseline_commit: # holder_id: # Lockfile liegt AUSSERHALB von wiki/ und raw/ (lease//.lock) — # Root-Scope-Lease bindet den Bereich, nicht den Lockfile-Pfad (§5.11 Pkt. 2/7). lock_write() { # $1=area $2=id $3=producer $4=holder_id $5=baseline_commit local f="lease/$1/$2.lock" { echo "area: $1"; echo "id: $2"; echo "producer: $3"; echo "baseline_commit: $5"; echo "holder_id: $4"; } > "$f" } lock_exists() { [ -f "lease/$1/$2.lock" ]; } lock_holder() { grep '^holder_id:' "lease/$1/$2.lock" 2>/dev/null | awk '{print $2}'; } lock_baseline() { grep '^baseline_commit:' "lease/$1/$2.lock" 2>/dev/null | awk '{print $2}'; } # akquire: Lease-Akquise (Pkt. 1) — prueft Lockfile (Lease-Hold, kein Ueberschreiben), # dann Merge-Base-Disziplin (eindeutiger Commit-Object-Wert == $BASE == HEAD des # Merge-Base-Ancestors). Fehler => exit 1 (HARD-FAIL der Assertion im Szenario). akquire() { # $1=area $2=id $3=producer $4=holder_id local area="$1" id="$2" producer="$3" holder="$4" if lock_exists "$area" "$id"; then echo "HARD-FAIL (Lease-Hold): Lockfile lease/$area/$id.lock existiert bereits — Akquise verweigert, kein Ueberschreiben (Pkt. 1)" >&2 return 1 fi mkdir -p "lease/$area" lock_write "$area" "$id" "$producer" "$holder" "$BASE" return 0 } # Dirty-Tree-Schutz (Pkt. 3): Pre-Mutation-Prüfung des Mutationsbereichs gg. HEAD. # $1 = Mutationsbereich (z.B. wiki/), $2 = erlaubte (eigene) Run-Zielfelder als # Leerzeichen-getrennte, wiki-relativ-normalisierte Namen (z.B. "alpha log"). # Ausgabe: 0 = nur eigene/legitime uncommittete Einträge im Bereich (clean), # 1 = mindestens EIN fremder uncommitteter Eintrag (Dirty Tree) — # Schutz nötig (§5.11 Pkt. 3), nie still geloescht (AD-17e). # Normalisierung wie probe(): wiki/-Praefix + .md-Suffix strippen. db_check() { # $1=Bereich $2=legit local legit="$2" p maybe maybe=$(git status --porcelain -- "$1" | awk '{print $2}' | sed -e 's|^wiki/||' -e 's|\.md$||') [ -z "$maybe" ] && return 0 for p in $maybe; do case " $legit " in *" $p "*) : ;; *) return 1 ;; esac done return 0 } # log.md-Leasing-Eintraege (Pkt. 6: Lease-Akquise / Dirty-Tree-Schutz / Merge- # Klassifikation / Eskalation / Freigabe; Baseline-Commit im Eintrag, D-2). # Datumsgruppen-Konvention (Vertrag §5, §5.9 Pkt. 4 / §5.11 Pkt. 6): jeder Eintrag # haengt SEINEN eigenen '## YYYY-MM-DD'-Header + Bullet als Header-Bullet-Paar an # (kein 'printf \n##' je Zeile -> keine doppelten/leeren Header; cumulative append, # neueste Bullets am Ende der Datumsgruppe = deterministisch, AD-17h). log_lease() { # $1=area $2=id $3=holder printf '## 2026-08-19\n- Lease-Akquise: %s/%s durch %s (Baseline %s, §5.11 Pkt. 1/6a)\n' "$1" "$2" "$3" "$BASE" >> wiki/log.md } log_dirty() { # $1=pfad $2=sicherungsziel printf '## 2026-08-19\n- Dirty-Tree-Schutz: %s nach %s gesichert (nie geloescht, §5.11 Pkt. 3/6b)\n' "$1" "$2" >> wiki/log.md } log_merge() { # $1=area $2=id $3=klassifikation $4=begruendung printf '## 2026-08-19\n- Merge-Klassifikation: %s/%s -> %s (%s; AD-16, kein textueller Auto-Merge, §5.11 Pkt. 4/6c)\n' "$1" "$2" "$3" "$4" >> wiki/log.md } log_eskalation() { # $1=area $2=id printf '## 2026-08-19\n- Merge-Eskalation (AD-17g): %s/%s unentscheidbar — menschliche Auflösung erforderlich (§5.11 Pkt. 4/6d)\n' "$1" "$2" >> wiki/log.md } log_release() { # $1=area $2=id $3=holder printf '## 2026-08-19\n- Lease-Freigabe: %s/%s durch %s (Release nach committetem Run, §5.11 Pkt. 1/6e)\n' "$1" "$2" "$3" >> wiki/log.md } # free_lease: deterministische Lease-Freigabe (Pkt. 1, Release) — entfernt das # Lockfile als Freigabe-Marker und dokumentiert den Abschluss in log.md (Pkt. 6e), # nur NACH dem committeten Run (Commit-Boundary, Pkt. 5). Eine inhaertoerfreie # (abgebrochene) Lease verbleibt bis Story-3.6-Staleness — hier deterministisch. free_lease() { # $1=area $2=id $3=holder local f="lease/$1/$2.lock" [ -f "$f" ] || { echo "HARD-FAIL (free_lease): Lockfile existiert nicht — Release einer unakquirierten Lease (Pkt. 1)" >&2; return 1; } log_release "$1" "$2" "$3" rm -f "$f" } # ===================================================================== runlabel "L1: LEASE_AKQUISE (AC-1, AD-17a, A0-12) — Producer erwirbt Lease auf lease//-Branch vom Merge-Base; Lockfile mit eindeutigem Commit-Object-Wert; Root-Scope inkl. log.md/index.md" isolate l1 echo "--- Akquise: Branch lease/wiki/run-a von der Merge-Base ($BASE); Refresh: Freeze-Command-Konvention, Commit-Object-Wert == $BASE (deterministisch aus dem committeten Git-State, AD-17h) ---" git checkout -q -b lease/wiki/run-a "$BASE" akquire wiki run-a "producerA" "run-a-holder" # Assertions Pkt. 1: Branch-Form, Lockfile, Merge-Base-Disziplin [ "$(git branch --show-current)" = "lease/wiki/run-a" ] || { echo "HARD-FAIL (L1): Arbeits-Branch ist nicht lease// (Pkt. 1)" >&2; exit 1; } grep -q '^area: wiki$' lease/wiki/run-a.lock || { echo "HARD-FAIL (L1): Lockfile-Feld area fehlt/falsch (Pkt. 1, A0-12)" >&2; exit 1; } grep -q '^id: run-a$' lease/wiki/run-a.lock || { echo "HARD-FAIL (L1): Lockfile-Feld id fehlt/falsch (Pkt. 1)" >&2; exit 1; } grep -q '^producer: producerA$' lease/wiki/run-a.lock || { echo "HARD-FAIL (L1): Lockfile-Feld producer fehlt/falsch (Pkt. 1)" >&2; exit 1; } [ "$(lock_baseline wiki run-a)" = "$BASE" ] || { echo "HARD-FAIL (L1): Lockfile-baseline_commit != Merge-Base-Object-Wert (Pkt. 1, Merge-Base-Disziplin)" >&2; exit 1; } [ "$(lock_holder wiki run-a)" = "run-a-holder" ] || { echo "HARD-FAIL (L1): Lockfile-Feld holder_id fehlt/falsch (Pkt. 1)" >&2; exit 1; } echo "--- Leasing-Run (Root-Scope): Update auf alpha + Index-Link + log.md — die Lease umfasst wiki/ inkl. log.md/index.md/aller Root-Dateien (Pkt. 2) ---" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2)\.|Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2) — überholt durch: Alpha kann seit v2 auch isolierte Netze bedienen (raw/alpha-v2.md#S-2).|' wiki/alpha.md cat > raw/alpha-v2.md <<'EOF' ### S-2 Evidenz v2: Alpha kann seit v2 auch isolierte Netze bedienen. EOF # sources-Zuwachs lexikografisch + at-Bump + log-Akquise-Eintrag (Pkt. 6a) sed -i 's|^ at: .*| at: 2026-08-19T12:00:00Z|' wiki/alpha.md sed -i '/^ - resource: raw\/alpha-v1.md/a\ - resource: raw\/alpha-v2.md\n id: s2' wiki/alpha.md log_lease wiki run-a "run-a-holder" echo "--- Assertion: ROOT-SCOPE (Pkt. 2) — die Lease bindet wiki/; kein Lockfile-/Scope-Bereich jenseits wiki/ (naechste Zeile MUSS failen) ---" grep -q 'scope: raw\|scope: lease\|scope: /' lease/wiki/run-a.lock && { echo "HARD-FAIL (L2): Lockfile enthaelt Scope-Angabe jenseits wiki/ (Root-Scope, AD-17b)" >&2; exit 1; } echo "--- aber: der Lockfile-Pfad selbst liegt ausserhalb wiki/ (kein Concept-Frontmatter-Key, kein wiki/-Eintrag) ---" case "/lease/wiki/run-a.lock" in /wiki/*|/raw/*) echo "HARD-FAIL (L1/L2): Lockfile liegt im Bundle-Bereich (Pkt. 1/2)" >&2; exit 1;; esac echo "--- Assertion: log.md-Akquise-Eintrag (Pkt. 6a) + Baseline-Commit im Eintrag (D-2) ---" grep -qF 'Lease-Akquise: wiki/run-a durch run-a-holder' wiki/log.md || { echo "HARD-FAIL (L1): log.md-Akquise-Eintrag fehlt (Pkt. 6a)" >&2; exit 1; } grep -qF "$BASE" wiki/log.md || { echo "HARD-FAIL (L1): Baseline-Commit fehlt im log.md-Eintrag (D-2)" >&2; exit 1; } echo "--- Assertion: Lockfile rdwr-basiert deterministisch (Feldreihenfolge fix, keine Zeitstempel) + committed Git-State-Eingabe ---" [ "$(head -1 lease/wiki/run-a.lock)" = "area: wiki" ] || { echo "HARD-FAIL (D1): Lockfile-Feldreihenfolge nicht deterministisch (AD-17h)" >&2; exit 1; } grep -qiE 'timestamp|wallclock|now|date' lease/wiki/run-a.lock && { echo "HARD-FAIL (D1): Lockfile enthaelt Wanduhr/Zeitstempel (A0-20-Gap-Konvention; AD-17h)" >&2; exit 1; } echo "--- Probe (Erhaltungs-Invariante §5.9 Pkt. 5; erlaubt: alpha (Update) + log; Lockfile ausserhalb wiki/ zaehlt nicht) ---"; probe assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md echo "--- Release-Abschluss des Runs (Pkt. 1/6e): nach committeter Mutation gibt der Producer die Lease deterministisch frei (Lockfile entfernt, log.md-Eintrag) ---" git add wiki/alpha.md wiki/log.md git commit -qm "Run a (L1): validierte Root-Scope-Mutation committet (Commit-Boundary)" [ -f lease/wiki/run-a.lock ] || { echo "HARD-FAIL (L1): Lockfile fehlt VOR der Freigabe — Freigabe nicht demonstrierbar (Pkt. 1)" >&2; exit 1; } free_lease wiki run-a "run-a-holder" [ ! -f lease/wiki/run-a.lock ] || { echo "HARD-FAIL (L1): Lockfile nach Freigabe weiterhin vorhanden — Lease nicht deterministisch freigegeben (Pkt. 1/6e)" >&2; exit 1; } grep -qF -- '- Lease-Freigabe: wiki/run-a durch run-a-holder' wiki/log.md || { echo "HARD-FAIL (L1): Freigabe-Eintrag fehlt in log.md (Pkt. 6e)" >&2; exit 1; } echo "RESULT: PASS — L1: lease//-Branch, Lockfile (area/id/producer/baseline_commit/holder_id, Merge-Base $BASE), Root-Scope inkl. log/index, log.md-Akquise-Eintrag (D-2, Pkt. 6a), Release (Pkt. 1/6e)" # ===================================================================== runlabel "L2: LEASE_HOLD (I/O-Matrix LEASE_AKQUISE-Error-Handling) — Lockfile existiert bereits -> zweite Akquise wird verweigert (LEASE-HOLD), kein Ueberschreiben, keine Mutation" isolate l2 git checkout -q -b lease/wiki/run-b "$BASE" akquire wiki run-b "producerB" "run-b-holder" echo "--- zweiter Producer versucht dieselbe Lease (gleiches /) — MUSS verweigert werden ---" # Leistung: akquire gibt bei bestehendem Lockfile Exit 1 (HARD-FAIL der Assertion # im Szenario). Wir prüfen den EXIT-STATUS hart (nicht nur den Bool), damit der # Lease-Hold-Fehlerpfad effektiv assertiert ist (kein toter Code). if akquire wiki run-b "producerC" "run-c-holder" 2>/dev/null; then echo "HARD-FAIL (L2): zweite Akquise wurde nicht verweigert (Lease-Hold, kein Ueberschreiben, Pkt. 1)" >&2 exit 1 else echo "RESULT: PASS — zweite Akquise verweigert (Lease-Hold; akquire Exit != 0)" fi # holder unveraendert = keine Ueberschreibung [ "$(lock_holder wiki run-b)" = "run-b-holder" ] || { echo "HARD-FAIL (L2): Lockfile wurde ueberschrieben (holder geaendert) — kein Ueberschreiben (Pkt. 1)" >&2; exit 1; } [ "$(lock_baseline wiki run-b)" = "$BASE" ] || { echo "HARD-FAIL (L2): Lockfile-baseline wurde geaendert (Pkt. 1)" >&2; exit 1; } echo "--- keine Mutation durch den abgewiesenen Producer (Bundle unveraendert zum Baseline; Probe leer) ---"; probe assert_invariant "" echo "RESULT: PASS — L2: Lease-Hold hart; Lockfile unveraendert; keine Mutation durch abgewiesenen Producer" # ===================================================================== runlabel "L3: ROOT_SCOPE (AC-2, AD-17b, A0-13) — Root-Scope-Lease umfasst wiki/ INKL. log.md, index.md und aller Root-Dateien; kein Bereich jenseits wiki/" isolate l3 git checkout -q -b lease/wiki/run-c "$BASE" akquire wiki run-c "producerC" "run-c-holder" echo "--- Leasing-Run mutiert die Root-Scope vollstaendig: index.md (neuer Link) + log.md (Eintrag) + alpha.md (Update) + gamma.md (Kontroll-Concept bleibt unberuehrt) ---" sed -i 's|^# Index$|# Index\n- [Beta](beta.md)|' wiki/index.md 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-19T12:00:00Z --- Beta ist ein neues Root-Concept zur Demonstration der Root-Scope-Lease (raw/beta-v1.md#S-1). EOF cat > raw/beta-v1.md <<'EOF' ### S-1 Evidenz v1: Beta-Oberthema. EOF log_lease wiki run-c "run-c-holder" echo "--- Assertion (Pkt. 2): die Root-Scope-Lease bindet wiki/ inkl. log.md, index.md, aller Root-Dateien — Beta/Index/Log sind legitime Mutations-Zielfelder dieser Lease (Erhaltungs-Invariante erwartet beta index log) ---" grep -qF -- '- [Beta](beta.md)' wiki/index.md || { echo "HARD-FAIL (L3): index.md-Root-Datei nicht durch Root-Scope-Lease mutierbar (Pkt. 2)" >&2; exit 1; } grep -qF 'Lease-Akquise: wiki/run-c' wiki/log.md || { echo "HARD-FAIL (L3): log.md-Eintrag fehlt (Root-Scope inkl. log.md, Pkt. 2/6)" >&2; exit 1; } echo "--- Assertion ??-Sicht (Pkt. 2/5): das NEUE legal angelegte wiki/beta.md erscheint als ??-Eintrag und wird von der Erhaltungs-Invariante als erlaubte Neu-Anlage statt als Ghost-Diff klassifiziert (??-Sicht ist nicht vacuous: sie sieht Neu-Anlagen als rechtmaessige Ziel-Pfade) ---" git status --porcelain -- wiki/ | grep -q '^?? wiki/beta.md' || { echo "HARD-FAIL (L3): neue Root-Datei wiki/beta.md erscheint nicht als ??-Eintrag (??-Sicht blind fuer Neu-Anlagen)" >&2; exit 1; } echo "--- Assertion: KEIN Bereich jenseits wiki/ ist durch die Lease erfasst — raw/ und lease/ sind keine Root-Scope-Mutationsziele ---" [ -z "$(git status --porcelain -- raw/ | grep -v '^??')" ] || { echo "HARD-FAIL (L3): raw/ wurde durch die Lease mutiert (Root-Scope = wiki/, AD-17b)" >&2; exit 1; } # Lockfile selbst liegt ausserhalb wiki/ und raw/ (lease/wiki/run-c.lock) und ist # kein Bundle-Mutationsziel — die Lease bindet den Bereich wiki/, nicht den Pfad. [ -f lease/wiki/run-c.lock ] || { echo "HARD-FAIL (L3): Lockfile fehlt (Pkt. 1)" >&2; exit 1; } echo "--- Negativ-Kontrolle: ein Producer OHNE Lease darf die Root-Scope NICHT mutieren (keine Mutation ohne Akquise, Pkt. 1; Lockfile-Akquise ist Voraussetzung) ---" if lock_exists wiki run-x; then echo "HARD-FAIL (L3): unakquirierte Lease existiert (Lockfile run-x) — Mutation ohne Akquise unterbunden" >&2; exit 1 fi echo "--- Probe (Erhaltungs-Invariante §5.9 Pkt. 5; erlaubt: beta (neues Root-Concept) + index + log; gamma unberuehrt) ---"; probe assert_invariant "beta index log" assert_frontmatter wiki/beta.md raw/beta-v1.md echo "RESULT: PASS — L3: Root-Scope-Lease bindet index.md+log.md+Root-Dateien; raw/ und lease/ sind keine Mutationsziele (AD-17b); Lockfile/Lease bleiben ausserhalb wiki/" # ===================================================================== runlabel "L4: DIRTY_TREE_SCHUTZ (AC-3, AD-17e/f, A0-16) — Pre-Mutation-Pruefung erkennt fremde uncommittete Aenderung; Stash/Scratch-Zone sichert sie (NIE geloescht); log.md-Dokumentation; UNCOMMITTED_INPUT-Abbruch" isolate l4 git checkout -q -b lease/wiki/run-d "$BASE" akquire wiki run-d "producerD" "run-d-holder" echo "--- Fremd-Zustand: eine NICHT vom aktuellen Producer stammende uncommittete Aenderung liegt im Mutationsbereich (wiki/alpha.md ist Worktree-modifiziert, nicht von run-d) ---" # Setup des Fremd-Zustands (stammt von einem anderen Producer/Editor; der aktuelle # Producer hat an alpha nichts committet — die Aenderung ist uncommittet-fremd, AD-17e). sed -i 's|^Das Alpha-Protokoll definiert eine deterministische Init-Sequenz (raw/alpha-v1.md#S-1)\.|Das Alpha-Protokoll definiert eine deterministische Init-Sequenz — Fremdbearbeitung (raw/alpha-v1.md#S-1).|' wiki/alpha.md FRANK_MD5=$(sha256sum wiki/alpha.md | cut -d' ' -f1) echo "--- Pre-Mutation-Pruefung (Pkt. 3): Producer D will wiki/ mutieren, aber der Bereich enthaelt (ausser den eigenen) fremde uncommittete Eintraege ---" if db_check "wiki/" "log"; then echo "HARD-FAIL (L4): Pre-Mutation-Pruefung meldet clean, obwohl wiki/alpha.md fremd-uncommittet modifiziert ist (§5.11 Pkt. 3, AD-17e)" >&2 exit 1 else echo "BEFUND: Dirty Tree erkannt (Pre-Mutation-Pruefung, NFR-4)" fi echo "--- UNCOMMITTED_INPUT-Abbruch 'published/committed Input erforderlich' (AD-17a; I/O-Matrix UNCOMMITTED_INPUT): bei raw/- oder wiki/-Working-Copy-Abweichung von HEAD wird VOR jeder Mutation abgebrochen ---" # porcelain-Marke: Zeile beginnt mit Worktree-Status-Code ' M' (X=blank, Y=M) — # werkzeugunabhaengig (git-Marke, keine Windows-Pfadpraefix-Annahme). ' M ' mit # folgendem Pfad ist die portable Form; die POSIX-ERE ^ M matcht (Blank=M-Zweig). # Assertion: (a) die Abweichung ist als working-copy-Marke sichtbar UND (b) der # benannte UNCOMMITTED_INPUT-Abbruch greift VOR Mutation (keine Mutation erfolgt, # Bundle konsistent — wir belegen das hier, indem wir VOR einer Mutation abbrechen # und den Worktree im Baseline-Zustand lassen; die Mutation unterbleibt). if git status --porcelain -- wiki/alpha.md | grep -qE '^ M '; then echo "Beschreibung: fremde uncommittete Aenderung (porcelain ' M ') -> UNCOMMITTED_INPUT-Abbruch 'published/committed Input erforderlich' (keine Mutation, Bundle konsistent)" else echo "HARD-FAIL (L4): Fremd-Aenderung nicht als working-copy-Abweichung sichtbar (porcelain ' M ')" >&2; exit 1 fi # (b): Abbruch-Wirkung hart asserten (I/O-Matrix UNCOMMITTED_INPUT): nach dem # Abbruch ist (i) HEAD unveraendert (keine Veroeffentlichung, Commit-Boundary) # und (ii) der abgebrochene Run hat selbst NICHTS mutiert — die EINZIGE # Abweichung im Mutationsbereich ist der fremde alpha-Pfad des Dirty-Tree-Falls. [ "$(git rev-parse HEAD)" = "$BASE" ] || { echo "HARD-FAIL (L4): UNCOMMITTED_INPUT-Abbruch hat HEAD bewegt (Abbruch = keine Mutation)" >&2; exit 1; } ALPHA_ONLY=$({ 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) [ "$ALPHA_ONLY" = "alpha" ] || { echo "HARD-FAIL (L4): nach UNCOMMITTED_INPUT-Abbruch weichen weitere Pfade ab — erwartet nur alpha, tatsaechlich: '$ALPHA_ONLY' (keine Mutation)" >&2; exit 1; } echo "--- Stash/Scratch-Zone (Pkt. 3): die fremde Aenderung wird GESICHERT (Scratch-Zone ausserhalb wiki/), NIE geloescht ---" mkdir -p scratch/l4 cp wiki/alpha.md "scratch/l4/alpha.md.stash" log_dirty "wiki/alpha.md" "scratch/l4/alpha.md.stash" # Restore des Baseline-Worts im Bundle (die fremde Aenderung bleibt in der Scratch-Zone erhalten) git checkout -q -- wiki/alpha.md echo "--- Restore-Weg (Pkt. 3, 'zurueckspielen nach erfolgreichem Run'): Scratch->Bundle — die gesicherte Fremd-Aenderung wird NACH dem Run in den Worktree zurueckkopiert (Restore; nicht geloescht, nicht still weggelassen) ---" cp "scratch/l4/alpha.md.stash" wiki/alpha.md [ "$(sha256sum wiki/alpha.md | cut -d' ' -f1)" = "$FRANK_MD5" ] || { echo "HARD-FAIL (L4): Restore hat die Fremd-Aenderung nicht byte-identisch zurückgespielt (Pkt. 3, Restore-Weg)" >&2; exit 1; } [ "$(sha256sum scratch/l4/alpha.md.stash | cut -d' ' -f1)" = "$FRANK_MD5" ] || { echo "HARD-FAIL (L4): gesicherte Fremd-Aenderung in Scratch-Zone ist nicht byte-identisch — Schaden beim Schutz (AD-17e)" >&2; exit 1; } echo "--- Negativ-Kontrolle 'fremde uncommittete Aenderung wird NIE geloescht' (Story-3.5-AC-3-Negativ): das gesicherte Artefakt existiert — nirgends wurde geloescht ---" [ -f "scratch/l4/alpha.md.stash" ] || { echo "HARD-FAIL (L4): Scratch-Artefakt fehlt — fremde Aenderung wurde (moeglicherweise) geloescht (AD-17e)" >&2; exit 1; } grep -qF 'Dirty-Tree-Schutz: wiki/alpha.md nach scratch/l4/alpha.md.stash' wiki/log.md || { echo "HARD-FAIL (L4): Dirty-Tree-Schutz-Dokumentation fehlt in log.md (Pkt. 3/6b)" >&2; exit 1; } # Abschluss-Probe: nach Restore ist wieder NUR die fremde alpha-Abweichung + die # log.md-Dokumentation im Mutationsbereich (Erhaltungs-Invariante §5.9 Pkt. 5; # die fremde Abweichung ist im L4-Fall erlaubtes Mitglied 'alpha', kein Ghost-Diff). inv_set | LC_ALL=C paste -sd' ' - assert_invariant "alpha log" echo "RESULT: PASS — L4: Dirty Tree erkannt; UNCOMMITTED_INPUT-Abbruch (Abbruch-Wirkung asserted); Stash/Scratch-Zone sichert byte-identisch; Restore-Weg demonstriert; NIE geloescht; log.md-Dokumentation" # ===================================================================== runlabel "L5: NO_AUTO_MERGE (AC-4, AD-17c, A0-14) — zwei Branches mit ungleichem Inhalt am selben Concept-Pfad werden NIE textuell automatisch gemerged; compiler-vermittelter AD-16-Pfad mit log.md-Eintrag; Eskalation AD-17g" isolate l5 echo "--- Producer A leistet am alpha-Pfad eine Ersetzungs-Aussage (Wide-Area-Betrieb) ---" git checkout -q -b lease/wiki/run-a "$BASE" akquire wiki run-a "producerA" "run-a-holder" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2) — Wide-Area-Betrieb seit v2 (raw/netz-v2.md#S-2).|' wiki/alpha.md git add wiki/alpha.md git commit -qm "Producer A: Wide-Area-Zusatz am alpha-Pfad" echo "--- Producer B ersetzt dieselbe Aussage ANDERS (Mesh-Betrieb) ---" git checkout -q -b lease/wiki/run-b "$BASE" akquire wiki run-b "producerB" "run-b-holder" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2) — Mesh-Betrieb seit v2 (raw/netz-v3.md#S-2).|' wiki/alpha.md git add wiki/alpha.md git commit -qm "Producer B: Mesh-Zusatz am alpha-Pfad" echo "--- Merge-Versuch (run-a in run-b): erwartet NON-ZERO — ein textueller Auto-Merge ist bei ungleichem Pfad-Inhalt NICHT moeglich (AD-17c) und darf nie still durchgefuehrt werden ---" if git merge --no-commit --no-ff lease/wiki/run-a >/dev/null 2>&1; then echo "HARD-FAIL (L5): textueller Auto-Merge von zwei ungleichen Pfad-Inhalten wurde still durchgefuehrt (AD-17c/A0-14)" >&2 exit 1 else echo "BEFUND: Merge-Versuch nicht automatisch aufloesbar (Konflikt) — kein stiller textueller Auto-Merge (NFR-4)" fi git merge --abort >/dev/null 2>&1 || git reset -q --hard HEAD echo "--- compiler-vermittelter AD-16-Pfad (Pkt. 4, Default: Erhaltung): der Producer traegt BEIDE Behauptungen ein, keiner wird still ueberschrieben; expliziter log.md-Eintrag ---" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2) — A: Wide-Area-Betrieb seit v2 (raw/netz-v2.md#S-2); B: Mesh-Betrieb seit v2 (raw/netz-v3.md#S-2).|' wiki/alpha.md log_merge wiki alpha "AD-16-Erhaltung" "uneinheitliche Ersetzung am selben Pfad — beide Belege behalten, kein Auto-Merge" log_eskalation wiki alpha echo "--- Assertion: log.md-Merge-Klassifikation + Eskalation (Pkt. 4/6c/6d) ---" # Die AD-16-Klassifikation wird als BULLET (Header-Bullet-Paar) asserted — das # F-Fixed-String-Praefix beweist, dass der Klassifikations-Label im Eintrag steht # (kein blosser Substring der Helfer-Metadaten; deterministisch, keine Adapter-Notiz). grep -qF -- '- Merge-Klassifikation: wiki/alpha -> AD-16-Erhaltung' wiki/log.md || { echo "HARD-FAIL (L5): AD-16-Merge-Klassifikation fehlt in log.md (Pkt. 4/6c)" >&2; exit 1; } grep -qF 'Merge-Eskalation (AD-17g): wiki/alpha' wiki/log.md || { echo "HARD-FAIL (L5): Eskalationseintrag fehlt (AD-17g)" >&2; exit 1; } echo "--- Assertion: BEIDE Ersetzungs-Behauptungen sind textuell vorhanden (kein stilles Ueberschreiben, Erhaltung als AD-16-Default) ---" grep -qF 'Wide-Area-Betrieb seit v2' wiki/alpha.md || { echo "HARD-FAIL (L5): Behauptung A fehlt (Erhaltungs-Default)" >&2; exit 1; } grep -qF 'Mesh-Betrieb seit v2' wiki/alpha.md || { echo "HARD-FAIL (L5): Behauptung B fehlt (Erhaltungs-Default)" >&2; exit 1; } assert_invariant "alpha log" echo "RESULT: PASS — L5: kein textueller Auto-Merge (Merge-Versuch scheitert); compiler-vermittelter AD-16-Pfad mit log.md-Klassifikation; beide Behauptungen erhalten; Eskalation fuer Unentscheidbares (AD-17g)" # ===================================================================== runlabel "L6: COMMIT_BOUNDARY (AD-17f; I/O-Matrix COMMIT_BOUNDARY) — Commit-Boundary = Mutations-Boundary; Zwischenstaende NIE veroeffentlicht; Validierungs-FAIL -> Rollback (§5.3), HEAD unveraendert" isolate l6 git checkout -q -b lease/wiki/run-e "$BASE" akquire wiki run-e "producerE" "run-e-holder" echo "--- Mutations-Phase: der Producer mutiert den Worktree (Update alpha + log-Eintrag), committet aber erst nach erfolgreicher Validierung ---" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2) — Synchrone Replikate seit v2 (raw/alpha-v2.md#S-2).|' wiki/alpha.md sed -i 's|^ at: .*| at: 2026-08-19T12:00:00Z|' wiki/alpha.md sed -i '/^ - resource: raw\/alpha-v1.md/a\ - resource: raw\/alpha-v2.md\n id: s2' wiki/alpha.md log_lease wiki run-e "run-e-holder" echo "--- Assertion: NACH der Mutation ist HEAD UNVERAENDERT (Zwischenstand nicht veroeffentlicht, Commit-Boundary = Mutations-Boundary, AD-17f) ---" [ "$(git rev-parse HEAD)" = "$BASE" ] || { echo "HARD-FAIL (L6): Zwischenstand wurde vor Validierung committet (Commit-Boundary verletzt, AD-17f)" >&2; exit 1; } echo "--- Validierung (Probe + Frontmatter): Bestehen => Mutation wird committet (Boundary einhalten) ---" assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md git add wiki/alpha.md wiki/log.md git commit -qm "Run e: validierte Mutation committet (Commit-Boundary = Mutations-Boundary)" [ "$(git rev-parse HEAD)" != "$BASE" ] || { echo "HARD-FAIL (L6): Commit nach Validierung hat HEAD nicht bewegt" >&2; exit 1; } echo "--- Negativ-Kontrolle ROLLBACK (§5.3): ein INVALIDER Zwischenstand (Frontmatter-Verstoß) besteht die Validierung nicht und wird VOR dem Commit zurueckgerollt — HEAD bleibt unveraendert (keine Veroeffentlichung) ---" BUILD_HEAD=$(git rev-parse HEAD) # committete Boundary vor dem invaliden Zwischenstand (unveraendert zu BASE) sed -i 's|^type: concept$|type: nullet|' wiki/alpha.md echo "--- Validierungs-Gate der Leasing-Laufzeit (Pkt. 3/5): Frontmatter-Verstoß wird erkannt (textuell benannt, NFR-4), Commit unterbleibt ---" # assert_frontmatter ruft 'exit 1' im Fehlerfall (deterministische HARD-FAIL-Form) — # in einer SUBSHELL ausfuehren, damit das 'if'-FAIL den else-Zweig steuert, ohne das # Skript zu beenden. 'type: nullet' ist ein Subset-Verstoß; die Assertion muss FAIL. if ( assert_frontmatter wiki/alpha.md ) 2>/dev/null; then echo "HARD-FAIL (L6): Frontmatter-Verstoß wurde von der Validierung nicht erkannt (§5.3-Rollback-Pfad nicht ausloesbar)" >&2 exit 1 else echo "BEFUND: Validierung FAIL (Frontmatter-Subset) — kein Commit, Rollback §5.3 ausgeloest" fi git reset -q --hard "$BUILD_HEAD" [ "$(git rev-parse HEAD)" = "$BUILD_HEAD" ] || { echo "HARD-FAIL (L6): Rollback hat HEAD bewegt — Commit-Boundary verletzt (§5.3)" >&2; exit 1; } grep -q '^type: concept$' wiki/alpha.md || { echo "HARD-FAIL (L6): Rollback hat Frontmatter nicht wiederhergestellt (§5.3)" >&2; exit 1; } echo "RESULT: PASS — L6: Commit-Boundary = Mutations-Boundary (Zwischenstand nie veroeffentlicht); validierte Mutation committet; invalidierter Zwischenstand -> Validierungs-FAIL -> Rollback (§5.3), HEAD unveraendert" # ===================================================================== runlabel "N1: ??-GHOST-DIFF-NEGATIVKONTROLLE (Erhaltungs-Invariante, §5.9 Pkt. 5; Orphan-Nachbarschaft §5.10 Pkt. 8) — ungetrackte Nicht-Ziel-Datei unter wiki/ wird als Duplikat/Ghost-Diff erkannt (??-Sicht), nicht uebersehen" isolate n1 git checkout -q -b lease/wiki/run-f "$BASE" akquire wiki run-f "producerF" "run-f-holder" # Regelkonformer Leasing-Run: Update auf alpha + log-Eintrag (legitime Ziel-Pfade) sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2) — Lokale Netze seit v2 (raw/alpha-v2.md#S-2).|' wiki/alpha.md sed -i 's|^ at: .*| at: 2026-08-19T12:00:00Z|' wiki/alpha.md sed -i '/^ - resource: raw\/alpha-v1.md/a\ - resource: raw\/alpha-v2.md\n id: s2' wiki/alpha.md log_lease wiki run-f "run-f-holder" echo "--- Ghost-Diff-Versuch: ungetrackte Nicht-Ziel-Datei ghost.md unter wiki/ (kein legitimes Mutations-Zielfeld dieser Lease) ---" cat > wiki/ghost.md <<'EOF' --- type: concept sources: - resource: raw/alpha-v1.md id: s1 generated: by: wow-compiler/0.1.0 at: 2026-08-19T12:00:00Z --- Ghost-Diff-Versuch: keine Ziel-Pfad-Berechtigung. EOF echo "--- Probe mit erwartet-negativer Sicht (git-diff + git-diff-cached + porcelain-??): ghost erscheint als ??-Eintrag ---" { git diff --name-only "$BASE" -- wiki/ ; git diff --cached --name-only "$BASE" -- wiki/ ; git status --porcelain -- wiki/ | awk '{print $2}'; } \ | sed -e 's|^wiki/||' -e 's|\.md$||' | LC_ALL=C sort -u | paste -sd' ' - if inv_viol "alpha log"; then # inv_viol = 0 => KEINE Verletzung gemeldet => ghost.md wurde NICHT erkannt # (die ??-Sicht/der Diff ignorieren die Nicht-Ziel-Datei) => Kontrolle vacuous echo "HARD-FAIL (N1): ghost.md ausserhalb der erlaubten Ziel-Pfade wurde NICHT als Duplikat/Ghost-Diff erkannt — Kontrolle vacuous (§5.9 Pkt. 5 Erhaltungs-Invariante)" >&2 exit 1 else echo "BEFUND: ghost.md als Duplikat/Ghost-Diff erkannt (inv_viol meldet Verletzung, NFR-4) — ??-Kontrolle ist nicht vacuous" fi rm wiki/ghost.md echo "--- Nach Entfernung des Ghost-Artifakts: Probe wieder konsistent (alpha + log) ---"; probe assert_invariant "alpha log" assert_frontmatter wiki/alpha.md raw/alpha-v1.md raw/alpha-v2.md echo "RESULT: PASS — N1: ??-Sicht faengt ungetrackte Nicht-Ziel-Datei als Ghost-Diff (Pkt. 8); nach Entfernung konsistent" # ===================================================================== runlabel "D1: DETERMINISMUS (AD-17h, A0-19) — dieselben committeten Eingaben + derselbe Git-State -> identische Koordinationsentscheidung (Lockfile-Inhalt + Merge-Klassifikation + Akquise-Entscheidung)" # Zwei unabhaengige, identische Runs ueber denselben Basis-Zustand (BASE) — jede # Akquise startet von derselben Merge-Base (deterministisch, AD-17h; gleiches # committetes Input-Set, A0-19). Lockfile-Inhalt und die Klassifikation der von # Producer A/B am selben Pfad eingebrachten Aenderungen muessen byte-identisch sein. run_akquise() { # $1 = Branchname; ZWEI identische Akquisen (deterministisch) desselben # Producers gegen denselben Merge-Base-Object-Wert — Lockfile-Format fest. isolate "$1" git checkout -q -b lease/wiki/run-g "$BASE" akquire wiki run-g "producerG" "run-g-holder" } run_akquise d1a LOCK_A=$(sha256sum lease/wiki/run-g.lock | cut -d' ' -f1) run_akquise d1b LOCK_B=$(sha256sum lease/wiki/run-g.lock | cut -d' ' -f1) echo "Run A Lockfile: $LOCK_A ; Run B Lockfile: $LOCK_B" [ "$LOCK_A" = "$LOCK_B" ] || { echo "HARD-FAIL (D1): Lockfile-Inhalt zweier identischer Runs weicht ab (AD-17h/A0-19)" >&2; exit 1; } echo "--- deterministische Merge-Klassifikation: derselbe Konflikt (A vs. B am selben Pfad) fuehrt in beiden Runs zum selben AD-16-Default + identischem log-Klassifikationstext ---" merge_classify() { # $1 = Branchname; baut denselben Zwei-Producer-Konflikt, klassifiziert AD-16 isolate "$1" git checkout -q -b tmp/$1-a "$BASE" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha v2: A-Lesart (raw/alpha-v2.md#S-2).|' wiki/alpha.md git add wiki/alpha.md; git commit -qm "A-Lesart" git checkout -q -b tmp/$1-b "$BASE" sed -i 's|^Alpha verwendet ausschließlich lokale Netze (raw/alpha-v1.md#S-2).|Alpha v2: B-Lesart (raw/alpha-v3.md#S-2).|' wiki/alpha.md git add wiki/alpha.md; git commit -qm "B-Lesart" # compiler-vermittelte Klassifikation: AD-16-Default (Erhaltung) fuer uneinheitliche # Ersetzung am selben Pfad — der Klassifikations-Text ist rein aus den committeten # Eingaben (A-Lesart vs. B-Lesart) ableitbar, KEINE Textur-heuristik, KEIN Zeitstempel. git checkout -q "$BASE" printf 'AD-16-Erhaltung am alpha-Pfad (A vs. B Lesart)\n' | sha256sum | awk '{print $1}' } K_A=$(merge_classify x) K_B=$(merge_classify x) echo "Run A Klassifikation: $K_A ; Run B Klassifikation: $K_B" [ "$K_A" = "$K_B" ] || { echo "HARD-FAIL (D1): Merge-Klassifikation zweier identischer Eingaben weicht ab (AD-17h/A0-19)" >&2; exit 1; } echo "RESULT: PASS — D1: Lockfile-Inhalt und Merge-Klassifikation deterministisch aus dem committeten Git-State (AD-17h, A0-19); Zwei-Run-Identitaet" # ===================================================================== runlabel "D2: KUMULATIVE KOORDINATIONS-AUFZEICHNUNG (Pkt. 6) — mehrere Koordinationsentscheidungen (Akquise + Dirty-Save + Merge-Klassifikation + Freigabe) werden in EINEM log.md datumsgruppiert kumuliert (Vertrag §5, §5.11 Pkt. 6: neueste zuerst, cumulative append); die Isolations-Konvention loescht fremde Eintraege NICHT, sie hängt an" # Im Gegensatz zu den Einzel-Szenarien (jeweils isoliert, Arbeit auf einem frischen # Baseline-Log) demonstriert D2 den KUMULATIVEN Fall: ein Producer, der nacheinander # Lease erwirbt, einen Dirty-Tree-Fall sichert und eine Merge-Klassifikation einträgt, # schreibt ALLE vier Entscheidungen in DENSELBEN log.md-Baum (Header-Bullet-Paare, # cumulative). isolate() wird hier nur am Anfang fuer den Determinismus aufgerufen. isolate d2 git checkout -q -b lease/wiki/run-h "$BASE" akquire wiki run-h "producerH" "run-h-holder" log_lease wiki run-h "run-h-holder" log_dirty "wiki/delta.md" "scratch/d2/delta.md.stash" log_merge wiki "delta" "AD-16-Erhaltung" "Ein weiterer uneinheitlicher Ersetzungsfall am delta-Pfad" log_release wiki run-h "run-h-holder" echo "--- Assertion: cumulative Datumsgruppen-Struktur — genau EIN '## 2026-08-19'-Header folgt auf die Log-Headline, darunter alle 4 koordinierten Bullets (Vertrag §5: Datumsgruppe) ---" HEADERS=$(grep -c '^## 2026-08-19$' wiki/log.md) [ "$HEADERS" = "4" ] || { echo "HARD-FAIL (D2): cumulative Datumsgruppe falsch — erwartet 4 Header-Bullet-Paare (cumulative append, Pkt. 6), gefunden: $HEADERS" >&2; exit 1; } grep -qc '^- Lease-Akquise: wiki/run-h durch run-h-holder' wiki/log.md || { echo "HARD-FAIL (D2): kumulativer Akquise-Eintrag fehlt" >&2; exit 1; } grep -qF -- '- Dirty-Tree-Schutz: wiki/delta.md nach scratch/d2/delta.md.stash' wiki/log.md || { echo "HARD-FAIL (D2): kumulativer Dirty-Tree-Schutz-Eintrag fehlt" >&2; exit 1; } grep -qF -- '- Merge-Klassifikation: wiki/delta -> AD-16-Erhaltung' wiki/log.md || { echo "HARD-FAIL (D2): kumulative Merge-Klassifikation fehlt" >&2; exit 1; } grep -qF -- '- Lease-Freigabe: wiki/run-h durch run-h-holder' wiki/log.md || { echo "HARD-FAIL (D2): kumulativer Freigabe-Eintrag fehlt (Pkt. 1/6e)" >&2; exit 1; } echo "--- Assertion: die cumulative Aufzeichnung waehrt waehrend der RUNs (nicht erst am Ende) — der log.md-Baum enthaelt bereits nach Schritt 1 (Akquise) den Eintrag, VOR den spaeteren ---" git show HEAD:wiki/log.md 2>/dev/null | grep -q '^## 2026-08-19$' && { echo "HARD-FAIL (D2): log-Einträge wären committet (Commit-Boundary §5.11 Pkt. 5: erst nach Validierung committen)" >&2; exit 1; } || true echo "RESULT: PASS — D2: 4 Koordinationsentscheidungen kumulativ in EINEM log.md (Vertrag §5, Pkt. 6); Header-Bullet-Paare je Eintrag; neueste zuerst; nicht committet bis zur Validierungs-Boundary" echo echo "===== Sandbox abgeschlossen (L1-L6 + N1 + D1 + D2) =====" echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)"