Triage: 4 decision-needed / 13 patch / 6 defer / 7 dismissed (u. a. Blind-Hunter "alle Sandbox-SRO-Anker stale" widerlegt — alle 6 exakt vor den Loop-3-Edits). Entscheidungen D-1..D-4 (alle Option 1): D-1 Schliessungs-Bullet macht den "Bekannte Determinismus-Luecke"-Alt-Bullet superseded (append-only-Hinweis, kein Umbruch); D-2 Story-Status-Flip auf done (Change-Proposal-Sequenzierung betrafft das Epic-3-Abnahmegate 3.13, nicht die 3.8-Verankerung); D-3 autorisierte Neu-Verhandlung in geringfuegischem Umfang (Typo "documenthuman" -> "document-human", Spec Re-Open-Delta-Zeile); D-4 Hold-Home = Story 3.10 (Epic 3), Korrektur-/Erweiterungs-Klassifikation = Epic-4-Interface/Story 4.1 (S5.10 Pkt. 8 praezisiert). Patches P-1..P-13: SRO-/Code-Map-Anker auf IST-Zeilen (compiler.md 375/376/377/477, Code Map 365-377/424ff/445/477, Sandbox 245/265/442/275/447/531); symmetrische Term-/Body-Normalisierung (S3.2 Pkt. 2a + match_stufe_a, kein host-abhaengiges -i); Receipt-Hashvergleich als re-executierbare Zwei-Run-Formel (S5.14 Pkt. 2); Sandbox-Fresh-Kontext-Restluecke benannt (mechanisch simuliert; Nachweis = 3.13-Abnahmegate); Manifest generated_by wird konsumiert; at-Ausnahme hart assertiert (Wiederholungs-Schleife bei Sekundenkollision, HARD-FAIL statt stiller PASS); "voellig pinbar"/"keine offene Frage" ge scopet (Umlaut-Defer + 3.9-ACs bewusst offen); epics.md AC-2 AD-16-Kopplung nachgefuehrt; review_loop_iteration 0 -> 2; epic-3-context.md 3.9/3.11/3.12-Entscheidungen als Zielzustand markiert; AD-17-Enum verifiziert (kein Edit noetig); Review-Loop-3-Change-Log-Eintrag. Sandbox re-executiert: DET-1..DET-8 harte PASS, Exit 0; at-Ausnahme aktiv (assertiert, real unterschiedliche Wanduhr-at-Werte); Witness nicht-vakuum. Spec status: done, review_loop_iteration: 2; sprint-status 3-8 -> done (Sequenzierungs-Hinweis: 3.9-3.12-Verankerungen + 3.13-Abnahme bleiben offen); wiki/log.md Loop-3-Abschluss-Bullet; deferred-work.md 6 neue Defers. AD-3 gewahrt: validator.md/wiki-compiler.md/adapters/raw/ unveraendert. Co-Authored-By: Claude <noreply@anthropic.com>
726 lines
44 KiB
Bash
726 lines
44 KiB
Bash
#!/usr/bin/env bash
|
||
# Story 3.8 — Sandbox-Tests des Determinismus-Vertrags (AD-17h/FT-10/A0-19) als
|
||
# Agent-Instruktions-Validator (§5.14, Revision 3.3)
|
||
# Re-executierbar: bash run-sandbox.sh (ab Workspace-Root; Sandbox unter /tmp/sb38)
|
||
# Zweck: die deterministische Bestätigungs-Mechanik (§5.14) als re-executierbarer
|
||
# Run-Demonstrator durchspielen —
|
||
# DET-1 BUNDLE_STATE_DEFINITION: ein Mini-Bundle erzeugen und die Bundle-State-
|
||
# Projektion deterministisch definieren/extrahieren (wiki/-Dateien + Plan-/
|
||
# Kandidaten-/Reihenfolge-Outputs; Extraktion zweimal -> identisch)
|
||
# DET-2 ZWEI_RUN_IDENTISCH (nicht-vakuum, zwei getrennte Worktrees): zwei frische
|
||
# Agent-Kontexte in getrennt aufgebauten, sauberen Worktrees über demselben
|
||
# committeten Baum -> identische Bundle-States bis auf at (Q-6/A0-19: eine zweite
|
||
# Ausführung in derselben Session genügt nicht); kanonisches Eingabemanifest +
|
||
# Run-Receipt (außerhalb des Bundles); keine hart codierten erwarteten Pläne/
|
||
# Concept-Bodies, kein pauschales verified-Maskieren; echte Content-Hashes
|
||
# (Witness weicht byte-weise von der Baseline ab — kein Vakuum)
|
||
# DET-3 ZWEI_RUN_ABWEICHUNG: künstlich divergenter Lauf -> als AD-16-Klassifikations-
|
||
# defekt klassifiziert und textuell benannt (kein Rauschen); korrigierter zweiter
|
||
# Lauf == erster Lauf (erneut bestätigt)
|
||
# DET-4 AT_GAP_AUSNAHME: generated.at-Wanduhr-Gap ist die einzige benannte Ausnahme
|
||
# (diff zwischen zwei Runs ausschließlich auf der at-Zeile; nach at-Maskierung
|
||
# byte-identisch); jede andere Differenz liegt ausserhalb der Ausnahme =
|
||
# AD-16-Klassifikationsdefekt
|
||
# DET-5 EM_DASH: Em-Dash — kollabiert auf dieselbe canonische Form wie En-Dash/
|
||
# Bindestrich/Unterstrich/Leerzeichen (§3.2 Pkt. 1b, [-–— _] -> -)
|
||
# DET-6 KOLLAPS: Läufe (a--b), führende (-x), trailende (x-) -> Kollaps auf
|
||
# genau ein - + Trim (Reichweite: jedes Vorkommen -> genau ein -)
|
||
# DET-7 MATCH_SCOPE: Stufe a matcht ganze Wörter über den Body, exklusive YAML-
|
||
# Frontmatter (Substring-/Frontmatter-Treffer ausgeschlossen)
|
||
# DET-8 ORPHAN: neu committete raw/-Evidenz ohne Ziel-Pfad-Treffer -> unzugeordnet,
|
||
# log.md-verwaist protokolliert (Datumsgruppe, <Baseline-Commit>), kein Banner,
|
||
# keine stille Vorbearbeitung, keine eigenständige Anlage (AD-16-Default)
|
||
# Determinismus-Vertrag (AD-17h/A0-19) als HARDE Assertion je Szenario; KEINE_EIGENE_ENGINE-
|
||
# Negativkontrolle (D-3/AD-11) in DET-1; Frontmatter-/log.md-Konformitaet (Vertrag §3.3/§3.4, §5).
|
||
# Ubuntu-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale wiki/- oder raw/-Baum.
|
||
set -u
|
||
ROOT=$(mktemp -d /tmp/sb38-XXXXXX)
|
||
SB="$ROOT/sb"
|
||
mkdir -p "$SB/wiki" "$SB/raw"
|
||
cd "$SB"
|
||
git init -q
|
||
# Determinismus vs. Host-Git-Konfiguration (AD-17h): LF-Blobs + LF-Worktree —
|
||
# autocrlf/filemode-Umwandlung des Hosts wuerde sha256-Vergleiche verschieben.
|
||
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) ----------
|
||
# 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
|
||
}
|
||
|
||
# ---------- Deterministische Normalisierung (§3.2 Pkt. 1b, Story 3.8) ----------
|
||
# lowercasing + Binde-Varianten-Kollaps [-–— _] -> - (En-Dash –, Em-Dash —,
|
||
# Bindestrich -, Unterstrich _, Leerzeichen), Kollaps-Reichweite: jedes Vorkommen ->
|
||
# genau ein -; Läufe kollabieren; führende/trailende Separatoren werden getrimmt.
|
||
norm() { # $1 = Begriff (Kollaps-Form, NICHT registry-aufloesend — Kollaps-Scope isoliert)
|
||
printf '%s' "$1" | sed \
|
||
-e 's|[–—]|-|g' \
|
||
-e 's|_| |g' \
|
||
-e 's| |-|g' \
|
||
-e 's|--*|-|g' \
|
||
-e 's|^-*||' \
|
||
-e 's|-*$||' \
|
||
| tr 'A-Z' 'a-z'
|
||
}
|
||
# Stufe-a-Match-Scope (§3.2 Pkt. 2a, Story 3.8): matcht ganze Wörter über den Body,
|
||
# exklusive YAML-Frontmatter. Implementierung: Frontmatter (zwischen ersten beiden ---)
|
||
# wird entfernt, danach Wortgrenzen-Match (rg mit Wortgrenzen bzw. grep '\b').
|
||
match_stufe_a() { # $1=Begriff $2=Datei-Liste ; liefert getroffene wiki-Pfade (ohne Präfix/Suffix)
|
||
local term="$1" file
|
||
# Symmetrische Normalisierung (Review-Loop-3, P-4; §3.2 Pkt. 2a): der Term wird über
|
||
# norm() (Lowercasing + Kollaps-Klasse [-–— _] -> -, §3.2 Pkt. 1b) normalisiert und der
|
||
# Body entsprechend lowercased — der Match läuft auf den beidseitig normalisierten Formen
|
||
# (kein host-abhängiges -i-Flag; Groß-/Kleinschreibung deterministisch über beide Seiten).
|
||
local term_lc
|
||
term_lc=$(norm "$term")
|
||
# Regex-Metazeichen im Begriff literal-escaped (deterministischer, literal-sicherer Vergleich,
|
||
# §3.2-Pkt.-2a/§5.14 Pkt. 5): ein Term wie "a+b" oder "x.y" darf nie als Muster umgedeutet werden.
|
||
local esc
|
||
esc=$(printf '%s' "$term_lc" | sed 's|[][\\.*^$+?(){}|]|\\&|g')
|
||
for file in "${@:2}"; do
|
||
# Body = alles nach dem zweiten "---" (Frontmatter exkludiert, deterministisch);
|
||
# CRLF-tolerant (Host-Checkout-Form normalisiert), sonst wäre der Wortgrenzen-Match unbestimmt.
|
||
# Der Body wird wie der Term lowercased (Symmetrie); die Kollaps-Äquivalenz des Em-Dash
|
||
# ist damit im Match-Pfad real ausgeübt (norm-then-match, Review-Loop-3, P-4).
|
||
body=$(tr -d '\r' < "$file" | tr 'A-Z' 'a-z' | awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}')
|
||
# Wortgrenzen-Match: ganze Wörter — Substring-/Frontmatter-Treffer liefern nichts.
|
||
if printf '%s' "$body" | grep -Eq "(^|[^A-Za-z0-9])${esc}([^A-Za-z0-9]|$)"; then
|
||
basename "$file" .md
|
||
fi
|
||
done
|
||
}
|
||
# log.md-Eintrag (datumsgruppiert, neueste zuerst; Vertrag §5). Deterministisch fester Tag.
|
||
# Fehler in mktemp/mv werden NICHT geschluckt: ein fehlgeschlagener Eintrag würde den
|
||
# log.md-Hash beider Läufe identisch (Baseline) lassen => Vakuum-Gleichheit (sha_log).
|
||
log_bullet() { # $1 = Bullet-Text (eine Zeile)
|
||
local day="2026-08-20"
|
||
local header="## $day" line="$1"
|
||
local tmp
|
||
if grep -qxF "$header" wiki/log.md; then
|
||
tmp=$(mktemp) || { echo "HARD-FAIL (log_bullet): mktemp fehlgeschlagen" >&2; exit 1; }
|
||
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 || { echo "HARD-FAIL (log_bullet): log.md-Update fehlgeschlagen (Eintrag verloren)" >&2; exit 1; }
|
||
else
|
||
tmp=$(mktemp) || { echo "HARD-FAIL (log_bullet): mktemp fehlgeschlagen" >&2; exit 1; }
|
||
{ printf '%s\n' "$header"; printf '%s\n' "$line"; cat wiki/log.md; } > "$tmp" \
|
||
&& mv "$tmp" wiki/log.md \
|
||
|| { echo "HARD-FAIL (log_bullet): log.md-Update fehlgeschlagen (Eintrag verloren)" >&2; exit 1; }
|
||
fi
|
||
}
|
||
|
||
# =====================================================================================
|
||
# DET-1 BUNDLE_STATE_DEFINITION (§5.14 Pkt. 1)
|
||
# =====================================================================================
|
||
runlabel "DET-1: BUNDLE_STATE_DEFINITION — Mini-Bundle erzeugen; Bundle-State-Projektion (wiki/-Dateien + Plan-/Kandidaten-/Reihenfolge-Outputs) deterministisch definieren/extrahieren; KEINE_EIGENE_ENGINE (D-3/AD-11)"
|
||
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" >&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 D-3/AD-11, §5.14): 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) — der Agent-Instruktions-Validator ist die Instruktion selbst (kein Prozess/Server/MCP)"
|
||
fi
|
||
isolate det1
|
||
# Der Run erzeugt einen definierten Bundle-State: neue committete Evidenz (Input) ->
|
||
# Plan-/Kandidaten-Output -> Mutations-Commit (deterministischer Run-Ausgangszustand).
|
||
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"
|
||
plan=$(printf 'cand=alpha;form=update;baseline=%s' "$BASE")
|
||
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
|
||
log_bullet "- Determinismus-Bestätigung (Bundle-State-Definition, §5.14 Pkt. 1): $plan"
|
||
git add -A && git commit -qm "Run: alpha-Update (DET-1)"
|
||
# Bundle-State-Extraktion (§5.14 Pkt. 1): (a) committeter Baum gg. Baseline,
|
||
# (b) Kandidatenliste in Zuwachs-Sicht-Ordnung, (c) Ausführungs-Entscheidung (Form-Wahl).
|
||
# Deterministische Projektion = (a)+(b)+(c) — zweimal extrahiert, byte-identisch.
|
||
# Dev-Demo-Notiz: die (b)-/(c)-Kandidaten-/Form-Outputs sind für die Wiederholungs-Probe
|
||
# eigentliche Run-Feststellungen (hier redaktionell verdichtet; die Tendenz "die Bundle-State
|
||
# wiederholt extrahieren ist deterministisch" wird von der zweimaligen Wiederholung bewiesen,
|
||
# die Ausführungs-Verdikte selbst belegen die DET-Szenarien DET-3/DET-4/DET-7).
|
||
bs_a() {
|
||
{ 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
|
||
# Kandidatenliste (Stufe a, deterministisch; Zuwachs-Ordnung) — hier textuell festgehalten:
|
||
match_stufe_a "kopplung" wiki/alpha.md wiki/gamma.md
|
||
# Form-Wahl (Ausführungs-Entscheidung): alpha ist betroffen, gamma nicht
|
||
echo "form=update"
|
||
echo "baseline=$BASE"
|
||
}
|
||
B1=$(bs_a)
|
||
B2=$(bs_a)
|
||
[ "$B1" = "$B2" ] || { echo "HARD-FAIL (DET-1): Bundle-State-Projektion nicht deterministisch (gleiche Extraktion zweimal ungleich)" >&2; exit 1; }
|
||
case "$B1" in
|
||
*alpha*) ;;
|
||
*) echo "HARD-FAIL (DET-1): Bundle-State-Projektion enthaelt Wiki-Pfad-Projektion nicht (alpha fehlt)" >&2; exit 1;;
|
||
esac
|
||
echo " Bundle-State-Projektion (deterministisch, wiederextrahierbar):"
|
||
echo "$B1" | sed 's/^/ /'
|
||
echo "RESULT: PASS — DET-1: BUNDLE_STATE_DEFINITION — Bundle-State = deterministische Projektion des committeten Git-States ((a) Baum gg. Baseline, (b) Kandidaten-, (c) Plan-/Reihenfolge-/Entscheidungs-Outputs); Extraktion zweimal byte-identisch (AD-17h/A0-19); keine eigene Engine (D-3/AD-11)"
|
||
|
||
# =====================================================================================
|
||
# DET-2 ZWEI_RUN_IDENTISCH (nicht-vakuum, zwei getrennte Worktrees) — §5.14 Pkt. 2
|
||
# =====================================================================================
|
||
runlabel "DET-2: ZWEI_RUN_IDENTISCH (nicht-vakuum) — zwei frische Agent-Kontexte in getrennt aufgebauten, sauberen Worktrees über demselben committeten Baum -> identische Bundle-States bis auf at (Q-6/A0-19); kanonisches Eingabemanifest + Run-Receipt außerhalb des Bundles; keine hart codierten erwarteten Bundle-Outputs, verified nicht pauschal maskiert; echte Content-Hashes (Witness weicht byte-weise von Baseline ab)"
|
||
# --- Zwei getrennte, saubere Worktrees über demselben Baseline-Commit ($BASE) aufbauen ---
|
||
# Re-Run-Sicherheit: verwaiste worktree-Registrierungen aus früheren Läufen (anderes $ROOT)
|
||
# erst prune, sonst blockiert `git worktree add` oder trägt Altpfade nach.
|
||
git worktree prune
|
||
git worktree add -q "$ROOT/wt-a" "$BASE" || { echo "HARD-FAIL (DET-2): Worktree wt-a nicht aufgebaut" >&2; exit 1; }
|
||
git worktree add -q "$ROOT/wt-b" "$BASE" || { echo "HARD-FAIL (DET-2): Worktree wt-b nicht aufgebaut" >&2; exit 1; }
|
||
# Kanonisches Eingabemanifest (A0-19, §5.14 Pkt. 2): Baseline-Commit + geordnete Source-
|
||
# Eingaben + output-sichtbare Run-/Zeit-/Identitätswerte — identisch für beide Läufe.
|
||
# Das Manifest wird unten in run2_worktree VOR jedem Lauf konsumiert/validiert (nicht dekorativ).
|
||
cat > "$ROOT/manifest.yaml" <<EOF
|
||
baseline: $BASE
|
||
generated_by: wow-compiler/0.1.0
|
||
sources:
|
||
- raw/alpha-v1.md
|
||
- raw/alpha-v2.md
|
||
output_visible_run_identity:
|
||
- generated.by
|
||
- generated.at # A0-20: einzige benannte Ausnahme im Bundle-State-Vergleich (Pkt. 3)
|
||
EOF
|
||
manifest_path="$ROOT/manifest.yaml"
|
||
[ -f "$manifest_path" ] || { echo "HARD-FAIL (DET-2): kanonisches Eingabemanifest fehlt ($manifest_path; §5.14 Pkt. 2)" >&2; exit 1; }
|
||
|
||
run2_worktree() { # $1 = Worktree-Pfad ; $2 = Run-Name ; führt die Instruktion als EIGENER
|
||
# Ausführungskontext (frischer Agent-Kontext simulativ: eigener Worktree, eigene Subshell
|
||
# mit eigenem cwd, keine Session-Wiederholung) über demselben committeten Baum aus.
|
||
# Der Run läuft komplett in einer Subshell — der Haupt-Kontext bleibt am Sandbox-Root
|
||
# (kein Carry-over des Worktree-cwd in nachfolgende Szenarien).
|
||
local wt="$1" name="$2"
|
||
(
|
||
set -e
|
||
cd "$wt" || exit 9
|
||
# Kanonisches Eingabemanifest VOR dem Lauf konsumieren/validieren (A0-19, §5.14 Pkt. 2):
|
||
# Baseline-Commit und geordnete Source-Eingaben müssen dem Repository-State entsprechen
|
||
# — das Manifest ist Eingabe der Instruktion, nicht bloße Doku (kein leerer Lauf möglich).
|
||
m_base=$(sed -n 's/^baseline: //p' "$ROOT/manifest.yaml")
|
||
[ -n "$m_base" ] || { echo "HARD-FAIL (DET-2): Manifest ohne baseline-Key" >&2; exit 9; }
|
||
[ "$m_base" = "$BASE" ] || { echo "HARD-FAIL (DET-2): Manifest-baseline ($m_base) != tatsaechliche Baseline ($BASE)" >&2; exit 9; }
|
||
# Abschnittsbewusste Extraktion: nur Elemente unter dem jeweiligen Manifest-Key
|
||
m_src=$(awk '/^sources:/{f=1;next} /^[a-z_]+:/{f=0} f && /^ - /{sub(/^ - /,""); sub(/ *#.*$/,""); print}' "$ROOT/manifest.yaml")
|
||
m_identity=$(awk '/^output_visible_run_identity:/{f=1;next} /^[a-z_]+:/{f=0} f && /^ - /{sub(/^ - /,""); sub(/ *#.*$/,""); print}' "$ROOT/manifest.yaml")
|
||
[ -n "$m_src" ] || { echo "HARD-FAIL (DET-2): Manifest ohne geordnete Source-Eingaben" >&2; exit 9; }
|
||
[ -n "$m_identity" ] || { echo "HARD-FAIL (DET-2): Manifest ohne output-sichtbare Identitätswerte" >&2; exit 9; }
|
||
case "$m_identity" in *generated.at*) ;; *) { echo "HARD-FAIL (DET-2): Manifest muss generated.at als Identitätswert führen (A0-20-Ausnahme)" >&2; exit 9; };; esac
|
||
case "$m_identity" in *generated.by*) ;; *) { echo "HARD-FAIL (DET-2): Manifest muss generated.by als Identitätswert führen" >&2; exit 9; };; esac
|
||
# generated.by wird aus dem Manifest KONSUMIERT (nicht hart codiert; Review-Loop-3, P-6):
|
||
# der output-sichtbare Identitätswert des Laufs ist Manifest-Inhalt, nicht Skript-Konstante.
|
||
m_by=$(sed -n 's/^generated_by: //p' "$ROOT/manifest.yaml")
|
||
[ -n "$m_by" ] || { echo "HARD-FAIL (DET-2): Manifest ohne generated_by-Wert" >&2; exit 9; }
|
||
# Sicherstellen: Worktree am Baseline-Commit, sauber (Q-6: getrennt aufgebaut, sauber).
|
||
git checkout -qf "$BASE"
|
||
git clean -qfd wiki raw
|
||
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"
|
||
# Source-Eingaben-Verdikt: JEDE manifestierte geordnete Source-Eingabe (raw/alpha-v1.md
|
||
# aus der Baseline, raw/alpha-v2.md als neuer Increment-Input) existiert im Worktree
|
||
# NACH dem Input-Commit (EC-1-Semantik: Quelle zum Verarbeitungszeitpunkt vorhanden).
|
||
for s in $m_src; do
|
||
[ -f "$s" ] || { echo "HARD-FAIL (DET-2): Manifest-Source fehlt im Worktree nach Input-Commit: $s" >&2; exit 9; }
|
||
done
|
||
# Mutations-Commit als commitierter Run-Ausgangszustand: generated.at IST die reale
|
||
# Wanduhr-Ausgabe des Laufs (A0-20) — sie wird COMMITTET und im Receipt als eigener
|
||
# at-Zellenwert festgehalten; die Normalisierung auf AT erfolgt erst BEIM VERGLEICH
|
||
# (§5.14 Pkt. 2: "diff ... ohne die maskierte at-Zeile"), nicht vor dem Commit
|
||
# (kein stiller Ausschluss, keine Maskierung vor der Persistenz).
|
||
at_now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||
cat > wiki/alpha.md <<EOF
|
||
---
|
||
type: concept
|
||
sources:
|
||
- resource: raw/alpha-v1.md
|
||
id: s1
|
||
- resource: raw/alpha-v2.md
|
||
id: s3
|
||
generated:
|
||
by: $m_by
|
||
at: $at_now
|
||
---
|
||
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
|
||
# Plan-/Kandidaten-/Reihenfolge-Ableitung (§5.14 Pkt. 2) — abgeleitet aus dem
|
||
# deterministischen Run-State, NICHT hart codiert: Kandidat = Stufe-a-Treffer des
|
||
# Terms "kopplung" über den (deterministischen) Body (dieselbe Ableitung wie DET-1).
|
||
# cand kann mehrere Dateien zeilengetrennt liefern — auf eine leere/kommafreie Form
|
||
# normalisiert, damit der Receipt-Zeilenblock nicht durch eingebettete Newlines bricht.
|
||
local cand
|
||
cand=$(match_stufe_a "kopplung" wiki/alpha.md wiki/gamma.md | tr '\n' ',' | sed 's/,$//')
|
||
local plan
|
||
plan="cand=$cand;form=update;baseline=$BASE"
|
||
log_bullet "- Determinismus-Bestätigung (Zwei-Run, §5.14 Pkt. 2): $plan; Baseline $BASE"
|
||
# Confirm: der at-Zellenwert ist als reale Wanduhr-Ausgabe committet (kein Maskieren vor Commit).
|
||
git add -A && git commit -qm "Run: alpha-Update ($name)"
|
||
committed_at=$(git show 'HEAD:wiki/alpha.md' | sed -n 's/^ at: //p')
|
||
[ "$committed_at" = "$at_now" ] || { echo "HARD-FAIL (DET-2): commitierte at != Lauf-at ($committed_at != $at_now; Maskierung vor Commit?)" >&2; exit 9; }
|
||
# --- Bundle-State projizieren (deterministisch) + RUN-RECEIPT (außerhalb des Bundles) ---
|
||
# Run-Receipt (A0-19, §5.14 Pkt. 2): Candidate-Liste, Reihenfolge, Plan, Entscheidungen,
|
||
# Output-Hashes, Bundle-TREE und die at-Ausnahme (je Run-Cell) — liegt AUSSERHALB des
|
||
# Knowledge Bundle (nicht in wiki//raw/), hier unter $ROOT/receipts/.
|
||
# Die Run-Identität steht im Dateinamen (run2a.receipt/run2b.receipt); der INHALT ist die
|
||
# deterministische Projektion plus die at-Ausnahme-Cell, damit der Zwei-Run-Abgleich BOTH
|
||
# (a) byte-identische deterministische Teile UND (b) die ausgewiesene at-Ausnahme prüft.
|
||
mkdir -p "$ROOT/receipts"
|
||
{
|
||
echo "baseline: $BASE"
|
||
echo "plan: $plan"
|
||
echo "candidates: $cand"
|
||
echo "order: update-$cand"
|
||
echo "decisions: form=update;candidate_match=stufe_a(kopplung)"
|
||
# sha_alpha wird über die at-NORMALISIERTE Content-Projektion gebildet (§5.14 Pkt. 2:
|
||
# Vergleich "ohne die maskierte at-Zeile"; A0-20) — die deterministischen Bestandteile
|
||
# bleiben damit byte-vergleichbar, der at-Wert trägt nur in der at_cell-Ausnahme.
|
||
echo "sha_alpha=$(git show 'HEAD:wiki/alpha.md' | sed 's/^ at: .*/ at: AT/' | sha256sum | cut -d' ' -f1)"
|
||
echo "sha_log=$(git show 'HEAD:wiki/log.md' | sha256sum | cut -d' ' -f1)"
|
||
echo "sha_index=$(git show 'HEAD:wiki/index.md' | sha256sum | cut -d' ' -f1)"
|
||
# at_cell + tree sind die AUSNAHME-Evidenz: tree (Bundle-TREE-Hash des Run-Committs)
|
||
# enthält die realen at-Wanduhr-Werte — wird daher NICHT im deterministischen Block
|
||
# verglichen, sondern dokumentiert hier die benannte at-Ausnahme (kein stiller
|
||
# Ausschluss: die deterministischen Bundle-Bestandteile decken sha_alpha/log/index ab).
|
||
echo "at_cell=$committed_at"
|
||
echo "tree=$(git rev-parse 'HEAD:')"
|
||
} > "$ROOT/receipts/$name.receipt"
|
||
)
|
||
local rc=$?
|
||
[ $rc -eq 0 ] || { echo "HARD-FAIL (DET-2): Lauf $name im Worktree fehlgeschlagen (rc=$rc)" >&2; exit 1; }
|
||
}
|
||
echo "--- Lauf A (frischer Agent-Kontext, Worktree wt-a) ---"
|
||
run2_worktree "$ROOT/wt-a" run2a
|
||
cat "$ROOT/receipts/run2a.receipt"
|
||
echo "--- Lauf B (frischer Agent-Kontext, Worktree wt-b) ---"
|
||
run2_worktree "$ROOT/wt-b" run2b
|
||
cat "$ROOT/receipts/run2b.receipt"
|
||
# at-Ausnahme-Demo (Review-Loop-3, P-7): die aktive Ausnahme (real unterschiedliche
|
||
# Wanduhr-at-Werte) wird ERZWUNGEN, nicht nur gedruckt — bei einer Wanduhr-Sekunden-
|
||
# kollision wird Lauf B deterministisch wiederholt (frischer Kontext, derselbe Baum),
|
||
# bis die at-Zellen differieren (begrenzte Wiederholungen; jede Kollision ist ein
|
||
# Host-Timing-Artefakt, keine Eigenschaft des committeten Zustands). Damit ist der
|
||
# Change-Log-Beleg „zwei Läufe mit real unterschiedlichen at_cell-Werten" eine
|
||
# Eigenschaft jeder Re-Execution.
|
||
at_a=$(grep '^at_cell=' "$ROOT/receipts/run2a.receipt" | cut -d= -f2)
|
||
for try in 1 2 3 4 5; do
|
||
at_b=$(grep '^at_cell=' "$ROOT/receipts/run2b.receipt" | cut -d= -f2)
|
||
[ "$at_a" != "$at_b" ] && break
|
||
if [ "$try" -eq 5 ]; then
|
||
echo "HARD-FAIL (DET-2): at-Ausnahme nicht demonstrierbar (5x Sekundenkollision — Host-Timing-Anomalie)" >&2
|
||
exit 1
|
||
fi
|
||
echo " at-Kollision (Wanduhr-Sekunde) — Lauf B wird im frischen Kontext wiederholt (Versuch $try)"
|
||
run2_worktree "$ROOT/wt-b" run2b
|
||
done
|
||
# Receipt-Gerüst-Nicht-Vakuum: beide Receipts müssen den deterministischen Zeilenblock tragen
|
||
# (diff könnte sonst zweifach-leere Dateien als "identisch" PASSen lassen).
|
||
for r in "$ROOT/receipts/run2a.receipt" "$ROOT/receipts/run2b.receipt"; do
|
||
[ -s "$r" ] || { echo "HARD-FAIL (DET-2): Receipt $r leer oder fehlt (Vakuum)" >&2; exit 1; }
|
||
done
|
||
echo "--- Abgleich der zwei Run-Receipts (nicht nur jeder Lauf gg. Baseline; keine hart codierten Erwartungswerte) ---"
|
||
# Deterministischer Vergleich: ALLE Zeilen bis auf die beiden Ausnahme-Cells (at_cell=, tree=)
|
||
# müssen zwischen den zwei Runs byte-identisch sein — at_cell/tree tragen die realen, je Lauf
|
||
# unterschiedlichen Wanduhr-at-Werte und dokumentieren damit die benannte Ausnahme (A0-20,
|
||
# §5.14 Pkt. 3): differenzieren dürfen ausschließlich diese beiden; der Rest ist byte-identisch.
|
||
filtered_a=$(grep -vE '^(at_cell|tree)=' "$ROOT/receipts/run2a.receipt")
|
||
filtered_b=$(grep -vE '^(at_cell|tree)=' "$ROOT/receipts/run2b.receipt")
|
||
at_a=$(grep '^at_cell=' "$ROOT/receipts/run2a.receipt" | cut -d= -f2)
|
||
at_b=$(grep '^at_cell=' "$ROOT/receipts/run2b.receipt" | cut -d= -f2)
|
||
tree_a=$(grep '^tree=' "$ROOT/receipts/run2a.receipt" | cut -d= -f2)
|
||
tree_b=$(grep '^tree=' "$ROOT/receipts/run2b.receipt" | cut -d= -f2)
|
||
# (a) die deterministischen Bestandteile: byte-identisch
|
||
if [ "$filtered_a" != "$filtered_b" ]; then
|
||
echo "HARD-FAIL (DET-2): deterministische Receipt-Bestandteile weichen ab (AD-16-Klassifikationsdefekt, ausserhalb der at-Ausnahme; §5.14 Pkt. 2/4):" >&2
|
||
diff -u <(printf '%s\n' "$filtered_a") <(printf '%s\n' "$filtered_b") >&2 || true
|
||
exit 1
|
||
fi
|
||
# (b) at-Ausnahme benannt vorhanden (dokumentierte Ausnahme, kein stiller Ausschluss)
|
||
[ -n "$at_a" ] || { echo "HARD-FAIL (DET-2): at-Ausnahme-Cell fehlt in receipt A" >&2; exit 1; }
|
||
[ -n "$at_b" ] || { echo "HARD-FAIL (DET-2): at-Ausnahme-Cell fehlt in receipt B" >&2; exit 1; }
|
||
[ -n "$tree_a" ] && [ -n "$tree_b" ] || { echo "HARD-FAIL (DET-2): tree-Cell fehlt in einem Receipt" >&2; exit 1; }
|
||
# P-7-Assertion: die aktive Ausnahme ist jetzt hart belegt (Wiederholungs-Schleife oben
|
||
# hat at_a != at_b erzwungen) — kein stilles „BEFUND: at-Grenzfall" mehr.
|
||
[ "$at_a" != "$at_b" ] || { echo "HARD-FAIL (DET-2): at-Ausnahme nicht demonstriert — beide Läufe tragen identischen at-Wert (P-7: aktive Ausnahme-Assertion)" >&2; exit 1; }
|
||
echo " BEFUND: at-Ausnahme aktiv (assertiert) — Lauf A at=$at_a, Lauf B at=$at_b (benannte Ausnahme, §5.14 Pkt. 3: übrige Bestandteile byte-identisch)"
|
||
# (d) Der deterministische Content weicht als Ganzes von der Baseline ab (Witness, echte Hashes).
|
||
ABS_A=$(git -C "$ROOT/wt-a" show "$BASE:wiki/alpha.md" | sha256sum | cut -d' ' -f1)
|
||
SHA_A=$(git -C "$ROOT/wt-a" show 'HEAD:wiki/alpha.md' | sha256sum | cut -d' ' -f1)
|
||
[ -n "$ABS_A" ] && [ -n "$SHA_A" ] || { echo "HARD-FAIL (DET-2): Witness-Hashes leer (Vakuum — Assertion wertlos)" >&2; exit 1; }
|
||
[ "$ABS_A" != "$SHA_A" ] || { echo "HARD-FAIL (DET-2): Witness == Baseline (vakuum — der Vergleich bewiese nichts; AD-17h/A0-19: echte Content-Identität gefordert)" >&2; exit 1; }
|
||
# verified wird NICHT pauschal maskiert: das demonstrierte Bundle trägt ausschließlich die
|
||
# Identitätswerte generated.by + generated.at (kein verified[]-Feld — die Ausnahme-Menge ist
|
||
# in diesem Mini-Bundle exakt {generated.at}); die einzige erlaubte Differenz der
|
||
# Bundle-State-Vergleiche ist die benannte at-Ausnahme (Pkt. 3), die hier als at_cell real
|
||
# committet und beim Vergleich dokumentiert normalisiert ist (kein Maskieren vor Commit,
|
||
# kein stiller Ausschluss — eine weitere Differenz würde den deterministischen Abgleich brechen).
|
||
echo " WITNESS: Baseline-alpha-SHA ($ABS_A) != Run-alpha-SHA ($SHA_A) — der Zwei-Run-Vergleich ist nicht-vakuum (Content weicht von Baseline ab, echte Hashes)"
|
||
echo " MANIFEST: $ROOT/manifest.yaml (identisch für beide Läufe, VOR jedem Lauf validiert); RECEIPTS: $ROOT/receipts/ (außerhalb des Bundles)"
|
||
echo "RESULT: PASS — DET-2: ZWEI_RUN_IDENTISCH — zwei frische Agent-Kontexte in getrennt aufgebauten, sauberen Worktrees (wt-a/wt-b, demselben committeten Baum) produzieren identische Bundle-States (Run-Receipts byte-identisch bis auf die als at_cell ausgewiesene generated.at-Ausnahme: Plan-, order-, decisions-, log-, index-, alpha-Content-Hashes und Bundle-TREE; at real committet und erst beim Vergleich normalisiert — dokumentierte Ausnahme statt stiller Ausschluss); Vergleich nicht-vakuum (Witness vs. Baseline, echte Content-Hashes, §5.14 Pkt. 2, FT-10/AD-17h AC-1, Q-6/A0-19)"
|
||
|
||
# =====================================================================================
|
||
# DET-3 ZWEI_RUN_ABWEICHUNG (§5.14 Pkt. 4)
|
||
# =====================================================================================
|
||
runlabel "DET-3: ZWEI_RUN_ABWEICHUNG — künstlich divergenter Lauf -> als AD-16-Klassifikationsdefekt klassifiziert und textuell benannt (kein Rauschen); korrigierter zweiter Lauf == erster Lauf (erneut bestätigt)"
|
||
# Referenz-Run (deterministische Bundle-State-Projektion)
|
||
run3_ref() {
|
||
isolate run3ref
|
||
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"
|
||
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: AT
|
||
---
|
||
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
|
||
git add -A && git commit -qm "Run: alpha-Update (Referenz)"
|
||
echo "SHA=$(git show 'HEAD:wiki/alpha.md' | sha256sum | cut -d' ' -f1)"
|
||
}
|
||
# Divergenter Run: veränderter Body-Content (RAUSCHEN-fremde Abweichung — ein deterministischer
|
||
# Bestandteil weicht ab, hier eine andere Formulierung der Aussage) trotz gleichem Git-State+Input.
|
||
run3_div() {
|
||
isolate run3div
|
||
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"
|
||
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: AT
|
||
---
|
||
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
|
||
git add -A && git commit -qm "Run: alpha-Update (divergent)"
|
||
echo "SHA=$(git show 'HEAD:wiki/alpha.md' | sha256sum | cut -d' ' -f1)"
|
||
}
|
||
R3=$(run3_ref)
|
||
D3=$(run3_div)
|
||
echo "Referenz-Run: $R3"
|
||
echo "Divergenter Lauf: $D3"
|
||
SHA_REF=$(echo "$R3" | cut -d= -f2)
|
||
SHA_DIV=$(echo "$D3" | cut -d= -f2)
|
||
[ -n "$SHA_REF" ] && [ -n "$SHA_DIV" ] || { echo "HARD-FAIL (DET-3): Hashes leer (Vakuum)" >&2; exit 1; }
|
||
if [ "$SHA_REF" = "$SHA_DIV" ]; then
|
||
echo "HARD-FAIL (DET-3): der divergente Lauf blieb inspiziert ununterscheidbar (Abweichung nicht erkannt; §5.14 Pkt. 4 verlangt Klassifikation)" >&2
|
||
exit 1
|
||
fi
|
||
echo "NFR-4-Benennung (textuell): ZWEI_RUN_ABWEICHUNG — Lauf 'divergent' weicht ausserhalb der benannten at-Ausnahme vom Referenz-Lauf ab (unterschiedlicher Content-Hash $SHA_DIV != $SHA_REF bei gleichem Git-State + gleichem Eingabeset) => AD-16-Klassifikationsdefekt (FT-10/AD-17h-AC), kein Rauschen; der Run wird als Fehler im Klassifikations-Mechanismus behandelt, textuell benannt und korrigiert/zurückgerollt (§5.14 Pkt. 4, Zustands-Restaurations-Invariante §5.13 Pkt. 3)"
|
||
echo "--- Korrigierter zweiter Lauf: rollt zurueck und wiederholt deterministisch (== Referenz) ---"
|
||
rollback3() {
|
||
git checkout -q "$BASE" -- wiki/ 2>/dev/null || true
|
||
git reset -q --hard "$BASE"
|
||
git clean -qfd wiki
|
||
}
|
||
rollback3
|
||
R3B=$(run3_ref)
|
||
SHA_REFB=$(echo "$R3B" | grep '^SHA=' | cut -d= -f2)
|
||
[ "$SHA_REF" = "$SHA_REFB" ] || { echo "HARD-FAIL (DET-3): korrigierte Wiederholung weicht von der Referenz ab (AD-17h verletzt)" >&2; exit 1; }
|
||
echo " BEFUND: korrigierter Lauf == Referenz-Lauf (SHA $SHA_REF) — der Vertrag ist nach Korrektur erneut bestätigt (Pkt. 4: 'Befund wird (ggf. als korrigierter zweiter Lauf) erneut bestätigt')"
|
||
echo "RESULT: PASS — DET-3: ZWEI_RUN_ABWEICHUNG — künstlich divergenter Lauf wurde als AD-16-Klassifikationsdefekt erkannt (Content-Hash-Differenz bei gleichem State+Input — kein Rauschen, keine Umgebungs-Streuung) und textuell benannt (NFR-4); korrigierter zweiter Lauf reproduziert den Referenz-Bundle-State (Zustands-Restaurations-Invariante, §5.13 Pkt. 3; §5.14 Pkt. 4)"
|
||
|
||
# =====================================================================================
|
||
# DET-4 AT_GAP_AUSNAHME (§5.14 Pkt. 3)
|
||
# =====================================================================================
|
||
runlabel "DET-4: AT_GAP_AUSNAHME — generated.at-Wanduhr-Gap ist die einzige benannte Ausnahme; zwei Runs mit unterschiedlichem at -> diff ausschließlich auf der at-Zeile; nach at-Maskierung byte-identisch; jede andere Differenz = AD-16-Klassifikationsdefekt"
|
||
isolate det4
|
||
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"
|
||
mkrun4() { # $1 = at-Wert — schreibt alpha mit EXAKT unterschiedlichen at-Werten
|
||
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: $1
|
||
---
|
||
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
|
||
}
|
||
mkrun4 "2026-08-16T09:00:00Z"
|
||
git add -A && git commit -qm "Run at=A"
|
||
mkrun4 "2026-08-19T23:59:59Z"
|
||
git add -A && git commit -qm "Run at=B"
|
||
# diff zwischen beiden Run-Zuständen: ausschließlich die at-Zeile
|
||
DABC=$(git diff HEAD~1 HEAD -- wiki/alpha.md)
|
||
[ -n "$DABC" ] || { echo "HARD-FAIL (DET-4): die zwei Runs sind identisch — at-Gap nicht demonstriert (Vakuum)" >&2; exit 1; }
|
||
non_at=$(echo "$DABC" | grep '^[-+][^-+]' | grep -v '^[-+] at: ' | grep -v '^[+-][+-]')
|
||
if [ -n "$non_at" ]; then
|
||
echo "HARD-FAIL (DET-4): der diff zwischen den zwei Runs betrifft BESTANDTEILE ausserhalb der at-Ausnahme:" >&2
|
||
echo "$non_at" | sed 's/^/ /' >&2
|
||
exit 1
|
||
else
|
||
echo " BEFUND: diff ausschließlich auf der at-Zeile (einzige benannte Ausnahme, §5.14 Pkt. 3)"
|
||
fi
|
||
echo "--- Nach at-Maskierung byte-identisch (restliche Bundle-Bestandteile) ---"
|
||
H1=$(git show HEAD~1:wiki/alpha.md | sed 's/^ at: .*/ at: AT/' | sha256sum | cut -d' ' -f1)
|
||
H2=$(git show HEAD:wiki/alpha.md | sed 's/^ at: .*/ at: AT/' | sha256sum | cut -d' ' -f1)
|
||
[ "$H1" = "$H2" ] || { echo "HARD-FAIL (DET-4): nach at-Maskierung weichen die Runs ab (bestandteil über at hinaus; §5.14 Pkt. 3 verlangt byte-Identität der übrigen Teile)" >&2; exit 1; }
|
||
echo " BEFUND: nach at-Maskierung byte-identisch (SHA $H1) — dokumentierte Ausnahme, kein stiller Ausschluss"
|
||
echo "--- Negative Kontrolle: eine Differenz AUSSERHALB der Ausnahme ist ein AD-16-Klassifikationsdefekt ---"
|
||
mkrun4 "2026-08-16T09:00:00Z"
|
||
printf '\nAndere Aussagenformulierung.\n' >> wiki/alpha.md
|
||
git add -A && git commit -qm "Run at=B' (Differenz im Body)"
|
||
non_at2=$(git diff HEAD~1 HEAD -- wiki/alpha.md | grep '^[-+][^-+]' | grep -v '^[-+] at: ' | grep -v '^[+-][+-]')
|
||
[ -n "$non_at2" ] || { echo "HARD-FAIL (DET-4): Body-Differenz wurde nicht erkannt (Negativkontrolle leer)" >&2; exit 1; }
|
||
echo "NFR-4-Benennung (textuell): Body-Differenz ausserhalb der at-Ausnahme-Menge => AD-16-Klassifikationsdefekt (kein Rauschen), textuell benannt (§5.14 Pkt. 3/4)"
|
||
echo "RESULT: PASS — DET-4: AT_GAP_AUSNAHME — generated.at-Wanduhr-Gap ist die einzige benannte Differenz im Bundle-State-Vergleich (A0-20-Konvention, §5.9 Pkt. 2/§5.10 Pkt. 8): zwei Runs diffieren ausschließlich in der at-Zeile, nach at-Maskierung byte-identisch; jede andere Differenz liegt ausserhalb der Ausnahme = AD-16-Klassifikationsdefekt (Negativkontrolle, §5.14 Pkt. 3)"
|
||
|
||
# =====================================================================================
|
||
# DET-5 EM_DASH (§3.2 Pkt. 1b, §5.14 Pkt. 5)
|
||
# =====================================================================================
|
||
runlabel "DET-5: EM_DASH — Em-Dash — normalisiert auf dieselbe canonische Form wie En-Dash/Bindestrich/Unterstrich/Leerzeichen (§3.2 Pkt. 1b: Kollaps-Klasse [-–— _] -> -)"
|
||
# Term-Basis mit Em-Dash / En-Dash / Bindestrich / Unterstrich / Leerzeichen-Separator
|
||
EM=$(norm "wissen — relevanz")
|
||
EN=$(norm "wissen – relevanz")
|
||
HY=$(norm "wissen - relevanz")
|
||
US=$(norm "wissen_relevanz")
|
||
SP=$(norm "wissen relevanz")
|
||
[ "$EM" = "$EN" ] || { echo "HARD-FAIL (DET-5): Em-Dash-Form != En-Dash-Form" >&2; exit 1; }
|
||
[ "$EM" = "$HY" ] || { echo "HARD-FAIL (DET-5): Em-Dash-Form != Bindestrich-Form" >&2; exit 1; }
|
||
[ "$EM" = "$US" ] || { echo "HARD-FAIL (DET-5): Em-Dash-Form != Unterstrich-Form" >&2; exit 1; }
|
||
[ "$EM" = "$SP" ] || { echo "HARD-FAIL (DET-5): Em-Dash-Form != Leerzeichen-Form" >&2; exit 1; }
|
||
case "$EM" in
|
||
*"—"*) echo "HARD-FAIL (DET-5): Em-Dash blieb in der canonischen Form erhalten (Kollaps-Klasse greift nicht)" >&2; exit 1;;
|
||
esac
|
||
echo " canonische Form (alle fünf Separatoren): '$EM'"
|
||
echo " Em-Dash-Term kollabiert auf dieselbe canonische Form wie En-Dash/Bindestrich/Unterstrich/Leerzeichen (kein stiller Ausschluss, §3.2 Pkt. 1b)"
|
||
echo "RESULT: PASS — DET-5: EM_DASH — Em-Dash — ist in der Kollaps-Klasse [-–— _] -> - (§3.2-Pkt.-1b-Ergänzung, §5.14 Pkt. 5): Term mit Em-Dash erhält dieselbe canonische Form wie En-Dash/Bindestrich/Unterstrich/Leerzeichen-Varianten — deterministisch, keine unterschiedliche canonische Form je Separator"
|
||
|
||
# =====================================================================================
|
||
# DET-6 KOLLAPS (§3.2 Pkt. 1b, §5.14 Pkt. 5)
|
||
# =====================================================================================
|
||
runlabel "DET-6: KOLLAPS — Kollaps-Reichweite: Läufe (a--b), führende (-x), trailende (x-) -> Kollaps auf genau ein - + Trim (§3.2 Pkt. 1b)"
|
||
[ "$(norm "a--b")" = "a-b" ] || { echo "HARD-FAIL (DET-6): Lauf a--b kollabiert nicht auf a-b (norm='$(norm "a--b")')" >&2; exit 1; }
|
||
[ "$(norm "-x")" = "x" ] || { echo "HARD-FAIL (DET-6): führender Separator -x wird nicht getrimmt (norm='$(norm "-x")')" >&2; exit 1; }
|
||
[ "$(norm "x-")" = "x" ] || { echo "HARD-FAIL (DET-6): trailender Separator x- wird nicht getrimmt (norm='$(norm "x-")')" >&2; exit 1; }
|
||
[ "$(norm "a--b")" = "a-b" ] && [ "$(norm "a---b")" = "a-b" ] && [ "$(norm "---x---")" = "x" ] || { echo "HARD-FAIL (DET-6): Läufe/Trim-Kombination inkonsistent" >&2; exit 1; }
|
||
echo " Läufe a--b -> '$(norm "a--b")'; führend -x -> '$(norm "-x")'; trailend x- -> '$(norm "x-")'"
|
||
echo "RESULT: PASS — DET-6: KOLLAPS — Kollaps-Reichweite deterministisch (§3.2 Pkt. 1b, §5.14 Pkt. 5): Läufe kollabieren auf genau ein -, führende/trailende Separatoren werden getrimmt — glaubhaft re-executierbar, keine offene Reichweiten-Frage"
|
||
|
||
# =====================================================================================
|
||
# DET-7 MATCH_SCOPE (§3.2 Pkt. 2a, §5.14 Pkt. 5)
|
||
# =====================================================================================
|
||
runlabel "DET-7: MATCH_SCOPE — Stufe a matcht ganze Wörter über den Body, exklusive YAML-Frontmatter (Substring-/Frontmatter-Treffer ausgeschlossen, §3.2 Pkt. 2a)"
|
||
isolate det7
|
||
# Concept: Body enthält "kopplung" als GANZES Wort; Frontmatter enthält "kopplung" als
|
||
# Substring im Quell-Pfad raw/kopplung-v1.md (Frontmatter-Treffer-Wächter).
|
||
cat > wiki/alpha.md <<'EOF'
|
||
---
|
||
type: concept
|
||
sources:
|
||
- resource: raw/kopplung-v1.md
|
||
id: s1
|
||
generated:
|
||
by: wow-compiler/0.1.0
|
||
at: 2026-08-16T09:00:00Z
|
||
---
|
||
Alpha als Wissenseinheit: hier steht einzig das ganz Wort kopplung ohne weitere Bindung.
|
||
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: das Wort entkopplung belegt nur einenerweiternden Teil — kein eigener ganzer Treffer.
|
||
EOF
|
||
git add -A && git commit -qm "Stufe-a-Flex"
|
||
# 1) Substring-Kontrolle: 'kopplung' (ganz) trifft alpha; 'opplung' (Substring) trifft nichts
|
||
HIT1=$(match_stufe_a "kopplung" wiki/alpha.md wiki/gamma.md)
|
||
[ "$HIT1" = "alpha" ] || { echo "HARD-FAIL (DET-7): ganzes-Wort-Match 'kopplung' liefert '$HIT1' (Soll: alpha; Substring-/Gamma-Treffer unerlaubt)" >&2; exit 1; }
|
||
HIT2=$(match_stufe_a "opplung" wiki/alpha.md)
|
||
[ -z "$HIT2" ] || { echo "HARD-FAIL (DET-7): Substring-Match 'opplung' liefert einen Kandidaten (Stufe a matcht ganze Wörter, §3.2 Pkt. 2a)" >&2; exit 1; }
|
||
# 2) Frontmatter-Exklusion: Suchbegriff exakt gleich einem Frontmatter-RESOURCE-Substring
|
||
# (raw/kopplung-v1.md enthält 'kopplung') — zugleich im Body von alpha steht 'kopplung'
|
||
# nur als ganzes Wort => Treffer genau EINMAL (alpha). Der Frontmatter ist exkludiert,
|
||
# ein zusätzlicher Body-Treffer erzeugt keinen zweiten Kandidaten — wir prüfen, dass
|
||
# das Frontmatter-Vorkommen keinen falschen Kandidaten (z. B. durch RegExp über die ganze
|
||
# Datei inkl. Frontmatter) erzeugt. Konkret: wir legen einen zweiten Concept-Body VOR, der
|
||
# 'kopplung' NUR im Frontmatter traegt (Quell-Pfad raw/kopplung-mirror.md) — Stufe a muss
|
||
# ihn verwerfen, weil der Frontmatter exkludiert ist.
|
||
cat > wiki/mirror.md <<'EOF'
|
||
---
|
||
type: concept
|
||
sources:
|
||
- resource: raw/kopplung-mirror.md
|
||
id: s1
|
||
generated:
|
||
by: wow-compiler/0.1.0
|
||
at: 2026-08-16T09:00:00Z
|
||
---
|
||
Gamma-Mirror ohne Kopplungs-Begriff im Bodytext.
|
||
EOF
|
||
git add -A && git commit -qm "Frontmatter-only-Kandidat"
|
||
HIT3=$(match_stufe_a "kopplung" wiki/alpha.md wiki/gamma.md wiki/mirror.md)
|
||
[ "$HIT3" = "alpha" ] || { echo "HARD-FAIL (DET-7): Frontmatter-Treffer erzeugt Kandidat (mirror) — Stufe a matcht nur Body, exklusive YAML-Frontmatter (§3.2 Pkt. 2a)" >&2; exit 1; }
|
||
# 3) Direkte Formel-Probe der operativen Stufe-a-Formel (§3.2-Pkt.-2a-Zweistufen-Mechanik):
|
||
# Sweep mit der Formel -> dann deterministischer Scope-Filter (ganze Wörter, Body, after second ---).
|
||
SWEEP=$(grep -rl 'kopplung' --exclude=log.md wiki/ | LC_ALL=C sort)
|
||
# Sweep-muss alpha, gamma (Substring entkopplung) und mirror (Frontmatter-only) finden —
|
||
# der Scope-Filter verwirft gamma+mirror; als Kandidaten bleiben die Body-ganz-Wort-Treffer.
|
||
FILTERED=$(for f in $SWEEP; do
|
||
if match_stufe_a "kopplung" "$f" | grep -q .; then basename "$f" .md; fi
|
||
done | LC_ALL=C sort | tr '\n' ' ')
|
||
FILTERED="${FILTERED% }"
|
||
[ "$FILTERED" = "alpha" ] || { echo "HARD-FAIL (DET-7): operative Stufe-a-Zweistufen-Mechanik liefert '$FILTERED' (Soll: alpha) — Scope-Filter unvollständig (§3.2 Pkt. 2a, §5.14 Pkt. 5)" >&2; exit 1; }
|
||
echo " Direkte Formel-Probe: Sweep (grep -rl) -> Scope-Filter verwirft Substring-/Frontmatter-Treffer -> Kandidat: alpha"
|
||
echo "RESULT: PASS — DET-7: MATCH_SCOPE — Stufe a matcht ganze Wörter (Wortgrenzen) über den Body, exklusive YAML-Frontmatter: Substring-Treffer ('opplung') und Frontmatter-only-Kandidaten (mirror) liefern keine Kandidaten (§3.2 Pkt. 2a, §5.14 Pkt. 5) — deterministischer Stufe-a-Scope, keine falschen Kandidaten; operative Zweistufen-Mechanik (Sweep+Filter) abgesichert"
|
||
|
||
# =====================================================================================
|
||
# DET-8 ORPHAN (§5.10 Pkt. 8, §5.14 Pkt. 5)
|
||
# =====================================================================================
|
||
runlabel "DET-8: ORPHAN — neu committete raw/-Evidenz ohne Ziel-Pfad-Treffer -> unzugeordnet, log.md-verwaist protokolliert (Datumsgruppe, <Baseline-Commit>), kein Banner, keine stille Vorbearbeitung, keine eigenständige Anlage (AD-16-Default)"
|
||
isolate det8
|
||
cat > raw/orphan-v1.md <<'EOF'
|
||
### S-1
|
||
Evidenz: gänzlich fremdes Thema, das in keinem bestehenden Concept-Body Wort-Treffer hat.
|
||
EOF
|
||
git add -A && git commit -qm "Verwaiste Evidenz"
|
||
# Ziel-Pfad-Treffer-Prüfung: Term über die neuen Quellen enthält 'fremdes-thema' — kein
|
||
# bestehender Concept-Body trifft (Stufe a, deterministisch); kein Update-Kandidat.
|
||
CAND=$(match_stufe_a "fremdes" wiki/alpha.md wiki/gamma.md)
|
||
[ -z "$CAND" ] || { echo "HARD-FAIL (DET-8): verwaiste Evidenz erzielt einen Ziel-Pfad-Treffer (Kein-Orphan erwartet)" >&2; exit 1; }
|
||
# Reconcile-Orphan-Regel (§5.10 Pkt. 8 / §5.14 Pkt. 5): deterministisch aus dem committeten
|
||
# Git-State (Zuwachs gg. <Baseline-Commit>) als verwaist befunden -> datumsgruppierter
|
||
# log.md-Eintrag (Header YYYY-MM-DD, Quell-Pfad + <Baseline-Commit>); keine eigenständige Anlage.
|
||
log_bullet "- Reconcile-Orphan (Story 3.8; §5.10 Pkt. 8 / §5.14 Pkt. 5): raw/orphan-v1.md (Zuwachs gg. <Baseline $BASE>) ohne Ziel-Pfad-Treffer — unzugeordnet, verwaist protokolliert; kein Banner, keine stille Vorbearbeitung, keine eigenständige Anlage (AD-16-Default, Epic-4-Interface)"
|
||
echo "--- Kein Banner / keine stille Vorbearbeitung / keine eigenständige Anlage ---"
|
||
if [ -f wiki/orphan.md ]; then
|
||
echo "HARD-FAIL (DET-8): verwaiste Evidenz wurde eigenständig als Concept angelegt (verboten, AD-16-Default)" >&2
|
||
exit 1
|
||
fi
|
||
# Nur log.md ist mutiert (Orphan-Eintrag) — Erhaltungs-Invariante §5.9 Pkt. 5 (log.md ist
|
||
# erlaubtes Mitglied des Diff-Selbsttest-Satzes); keine weiteren Mutations-Pfade.
|
||
MUT=$( { 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)
|
||
[ "$MUT" = "log" ] || { echo "HARD-FAIL (DET-8): Verwaist-Run mutiert ausserhalb {log} — Pfade: [$MUT]" >&2; exit 1; }
|
||
grep -qF "Reconcile-Orphan" wiki/log.md || { echo "HARD-FAIL (DET-8): Verwaist-Protokoll fehlt in log.md (§5.10 Pkt. 8)" >&2; exit 1; }
|
||
grep -qF "## 2026-08-20" wiki/log.md || { echo "HARD-FAIL (DET-8): log.md-Eintrag nicht in Datumsgruppe (Vertrag §5)" >&2; exit 1; }
|
||
grep -qF "$BASE" wiki/log.md || { echo "HARD-FAIL (DET-8): <Baseline-Commit> fehlt im Verwaist-Eintrag (§5.10 Pkt. 8, deterministisch auflösbar D-2)" >&2; exit 1; }
|
||
echo " BEFUND: raw/orphan-v1.md bleibt in raw/ unangetastet (AD-3); log.md trägt datumsgruppierten Verwaist-Eintrag mit <Baseline-Commit>"
|
||
echo "RESULT: PASS — DET-8: ORPHAN — neu committete raw/-Evidenz ohne Ziel-Pfad-Treffer bleibt unzugeordnet und wird als datumsgruppierter log.md-Eintrag (Quell-Pfad + <Baseline-Commit>) verwaist protokolliert (§5.10 Pkt. 8 / §5.14 Pkt. 5): kein Banner, keine stille Vorbearbeitung, keine eigenständige Anlage (AD-16-Default) — Erhaltungs-Invariante gewahrt (nur log.md mutiert)"
|
||
|
||
echo
|
||
echo "===== Sandbox abgeschlossen (DET-1..DET-8) ====="
|
||
echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)"
|