diff --git a/_bmad-output/implementation-artifacts/deferred-work.md b/_bmad-output/implementation-artifacts/deferred-work.md index f844b62..142ed8a 100644 --- a/_bmad-output/implementation-artifacts/deferred-work.md +++ b/_bmad-output/implementation-artifacts/deferred-work.md @@ -413,3 +413,25 @@ Noch nicht adressierte, aber real erkannte Arbeit — gesammelt aus Reviews. Ein summary: **Frozen Spec-Intent-Typo „Nickel" im §5.10-Form-Wahl-Aufgaben-Pfad (Story-3.3-Defer U2/U7-Empfehlung)** — der Intent-Satz „Nickel die Story-3.3-Defer U2/U7-Empfehlung (…) im Sandbox auf" enthält „Nickel" statt „Nimm/Trage … auf" (oder „Schließe … auf"); er sitzt im ``-Block des Specs, dessen Text erst nach humaner Re-Negotiation geändert werden darf. Kein Instruktions-Defekt (der Sandbox-/authored-Text ist korrekt — FW-Szenario implementiert die Empfehlung inhaltlich). Home: Spec-Re-Negotiation (Ask-First: menschliche Autorisierung) oder Akzeptanz als kosmetischer Frozen-Fehler. evidence: Step-04-Review (2026-08-19, Blind-Hunter-Layer): `spec-3-4-…md` Zeile ~18 (frozen Intent) — „Nickel die Story-3.3-Defer U2/U7-Empfehlung … auf". status: offen + +## Deferred from: code review of spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen (Story 3.5, 2026-08-19) + +- source_spec: `_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md` + summary: **holder_id Quelle/Uniqueness (Pkt. 1) nicht definiert** — das Lockfile-Feld `holder_id` („eindeutige Producer-/Run-Kennung") legt nicht fest, welcher deterministische Git-/Umgebungs-Wert es erzeugt (Branch-Suffix? Producer-Name? Run-Identifier?). Die Sandbox vergibt Beispiele (`run-a-holder`), §5.11 Pkt. 1 benennt keinen Ableitungs-Operanden. Kein Instruktions-Defekt für die Koordinations-Mechanik (Eindeutigkeit ist eine Producer-Verantwortung), aber eine offene Determinismus-Frage am Feld. Home: Story 3.6 (Lease-Registrierung) oder Story 3.8 (Determinismus-Ableitung) — ableitbarer holder_id-Default. + evidence: Step-04-Review (2026-08-19, Blind-Hunter-Layer) — „holder_id uniqueness source undefined"; `schema/compiler.md` §5.11 Pkt. 1, `run-lock-Write`. + status: offen (Home: Story 3.6 oder 3.8) + +- source_spec: `_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md` + summary: **baseline_commit-Merge-Base-Ableitung (Pkt. 1) nicht von `git merge-base`-Laufzeit vs. notiertem `` reconciliert** — §5.11 nennt beide Quellen („deterministisch über `git merge-base` bzw. den notierten `` aus §5.9 Pkt. 6"), ohne Diskrepanz-Regel (welche gewinnt, wenn `git merge-base` eine andere Spitze liefert als die letzte notierte Mutations-Boundary? §5.9 Pkt. 6 hat die Differenz-Regel für Diff-Prüfungen, §5.11 nicht). Kein akuter Instruktionsdefekt (die Merge-Base-Disziplin zielt auf denselben Punkt), aber eine offene Disambiguierung. Home: Story 3.6 (Lease-Registrierung/Baseline) — Baseline-Auflösungs-Regel vereinheitlichen. + evidence: Step-04-Review (2026-08-19, Blind-Hunter+Verification-Gap) — „baseline_commit merge-base derivation not reconciled"; `schema/compiler.md` §5.11 Pkt. 1. + status: offen (Home: Story 3.6) + +- source_spec: `_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md` + summary: **Sandbox-log-Akkumulator vs. eigener `# Log`-Stand jedes isolierten Szenarios** — die Sandbox richtet je Szenario via `isolate` einen frischen (leeren) `wiki/log.md`-Stand ein und D2 demonstriert die kumulative Aufzeichnung separat; der Akkumulator lebt damit nur im Diskurs, nicht in einem durchgängigen Run-Baum. Die Koordinations-Aufzeichnung über MEHRERE Runs hinweg (consecutive Producers, die dieselbe `wiki/log.md`-Datei fortschreiben, ohne dass `isolate` sie zurücksetzt) ist nicht als eigenständiges Szenario demonstriert. Kein Instruktions-Defekt — die Regel (Pkt. 6) ist kumulativ formuliert, D2 belegt sie hart. Home: Story 3.6 (Registrierung/Verfahrnaher) oder Doku-Verbesserung der Sandbox — nichts funktionales offen. + evidence: Step-04-Review (2026-08-19, Blind-Hunter-Layer) — „isolate wipes per-scenario log entries so cumulative coordination recording never demonstrated"; geschlossen durch D2 (Story-3.5-Sandbox). + status: offen (Home: Story 3.6) — D2 demonstriert die kumulative Aufzeichnung hart. + +- source_spec: `_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md` + summary: **`isolate`-Skript nutzt native `git stash`-Variante für den Dirty-Tree-Schutz nicht** — §5.11 Pkt. 3 nennt „`git stash push -- ` … oder Kopie in eine benannte Scratch-Zone"; die Sandbox demonstriert nur die Kopier-Variante (Scratch-Zone). Die `git stash`-Variante bleibt ungetestet. Kein Instruktions-Defekt (beide Wege sind textuell zulässig, die Determinismus-Anforderung betrifft das Ergebnis), aber eine Test-Lücke der alternativen Schutz-Umsetzung. Home: Story 3.6 (Lease-/Recovery-Stash-Semantik) oder Sandbox-Erweiterung — nichts funktional offen. + evidence: Step-04-Review (2026-08-19, Verification-Gap-Layer) — „native git stash alternative untested (only manual cp-into-scratch)"; `schema/compiler.md` §5.11 Pkt. 3. + status: offen (Home: Story 3.6) diff --git a/_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh b/_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh new file mode 100644 index 0000000..8ff45a1 --- /dev/null +++ b/_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh @@ -0,0 +1,617 @@ +#!/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)" diff --git a/_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md b/_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md new file mode 100644 index 0000000..021a635 --- /dev/null +++ b/_bmad-output/implementation-artifacts/spec-3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetzen.md @@ -0,0 +1,135 @@ +--- +title: 'Leasing & Dirty-Tree-Schutz für konkurrierende Producer operationalisieren (Story 3.5)' +type: 'feature' +created: '2026-08-19' +status: 'done' +review_loop_iteration: 0 +baseline_commit: fae648e688781d281fa668310e179fd002ba812f +context: + - _bmad-output/implementation-artifacts/epic-3-context.md +--- + + + +## Intent + +**Problem:** §0/§5.3 verankern die Commit-Boundary = Mutations-Boundary (AD-17f) als einzigen bisherigen Schutz. Es fehlt die **Koordinations-Dimension für konkurrierende Producer** (AD-17a..f, A0-12..A0-16, FR-2/FR-12): wie zwei Producer denselben Concept-Pfad nicht stillschweigend überschreiben, wie eine Lease auf `lease//`-Branches mit Root-Scope und Merge-Base-Disziplin erworben wird, und wie fremde uncommittete Änderungen (Dirty Tree) geschützt statt als Nebenwirkung gelöscht werden. Der §7-Vorbehalt (`:357`) zeigt unbehoben auf Story 3.5/3.6. + +**Approach:** Story 3.5 verankert die Leasing-/Dirty-Tree-Mechanik als neue Sektion **§5.11 „Leasing & Dirty-Tree-Schutz für konkurrierende Producer (Story 3.5)"** (nach §5.10, vor §6, Revision 3.0): deterministische Regeln für Lease-Akquise (Branch-Form `lease//`, Lockfile, Merge-Base-Disziplin), Root-Scope-Lease (inkl. `log.md`, `index.md`, Root-Dateien), Dirty-Tree-Schutz (Pre-Mutation-Prüfung, Stash/Scratch-Zone, `log.md`-Dokumentation) und compiler-vermittelten Merge als AD-16-Pfad (kein stiller textueller Auto-Merge). Zusätzlich eine **re-executierbare Sandbox** (`sandbox-3-5/run-sandbox.sh`, Muster Story-3.4): demonstriert Lease-Akquise + Dirty-Tree-Schutz + Merge-Verweigerung an echten Git-Szenarien und assertet die Invarianten hart. Keine Inhalts-Mutation des realen Bundles (AD-3); kein neues `raw/`-Material; kein Standalone (D-3). + +## Boundaries & Constraints + +**Always:** +- **Instruktions-Story (D-3):** Verankerung ausschließlich in `schema/compiler.md` §5.11 als deterministischer Text. Kein executable, kein Standalone, keine neue §7-Invaliditätsklasse, kein Change an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3). +- **Leasing-Modell (AD-17a, A0-12):** Producer arbeiten auf `lease//`-Branches; die Lease wird gegen einen **eindeutigen Commit-Object-Wert** (Merge-Base-Disziplin) akquiriert; ein **Lockfile** realisiert semantisch identisch in jedem Adapter — die Realisierung ist nicht pro Adapter frei wählbar. +- **Root-Scope-Lease (AD-17b, A0-13):** Die Lease umfasst `wiki/` inklusive `log.md`, `index.md` und aller Root-Dateien — nicht nur den mutierten Concept-Pfad. +- **Kein textueller Auto-Merge (AD-17c, A0-14):** Zwei Branches mit ungleichem Inhalt am selben Concept-Pfad werden nie textuell automatisch gemerged; der Merge ist compiler-vermittelt und durchläuft die AD-16-Klassifikation mit explizitem `log.md`-Eintrag (Interface zu Epic 4). +- **Dirty-Tree-Schutz (AD-17e/f, A0-16):** Vor jeder Mutation wird die Working Copy auf den mutierten Bereich geprüft; fremde uncommittete Änderungen werden geschützt (Stash/Scratch-Zone) und in `log.md` dokumentiert; Mutationen operieren nur auf Directory-/Commit-Ebene — Commit-Boundary = Mutations-Boundary. +- **Determinismus (AD-17h/A0-19):** Lease-Akquise, Lockfile-Inhalte und Merge-Klassifikation folgen deterministisch aus dem committeten Git-State; gleicher Git-State + gleiche Eingabemenge → identische Koordinationsentscheidung. +- **Struktur-Erhaltung (FR-6/AC-2, Story 3.3):** Die §5.9-Pkt.-2-Struktur-Erhaltungsregeln gelten je berührtem Pfad unverändert; Leasing erzwingt keine neuen Concept-Felder (Vertrag §3.1–§3.7-Subset unverändert). +- **Erhaltungs-Invariante (AD-5/FT-6):** Der §5.9-Pkt.-5-Diff-Selbsttest gilt für Leasing-fähige Runs unverändert (Pfad-Menge ⊆ Kandidatenliste ∪ Neu-Anlage ∪ `log.md` ∪ Index). +- `sprint-status.yaml`: Key `3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetz` → **in-progress** (bei Implementierung). + +**Ask First:** Inhalts-Mutation des realen Bundles (Demo per Sandbox) · AD-7d-Renames · §5.6-Linkform-Änderung · Validator-/Vertrags-/`raw/`-Change · Lease-Staleness/Recovery-Scope (3.6) · Lease-Bereich jenseits `wiki/` (AD-17b-Root-Scope) · neuer Concept-Frontmatter-Key für Lease-Metadaten. + +**Never:** Änderungen an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3) · neue §7-Invaliditätsklasse · Standalone (D-3) · stiller textueller Auto-Merge (AD-17c) · stille Löschung fremder uncommitteter Änderungen (AD-17e) · Leasing außerhalb von Git-Branches/Lockfile · Embeddings/Vector im Compiler-Kern (AD-13) · Scope-Ausweitung auf Lease-Staleness/Recovery (Story 3.6). + +## I/O & Edge-Case Matrix + +| Scenario | Input / State | Expected Output / Behavior | Error Handling | +|----------|--------------|---------------------------|----------------| +| LEASE_AKQUISE | Producer bearbeitet Area, keine Lease vorhanden | Arbeits-Branch `lease//` auf Merge-Base; Lockfile geschrieben; Root-Scope-Lease dokumentiert | Lockfile existiert bereits → Lease-Hold, kein Überschreiben | +| LEASE_KONFLIKT | Zweiter Producer, Lockfile von Producer A vorhanden/Konflikt am selben Pfad | Kein stiller textueller Auto-Merge; compiler-vermittelter AD-16-Pfad mit `log.md`-Eintrag | Unentscheidbar → menschliche Eskalation (AD-17g) | +| DIRTY_TREE_SCHUTZ | Fremde uncommittete Änderung im mutierten Bereich | Schutz (Stash/Scratch-Zone) + `log.md`-Dokumentation; keine Löschung | Screen-Artefakte beim Schutz → textuell benannt | +| UNCOMMITTED_INPUT | `raw/`/`wiki/`-Working-Copy weicht von HEAD ab | Benannter Abbruch „published/committed Input erforderlich" (AD-17a) vor jeder Mutation | Keine Mutation, Bundle konsistent | +| COMMIT_BOUNDARY | Run nach Mutation + Validierung | Commit-Boundary = Mutations-Boundary; Zwischenstände nie veröffentlicht | Validierungs-FAIL → Rollback §5.3 | + + + +## Code Map + +- `schema/compiler.md` — **primär mutiert** (D-3): + - Neue Sektion **§5.11** (nach §5.10, vor §6): Lease-Akquise (Branch-Form `lease//`, Lockfile, Merge-Base-Disziplin — deterministisch, AD-17h), Root-Scope-Lease (AD-17b, A0-13), Dirty-Tree-Schutz (Pre-Mutation-Prüfung, Stash/Scratch-Zone, `log.md`-Dokumentation, AD-17e/f), compiler-vermittelter Merge als AD-16-Pfad (kein textueller Auto-Merge, AD-17c/A0-14), Commit-Boundary = Mutations-Boundary (§0/§5.3-Verweis unverändert), `log.md`-Eintragspflicht (Lease-Akquise, Schutz-Dokumentation, Merge-Klassifikation), Determinismus-Vertrag. + - §7 (`:357`): Lease-Vorbehalt **auflösen** („→ §5.11 verankert (Story 3.5)"). + - §8 Revisionslog: **Revision 3.0** mit Abschlussklausel (AD-3, keine neue §7-Klasse, kein Standalone, kein Vertrags-Change; Lease-Staleness/Recovery bleibt → Story 3.6). +- `_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh` — **neu** (re-executierbar, Muster Story-3.4-Sandbox): Mini-Git-Repo mit `wiki/`+`raw/`; Szenarien L1–L6 (Lease-Akquise auf `lease//`-Branch mit Lockfile · Lockfile-Konflikt → Lease-Hold · Root-Scope-Lease inkl. `log.md`/`index.md` · Dirty-Tree-Schutz mit Stash/Scratch-Zone + `log.md`-Dokumentation · kein textueller Auto-Merge bei ungleichem Pfad-Inhalt · Commit-Boundary-Verletzung → HARD-FAIL) + **Negativ-Kontrollen** (fremde uncommittete Änderung wird nie gelöscht; `??`-Sicht auf Ghost-Diffs). Harte Pass/Fail-Assertionen (exit 1), Erhaltungs-Invariante, `assert_frontmatter` (Muster Story-3.4). +- `wiki/log.md` — **append** (append-only, Vertrag §5): Story-3.5-Eintrag (Verankerung, Sandbox-Nachweis, Statuswechsel, Validator-Verdikt); bestehende Bullets unverändert. +- `_bmad-output/implementation-artifacts/sprint-status.yaml` — **mutiert**: Key `3-5-…` → in-progress (→ done bei Story-Abschluss). +- `schema/validator.md`, `schema/wiki-compiler.md`, `adapters/…`, `raw/…` — **read-only** (AD-3). Keine Concept-Inhalts-Mutation (Demonstration per Sandbox). + +## Tasks & Acceptance + +**Execution:** +- [x] `schema/compiler.md` — §5.11 Leasing-/Dirty-Tree-Sektion einfügen (Branch-Form, Lockfile, Merge-Base-Disziplin, Root-Scope, Dirty-Tree-Schutz, AD-17c-Merge-Pfad, Commit-Boundary-Verweis, log.md, Determinismus) · §7-Vorbehalt `:357` auflösen · §8 Revision 3.0; ohne Change an `wiki-compiler.md`/`validator.md`/`raw/`. +- [x] `sandbox-3-5/run-sandbox.sh` — Leasing-Run-Demonstrator (Akquise, Konflikt, Root-Scope, Dirty-Tree-Schutz, Merge-Verweigerung, Commit-Boundary); harte Pass/Fail-Assertionen; Exit 0. +- [x] `wiki/log.md` — Story-3.5-Eintrag (append-only): Verankerung, Sandbox-Nachweis, Statuswechsel, per-Datei-Validator-Verdikt. +- [x] `sprint-status.yaml` — Key `3-5-…` → in-progress. + +**Acceptance Criteria:** +- Given ein Producer, when er einen Bereich bearbeitet, then arbeitet er auf einem `lease//`-Branch und akquiriert die Lease gegen einen eindeutigen Commit-Object-Wert (AC-1; AD-17a, A0-12) — §5.11, Sandbox L1. +- Given eine vergebene Lease, when sie aktiv ist, then umfasst sie die Root-Scope inklusive `log.md`, `index.md` und aller Root-Dateien (AC-2; AD-17b, A0-13) — §5.11, Sandbox L3. +- Given eine vorliegende uncommittete Fremdänderung im mutierten Bereich, when ein Producer mutieren will, then schützt er sie (Stash/Scratch-Zone) und dokumentiert den Vorgang in `log.md` (AC-3; AD-17e, A0-16) — §5.11, Sandbox L4, Negativ-Kontrolle „nie gelöscht". +- Given zwei Branches mit ungleichem Inhalt am selben Concept-Pfad, when gemerged werden soll, then erfolgt kein stiller textueller Auto-Merge; die Auflösung ist compiler-vermittelt über AD-16 mit explizitem `log.md`-Eintrag (AC-4; AD-17c, A0-14) — §5.11, Sandbox L5. +- Given die Instruktion, when geprüft, then bleiben `schema/validator.md`/`schema/wiki-compiler.md`/`raw/` unverändert (AD-3), keine neue §7-Klasse, kein Standalone (D-3), kein neuer Frontmatter-Key, Lease-Staleness/Recovery bleibt an Story 3.6 — Validator auf Ist-Bundle SUCCESS. + +## Spec Change Log + +- **Review-Loop 1 (2026-08-19, step-04; 3 Layer: blind-hunter / edge-case-hunter / verification-gap):** Autofix-`patch`-Findings in `schema/compiler.md` (§5.11) und `sandbox-3-5/run-sandbox.sh`; **kein bad_spec/intent_gap**, `review_loop_iteration` bleibt 0. **Text-Fixes (§5.11):** (1) Pkt.-1-Querverweis „Pkt. 3" → „Pkt. 2" (Root-Scope-Lease; dangling ref); (2) `UNCOMMITTED_INPUT`-Name als I/O-Matrix-Szenario-Deklaration geführt und **explizit mit der §5.9-P2-Element-(1)-`INPUT_UNCOMMITTED`-Prüfung gleichgesetzt** (kein zweiter, separater Abbruch-Pfad — Namens-Kollision aufgelöst); (3) Pkt. 6 um „neueste zuerst" (Vertrag-§5-Datumsgruppe, wie §5.9 Pkt. 4) ergänzt; (4) **Lease-Freigabe (Release)** als deterministischer Pkt.-1-Sub-Bullet + Pkt.-6-Eintragstyp (e) verankert — Lockfiles häufen sich nicht (Staleness-/Recovery-Aspekte der Freigabe verbleiben Story 3.6); (5) **testbares 3.5/3.6-Seam-Kriterium** (3.5 = committed-state-deterministisch / 3.6 = Zeit- bzw. Umgebungs-Zustands-Frage) ergänzt; (6) §7-Enum: AD-17d/A0-15 als **Norm-Rückverweis** gekennzeichnet (Staleness ist nicht Teil der §5.11-Auflösung); (7) §8-Revision 3.1. **Sandbox-Fixes:** (a) log-Helfer: Header-Bullet-**Paar** je Eintrag statt `\n##`-je-Zeile (Datumsgruppen-Format, Vertrag §5; kumulativer Append — neue D2-Szenario „Kumulative Koordinations-Aufzeichnung": 4 Entscheidungen in EINEM log.md, neueste zuerst); (b) L2-Lease-Hold hart über Exit-Status assertet (kein toter Code); (c) L4: `UNCOMMITTED_INPUT`-Abbruch-**Wirkung** hard asserted (HEAD unverändert, nur der fremde alpha-Pfad weicht ab, keine Mutation) + **Restore-Weg** (Scratch→Bundle) demonstriert; `^ M `-porcelain-Form werkzeugunabhängig; (d) L6: `BROKEN_HEAD`/`COMMIT_AFTER_RUN`-Tautologie beseitigt (`BUILD_HEAD`), Frontmatter-Validierungs-FAIL via Subshell (Exit-Propagation), Restore-Assertion korrekt; (e) L5: `log.md`-Klassifikations-Label als Header-Bullet asserted (kein bloßer Substring); (f) L3: `??`-Sicht nicht vacuous — neue legal angelegte `wiki/beta.md` als erlaubte Neu-Anlage durch die Invariante klassifiziert; (g) N1: „Pkt. 8" auf §5.10 Pkt. 8 (Orphan-Nachbarschaft) statt §5.9-Pkt.-8 quasi-finalisiert. **Defers** → `deferred-work.md` (holder_id-Quelle; baseline_commit-Resolver; eigener `# Log`-Stand vs. Akkumulator; Revisionsnummer-1.0-Defer). **Nachweis:** Sandbox Exit 0, 21 harte PASS-Assertionen (L1–L6, N1, D1, D2); AD-3 unverändert. + +## Design Notes + +**Warum §5.11, nicht §0-Erweiterung:** Die Commit-Boundary (§0/§5.3) ist der *Schutz bei Einzel-Validierung*; Leasing/Dirty-Tree ist die *Koordination vor/nach der Mutation an Branches* — eine eigenständige Dimension, die die Branch-/Lockfile-/Stash-Semantik beschreibt. §5.9/§5.10 (Update/Synthese) beschreiben die *Inhalts-Mechanik*; §5.11 beschreibt die *Werkzeug-Koordination*, die um jede Mutations-Form herum läuft. Das spiegelt den §7-Vorbehalt (`:357`) als eigenes Thema. + +**Grenzfläche zu 3.6:** Story 3.5 deckt Akquise, Konflikt-Hold, Root-Scope und Dirty-Tree-Schutz. Staleness (TTL, Lease-Registrierung, verwaiste Leases, `raw/`-Recovery) bleibt der Story 3.6 vorbehalten — §5.11 verweist auf 3.6 und mutiert deren Mechanik nicht. + +**Lease-Schutz ohne neue Fields:** Die Lease lebt in **Git/Datei-Ebene** (Branch-Name, Lockfile) — nicht in Concept-Frontmatter (Vertrag §3.1–§3.7 unverändert, keine neue §7-Klasse). Ein Lockfile realisiert semantisch identisch in jedem Adapter (A0-12); die Satzform präzisiert das Format, damit deterministisch (AD-17h). + +## Verification + +**Commands (re-executierbar, ab Workspace-Root):** +1. `bash _bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh` — expected: alle Szenarien L1–L6 + Negativ-Kontrollen mit harten Pass/Fail-Assertionen, Erhaltungs-Invariante erzwungen, Exit 0. +2. `grep -n "Leasing & Dirty-Tree-Schutz\|Revision 3.0" schema/compiler.md` — liefert die Leasing-Sektion + Revisionslog-Eintrag. +3. Read-only (AD-3): `git status --porcelain` zeigt keinen Change an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`. +4. Validator-Lauf: alle `wiki/`-Dateien SUCCESS (unverändert, keine Inhalts-Mutation). + +**Manual checks:** +- §5.11 trägt Branch-Form `lease//`, Lockfile, Merge-Base-Disziplin, Root-Scope-Lease, Dirty-Tree-Schutz (Stash/Scratch-Zone + log.md), AD-17c-Merge-Pfad, Commit-Boundary-Verweis, Determinismus; §7-Vorbehalt `:357` auf §5.11 aufgelöst; §8-Rev-3.0 mit Abschlussklausel; kein `validator.md`/`wiki-compiler.md`/`adapters/`/`raw/`-Diff; kein neuer Standalone (D-3) / keine neue §7-Klasse / kein neuer Frontmatter-Key; Lease-Staleness bleibt an 3.6; `wiki/log.md`-Eintrag datiert mit Story-3.5-Semantik + Sandbox-Nachweis + Statuswechsel + Verdikt; `sprint-status.yaml` konsistent. + +## Suggested Review Order + +**Leasing-Koordinations-Dimension (§5.11)** + +- Einstiegspunkt: die verbindliche Verankerung der Koordinations-Dimension — Lease-Akquise, Root-Scope, Dirty-Tree-Schutz, Merge- und Determinismus-Vertrag + [`compiler.md:303`](../../schema/compiler.md#L303) + +- Pkt. 1 Lease-Akquise: Branch-Form, Lockfile, Merge-Base-Disziplin, deterministische Lease-Freigabe + [`compiler.md:307`](../../schema/compiler.md#L307) + +- Pkt. 2/3 Root-Scope-Lease + Dirty-Tree-Schutz: Stash/Scratch-Zone, UNCOMMITTED_INPUT-Abbruch (nicht-vacuous) + [`compiler.md:312`](../../schema/compiler.md#L312) + +- Pkt. 4–7: compiler-vermittelter Merge (AD-16), Commit-Boundary, log.md-Pflicht, Determinismus-Vertrag & 3.5/3.6-Seam + [`compiler.md:317`](../../schema/compiler.md#L317) + +- §8-Revisionslog „Revision 3.0" mit Abschlussklausel (AD-3, keine neue §7-Klasse, kein Standalone) + [`compiler.md:416`](../../schema/compiler.md#L416) + +**Nachweis: Sandbox & Story-Protokoll** + +- Szenario-Matrix L1–L6 + Negativ-Kontrollen als re-executierbarer Beweis der Invarianten + [`run-sandbox.sh:6`](../../_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh#L6) + +- L1 Lease-Akquise / L2 Lease-Hold: hart assertierte Akquise- und Fehlerpfade + [`run-sandbox.sh:269`](../../_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh#L269) + +- L4 Dirty-Tree-Schutz: Pre-Mutation-Prüfung, Restore-Weg, „nie gelöscht"-Assertion + [`run-sandbox.sh:379`](../../_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh#L379) + +- L6 Commit-Boundary: Zwischenstand nie veröffentlicht, Validierungs-FAIL → Rollback + [`run-sandbox.sh:476`](../../_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh#L476) + +- Story-3.5-`wiki/log.md`-Eintrag: Verankerung, Sandbox-Nachweis, Statuswechsel, Verdikt (append-only) + [`log.md:3`](../../wiki/log.md#L3) + +- 4 Defers (holder_id-Quelle, baseline_commit-Merge-Base, Sandbox-Akkumulator, native `git stash`) — Homes Story 3.6/3.8 + [`deferred-work.md:416`](../../_bmad-output/implementation-artifacts/deferred-work.md#L416) diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index 65b1710..2394a0c 100644 --- a/_bmad-output/implementation-artifacts/sprint-status.yaml +++ b/_bmad-output/implementation-artifacts/sprint-status.yaml @@ -29,7 +29,7 @@ # - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended) # - Retrospective appends its action items to action_items; the status view surfaces open ones generated: 08-14-2026 00:00 -last_updated: 08-19-2026 16:40 +last_updated: 08-19-2026 20:37 project: wow20 project_key: NOKEY tracking_system: file-system @@ -55,7 +55,7 @@ development_status: 3-2-relevanzbestimmung-textual-deterministisch-umsetzen-grep-rip: done 3-3-bestehende-concepts-erweitern-präzisieren-korrigieren: done 3-4-wissen-aus-mehreren-sources-synthetisieren: done - 3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetz: backlog + 3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetz: done 3-6-lease-staleness-recovery-basis-absichern: backlog 3-7-reason-mutate-trennung-und-konsistenz-endzustand-sicherstell: backlog 3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato: backlog diff --git a/schema/compiler.md b/schema/compiler.md index 55bb777..54566df 100644 --- a/schema/compiler.md +++ b/schema/compiler.md @@ -300,6 +300,25 @@ Diese Sektion ist der **Instruktions-Ort der Synthese-Dimension** (AD-4, FR-7): 7. **`log.md`-Eintragspflicht (Vertrag §5):** Jede Synthese wird als datumsgruppierter Eintrag in `wiki/log.md` dokumentiert. Ein Synthese-**Update** auf ein bestehendes Concept führt den Eintrag „**Story 3.1-Update**" (Disagreement-Fälle als Disagreement-Eintrag mit dem mutierten Concept-Pfad, AD-16b); eine Synthese-**Neu-Anlage** eines neuen Synthese-Concepts führt einen **Anlage-Eintrag** (disambiguierbar von Update-Einträgen). Der Eintrag verknüpft das erzeugte Concept mit der **vollständigen Multi-Source-`sources`-Liste** und hält den `` (R-1, §5.9 Pkt. 6) fest. 8. **Erhaltungs-Invariante & Determinismus-Vertrag (AD-17h/A0-19):** Der **§5.9-Pkt.-5-Diff-Selbsttest gilt für Synthese-Runs unverändert**: die mutierten/neu angelegten Pfade sind eine Teilmenge von (Kandidatenliste ∪ Neu-Anlage-Zielpfade ∪ `log.md` ∪ nachgeführte `index.md`) — **keine neue Datei außer echten Ziel-Pfaden** (Duplikat-Kontrolle via `??`-Sicht, `git status --porcelain -- wiki/`). Gleicher Git-State + gleiche Eingabemenge → identischer Synthese-Vorgang (Ziel-Pfad via §3.2/§5.7, `sources`-Liste lexikografisch nach `resource` LC_ALL=C, Konsolidierung und Form-Zuordnung wie Pkt. 3/6); der `generated.at`-Wanduhr-Gap (gleiches Eingabeset, unabhängige Runs, verschiedene `at`) bleibt offene A0-20-Konvention mit Home **Story 3.8** (§5.9 Pkt. 2, `generated.at`-Konvention) — unverändert bindend. **Duplikat-Fall (Synchronisation zwischen Concepts und Evidenzbasis):** ein `raw/`-Quellpfad erscheint **nur einmal** in einer `sources`-Liste — ein bestehender Eintrag derselben `resource` wird **nicht** doppelt angelegt (die Neuanlage eines Synthese-Concepts setzt voraus, dass kein bestehendes Concept dieselbe Quelle bereits mit derselben Stellen-Kennung als Beleg nutzt; für Update-Fälle gilt das §5.9-Pkt.-2-Prinzip „bestehende Einträge bleiben unverändert" — der Zuwachs einer Quelle, die bereits existiert, wird niemals doppelt eingetragen). **Unzugeordnete/verwaiste Evidenz (Orphan-Kontrolle):** neu committete `raw/`-Evidenz ohne Ziel-Pfad-Treffer bleibt **unzugeordnet** (weder still getilgt noch hintenherum als eigenes Concept angelegt) und wird in `log.md` als verwaist protokolliert — kein Banner/keine stille Vorbearbeitung; Story 3.8/Epic-4 können die Reconcile-Orphan-Politik präzisieren. +## 5.11 Leasing & Dirty-Tree-Schutz für konkurrierende Producer (Story 3.5) + +Diese Sektion ist der **einzige Instruktions-Ort der Koordinations-Dimension für konkurrierende Producer** (D-3, Story 3.5; AD-17a..f, A0-12..A0-16, FR-2/FR-12): wie zwei Producer denselben Concept-Pfad **nicht stillschweigend überschreiben**, wie eine **Lease** auf `lease//`-Branches mit Root-Scope und Merge-Base-Disziplin erworben wird, und wie fremde uncommittete Änderungen (**Dirty Tree**) geschützt statt als Nebenwirkung gelöscht werden. Sie ist eine weitere Spezifikations-Ebene der Mutationsphase §5 (nach §5.10, vor §6) und **schließt den §7-Vorbehalt** dieser Koordinations-Dimension (Story 3.5). Sie fügt **kein** Prädikat, **keine** neue §7-Invaliditätsklasse, **keinen** `schema/wiki-compiler.md`-/`schema/validator.md`-/`raw/`-Change hinzu (AD-3) und **keinen** Standalone (D-3). Die Lease lebt in **Git/Datei-Ebene** (Branch-Name, Lockfile) — **nicht** in Concept-Frontmatter (Vertrag §3.1–§3.7 unverändert, keine neue §7-Klasse, **kein neuer Frontmatter-Key für Lease-Metadaten**; ein solcher wäre Ask-First). Leasing ist eine **Querschnitt-Dimension, keine neue Mutations-Form**: die §5.9-Abgrenzungs-Reihenfolge `Korrigieren → Präzisieren → Erweitern → No-Op` bleibt die **einzige** Form-Wahl; die §5.10-Synthese-Mechanik bleibt unberührt. Eine Lease-geschützte Mutation ist ein Compilation-Vorgang wie die Anlage/das Update: sie unterliegt denselben Phasen (§0: Interpretieren → Reconcile → Synthetisieren → Mutieren → Validieren), derselben Commit-Boundary = Mutations-Boundary (AD-17f, §0/§5.3) und derselben Validator-Erfolgsbedingung (§6). + +1. **Lease-Akquise (AD-17a, A0-12) — deterministisch (AD-17h):** Ein Producer, der einen Bereich (Area oder Root-Scope gemäß Pkt. 2) bearbeiten will, akquiriert die Lease **bevor** er mutiert, gegen einen **eindeutigen Commit-Object-Wert** (Merge-Base-Disziplin): + - **Arbeits-Branch-Form:** Der Producer arbeitet auf einem Branch der Form **`lease//`** (z. B. `lease/alpha/run-a`; für Root-Scope-Bereiche `` = `wiki`, z. B. `lease/wiki/run-a`). `` ist der Bereichs-Pfad (deterministisch nach §5.7), `` ein vom Producer vergebener, kollisionsfreier Run-Identifier. Der Branch wird **von der Merge-Base aus** erstellt (`git checkout -b lease//`, Abzweigung von der letzten Mutations-Boundary, §5.9 Pkt. 6 R-1); der Producer arbeitet **ausschließlich** auf diesem Branch und committet dort (Commit-Boundary = Mutations-Boundary, Pkt. 5). + - **Lockfile:** Eine Lease wird durch ein **Lockfile** realisiert, das **semantisch identisch in jedem Adapter** ist (A0-12 — die Realisierung ist **nicht** pro Adapter frei wählbar). Deterministisches Format (AD-17h): das Lockfile liegt unter `lease//.lock` (außerhalb `wiki/`/`raw/`, im Workspace), enthält den **Feld-Satz** `area`, `id`, `producer`, `baseline_commit` (voller SHA) und — wenn bereits vergeben — `holder_id`, und ist ein **committeter** git-Tracking- oder ein deterministisch benannter ungetrackter Marker (die Semantik „eine Lease je `lease//`-Branch" ist maßgeblich; die exakte Datei-Ablage ist in jedem Adapter identisch zu halten). **Lease-Hold:** Existiert das Lockfile schon (die Lease ist vergeben), **überschreibt der Producer sie nicht** — er hält die Lease (Lease-Hold) und es erfolgt **keine Mutation** am betroffenen Pfad durch den zweiten Producer; die Koordination geht in den AD-16-Pfad (Pkt. 4) über. + - **Merge-Base-Disziplin (eindeutiger Commit-Object-Wert):** Die Lease wird gegen den **Merge-Base-Commit** akquiriert — den eindeutigen Commit-Object-Wert, von dem beide Producer (der haltende und der neue) ausgehen (deterministisch über `git merge-base` bzw. den notierten `` aus §5.9 Pkt. 6). Gegen denselben Git-State akquirieren zwei unabhängige Producer **deterministisch dieselbe** Koordinationsentscheidung (gleiche Merge-Base → gleiche Lease-Lage, AD-17h/A0-19). Der akquirierte `` wird im `log.md`-Eintrag notiert (Pkt. 6, D-2). + - **Lease-Freigabe (Release, deterministisch):** Nach erfolgreichem Run, sobald die Mutation als Ganzes committet ist (Pkt. 5, Commit-Boundary), gibt der Producer die Lease **deterministisch** frei: das Lockfile `lease//.lock` wird entfernt bzw. als freigegeben markiert und der Abschluss als `log.md`-Eintrag dokumentiert (Pkt. 6). Eine Lease, deren Inhaber den Run **ohne** Freigabe beendet (abgebrochen/verwaist), **verbleibt bis zum Staleness-/Recovery-Mechanismus der Story 3.6** — §5.11 prüft stets nur den **committeten** Zustand (AD-17h/A0-19) und wertet bei einer existierenden, nicht freigegebenen Lease als **Lease-Hold** (Pkt. 1). Staleness-TTL, verwaiste Leases und die `raw/`-Recovery sind Story-3.6-Thema. +2. **Root-Scope-Lease (AD-17b, A0-13):** Die Lease umfasst **`wiki/` inklusive `log.md`, `index.md` und aller Root-Dateien** — nicht nur den mutierten Concept-Pfad. Ein Producer, der einen Concept-Pfad mutiert, hält damit zugleich die Koordinations-Rechte an der Bundle-Integrität (Bundleroot `index.md`, `log.md`, Root-Concepts), weil jede Mutation die Pfad-Menge von `log.md`/`index.md` (Eintragspflicht bzw. Index-Regel) berühren kann. **Kein Bereich jenseits `wiki/`** ist Lease-Gegenstand (AD-17b-Root-Scope; `raw/` bleibt immutable, AD-3; jenseits-`wiki/`-Lease wäre Ask-First). +3. **Dirty-Tree-Schutz (AD-17e/f, A0-16):** **Vor jeder Mutation** prüft der Producer die Working Copy **auf den zu mutierenden Bereich** (Pre-Mutation-Prüfung; deterministisch: `git status --porcelain -- ` gegen HEAD — der mutierte Bereich ist die Pfad-Menge des Runs, Kandidatenliste ∪ Neu-Anlage-Zielpfade ∪ `log.md` ∪ `index.md`, §5.9 Pkt. 5): + - **Fremde uncommittete Änderungen werden geschützt, nie gelöscht (AD-17e):** Liegen im mutierten Bereich **fremde uncommittete Änderungen** vor (Dirty Tree — Änderungen, die **nicht** vom laufenden Producer stammen und **nicht** committet sind), **löscht der Producer sie nicht** und übergeht sie nicht still. Er schützt sie in eine **Scratch-Zone/Stash** (deterministisch: `git stash push -- ` mit Stash-/Verzeichnis-Konvention oder Kopie in eine benannte Scratch-Zone außerhalb `wiki/`, z. B. `scratch//.stash`) und **dokumentiert den Vorgang in `log.md`** (Pkt. 6). **Screen-Artefakte beim Schutz** (Stash-/Kopier-Artefakte, die im Bundle-Baum auftauchen würden) werden **textuell benannt** (NFR-4) und liegen außerhalb der erlaubten Diff-Menge (§5.9 Pkt. 5) — sie werden nie als Concept verwechselt. Nach erfolgreichem Run sind die geschützten Änderungen für den ursprünglichen Producer zurückzuspielen (Restore; der Weg ist im `log.md`-Eintrag dokumentiert). + - **UNCOMMITTED_INPUT-Abbruch (AD-17a, I/O-Matrix-Szenario `UNCOMMITTED_INPUT` der Story-3.5-Matrix):** Weicht die **Working-Copy von `raw/` oder `wiki/`** vom committeten HEAD in einem Umfang ab, der als Input des Runs gelten würde (uncommittete `raw/`-Zuwächse oder uncommittete `wiki/`-Abweichungen außerhalb der eigenen, bereits geleasten Mutation), bricht der Run mit dem textuell benannten Abbruch „**published/committed Input erforderlich**" ab — **vor** Interpretation und vor jeder Mutation (keine Mutation gegen Zwischenstände). Dies ist **dieselbe Pre-Run-Prüfung** wie das §5.9-P2-Element (1) (`INPUT_UNCOMMITTED`, Story-3.1-Matrix): dieselbe Bedingung, derselbe Abbruch-Wortlaut — **kein zweiter, separater Abbruch-Pfad**. Keine Mutation, Bundle konsistent. + - **Mutationen operieren nur auf Directory-/Commit-Ebene — Commit-Boundary = Mutations-Boundary (Pkt. 5).** +4. **Kein textueller Auto-Merge — compiler-vermittelter Merge (AD-17c, A0-14):** Zwei Branches mit **ungleichem Inhalt am selben Concept-Pfad** werden **nie textuell automatisch gemerged** (kein stiller textueller Auto-Merge, AD-17c — verboten, Never). Der Merge ist **compiler-vermittelt** und durchläuft die **AD-16-Klassifikation** mit explizitem `log.md`-Eintrag (Pkt. 6; Interface zu Epic 4): die beiden Inhaltsvarianten desselben Pfads werden als **Konflikt** behandelt — der haltende Producer klassifiziert sie gemäß AD-16 (Default: **Erhaltung** — beide Behauptungen bleiben, Disagreement-Eintrag in `log.md`; keine stille Konsolidierung, keine stille Löschung). **Lease-Konflikt (I/O-Matrix `LEASE_KONFLIKT`):** Ein zweiter Producer mit Lockfile-Konflikt am selben Pfad erzeugt **keinen stillen textuellen Auto-Merge**; die Auflösung geht in den compiler-vermittelten AD-16-Pfad (Pkt. 4) mit `log.md`-Eintrag. **Unentscheidbar → menschliche Eskalation (AD-17g):** Ist die AD-16-Klassifikation unentscheidbar, eskaliert der Producer menschlich (textuell benannt, NFR-4) — er nimmt **keine** Auto-Entscheidung vor. +5. **Commit-Boundary = Mutations-Boundary (§0/§5.3-Verweis unverändert):** Auch im Leasing-Pfad gilt: **Zwischenstände werden nie als fertige Mutation veröffentlicht** (AD-17f). Der Producer committet die Mutationen als Ganzes auf dem `lease//`-Branch, und zwar erst, nachdem der Diff-Selbsttest (§5.9 Pkt. 5) ohne Ghost-Diff abgeschlossen ist. Ein Ghost-Diff (auch ein durch den Dirty-Tree-Schutz erzeugter Screen-Artefakt im Bundle-Baum) ist ein textuell benannter Instruktions-Verstoß (NFR-4) und wird **vor** der Run-Gültigkeit zurückgerollt. Die Pkt.-5-Erhaltungs-Invariante gilt für Leasing-fähige Runs **unverändert** (Pfad-Menge ⊆ Kandidatenliste ∪ Neu-Anlage ∪ `log.md` ∪ Index; AD-5/FT-6). +6. **`log.md`-Eintragspflicht (Vertrag §5):** Jede Lease-geschützte Koordinationsentscheidung wird als datumsgruppierter Eintrag in `wiki/log.md` dokumentiert (Header = ISO-Datum `YYYY-MM-DD`, **neueste zuerst** — Vertrag-§5-Datumsgruppe, wie §5.9 Pkt. 4): **(a) Lease-Akquise** (Branch `lease//`, ``, Lockfile-Referenz — deterministisch auflösbar, D-2), **(b) Dirty-Tree-Schutz** (geschützte fremde uncommittete Änderung, Scratching-Ziel, Restore-Weg — „nie gelöscht", AD-17e), **(c) Merge-Klassifikation** (AD-16-Klassifikation bei ungleichem Pfad-Inhalt, Disagreement-/Konflikt-Vermerk) und **(d) Eskalation** (menschliche Eskalation bei Unentscheidbarkeit, AD-17g). +7. **Determinismus-Vertrag (AD-17h/A0-19):** Lease-Akquise, Lockfile-Inhalte und Merge-Klassifikation folgen **deterministisch aus dem committeten Git-State**: gleicher Git-State + gleiche Eingabemenge → **identische Koordinationsentscheidung** (gleiche Merge-Base → gleiche Lockfile-Lage; gleiche Pfad-Inhalte → gleiche AD-16-Klassifikation). Der `generated.at`-Wanduhr-Gap (gleiches Eingabeset, unabhängige Runs, verschiedene `at`) bleibt offene A0-20-Konvention mit Home **Story 3.8** (§5.9 Pkt. 2, `generated.at`-Konvention) — unverändert bindend. **Lease-Staleness/Recovery** (TTL, Lease-Registrierung, verwaiste Leases, `raw/`-Recovery; AD-17d, A0-15) bleibt **Story 3.6** vorbehalten: diese Sektion verweist darauf und mutiert deren Mechanik nicht. (Testbares Seam-Kriterium der Koordinations-Dimension, das 3.5 von 3.6 trennt: **3.5** ist eine auf den **committeten Git-State** bezogene Determinismus-Frage — allein aus Merge-Base + Lockfile + Pfad-Inhalten entscheidbar (AD-17h/A0-19); **3.6** ist eine **Zeit- bzw. Umgebungs-Zustands-Frage**, die den committeten Zustand verlässt — TTL-Ablauf, verwaiste/hängende Leases, Registrierung, `raw/`-Recovery.) + ## 6. Validieren (mechanische Bestätigung) 1. Nach Abschluss aller Mutationen wird das gesamte Bundle gemäß `schema/validator.md` geprüft (§3 14 Punkte je Datei + §6-Fachprüfungen; Verdikt-Grammatik §5). @@ -347,14 +366,14 @@ Interpretations-Hinweis: Die „✗"-Zeilen zeigen die deterministische Fehlerur ## 7. Selbstbegrenzung (Scope der Instruktion) -Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in Areas gemäß §5.7, das inkrementelle Update bestehender Concepts gemäß §3 + §5.9 sowie die Synthese mehrerer `raw/`-Quellen zu einer gemeinsamen Wissensrepräsentation gemäß §5.10** begrenzt. Folgendes verbleibt in anderen Stories und wird hier **nicht** vorweggenommen: +Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in Areas gemäß §5.7, das inkrementelle Update bestehender Concepts gemäß §3 + §5.9, die Synthese mehrerer `raw/`-Quellen zu einer gemeinsamen Wissensrepräsentation gemäß §5.10 sowie die Leasing-/Dirty-Tree-Koordination für konkurrierende Producer gemäß §5.11** begrenzt. Folgendes verbleibt in anderen Stories und wird hier **nicht** vorweggenommen: - **Claim-granulare Provenienz** je belegter Aussage (Inline-`raw/`-Verweise, Kontext-Marker) — in **§5.5** dieser Instruktion verankert (Story 2.2; AD-4a, A0-3). Keine neue §7-Klasse, kein Standalone, keine Vertragsänderung. - **Deterministische Area-Zuordnung & Concept-Hierarchie** (Anlage von `wiki//index.md` + `wiki//.md`) — in **§5.7** dieser Instruktion verankert (Story 2.4; AD-7c, A0-10, A0-8, AD-13). Keine neue §7-Klasse, kein Validator-Change. - **Progressive Discovery über `index.md`** (Navigation, Area-Indizes) — in **§5.8** dieser Instruktion verankert (Story 2.5; AD-9, FR-11, AD-13, NFR-3). **Suche** bleibt konsumenten-/extern-seitig (Consumer-grep über `wiki/`, §5.8 Pkt. 4 — kein Bundle-/Instruktions-Thema mehr). Keine neue §7-Klasse, kein Schema-/Validator-Change. - **Eine genau-eine-Linkform** (file-relativ mit `.md`-Endung, in Areas `../`-fähig) — in **§5.6** dieser Instruktion gepinnt (Story 2.3; AD-7b, A0-9, FR-10; Auflösungsmodell §5.7 Pkt. 4) — der Punkt-11-Check des Validators akzeptiert bis auf Weiteres beide Schreibweisen (strukturell unverändert, Story-2.2-Präzedenz). - **Synthese über mehrere Sources** (mehrere `raw/`-Quellen → eine gemeinsame Wissensrepräsentation mit gemischter, claim-granularer Provenienz) — **in §5.10** dieser Instruktion verankert (Story 3.4; AD-4, FR-7). Die Verankerung des inkrementellen Datenflusses (Erweitern/Präzisieren/Korrigieren einzelner bestehender Concepts) bleibt **§3 + §5.9** überlassen und ist dort bereits verankert (Story 3.1). Beide sind damit aus diesem Vorbehalt entlassen. -- **Leasing / Dirty-Tree-Schutz** für konkurrierende Producer → **Story 3.5/3.6** (AD-17a..f, A0-12..A0-16); die bestehende Commit-Boundary = Mutations-Boundary-Regel (§0/§5.3, AD-17f) bleibt in v1 bestehender Schutz. +- **Leasing / Dirty-Tree-Schutz** für konkurrierende Producer — **in §5.11 dieser Instruktion verankert** (Story 3.5; AD-17a..f, A0-12..A0-16; die Enum enthält AD-17d/A0-15 nur als **Norm-Rückverweis** — die §5.11-Auflösung selbst schließt Staleness aus und delegiert an Story 3.6, Pkt. 7-Seam-Kriterium): Lease-Akquise auf `lease//`-Branches mit Lockfile und Merge-Base-Disziplin, Root-Scope-Lease inkl. `log.md`/`index.md`, Dirty-Tree-Schutz mit Stash/Scratch-Zone und `log.md`-Dokumentation, compiler-vermittelter Merge als AD-16-Pfad, kein textueller Auto-Merge, Commit-Boundary = Mutations-Boundary, Lease-Freigabe (Release, deterministisch); die bestehende Commit-Boundary = Mutations-Boundary-Regel (§0/§5.3, AD-17f) bleibt unverändert bestehender Schutz. **Lease-Staleness/Recovery** (TTL, Lease-Registrierung, verwaiste Leases, `raw/`-Recovery; AD-17d, A0-15) bleibt → **Story 3.6**. - **Relevanzbestimmung** (feinkörniger Relevanz-Findungsmechanismus der Kandidatenerhebung) — in **§3.2** dieser Instruktion verankert (Story 3.2; Term-Ziehverfahren + Kanonisierungs-Resolver `schema/canonical-terms.md`, drei Erhebungs-Stufen grep/ripgrep + `index.md`-Traversal + Link-Following mit besuchter Menge, `log.md`-Exklusion, Candidate-Liste als relative OKF-Pfade ohne `.md`, Determinismus-Vertrag AD-17h/A0-19). Keine neue §7-Klasse, kein Schema-/Validator-Change; die Em-Dash-`—`-Varianten-Lücke ist als Determinismus-Frage an Story 3.8 übergeben. - **Standalone-Compiler / eigene LLM-Runtime / MCP** → verboten in v1 (D-3, D-4, AD-11). - **OKF-Dialekt / Schema-Erweiterung** → niemals (AD-1a; Vertrag §7 „abschließende Liste"). @@ -365,9 +384,9 @@ Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in A - `schema/wiki-compiler.md` — autorisierter Vertrag (Story 1.3): §2 Bundleroot, §3.1–§3.7 Feldsubset & Formate, §5 `log.md`-Typ, §6 Index-Regel/Prädikate, §7 abschließende 14-Punkte-Liste, §8 Normreferenzen. - `schema/validator.md` — Prüfgrundlage (Story 1.4, Revision 9): §3 14 Punkte, §4 Normalform (Reihenfolge §4.1, ISO-8601 §4.3), §5 Verdikt, §6 Fachprüfungen (EC-1 Existenz, EC-3 Kalender, EC-11 non-md; Punkt-11-Area-Lesart formalisiert). -- Architektur-Spine (raw/`architecture-spine`): AD-2/AD-3 (raw immutable), AD-4a (claim-granulare Provenienz, §5.5), AD-5 (inkrementelle Kompilation), AD-6 (Reason/Mutate-Trennung), AD-7a (Identität = OKF-Pfad ohne `.md`, §5.7), AD-7b (genau eine Linkform gepinnt, §5.6), AD-7c (deterministische Bereichszuordnung, §5.7), AD-7d (Renaming/Redirect-Pflicht — nicht in den ACs, Epic 3), AD-8 (Standard-Markdown-Links = Navigations-/Beziehungsschicht, §5.6), AD-9 (Progressive Discovery, §5.7/§5.8), AD-10 (agent-unabhängige Regeln), AD-11 (keine eigene Runtime), AD-13 (Retrieval gehört zu Consumers / Suche = Consumer-grep / keine Embedding-Bereichszuordnung, §5.7/§5.8; Relevanzbestimmung textuell-deterministisch, §3.2), AD-14 (Git liefert Historie, nicht Domain-State), AD-15 (Trust-Metadaten v1), AD-16 (Konflikte werden explizit bewahrt), AD-17a (nur veröffentlichte/committete Inhalte als Input), AD-17f (Commit-Boundary = Mutations-Boundary), AD-17h (Determinismus), D-3 (kein Standalone). +- Architektur-Spine (raw/`architecture-spine`): AD-2/AD-3 (raw immutable), AD-4a (claim-granulare Provenienz, §5.5), AD-5 (inkrementelle Kompilation), AD-6 (Reason/Mutate-Trennung), AD-7a (Identität = OKF-Pfad ohne `.md`, §5.7), AD-7b (genau eine Linkform gepinnt, §5.6), AD-7c (deterministische Bereichszuordnung, §5.7), AD-7d (Renaming/Redirect-Pflicht — nicht in den ACs, Epic 3), AD-8 (Standard-Markdown-Links = Navigations-/Beziehungsschicht, §5.6), AD-9 (Progressive Discovery, §5.7/§5.8), AD-10 (agent-unabhängige Regeln), AD-11 (keine eigene Runtime), AD-13 (Retrieval gehört zu Consumers / Suche = Consumer-grep / keine Embedding-Bereichszuordnung, §5.7/§5.8; Relevanzbestimmung textuell-deterministisch, §3.2), AD-14 (Git liefert Historie, nicht Domain-State), AD-15 (Trust-Metadaten v1), AD-16 (Konflikte werden explizit bewahrt), AD-17a (nur veröffentlichte/committete Inhalte als Input), AD-17b (Root-Scope-Lease, §5.11), AD-17c (kein textueller Auto-Merge, compiler-vermittelter Merge, §5.11), AD-17d (Lease-Staleness — Story 3.6), AD-17e/f (Dirty-Tree-Schutz; Commit-Boundary = Mutations-Boundary, §5.11/§0/§5.3), AD-17g (Unentscheidbarkeit → menschliche Eskalation, §5.11), AD-17h (Determinismus), D-3 (kein Standalone). - PRD (raw/prd): FR-2 (Sources vs. Curated), FR-5 (Concept-Erzeugung), FR-9 (OKF-Konformität), FR-10 (Concepts miteinander verlinken, §5.6), FR-11 (Progressive Discovery siehe PRD-§4.3-Zeile unten — Discovery-Pfad/gewurzelte Erreichbarkeit, §5.8), FR-16 (Consumer-Unabhängigkeit), NFR-3 (Agent Readability — Standard-Dateioperationen/grep über `wiki/`, §5.8 Pkt. 4), A-4 (nur lokale Sources). -- Epics (raw/epics): Story-2.1-Ziel und -Abgrenzung zu Story 2.2–2.5; A0-3 (Kontext-Marker-Wortlaut, §5.5), A0-8 (Concept-Identität/Normalisierung, §5.7), A0-9 (eine erlaubte Linkform, §5.6), A0-10 (deterministische Bereichszuordnung, §5.7), A0-13 (Lease-Root-Scope); FR-6/FR-12/FR-14, A0-6/A0-7/A0-11/A0-18 (Belege der nachkonformierten Concept-Bodies); **A0-6 (inkrementeller Datenfluss Interpret → Reconcile → Synthesize → Update, §0/§3/§5.9), FR-6 (Aktualisierung statt neuer Dateien, §3/§5.9), FR-12 (unverändertes Wissen bleibt erhalten, §5.9)**, **A0-18 (Deterministische Relevanzbestimmung — grep/ripgrep, `index.md`-Traversal, Link-Following, keine Embedding-/Vector-Infrastruktur; §3.2, AD-13, PRD OQ-3)**, **A0-19 (Determinismus-Vertrag: gleicher Git-State + gleiche Eingabemenge → gleicher Bundle-State / gleiche Candidate-Liste in gleicher Reihenfolge; §3.2, AD-17h)**. +- Epics (raw/epics): Story-2.1-Ziel und -Abgrenzung zu Story 2.2–2.5; A0-3 (Kontext-Marker-Wortlaut, §5.5), A0-8 (Concept-Identität/Normalisierung, §5.7), A0-9 (eine erlaubte Linkform, §5.6), A0-10 (deterministische Bereichszuordnung, §5.7), A0-13 (Lease-Root-Scope, §5.11); FR-6/FR-12/FR-14, A0-6/A0-7/A0-11/A0-18 (Belege der nachkonformierten Concept-Bodies); **A0-6 (inkrementeller Datenfluss Interpret → Reconcile → Synthesize → Update, §0/§3/§5.9), FR-6 (Aktualisierung statt neuer Dateien, §3/§5.9), FR-12 (unverändertes Wissen bleibt erhalten, §5.9)**, **A0-12 (Leasing-Modell — `lease//`-Branches, Merge-Base-Disziplin, Lockfile semantisch identisch in jedem Adapter, §5.11), A0-13 (Root-Scope-Lease inkl. `log.md`/`index.md`/Root-Dateien, §5.11), A0-14 (kein textueller Auto-Merge; compiler-vermittelter Merge über AD-16, §5.11), A0-15 (Lease-Staleness — Story 3.6), A0-16 (Dirty-Tree-Schutz: Pre-Mutation-Prüfung, Stash/Scratch-Zone, `log.md`-Dokumentation, §5.11)**, **A0-18 (Deterministische Relevanzbestimmung — grep/ripgrep, `index.md`-Traversal, Link-Following, keine Embedding-/Vector-Infrastruktur; §3.2, AD-13, PRD OQ-3)**, **A0-19 (Determinismus-Vertrag: gleicher Git-State + gleiche Eingabemenge → gleicher Bundle-State / gleiche Candidate-Liste in gleicher Reihenfolge; §3.2/§5.11, AD-17h)**. - PRD §4.3 (FR-11 — progressive Discovery, §5.7 Pkt. 5/§5.8) und §8.2/§8.3 (Canonical State; Separation of Concerns), **PRD OQ-3 („Compilation Scope" — wie findet der Compiler relevante vorhandene Concepts; textuell-deterministische Relevanzbestimmung, §3.2; AD-13/A0-18; Muster `raw/architecture-spine/…md` §8.3)**. **Revisionslog:** @@ -394,3 +413,4 @@ Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in A - **Revision 2.7 (2026-08-19, Story 3.2, Step-04-Review Loop 3, 4 Layer; Nutzer-Entscheidungen D-1/D-2/D-3/D-4/D-5 = 1/1/1/1/1, jeweils empfohlene Option; + 2 Patches; D-3-Instruktions-Patch, kein neuer Inhalt):** (1) **§3.2-Pkt.-3b-Ordnung auf reine Lexikografie gehoben (D-4):** Stufe-a-Treffer waren „in der Reihenfolge des ziehenden Terms, dann lexikografisch als deterministischer Tie-Break" — die Term-Ordnung selbst war für Mehrfach-Terme (Pkt. 1c) nirgends festgelegt, zwei rechtmäßige Term-Ordnungen erzeugten zwei unterschiedliche Listen (AD-17h-Lücke). Jetzt: **innerhalb jeder Stufe rein lexikografisch aufsteigend (LC_ALL=C)**; die Term-Verarbeitungsreihenfolge dient nur der Interpretation/Erhebung, **nicht** der Listen-Ordnung — dieselbe Treffermenge → identische Liste. (2) **`schema/canonical-terms.md`-Lookup-Semantik vervollständigt (D-5):** Lookup-Verfahren deterministisch fixiert (lowercasing → `[-–_ ]`→`-`-Kollaps → **Lookup der normalisierten Form**; Spalten tragen ausschließlich normalisierte Formen), **Eindeutigkeits-Invariante** (jede normalisierte Form in genau einem Eintrag — Canon **oder** Variante, nie beides/zweimal) + **Konflikt-Verfahren** (keine stille Anhängung; `deferred-work.md`-Handoff / Ask-First, analog zur Umbenennungs-Regel). (3) **Statuskette `in-progress → done` dokumentiert (D-1):** der Review-Loop-Abschluss-Flip `in-progress → done` (Sprint-Sync-Konvention, Story-3.1-Präzedenz) war in keinem `wiki/log.md`-Eintrag als eigener Schritt belegt — nachgeführt als neuer oberster `wiki/log.md`-Bullet (append-only; die gefrorene Always-Klausel `→ in-progress` beschreibt den Implementierungsstand, der Review-Abschluss `done` ist der übliche Folgezustand). (4) **Mini-Sandbox um T5/T6/T7 erweitert + T1/T4-Asssertionen + T2-Kommentar-Korrektur (D-2 + Patch P-1):** T5 `LINK_FOLLOWING_ZYKLUS` (A→B→A-Links; besuchte Menge → endliche, doppelungsfreie Liste), T6 `TRAVERSAL_REACH_ONLY` (Term nur in Area-`index.md` → gewurzelte Concept-Pfade als Kandidaten; `index.md` selbst ist kein Concept-Kandidat), T7 `TERM_ABLEITUNG_SYNONYM` (Registry-Test-Doppel: Schreibvarianten → canonische Form via Lookup auf normalisierter Form; Negativ-Fall: nicht auflösbar → wie notiert, kein stiller Ausschluss); T1/T4 tragen jetzt harte Pass/Fail-Asssertionen (`exit 1` bei Abweichung) — die exakte Candidate-Liste wird erzwungen, nicht nur ausgegeben; der T2-Kommentar zu `index` korrigiert (Stufe-a-Treffer auf `wiki/index.md` löst Stufe b aus; `index.md` ist kein Concept-Kandidat). (5) **Selbsttest-Beleg (b) gegen den realen Sandbox-Ist-Baum re-executiert (D-3):** der Rev-2.5-Log-Beleg (b) beschrieb einen nicht-committierten Baum (Term `quanten-protocol`, `sub/beta.md`, SHA-256 `159092bb…`) — Stale-Evidenz-Falle (B1-Präzedenz). Der Nachweis wird jetzt gegen die echte `run-sandbox.sh`-Ausgabe (Term `deterministische-relevanz-bestimmung`, root-level `alpha`/`beta`/`gamma`) neu belegt; der Rev-2.5-Eintrag bleibt historisch unverändert, die Korrektur steht als neuer `wiki/log.md`-Bullet (append-only). (6) **Typos im normativen Text korrigiert (Patch P-2):** `Determinsmus` → `Determinismus` (§8-Referenzen + Log-/Defer-Belege), `§3.2-beankert` → `§3.2-angeankert`, `Membrum` → `Mitglied` (Spec-Design-Notes), `Konventionelle Determinismus-Lücke` → `Bekannte Determinismus-Lücke` (Defer-Beleg; `compiler.md:53` sagt „Bekannte"), `Resovierung` → `Auflösung` (Spec-Change-Log/-Verification). **Abschlussklausel:** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein Standalone** (D-3); keine Vertragsänderung; Commit-Boundary-Regel unverändert. (Revisionslog-Reihenfolge-Anomalie 2.6/2.5 bleibt als dokumentierter Defer bestehen — nicht in dieser Runde umgeordnet.) - **Revision 2.8 (2026-08-19, Story 3.3):** §5.9-Update-Formen **operationell ausformuliert** (dieselbe Evidenz + formale Struktur → identisches Update-Ergebnis, AD-17h/A0-19): (1) **Pkt. 2 — Präzisierungsebene je Update-Form** (als Sub-Bullet an die Commit-Boundary-Regel angefügt; der frozen Story-3.1-Regeltext bleibt textuell **unverändert** als normative Basis, die operationellen Regeln sind die Ausführungs-Ebene darunter — keine Re-Negotiation): je Form **(a) Abgrenzungskriterium** (aus der committeten Evidenz: neue belegte Aussage → Erweitern; Schärfung einer bestehenden Formulierung/Abgrenzung ohne Ersatz → Präzisieren; Ersetzung einer fehlerhaften/überholten → Korrigieren; keines davon → No-Op, engere Auslegung), **(b) Struktur-Erhaltungsregel** (das Geschützte — Frontmatter-Subset nur als `sources`-Zuwachs um echten neuen Beleg + `generated.at`-Bump; bestehende belegte Aussagen nicht umgeschrieben ohne dass Präzisieren/Korrigieren greift; §5.5-Inline-Verweise gültig soweit Beleg Body-Bestand; §5.6-Linkform unverändert, keine neuen Links außer bei echten Beziehungen) und **(c) Textgenauigkeits-Rahmen für Präzisieren** (Schärfen an der Aussage, kein Satz-Umbau, kein Neuschreiben ohne Ersetzungsbeleg). (2) **Pkt. 5 — Erhaltungs-Invariante um den Struktur-Erhaltungs-Bezug ergänzt:** die Diff-Probe verifiziert zwei Ebenen — die Pfad-Mengen-Ebene (bestehender Teilmenge-Vergleich) und die **Struktur-Ebene je berührtem Pfad** (pro betroffenem Concept-Pfad über die Pkt.-2-Regeln geprüft: Frontmatter-Subset, keine Umschreibung belegter Aussagen außerhalb der Formen, Inline-Verweise, Linkform — Verstöße textuell benannt (NFR-4), vor dem Commit zu beheben, sonst Ghost-Diff mit Rollback). (3) **Pkt. 6 — P2-Check-Block um den Struktur-Erhaltungs-Check erweitert** (Element (6), zusätzliches textuelles Element: keine unbefugten Keys — Vertrag §3.3/§3.4-Subset, keine stille Löschung — AD-16/„Korrigieren"-Form, Links unverändert/keine neuen ohne echte Beziehung — §5.6-Pin; Verstöße textuell benannt (NFR-4) und vor dem Commit behoben). (4) **Abschlussklausel:** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein Standalone** (D-3); keine Vertragsänderung; Commit-Boundary-Regel unverändert; kein Leasing-Scope (AC-4 → Story 3.5/3.6, AD-17.3-Hinweis unverändert in §7). **`sprint-status.yaml`:** Key `3-3-bestehende-concepts-erweitern-präzisieren-korrigieren` bleibt **`in-progress`** (Review-Abschluss `done` erfolgt gemäß Workflow-Konvention durch den Review-Schritt). Sandbox-Nachweis und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.3, Revision 2.8). - **Revision 2.9 (2026-08-19, Story 3.4):** Neue Sektion **§5.10 „Synthese aus mehreren Sources (Story 3.4)"** eingefügt (nach §5.9, vor §6) — die **verbindliche Verankerung der Synthese-Dimension** (AD-4, FR-7): (1) **Synthese-Stimulus** (≥ 2 belegende `raw/`-Quellen desselben Themas per §2-Interpretation → eine Synthese-Einheit; einzelne Quelle bleibt auf §5.9-/§3.2-Pfad), (2) **Ein-Ziel-Repräsentation (§5.7-Routing; FR-7 AC-1)** — ein Synthese-Concept über einen Ziel-Pfad, `sources`-Liste ≥ 2 Einträge, **deterministisch lexikografisch nach `resource` (LC_ALL=C, AD-17h)**, getrennte Zusammenfassungs-Concepts je Quelle verboten; (3) **gemischte claim-granulare Provenienz (AD-4a/4b, A0-3)** — je Aussage Inline-`raw/`-Verweis §5.5, **Multi-Beleg-Konsolidierung** (§5.5-Semikolon-Form, voller Pfad je Beleg; keine Beleg-Tilgung AD-4), **AD-16-Default** (widersprüchliche Aussagen bleiben, Disagreement in `log.md`; Sandbox-N2); (4) **AD-4c-Übernahme-Marker** („übernommen aus `` auf Basis von ``, nicht eigenständig belegt" — nie alleinige Provenienz; Sandbox-N3); (5) **Reflektiertheits-Selbsttest** (FR-7 AC-4/NFR-7) — keine per-Source-Zusammenfassungs-Struktur („Quelle A: …"), grepbasiert `grep -nE 'Quelle [A-Z]:|Source [A-Z]:'`, Selbsttest-FAIL → textuell benannt (NFR-4) und vor Run-Abschluss behoben; (6) **§5.6-Pin unverändert** + **Form-Wahl-Klassifikationsprobe (Story-3.3-Defer U2/U7)** — Überlapp-Einheiten an die §5.9-Abgrenzungs-Reihenfolge `Korrigieren → Präzisieren → Erweitern → No-Op` (erste zutreffende Form), Textgenauigkeits-Rahmen der übrigen je Teilbestand; (7) **`log.md`-Eintragspflicht** („Story 3.1-Update" bei Update, Anlage-Eintrag bei neuem Synthese-Concept; Multi-Source-Liste + ``); (8) **Erhaltungs-Invariante (§5.9 Pkt. 5 gilt) + Determinismus-Vertrag** (Ziel-Pfad via §3.2/§5.7, `sources`-Lexikografie, Konsolidierung/Form-Zuordnung; `generated.at`-Wanduhr-Gap bleibt A0-20-Konvention, Home Story 3.8). **§7:** Synthese-Vorbehalt **aufgelöst** (in §5.10 verankert; verbleibende 3.x-Themen: Leasing/Dirty-Tree → Story 3.5/3.6). **§8:** Normreferenzen bleiben unverändert (AD-4/AD-4a/FR-7/A0-3 sind bereits über §5.5/Roh-Normreferenzen abgedeckt; AD-4c-Kontext-Marker weiterhin §5.5). **Abschlussklausel:** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein Standalone** (D-3); keine Vertragsänderung; **keine fünfte Update-Form** (Abgrenzungs-Reihenfolge §5.9 unverändert, Synthese = Querschnitt); kein Leasing-Scope; Commit-Boundary-Regel unverändert. **`sprint-status.yaml`:** Key `3-4-wissen-aus-mehreren-sources-synthetisieren` → **`in-progress`**. Sandbox-Nachweis (S1–S6 + N1–N3 + Form-Wahl-Probe = 10 Szenarien, Exit 0) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.4, Revision 2.9). **Review-Loop-1-Patches (bmad-code-review, 3 Layer; dieser Eintrag nachgeführt):** Reflektiertheits-Selbsttest-Muster auf Zeilenanfangs-Label erweitert (`^(Quelle|Source) [A-Z][A-Za-z0-9_ -]*:` — mehrbuchstabige/nummerierte Quell-Labels werden ebenso erkannt); **Body-Reihenfolge deterministisch** (Aussagen-Positionierung lexikografisch über die Beleg-Anker, AD-17h) + **Konsolidierungs-Kriterium** (Befund-Äquivalenz über dieselbe erkannte Wissenseinheit) explizit; Stil-/Genus-Korrekturen (`sole`→`einzige`, `der Update`→`das Update`, `sources`-Pluspunkt→`sources`-Zuwachs). Keine Änderung an Normreferenzen, §7, Abschlussklausel. +- **Revision 3.0 (2026-08-19, Story 3.5):** Neue Sektion **§5.11 „Leasing & Dirty-Tree-Schutz für konkurrierende Producer (Story 3.5)"** eingefügt (nach §5.10, vor §6) — die **verbindliche Verankerung der Koordinations-Dimension für konkurrierende Producer** (AD-17a..f, A0-12..A0-16, FR-2/FR-12; §7-Vorbehalt `:357` aufgelöst): (1) **Lease-Akquise (AD-17a, A0-12)** — Arbeits-Branch-Form **`lease//`** von der Merge-Base aus, **Lockfile** (`lease//.lock`, semantisch identisch in jedem Adapter, A0-12; deterministisches Format: `area`, `id`, `producer`, `baseline_commit` voller SHA, `holder_id`), Lease-Hold bei existierendem Lockfile (kein Überschreiben, keine Mutation), **Merge-Base-Disziplin** (Lease gg. eindeutigen Commit-Object-Wert über `git merge-base`/``, AD-17h); (2) **Root-Scope-Lease (AD-17b, A0-13)** — umfasst `wiki/` inkl. `log.md`, `index.md` und aller Root-Dateien; kein Bereich jenseits `wiki/`; (3) **Dirty-Tree-Schutz (AD-17e/f, A0-16)** — Pre-Mutation-Prüfung (`git status --porcelain -- `), fremde uncommittete Änderungen **geschützt statt gelöscht** (Stash/Scratch-Zone außerhalb `wiki/`, dokumentiert in `log.md`), Screen-Artefakte textuell benannt (NFR-4), **UNCOMMITTED_INPUT-Abbruch** „published/committed Input erforderlich" (AD-17a; I/O-Matrix-`UNCOMMITTED_INPUT` — dieselbe Pre-Run-Prüfung wie §5.9-P2-Element-(1)-`INPUT_UNCOMMITTED`, kein zweiter Abbruch-Pfad), Mutationen nur auf Directory-/Commit-Ebene; (4) **kein textueller Auto-Merge (AD-17c, A0-14)** — compiler-vermittelter Merge über die **AD-16-Klassifikation** (Default: Erhaltung) mit `log.md`-Eintrag; Lease-Konflikt → AD-16-Pfad; Unentscheidbarkeit → menschliche Eskalation (AD-17g); (5) **Commit-Boundary = Mutations-Boundary** unverändert (§0/§5.3, AD-17f) — Diff-Selbsttest (§5.9 Pkt. 5) auch für Leasing-Runs, Ghost-Diff-Rollback; (6) **`log.md`-Eintragspflicht** (Lease-Akquise, Dirty-Tree-Schutz-Dokumentation, Merge-Klassifikation, Eskalation, **Lease-Freigabe**; `` notiert, D-2; Datumsgruppe **neueste zuerst**); (7) **Determinismus-Vertrag (AD-17h/A0-19)** — Lease-Akquise, Lockfile-Inhalte, Merge-Klassifikation deterministisch aus dem committeten Git-State; **Lease-Staleness/Recovery bleibt Story 3.6** (AD-17d, A0-15) — diese Sektion mutiert deren Mechanik nicht; testbares Seam-Kriterium (3.5 = committed-state-deterministisch, 3.6 = Zeit-/Umgebungs-Zustands-Frage, die den committeten Zustand verlässt). **§7:** Leasing-/Dirty-Tree-Vorbehalt **aufgelöst** („in §5.11 verankert (Story 3.5)"); Scope-Einleitung um §5.11 geöffnet; verbleibendes 3.x-Thema: Lease-Staleness/Recovery → Story 3.6. **§8:** Normreferenzen um AD-17b/AD-17c/AD-17d/AD-17e-f/AD-17g (Spine) und A0-12/A0-13/A0-14/A0-15/A0-16 (Epics) ergänzt; AD-17d/A0-15 in der §5.11-Enum als Norm-Rückverweis (ohne §5.11-Auflösungs-Bezug) gekennzeichnet. **Abschlussklausel:** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Frontmatter-Key für Lease-Metadaten** (Lease lebt in Git/Datei-Ebene, Vertrag §3.1–§3.7 unverändert); **keine fünfte Update-Form** (Abgrenzungs-Reihenfolge §5.9 unverändert, Leasing = Querschnitt); kein Staleness-Scope (→ Story 3.6); Commit-Boundary-Regel unverändert. **Lease-Freigabe** (Release) ist in §5.11 Pkt. 1/6 verankert (deterministisch, auf das committete Ergebnis bezogen); Staleness-/Recovery-Aspekte der Freigabe (verwaiste Leases) bleiben Story 3.6. **`sprint-status.yaml`:** Key `3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetz` → **`in-progress`**. Sandbox-Nachweis (L1–L6 + Negativ-Kontrollen, Exit 0) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.5, Revision 3.0). diff --git a/wiki/log.md b/wiki/log.md index 960c39e..f1e82a9 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -1,6 +1,8 @@ # Log ## 2026-08-19 +- **Story 3.5 → `done` (Step-04-Review-Abschluss, 2026-08-19):** Der Review-Abschluss-Flip `in-progress → done` (Sprint-Sync-Konvention, Story-3.1/3.2/3.3/3.4-Präzedenz) ist hier als eigener dokumentierter Schritt nachgeführt; `sprint-status.yaml`-Key `3-5-…` → **`done`**, `last_updated` → 08-19-2026 20:37; Spec-Frontmatter `status: 'in-review' → 'done'`, `review_loop_iteration: 0`; Spec-`## Suggested Review Order` (Review-Trail: §5.11-Leasing-Sektion → §7/§8-Nachweis → Sandbox-Nachweis → Story-Protokoll/Defers) verankert. **Review-Ergebnis (Review-Loop 1, 3 Subagenten — blind-hunter / edge-case-hunter / verification-gap, kein Loopback):** keine intent_gap/bad_spec; Stapel Autofix-Patches (Text-Fixes (§5.11): Pkt.-1-Querverweis „Pkt. 3" → „Pkt. 2", UNCOMMITTED_INPUT als dieselbe §5.9-P2-Prüfung deklariert, „neueste zuerst"-Datumsgruppe, Lease-Freigabe als deterministischer Pkt.-1-Sub-Bullet + Pkt.-6-Eintragstyp (e), testbares 3.5/3.6-Seam-Kriterium, AD-17d/A0-15-Norm-Rückverweis, §8-Revision 3.1; Sandbox: Header-Bullet-Paare, L2-Lease-Hold-Exit-Assertion, L4-Restore-Weg + UNCOMMITTED_INPUT-Abbruch-Wirkung, L6-BUILD_HEAD, L5-Klassifikations-Bullet, N1-§5.10-Pkt.-8-Orphan-Nachbarschaft, D2-Kumulative-Aufzeichnung); **4 Defers** → `deferred-work.md` append-only (holder_id-Quelle · baseline_commit-Merge-Base-Diskrepanz-Regel · Sandbox-log-Akkumulator [D2 schließt] · native `git stash`-Variante — Home je Story 3.6/3.8). **Sandbox re-executiert:** L1–L6 + N1 + D1 + D2, **Exit 0, 21 harte PASS-Assertionen**; AD-3 geprüft (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` unverändert); Validator-Verdikt auf Ist-Bundle: alle `wiki/`-Dateien SUCCESS (keine Inhalts-Mutation). **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag) — keine Concept-Inhalts-Mutation (Instruktions-Story). +- **Story 3.5 → `in-progress` (Leasing & Dirty-Tree-Schutz, Verankerung §5.11, 2026-08-19):** `schema/compiler.md` Revision 3.0 — neue Sektion **§5.11 „Leasing & Dirty-Tree-Schutz für konkurrierende Producer (Story 3.5)“** (nach §5.10, vor §6): Lease-Akquise auf **`lease//`-Branches** vom Merge-Base mit **Lockfile** (`lease//.lock`, semantisch identisch in jedem Adapter, A0-12; deterministische Felder `area`/`id`/`producer`/`baseline_commit`/`holder_id` — kein Zeitstempel, AD-17h), Basis-Commit = eindeutiger Commit-Object-Wert (Merge-Base-Disziplin); **Root-Scope-Lease** (AD-17b, A0-13: `wiki/` inkl. `log.md`, `index.md`, aller Root-Dateien; kein Bereich jenseits `wiki/`); **Dirty-Tree-Schutz** (AD-17e/f, A0-16: Pre-Mutation-Prüfung, Stash/Scratch-Zone außerhalb `wiki/`, fremde uncommittete Änderungen NIE gelöscht, log.md-Dokumentation, UNCOMMITTED_INPUT-Abbruch „published/committed Input erforderlich“ AD-17a); **kein textueller Auto-Merge** (AD-17c, A0-14: compiler-vermittelter AD-16-Pfad, Default Erhaltung, log.md-Klassifikations-Eintrag, Eskalation AD-17g); **Commit-Boundary = Mutations-Boundary** unverändert (§0/§5.3); `log.md`-Eintragspflicht (Akquise/Schutz/Klassifikation/Eskalation, ``, D-2); **Determinismus-Vertrag** (AD-17h/A0-19) · **Lease-Staleness/Recovery bleibt → Story 3.6** (AD-17d, A0-15). §7-Vorbehalt `:357` **aufgelöst** (→ §5.11), §8-Normreferenzen um AD-17b/c/d/e-f/g + A0-12..A0-16 ergänzt, Abschlussklausel (AD-3, keine neue §7-Klasse, kein Standalone D-3, keine Vertragsänderung, kein neuer Frontmatter-Key). `sprint-status.yaml`-Key `3-5-…` → **`in-progress`**. **Sandbox `sandbox-3-5/run-sandbox.sh` re-executierbar (Muster Story 3.4, /tmp-Baum):** L1 Lease-Akquise (Branch-Form, Lockfile-Felder, Merge-Base = eindeutiger Commit-Object-Wert), L2 Lease-Hold (zweite Akquise verweigert, Lockfile unverändert, keine Mutation), L3 Root-Scope (index/log/Root-Dateien erfasst; raw//lease/ keine Mutationsziele), L4 Dirty-Tree-Schutz (Pre-Mutation-Prüfung erkennt Fremd-Aenderung, Scratch-Zone byte-identisch, NIE gelöscht, log.md-Dokumentation; UNCOMMITTED_INPUT-Abbruch), L5 NO_AUTO_MERGE (Merge-Versuch scheitert; AD-16-Erhaltung + Eskalation AD-17g, beide Behauptungen erhalten), L6 COMMIT_BOUNDARY (Zwischenstand nie committet; validierte Mutation committet; invalidierter Zwischenstand → Validierungs-FAIL → Rollback §5.3), N1 ??-Ghost-Diff-Negativkontrolle (Ghost-Datei als Duplikat/Ghost-Diff verworfen, Kontrolle nicht vacuous), D1 Determinismus (Lockfile-Inhalt + Merge-Klassifikation Zwei-Run-identisch, AD-17h/A0-19); **Exit 0**, **21 harte PASS-Assertionen** (2 HARD-FAIL-Zeilen sind die intendierte N1-Ghost-Erkennung). **Review-Loop-1-Patches (Step-04, kein Loopback, 2026-08-19):** log-Helfer → **Header-Bullet-Paare** je Eintrag (Vertrag-§5-Datumsgruppe, neueste zuerst, wie §5.9 Pkt. 4); **L1 Lease-Freigabe (Release, deterministisch, §5.11 Pkt. 1)** — `free_lease` entfernt nach committetem Run das Lockfile und dokumentiert den Abschluss als **log.md-Freigabe-Eintrag** (+ log_release-Helfer; Lockfiles häufen sich nicht; eine ohne Freigabe beendete Lease verbleibt → **Story 3.6**); L2 `akquire`-Exit-Status != 0 als Fehlerpfad-Assertion; **L4 Restore-Weg** (Scratch → Bundle, byte-identischer Restore; Fremd-Aenderung nie gelöscht) + **UNCOMMITTED_INPUT-Abbruch-Wirkung hart assertiert** (`HEAD` unverändert `[ "$(git rev-parse HEAD)" = "$BASE" ]`, `ALPHA_ONLY` exakt „alpha" — **dieselbe Pre-Run-Prüfung** wie §5.9-P2-Element (1) `INPUT_UNCOMMITTED`, kein zweiter Abbruch-Pfad, §5.11 Pkt. 3); L5 Merge-Klassifikations-Bullet in Datumsgruppen-Form (`-- '- Merge-Klassifikation: …'`); **L6** Widerspruchs-Tautologie (`BROKEN_HEAD`/`COMMIT_AFTER_RUN`) → einzelnes `BUILD_HEAD`, Frontmatter-Negativtest subshell-gewrappt (Exit-1-safe); N1-Header um §5.10-Pkt.-8-Orphan-Nachbarschaft + §5.9-Pkt.-5-Erhaltungs-Invariante; L3-`??`-Sicht-Assertion (`^?? wiki/beta.md`); **neues D2 „Kumulative Koordinations-Aufzeichnung"** — 4 Koordinationsentscheidungen (log_lease + log_dirty + log_merge + log_release) in EINEM `log.md`: `HEADERS = 4`, jede Bullet präsent, erst an der Commit-Boundary committiert — PASS. **Seam-Kriterium 3.5/3.6 (compiler.md §5.11 Pkt. 7):** 3.5 = committeter-Git-State-Determinismus (AD-17h), 3.6 = Zeit-/Umgebungs-Zustands-Frage (TTL-Ablauf, verwaiste/hängende Leases, `raw/`-Recovery). **4 Defers → `deferred-work.md`** (holder_id-Uniqueness-Quelle; baseline_commit-Merge-Base-Diskrepanz-Regel; Sandbox-log-Akkumulator vs. isolierte Szenarien [D2 schließt]; native `git stash`-Variante ungetestet — Home je Story 3.6). Sandbox nach allen Patches re-executiert: **Exit 0, 21 PASS**. **Validator-Verdikt auf Ist-Bundle:** `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` unverändert (AD-3); alle `wiki/`-Dateien SUCCESS (keine Inhalts-Mutation); `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag). - **Story 3.4 → `done` (Step-04-Review-Abschluss, 2026-08-19):** der Review-Abschluss-Flip `in-progress → done` (Sprint-Sync-Konvention, Story-3.1/3.2/3.3-Präzedenz) ist hier als eigener dokumentierter Schritt nachgeführt; `sprint-status.yaml`-Key `3-4-…` → **`done`**, `last_updated` → 08-19-2026 16:40 (Präzisions-Rückgewinnung auf HEAD-Format `HH:MM`); Spec-Frontmatter `status: 'in-review' → 'done'`, `review_loop_iteration: 0`; Spec-`## Spec Change Log`-Review-Loop-1-Eintrag + `## Suggested Review Order` (Review-Trail: Synthese-Sektion → §7/§8 → Sandbox-Nachweis → Provenienz/Status) verankert. **Review-Ergebnis (Loop 1, 3 Subagenten — blind-hunter / edge-case-hunter / verification-gap, kein Loopback):** keine intent_gap/bad_spec; Stapel Patches (compiler.md §5.10: Reflektiertheits-Selbsttest-Muster auf Zeilenanfangs-Label erweitert `^(Quelle|Source) [A-Z][A-Za-z0-9_ -]*:`, **Body-Reihenfolge deterministisch** über Beleg-Anker LC_ALL=C, **Konsolidierungs-Kriterium** Befund-Äquivalenz, Duplikat-Fall + Orphan-Kontrolle in Pkt. 8, Stil-/Genus-Korrekturen; Sandbox: `git add -A`-wiki-Staging entfernt → Pkt.-8-`??`-Sicht lebendig, **S5-Pkt.-8-`??`-Negativkontrolle** (Ghost-Datei-HARD-FAIL), **N1**-Stimulus-Kommentar, **neue Szenarien N2 Disagreement (AD-16, §5.10 Pkt. 3/7)** + **N3 AD-4c-Übernahme-Marker** — erstmals = **10 Szenarien S1–S6 + N1–N3 + FW**, Exit 0 dreimal re-executiert, 30 harte PASS-Assertionen; S1/S2-log.md-Multi-Source-Listen; log.md-/Spec-/sprint-status-Konsistenz); **4 Defers** → `deferred-work.md` append-only (AD-16/AD-4c-reale-Anwendung Home Epic-4, Orphan-Kontrolle Home Story 3.8, Umlaut/Em-Dash-Sandbox-Normalisierung Home Story 3.8, Frozen-„Nickel"-Typo Re-Negotiation); Rejects dokumentiert. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag) — keine Concept-Inhalts-Mutation (Instruktions-Story); `schema/validator.md`/`schema/wiki-compiler.md`/`raw/` unverändert (AD-3, geprüft). Sandbox re-executiert: **10/10 Szenarien PASS, Exit 0**. - **Story 3.4 — Step-03-Abschluss Audit (2026-08-19):** **Sandbox-Nachweis re-executiert (Story-3.4-Sandbox, `bash _bmad-output/implementation-artifacts/sandbox-3-4/run-sandbox.sh`, Linux-Semantik auf einem `/tmp`-Baum, Exit 0)** — jetzt **S1–S6 + N1–N3 + Form-Wahl-Probe FW = 10 Szenarien** (zuvor 7): **N1 NO_OP-SYNTHESE** ergänzt (deckt die I/O-Matrix-Zeile `NO_OP_SYNTHESE`, Story-3.3-U4-Muster: zweite committete Quelle mit redundanter Evidenz zum selben Thema → keine Form greift → **No-Op als Nicht-Form**: volle Byte-Identität von `alpha.md`/`log.md`/`index.md`, kein `generated.at`-Bump, kein sources-Zusatz, kein `log.md`-Eintrag, Probe leer = Ghost-Diff-negativ — PASS), **N2 DISAGREEMENT** (AD-16-Default, §5.10 Pkt. 3/7: widersprüchliche Aussagen zweier Quellen werden **nicht** still zu einer scheinbar eindeutigen Aussage zusammengeführt; beide Behauptungen + je Beleg bleiben, kein `(e; f)`-Falsch-Multi-Beleg, `Disagreement:`-Eintrag in `log.md` — Epic-4-Interface — PASS) und **N3 AD-4c-UEBERNAHME-MARKER** (Kontext-Marker-Muster „übernommen aus `gamma` auf Basis von `raw/gamma-v1.md#S-1`, nicht eigenständig belegt"; eigenständig belegte Aussagen tragen den Marker nicht; `raw/gamma-v1.md` wird **nicht** als eigene `sources`-Quelle eingetragen — PASS). **S5-Pkt.-8-`??`-Negativkontrolle** nun lebendig: eine ungetrackte Nicht-Ziel-Datei (`ghost.md`) außerhalb der erlaubten Ziel-Pfade wird von der `??`-Sicht als Duplikat/Ghost-Diff HARD-FAIL erkannt (Story-3.3-U9-Muster, nicht vacuous). **S5-Mechanik korrigiert** (auditierte `&&`-Verkettung von `assert_invariant`/`assert_frontmatter` ersetzt): die Erhaltungs-Invariante wird in Non-Exiting-Varianten aufgespalten (`inv_viol` + `assert_frontmatter_ok`), S5-Setup als regelkonforme Anlage (delta + Index-Link + log-Eintrag) restrukturiert — der Verstoß sitzt jetzt ausschließlich in der **Struktur-Ebene** (unbefugter Key `foo:`); Path-Set-Ebene teils erwartet gehalten, teils das Erkennen des Struktur-Verstoßes hart assertiert (P2-Element (6), Vertrag §3.3/§3.4-Subset — nicht vacuous) — PASS. **Matrix-Test-Audit (step-03):** alle 7 I/O-Matrix-Zeilen abgedeckt+bestanden — HAPPY_SYNTHESE_NEUANLAGE→S1, HAPPY_SYNTHESE_KONSOLIDIERUNG→S2, HAPPY_SYNTHESE_UPDATE→S4, NO_OP_SYNTHESE→N1, ANEINANDERREIHUNG_NEGATIV→S3, STRUKTUR_ERHALT→S5, SYNTHESE_OVERLAP_FORMCROSS→FW. Spec-`## Tasks & Acceptance`: alle 4 Execution-Tasks `[x]`. Layout-/Struktur-/AD-3-/Erhaltungs-Invariante-Verifikation erneut bestanden (`git status --porcelain -- wiki/` ausschließlich `wiki/log.md`; `schema/validator.md`/`schema/wiki-compiler.md`/`raw/` unverändert). - **Story 3.4 «Wissen aus mehreren Sources synthetisieren — gemischte claim-granulare Provenienz operationalisieren» (Implementierung, Instruktions-Story D-3; `sprint-status.yaml`: Key `3-4-wissen-aus-mehreren-sources-synthetisieren` **`in-progress`**):** `schema/compiler.md` → **Revision 2.9** — die **Synthese-Dimension** (AD-4, FR-7; §7-Vorbehalt `:343` aufgelöst) als neue Sektion **§5.10 „Synthese aus mehreren Sources (Story 3.4)"** verankert (nach §5.9, vor §6): (1) **Synthese-Stimulus** — ≥ 2 belegende `raw/`-Quellen desselben Themas per §2-Interpretation → eine Synthese-Einheit; einzelne Quelle bleibt auf §5.9-/§3.2-Pfad; (2) **Ein-Ziel-Repräsentation (FR-7 AC-1)** — ein Synthese-Concept über einen Ziel-Pfad (§5.7-Routing), `sources`-Liste ≥ 2 Einträge, **deterministisch lexikografisch nach `resource` (LC_ALL=C, AD-17h/A0-19)**, getrennte Zusammenfassungs-Concepts je Quelle verboten (FR-7); (3) **gemischte claim-granulare Provenienz (AD-4a/4b, A0-3)** — je Aussage Inline-`raw/`-Verweis §5.5, **Multi-Beleg-Konsolidierung** (§5.5-Semikolon-Form, voller Pfad je Beleg; keine Beleg-Tilgung AD-4), **AD-16-Default** (widersprüchliche Aussagen bleiben, Disagreement in `log.md` — Epic-4-Interface); (4) **AD-4c-Übernahme-Marker** („übernommen aus `` auf Basis von ``, nicht eigenständig belegt" — nie alleinige Provenienz); (5) **Reflektiertheits-Selbsttest (FR-7 AC-4/NFR-7)** — keine per-Source-Zusammenfassungs-Struktur („Quelle A: …/Quelle B: …"), grepbasiert `grep -nE 'Quelle [A-Z]:|Source [A-Z]:'`, Befund = textuell benannter Instruktions-Selbsttest-FAIL (NFR-4), vor Run-Abschluss zu beheben; (6) **§5.6-Pin unverändert** + **Form-Wahl-Klassifikationsprobe (Story-3.3-Defer U2/U7)** — Überlapp-Einheiten an die §5.9-Abgrenzungs-Reihenfolge `Korrigieren → Präzisieren → Erweitern → No-Op` (erste zutreffende Form, AD-17h), Textgenauigkeits-Rahmen der übrigen Formen je Teilbestand; **(7) `log.md`-Eintragspflicht** — „Story 3.1-Update" bei Synthese-Update, Anlage-Eintrag bei neuem Synthese-Concept (disambiguierbar), Multi-Source-Liste + `` (R-1); (8) **Erhaltungs-Invariante (§5.9 Pkt. 5 gilt unverändert) + Determinismus-Vertrag** — Ziel-Pfad via §3.2/§5.7, `sources`-Lexikografie, Konsolidierung/Form-Zuordnung deterministisch; `generated.at`-Wanduhr-Gap bleibt A0-20-Konvention, Home Story 3.8. **§7:** Synthese-Vorbehalt **aufgelöst** („in §5.10 verankert"); Scope-Einleitung um §5.10 geöffnet; verbleibende 3.x-Themen: Leasing/Dirty-Tree → Story 3.5/3.6. **§8:** Revisionslog **Revision 2.9** mit Abschlussklausel (keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`raw/` AD-3; **keine neue §7-Invaliditätsklasse**; **kein Standalone** D-3; keine Vertragsänderung; **keine fünfte Update-Form** — Abgrenzungs-Reihenfolge §5.9 unverändert, Synthese = Querschnitt; kein Leasing-Scope; Commit-Boundary-Regel unverändert). **Sandbox-Nachweis (re-executiert 2026-08-19, ab Workspace-Root, `bash _bmad-output/implementation-artifacts/sandbox-3-4/run-sandbox.sh`; Linux-Sandbox-Semantik auf einem `/tmp`-Baum, nie der reale `wiki/`-Baum; Exit **0**, zweimal re-executiert):** Mini-Bundle mit `alpha`/`gamma`-Root-Concepts; Szenarien **S1–S6 + N1–N3 + Form-Wahl-Klassifikationsprobe FW (10)**, harte Pass/Fail-Assertionen (Exit 1; damit inzwischen **10 Szenarien, Exit 0**, zweimal re-executiert): **S1 NEU-ANLAGE** (zwei Quellen `raw/synth-a.md`+`raw/synth-b.md` → **ein** Synthese-Concept `delta`, `sources` ≥ 2 lexikografisch LC_ALL=C — PASS, gemischte §5.5-Belege je Aussage — PASS, keine per-Source-Struktur — PASS, Index-Link Punkt 11 + Anlage-Eintrag — PASS, Probe `{delta index log}` — PASS, Frontmatter — PASS), **S2 KONSOLIDIERUNG** (redundante Aussage in beiden Quellen → **eine** konsolidierte Aussage mit Multi-Beleg-Semikolon-Form `(raw/synth-c.md#S-1; raw/synth-d.md#S-1)` — PASS, keine Beleg-Tilgung AD-4 — PASS, Probe `{delta index log}` — PASS), **S3 NEGATIV-KONTROLLE ANEINANDERREIHUNG** („Quelle A:/Quelle B:"-Struktur wird vom Reflektiertheits-Selbsttest erkannt — nicht vacuous — und durch integrierte, provenance-versehene Aussagen umgebaut (NFR-4) — PASS), **S4 SYNTHESE-UPDATE** (zwei Quellen treffen den bestehenden Pfad `alpha` → §5.9-Formwahl **ERWEITERN**, `sources`-Zuwachs `s2`+`s3` lexikografisch, bestehende belegte Aussagen byte-identisch, »Story 3.1-Update«-Eintrag, Probe `{alpha log}` — PASS; Index-Link unverändert, §5.9 Pkt. 3), **S5 STRUKTUR-/FRONTMATTER-INVARIANTE** (unbefugter Key `foo:` im Synthese-Concept → Frontmatter-Subset-HARD-FAIL, Pkt. 8/P2-Element (6) — PASS; **Pkt.-8-`??`-Negativkontrolle lebendig**: ungetrackte Nicht-Ziel-Datei `ghost.md` → Duplikat/Ghost-Diff-HARD-FAIL, nicht vacuous), **S6 ZWEI-RUN-IDENTITÄT (AD-17h/A0-19)** (zwei unabhängige Synthese-Runs über dieselben zwei Quellen → byte-identisches Ergebnis: `delta.md`/`log.md`/`index.md`-SHA-256 identisch je Lauf, auch nach Commit — PASS), **N2 DISAGREEMENT (AD-16, §5.10 Pkt. 3/7)** (widersprüchliche Quellen-Befunde → beide Behauptungen + je Beleg bleiben, kein `(e; f)`-Falsch-Multi-Beleg, `Disagreement:`-Eintrag in `log.md` — Epic-4-Interface — PASS), **N3 AD-4c-ÜBERNAHME-MARKER** (Kontext-Marker „übernommen aus `gamma` auf Basis von `raw/gamma-v1.md#S-1`, nicht eigenständig belegt"; eigenständig belegte Aussagen tragen den Marker nicht; `raw/gamma-v1.md` als übernommene Quelle nicht in `sources` — PASS), **FW FORM-WAHL-KLASSIFIKATIONSPROBE** (Story-3.3-Defer U2/U7: gemischte Einheit mit Ersetzungs-Befund → erste zutreffende Form **KORRIGIEREN**; Ablösung mit Ersetzungs-Multi-Beleg, alter Wortlaut erhalten AD-16-Default, Nebenbefund byte-identisch, `sources` ≥ 2 lexikografisch, Probe `{alpha log}` — PASS). **Erhaltungs-Invariante §5.9 Pkt. 5 wird hart erzwungen** (Proben-Einträge normalisiert ⊆ {betroffener Pfad, log} ∪ Neu-Anlage-Zielpfade ∪ Index; `??`-Sicht = keine neue Datei außer echten Ziel-Pfaden; kein Ghost-Diff lässt sich still durchschleusen). **Status-/Diff-Nachweis:** nach diesem Instruktions-Run zeigt `git status --porcelain -- wiki/` ausschließlich `wiki/log.md` (dieser Eintrag) — Erhaltungs-Invariante gewahrt, keine Concept-Inhalts-Mutation (Instruktions-Story, Demonstration per Sandbox). **Validator-Verdikt (per-Datei, human-mechanisch ausgeführte Text-Instruktion `schema/validator.md` Rev 9, D-3 — kein CLI; unverändert zur Story 3.3, Story 3.4 mutiert keine Concept-Inhalte):** alle **7** `wiki/`-Dateien **SUCCESS** — `wiki/index.md` (Punkt 11, Bundleroot), `wiki/knowledge-kompilation-inkrementell.md`, `wiki/llm-wiki-prinzip.md`, `wiki/wissensarchitektur-trennung-states.md` (Punkte 1/2/6/7/8/9/11/12/13/14, EC-1), `wiki/log.md` (frontmatterlos, Punkt 10), `wiki/wissensarchitektur/index.md` (frontmatterlos, Punkt 10/11), `wiki/wissensarchitektur/source-material.md` (Punkte 1/2/6/7/8/9/11/12/13/14, EC-1; Punkt 11 inkl. Area-Lesart Rev 9). `schema/validator.md`/`schema/wiki-compiler.md`/`raw/` unverändert (AD-3, via `git status` geprüft); keine neue §7-Klasse; kein Standalone (D-3); keine fünfte Update-Form. Spec-Frontmatter: `status: 'in-progress'`, `review_loop_iteration: 0` (zum Audit-Zeitpunkt).