From e02cf8450188a7d91f5836428c6fb0a199d57d78 Mon Sep 17 00:00:00 2001 From: Michael Tamse Date: Fri, 21 Aug 2026 13:40:10 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Story=203.11=20=E2=80=94=20Root-Scope-L?= =?UTF-8?q?easing=20atomar=20und=20worktree-=C3=BCbergreifend=20akquiriere?= =?UTF-8?q?n=20(Revision=203.6,=20Verankerung=20=C2=A75.17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../implementation-artifacts/deferred-work.md | 15 + .../epic-3-context.md | 2 +- .../sandbox-3-11/run-sandbox.sh | 498 ++++++++++++++++++ ...1-root-scope-leasing-atomar-akquirieren.md | 124 +++++ .../sprint-status.yaml | 4 +- schema/compiler.md | 14 +- wiki/log.md | 1 + 7 files changed, 654 insertions(+), 4 deletions(-) create mode 100644 _bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh create mode 100644 _bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md diff --git a/_bmad-output/implementation-artifacts/deferred-work.md b/_bmad-output/implementation-artifacts/deferred-work.md index 4e5c1d8..e1b55d5 100644 --- a/_bmad-output/implementation-artifacts/deferred-work.md +++ b/_bmad-output/implementation-artifacts/deferred-work.md @@ -574,3 +574,18 @@ Noch nicht adressierte, aber real erkannte Arbeit — gesammelt aus Reviews. Ein - source_spec: `spec-3-10-inkrementelle-update-und-synthese-erhaltung-absichern.md` summary: Die Sandbox-3.10 validiert ihre Erhaltungs-Invarianten ausschliesslich im isolierten /tmp-Baum (fixture-eigene `git status`-/`log.md`-Pruefungen); ein externer, gegen das reale committete Bundle (wiki/-+raw/) laufender Validator auf Abnahme-Ebene wird nicht ausgefuehrt. evidence: run-sandbox.sh definiert `SB_DIR=/tmp/sandbox-3-10` und beruehrt nie den realen Ist-Baum (Kommentar Z. 55-58); die `wiki/`-nur-`log.md`-Invariante und die `raw/`-Unangetastetheit liegen ausserhalb der Sandbox — Home: Story-3.13-Abnahmegate. + +## Deferred from: code review of spec-3-11-root-scope-leasing-atomar-akquirieren (2026-08-21) + +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Das von Story 3.11 verwiesene AC-d („niemals zwei aktive Root-Leases gleichzeitig") ist in der Vorlage von epics.md A0-13/AD-17b nicht separat gelistet; die Sandbox und §5.17 verwenden den Token AC-d ohne normative Vorlagen-Definition. + evidence: epics.md Z. 412-416 listet AC-a..c und AC-e, aber kein AC-d; §5.17 Pkt. 1/2/3/5 nutzen AC-a/b/c/e, die Sandbox A-2/A-3 und der log.md-Eintrag verwenden „AC-d"; der Scope ist bei A0-13/AD-17b (genau ein scope-bezogener Lock) und der Zwischenzustands-Assertion verankert — der AC-d-Token ist ein konsistenzerhaltender Behelf, kein neuer Anforderungskanon. Erhaltender Konsistenz-Defer; Koordinator kann AC-d bei der Epic-4-Statussynchronisation der Architecture-Spine formalisieren. +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Die Zeilenanker im Code Map-Verweis auf §5.11 (Z. 304-321) / §5.12 (Z. 323-342) der Spec sind nach dem Wachstum des Dokuments (§5.13-§5.17) nicht mehr die aktuellen Zeilennummern. + evidence: Die Spec (Code Map) und die Task-1-Rationale nennen die §5.11-Zeilen als Verweisanker; `schema/compiler.md` hat seit Story 3.8-3.10 weitere Sektionen erhalten, sodass die Zeilen heute woanders liegen — reine Dokumentationsdrift im Planungsartefakt, kein Instruktionsdefekt. Beim nächsten Durchlauf aktuelle Zeilen neu ermitteln. +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Die A-1/A-5-Negativprüfungen „Schlüssel trägt keine Run-ID" sind gegen die hart gesetzte Konstante `SCOPELOCK="refs/leases/wiki"` tauglich, konstruieren aber keinen dynamischen Gegen-Beweis (Ref-Name aus einer Run-ID gebaut, der nicht matchen dürfte). + evidence: run-sandbox.sh A-1 (Z. 182) und A-5 (Z. 333) matchen `$SCOPELOCK` gegen statische Muster (`*RUN-A1*|*run-a1*|*a1*`); ein Ref-Name, der tatsächlich eine Run-ID trüge, wäre nur indirekt ausgeschlossen. Strukturell trägt der Ref-Name keinerlei Run-ID (eine Scope-Ref), der Nachweis ist vorhanden — eine dynamische Negative-Kontrolle (Konstruktion eines run-id-haltigen Refs und Assert, dass dieser NICHT auftritt) würde die Assertion schärfen. Home: künftige Sandbox-Härtung. +- source_spec: `spec-3-11-root-scope-leasing-atomar-akquirieren.md` + summary: Die Helfer-Funktion `scopelock_header_banner() { :; }` in der Sandbox-3.11 ist ein leerer Platzhalter. + evidence: run-sandbox.sh Z. 166 definiert `scopelock_header_banner() { :; } # (placeholder für Vereinheitlichung mit Story-3.5-Konvention)` — die Funktion wird nie aufgerufen und trägt nichts bei; kosmetisch. Home: Story-3.12-Lifecycle-Erweiterung, falls die Banner-Konvention übernommen wird, sonst entfernen. diff --git a/_bmad-output/implementation-artifacts/epic-3-context.md b/_bmad-output/implementation-artifacts/epic-3-context.md index ac534e3..20c869f 100644 --- a/_bmad-output/implementation-artifacts/epic-3-context.md +++ b/_bmad-output/implementation-artifacts/epic-3-context.md @@ -38,7 +38,7 @@ Der Compiler verarbeitet neues Source Material gegen das bestehende Knowledge Bu - **Reason/Mutate-Trennung (AD-6, A0-7):** Logische Phasen Analyse → Reconcile → Plan Changes → Mutate → Validate. Keine eigene Workflow Engine; ein Agent kann die Phasen in einer Session durchführen, der beobachtbare Endzustand des Bundles muss auch bei Abbruch konsistent sein. - **Deterministische Relevanz & Routing (A0-18):** Geschlossene, geordnete Term-Gewinnung bzw. explizites persistiertes Term-Manifest; Suchterm und Concept-Body werden identisch normalisiert und literal-sicher verglichen. Eine exklusive Routing-Tabelle unterscheidet `UPDATE`, `CREATE`, `ORPHAN/HOLD` und echten `NO_OP`; gleicher Git-State plus gleiches Eingabemanifest erzeugt dieselbe Candidate-Liste und Reihenfolge. *Ist (Story 3.9, 2026-08-20): in `schema/compiler.md` **§5.15** verankert (Termgewinnung geschlossen, eine exklusive Routing-Tabelle, Raw-Immutability-Guard, reservierte Zielpfade, Zwei-Run-Identität; §3.2 bleibt Erhebungs-Anker, §5.15 Pkt. 3 die Routing-Zuordnung).* *Ist (Story 3.10, 2026-08-21): die Erhaltungs-Absicherung der operativen Update-/Synthese-Schritte und der Hold-Ausbau sind in `schema/compiler.md` **§5.16** verankert (Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau, Punkte 1–8: Kontinuitäts-Garantie AC-1, Korrigieren mit Run-Receipt-Trace AC-2, Schutzbestandteile & Byte-Identität AC-3, CONFIRMING-Konsolidierung ohne NO_OP AC-4, gemeinsame Wissensrepräsentation als Synthese-Erhaltung AC-5, byte-erhaltender NO_OP AC-6, Provenienz-/Link-Selbsttest aus aktuellem Run AC-7, benannter Hold über die Erhebungs-Stufen a/b/c + Mehrziel-Auflösung AC-8/NFR-7; Erhaltungs-Nachweis als re-executierbare Sandbox E-1..E-9, Exit 0; kein neuer Regel-Operand, keine §7-Klasse, kein Standalone — Umlaut-vs-Transkription bleibt benannter Defer).* - **Keine eigene LLM-Runtime:** Der ausführende agentische Host orchestriert den AD-17-Ablauf (Lease holen, innerhalb des geleasten Bereichs mutieren, committen, freigeben); keine separaten Prozesse oder ein Server (AD-11). -- **Atomare Root-Scope-Lease (AD-17a/b, A0-12/13):** Producer behalten die Branch-Konvention `lease//`, akquirieren aber genau einen atomaren, scope-bezogenen Lock im clone-geteilten Zustand. Die Run-ID ist Lock-Inhalt, nicht Exklusivitätsschlüssel; konkurrierende Producer verschiedener IDs und Worktrees teilen denselben Root-Scope (`wiki/` inklusive `log.md`, `index.md` und aller Root-Dateien). *Zielzustand (Review-Loop-3, P-11): geplant für Story 3.11 (Sprint-Change-Proposal 2026-08-20) — die atomare Lock-Präzisierung ist noch nicht in `schema/compiler.md` §5.11 verankert; die bestehende §5.11-Verankerung (Branch-Konvention, Root-Scope-Lease) bleibt unverändert maßgeblich.* +- **Atomare Root-Scope-Lease (AD-17a/b, A0-12/13):** Producer behalten die Branch-Konvention `lease//`, akquirieren aber genau einen atomaren, scope-bezogenen Lock im clone-geteilten Zustand. Die Run-ID ist Lock-Inhalt, nicht Exklusivitätsschlüssel; konkurrierende Producer verschiedener IDs und Worktrees teilen denselben Root-Scope (`wiki/` inklusive `log.md`, `index.md` und aller Root-Dateien). *Ist (Story 3.11, 2026-08-21): die atomare Lock-Präzisierung ist in `schema/compiler.md` **§5.17** verankert (Revision 3.6 — Atomare Root-Scope-Lease-Akquise: Exklusivitätsschlüssel = einziger scope-bezogener Lock im clone-geteilten Zustand, eine committete Ref je Root-Scope `wiki/`, `git update-ref $ZERO_SHA` create-only, Run-ID als Lock-Inhalt statt Schlüsselbestandteil, atomare Akquise mit genau einem Gewinner und `LEASE_HOLD` für den Abgewiesenen, Kollisions-Hold mit beiden Commit-Hashes an Epic 4 statt textuellem Auto-Merge; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker bleiben unverändert maßgeblich, Fugen-Identität).* - **Fail-closed Kollisionsgrenze (AD-17c, A0-14):** Zwei Branches mit ungleichen Änderungen am selben Concept-Pfad werden nie textuell automatisch gemerged. Epic 3 erhält beide Commit-Hashes und den Scope in einem strukturierten Hold; AD-16-Klassifikation und semantische Auflösung sind Epic 4 / Story 4.x. - **Transaktionaler Lifecycle (AD-17d–f, A0-15/16, AD-6):** Preflight schützt getrackte und ungetrackte Fremdänderungen (eindeutige Abort-/Protect-Zustandsmaschine), Rollback restauriert exakt den bezeichneten Baseline-Commit (Index + Worktree), Release hinterlässt Mutation, zulässigen Nachweis und sauberen Worktree dauerhaft. Eine lebende Lease wird nicht allein durch Generationserhöhung stale; Staleness verlangt bestätigten Abbruch oder abgelaufene Liveness plus atomare Ownership-Prüfung. *Zielzustand (Review-Loop-3, P-11): geplant für Story 3.12 (Sprint-Change-Proposal 2026-08-20) — die transaktionale Lifecycle-Präzisierung (Abort-/Protect-Zustandsmaschine, Liveness-Prüfung) ist noch nicht in `schema/compiler.md` §5.11/§5.12 verankert; die bestehende Verankerung bleibt unverändert maßgeblich.* - **Determinismus-Vertrag (AD-17h/FT-10, A0-19):** Das kanonische Eingabemanifest bindet Baseline, geordnete Sources und jeden output-sichtbaren Run-/Zeit-/Identitätswert; der Run-Receipt (Candidates, Reihenfolge, Plan, Entscheidungen, Output-Hashes) liegt außerhalb des Bundles. Zwei getrennte saubere Worktrees mit frischen Agent-Kontexten erzeugen denselben Bundle-State; hart codierte erwartete Pläne oder Concept-Bodies und pauschal maskierte `verified`-Ereignisse sind kein gültiger Nachweis. diff --git a/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh b/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh new file mode 100644 index 0000000..f7055d3 --- /dev/null +++ b/_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh @@ -0,0 +1,498 @@ +#!/usr/bin/env bash +# Story 3.11 — Sandbox-Tests der atomaren Root-Scope-Lease-Akquise (§5.17, Revision 3.6) +# im clone-geteilten Zustand (AD-17b/A0-13, AC-a..AC-e) +# Re-executierbar: bash run-sandbox.sh (ab Workspace-Root; Sandbox unter /tmp/sb311) +# Zweck: die §5.17-Atomaritäts-Präzisierung (Revision 3.6) als re-executierbarer +# Run-Demonstrator durchspielen — +# A-1 EXKLUSIVITAETS_SCHLUESSEL: ein Mini-Bundle + Root-Scope-Lock im clone-geteilten +# Zustand; der Exklusivitätsschlüssel ist der scope-bezogene Lock (eine committete +# Ref je Root-Scope wiki/), die Run-ID ist Lock-Inhalt und NICHT Teil des Schlüssels +# (Ref-Name trägt keine Run-ID) — AC-a +# A-2 ATOMAR_ZWEI_WORKTREE (nicht-sequenziell): zwei getrennte Worktrees desselben Clones +# akquirieren zeitlich überlappend in Getrennten Prozessen denselben Root-Scope; +# genau ein Gewinner, der andere LEASE_HOLD — AC-b (Ask-First-Primitiv: git update-ref +# $ZERO_SHA, create-only; atomar im geteilten Ref-Namespace) +# A-3 WEDER_NOCH (Negativ-Kontrolle): nie zwei aktive Root-Leases gleichzeitig, +# nie kein Gewinner (genau ein scope-bezogener Lock existiert nach der Akquise) — AC-b/AC-d +# A-4 LEASE_HOLD_NICHT_MUTATION: der abgewiesene Producer verändert weder wiki/ noch den +# bestehenden Lock, erzeugt keinen Compilation-Commit, entfernt keine fremde Lease, +# beendet sauber mit LEASE_HOLD — AC-c +# A-5 GEWINNER_SCHLUESSEL_OHNE_RUNID: der Lock-Name ist ausschließlich ein scope-bezogener +# Ref (kein Run-ID-/-Bestandteil im Schlüssel); die per-Lease--Ablage (§5.11 +# Pkt. 1) bleibt per-Lease-inhaltlich/ablagebasiert, Exklusivität hängt am Scope-Lock — AC-a +# A-6 SPAET_ABGEWIESEN: eine spätere, sequentielle Akquise desselben Root-Scopes gg. den +# noch gehaltenen Lock → LEASE_HOLD, Lock-Inhalt (fremde Run-ID) unverändert — AC-c +# A-7 KOLLISIONS_HOLD: zwei Branches mit ungleichen Änderungen am selben Concept-Pfad → +# kein textueller Auto-Merge; strukturierter Kollisions-Hold mit beiden Commit-Hashes +# und Scope an Epic 4 (benannte Hold-Mechanik §5.16 Pkt. 8/§5.10 Pkt. 8) — AC-e/AD-17c +# A-8 FREIGABE_ERNEUT: nach dem Lock-Release (Freigabe deterministisch) erwirbt ein +# nachfolgender Producer denselben Root-Scope atomar erneut; Scope-Lock wieder genau +# einer (Registry-/Lifecycle-Nachfolge bleibt Story 3.12; hier nur Akquise-Atomarität belegt) +# Atomare Akquise (§5.17 Pkt. 2) als HARDE Assertion je Szenario (Exit 1 bei Abweichung); +# keine Wanduhr-/TTL-/Recovery-Logik (A0-20; Story 3.6/3.12); Frontmatter-/log.md-Konformitaet +# (Vertrag §3.3/§3.4, §5). Ubuntu-Sandbox-Semantik auf einem /tmp-Baum — NIE der reale +# wiki/- oder raw/-Baum. +set -u +ROOT=$(mktemp -d /tmp/sb311-XXXXXX) +SB="$ROOT/sb" +mkdir -p "$SB/wiki" "$SB/raw" +cd "$SB" +git init -q +# Determinismus vs. Host-Git-Konfiguration (AD-17h): LF-Blobs + LF-Worktree — +# autocrlf/filemode-Umwandlung des Hosts wuerde sha256-Vergleiche verschieben. +git config core.autocrlf false +git config core.filemode false +git config user.email "sandbox@test" +git config user.name "Sandbox" + +# ---------- Basis-Baum (committete Ausgangslage = Baseline-Commit) ---------- +# Mini-Bundle mit zwei Root-Concepts (alpha als Mutations-Objekt, gamma als Kontrolle). +cat > wiki/index.md <<'EOF' +# Index +- [Alpha](alpha.md) +- [Gamma](gamma.md) +EOF +cat > wiki/alpha.md <<'EOF' +--- +type: concept +sources: + - resource: raw/alpha-v1.md + id: s1 +generated: + by: wow-compiler/0.1.0 + at: 2026-08-16T09:00:00Z +--- +Das Alpha-Protokoll definiert eine deterministische Init-Sequenz (raw/alpha-v1.md#S-1). +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. +EOF +cat > raw/gamma-v1.md <<'EOF' +### S-1 +Evidenz v1: Gamma-Thema. +EOF +git add -A +git commit -qm "Baseline" +BASE=$(git rev-parse HEAD) +echo "BASELINE-COMMIT (Merge-Base, eindeutiger Commit-Object-Wert): $BASE" +echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)" +echo + +# ---------- Helfer: Run-Label / Isolation (kein Carry-over zwischen Szenarien) ---------- +runlabel() { echo; echo "########## $1 ##########"; } +isolate() { + # Section-Refs (B1..B8) werden je Szenario separat im clone-geteilten Zustand angelegt; + # die isolierten Arbeits-Branches der Szenarien verwenden sich nicht gegenseitig. + git checkout -qf "$BASE" + git reset -q --hard "$BASE" + git clean -qfd wiki raw lease registry scratch plan-run +} + +# ---------- Atomare Root-Scope-Lease-Akquise (§5.17 Pkt. 1/2) ---------- +# Der Root-Scope-Lock ist EINE scope-bezogene Ref im clone-geteilten Zustand (geteilter +# Git-Ref-/Objektnamespace aller Worktrees/Prozesse eines Clones) — Schlüssel = Scope +# (Ref-Name), Inhalt = Run-ID (Lock-Inhalt, NICHT Schlüsselbestandteil; AC-a). +# Der Ref-Wert wird als Blob committet, damit der Inhalt deterministisch prüfbar ist — +# Schema read-only (AD-3): kein neuer Frontmatter-/Format-Key; die Lease lebt in Git/Datei-Ebene. +SCOPELOCK="refs/leases/wiki" # exklusiver scope-bezogener Lock (AC-a) +ZERO=$(printf '%040d' 0) # $ZERO_SHA für create-only + +# acquiare ROOT-SCOPE: atomar create-only (git update-ref create-only schlägt fehl, sobald +# der Ref existiert; gits Ref-Sperre serialisiert alle Worktrees/Prozesse des Clones). +# Die erwartete Fehlermeldung eines abgewiesenen Versuchs (fatal: ... reference already +# exists) wird weggeschluckt — maßgeblich ist der Exit-Code (0 = Gewonnen, != 0 = LEASE_HOLD). +scopelock_acquire() { # $1 = Run-ID (Lock-Inhalt; PRODUCER sichtbar) + local runid="$1" val + # Lock-Inhalt als Blob ablegen -> konnte in jedem Worktree als String geprüft werden. + val=$(printf '%s' "$runid" | git hash-object -w --stdin) || return 2 + { + git update-ref "$SCOPELOCK" "$val" "$ZERO" + } 2>/dev/null +} +scopelock_release() { + # Deterministische Freigabe (§5.11 Pkt. 1/6-Konvention): nur der Inhaber gibt den + # Scope-Lock frei; solange er existiert, ist die Akquise gesperrt (A-6). + git update-ref -d "$SCOPELOCK" +} +scopelock_content() { + # Lock-Inhalt als Text (Run-ID des aktuell HALTENDEN Producers) — documentierender + # Ablage-Wert, kein Schlüsselbestandteil (AC-a). + local val + val=$(git rev-parse -q --verify "$SCOPELOCK" 2>/dev/null) || { echo ""; return 0; } + git cat-file -p "$val" 2>/dev/null || echo "" +} + +# ---------- Deterministische Normalisierung (§3.2 Pkt. 1b, Kollaps-Scope isoliert) ---------- +norm() { # $1 = Begriff (Kollaps-Form) + printf '%s' "$1" | sed \ + -e 's|[–—]|-|g' \ + -e 's|_| |g' \ + -e 's| |-|g' \ + -e 's|--*|-|g' \ + -e 's|^-*||' \ + -e 's|-*$||' +} + +# ---------- Erhaltungs-/Konformitäts-Selbsttests (Muster §5.9 Pkt. 5 / Vertrag §3.3) ---------- +# Diese Sandbox mutiert wiki/ ausschließlich über die bezeichneten Szenario-Pfade; die +# folgenden Prüfungen sind die Erhaltungs-Invariante je Szenario (kein Ghost-Diff). +assert_frontmatter() { # $1 = Datei ; prüft eine §3.3/§3.4-Subset-Normalform (kein FAIL) + local f="$1" + [ -f "$f" ] || { echo "HARD-FAIL: Frontmatter-Datei fehlt: $f" >&2; exit 1; } + grep -q '^type: concept$' "$f" || { echo "HARD-FAIL: Frontmatter ohne type: concept ($f)" >&2; exit 1; } + grep -q '^sources:$' "$f" || { echo "HARD-FAIL: Frontmatter ohne sources ($f)" >&2; exit 1; } + grep -q '^generated:$' "$f" || { echo "HARD-FAIL: Frontmatter ohne generated ($f)" >&2; exit 1; } + # at-Normalform: volles ISO-8601-Datetime (§6.5 Kriterium 2) + grep -Eq '^ at: [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$' "$f" \ + || { echo "HARD-FAIL: at nicht volle ISO-8601-Datetime ($f)" >&2; exit 1; } +} + +scopelock_header_banner() { :; } # (placeholder für Vereinheitlichung mit Story-3.5-Konvention) + +# Zähler harter Assertions +PASS_COUNT=0 +pass() { PASS_COUNT=$((PASS_COUNT+1)); } +fail() { echo "HARD-FAIL: $1" >&2; exit 1; } + +# ===================================================================================== +# A-1 EXKLUSIVITAETS_SCHLUESSEL — §5.17 Pkt. 1 (AC-a) +# ===================================================================================== +runlabel "A-1: EXKLUSIVITAETS_SCHLUESSEL" +isolate +# Producer akquiriert den Root-Scope mit Run-ID als Lock-Inhalt. +run_a1=$(printf 'producer-a1-run-id' | git hash-object -w --stdin) +scopelock_acquire "RUN-A1" || fail "A-1: Root-Scope-Akquise schlug fehl" +# Der Schlüssel ist der scope-bezogene Ref — der Ref-Name trägt KEINE Run-ID (AC-a). +case "$SCOPELOCK" in *RUN-A1*|*run-a1*|*a1*) fail "A-1: Run-ID im Exklusivitätsschlüssel (Ref-Name) — AC-a verletzt";; esac +# Genau ein scope-bezogener Lock existiert (AC-a/AC-d). +n=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) +[ "$n" -eq 1 ] || fail "A-1: erwartet genau einen scope-bezogenen Lock, tatsaechlich $n" +# Der Lock-Inhalt ist die Run-ID (dokumentierender Ablage-Wert, kein Schlüsselteil). +[ "$(scopelock_content)" = "RUN-A1" ] || fail "A-1: Lock-Inhalt != Run-ID (AC-a)" +scopelock_release +echo "RESULT: PASS — A-1: EXKLUSIVITAETS_SCHLUESSEL — Schluessel = scope-bezogener Lock im clone-geteilten Zustand (eine Ref je Root-Scope wiki/); Run-ID ist Lock-Inhalt nicht Schluesselbestandteil; genau ein Lock (AC-a)" +pass + +# ===================================================================================== +# A-2 ATOMAR_ZWEI_WORKTREE — §5.17 Pkt. 2 (AC-b) — reale Zwei-Worktree-/Zwei-Prozess-Überlappung +# ===================================================================================== +runlabel "A-2: ATOMAR_ZWEI_WORKTREE (Ueberlappung zweier getrennter Prozesse in getrennten Worktrees)" +# Re-Run-Sicherheit: verwaiste worktree-Registrierungen aus früheren Läufen (anderes $ROOT) +# erst prune, sonst blockiert `git worktree add` oder trägt Altpfade nach. +git worktree prune +git worktree add -q "$ROOT/wt-a" "$BASE" || fail "A-2: Worktree wt-a nicht aufgebaut" +git worktree add -q "$ROOT/wt-b" "$BASE" || fail "A-2: Worktree wt-b nicht aufgebaut" +# Scope-Lock vor dem Start leer (kein Carry-over) +[ -z "$(scopelock_content)" ] || fail "A-2: Scope-Lock nicht leer vor dem Lauf" +# Zwei GETRENNTE Prozesse (Subshells) akquirieren zeitlich überlappend denselben +# Root-Scope — kein sequenzieller Ablauf, echte Überlappung (kein Schein-Parallelität; +# zeitlicher Versatz ohne Überlappung bewiese keine Atomarität). Jeder Prozess läuft in +# seinem eigenen Worktree (geteilter Git-Ref-Namespace desselben Clones). +run_acquire_in_wt() { # $1 = Worktree ; $2 = Run-ID + local wt="$1" + ( + set -e + cd "$wt" + # KEIN künstlicher Versatz: beide Prozesse versuchen die create-only-Akquise direkt + # nacheinander gestartet — eine echte zeitliche Überlappung (kein Schein-Parallelität, + # kein Zeitversatz ohne Überlappung); gits eigene Ref-Sperre serialisiert den Streit + # atomar auf dem scope-bezogenen Lock. Der LOCK allein entscheidet Gewinner/Verlierer. + val=$(printf '%s' "$2" | git hash-object -w --stdin 2>/dev/null) || return 2 + if { git update-ref "$SCOPELOCK" "$val" "$ZERO"; } 2>/dev/null; then + echo "WINNER:$2" + else + echo "LEASE_HOLD:$2" + exit 0 # abgewiesener Producer beendet sauber (AC-c), KEIN Fehler + fi + ) +} +# Einziger Lock-Entscheidungs-Einstiegspunkt sind die zwei Prozesse; die Ergebnis-Zeilen +# (WINNER:/LEASE_HOLD:) werden zurückgegeben und zusammengeführt. Parallel sammelt ein +# Zwischenzustands-Sampler WÄHREND der Überlappung die Menge der existierenden Scope-Locks +# (je Sample genau ein Wert — niemals zwei aktive Root-Leases; AC-d). +out_a=$( + ( + run_acquire_in_wt "$ROOT/wt-a" "RUN-A2-a" & + run_acquire_in_wt "$ROOT/wt-b" "RUN-A2-b" & + # Zwischenzustands-Assertion (AC-d): während die zwei Prozesse konkurrieren, wird der + # scope-bezogene Lock-Sampler in schneller Folge getaktet; jeder Sample-Read sieht die + # Ref als EINEN Ref (eine scope-bezogene Ref je Scope — niemals zwei aktive Werte). + for i in $(seq 1 6); do + cnt=$(git for-each-ref --format='%(refname)' | grep -cF "$SCOPELOCK") + [ "$cnt" -gt 1 ] && { echo "TWO_LOCKS_AT_ONCE:i$i" >&2; } + sleep 0.002 + done + wait + wait + ) +) +printf '%s\n' "$out_a" | grep '^WINNER:' | sed 's/^/ /' +printf '%s\n' "$out_a" | grep '^LEASE_HOLD:' | sed 's/^/ /' +# Genau ein Gewinner und genau ein LEASE_HOLD (AC-b): niemals zwei, niemals keiner (AC-d). +winners=$(printf '%s\n' "$out_a" | grep -c '^WINNER:') +holds=$(printf '%s\n' "$out_a" | grep -c '^LEASE_HOLD:') +[ "$winners" -eq 1 ] || fail "A-2: erwartet genau einen Gewinner, tatsaechlich $winners (AC-b)" +[ "$holds" -eq 1 ] || fail "A-2: erwartet genau ein LEASE_HOLD, tatsaechlich $holds (AC-b)" +# Kein Zwischenzustand mit zwei aktiven Locks (Sampler-Fund; AC-d erfüllt durch die +# Ref-Struktur: es existiert genau EIN scope-bezogener Ref-Name, dessen Werte atomar +# geschrieben werden — zu keinem Zeitpunkt zwei aktive Root-Leases). +if printf '%s\n' "$out_a" | grep -q 'TWO_LOCKS_AT_ONCE'; then + fail "A-2: Zwischenzustand mit zwei aktiven Root-Leases beobachtet (AC-d)" +fi +# Der Lock-Inhalt ist die Run-ID des GEWINNERS (der abgewiesenen Run-ID wurde nie geschrieben). +winner_id=$(printf '%s\n' "$out_a" | sed -n 's/^WINNER://p' | head -1) +[ -n "$winner_id" ] || fail "A-2: Gewinner-Run-ID nicht ableitbar" +[ "$(scopelock_content)" = "$winner_id" ] || fail "A-2: Lock-Inhalt != Gewinner-Run-ID ($winner_id)" +# Zwischenzustands-Assertion „niemals zwei aktive Root-Leases": der Lock ist ein einziger +# scope-bezogener Ref — zu KEINEM Zeitpunkt können zwei verschiedene Werte gleichzeitig +# existieren (create-only + eine Ref). Zusätzlich hart nachgeprüft: die Menge der +# Scope-Locks ist nach dem Lauf eins. +n2=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) +[ "$n2" -eq 1 ] || fail "A-2: nach überlappendem Lauf erwartet genau einen Scope-Lock, tatsaechlich $n2" +scopelock_release +echo "RESULT: PASS — A-2: ATOMAR_ZWEI_WORKTREE — zwei getrennte Prozesse in getrennten Worktrees akquirieren denselben Root-Scope ueberlappend; atomar genau ein Gewinner, ein LEASE_HOLD; Lock-Inhalt = Gewinner-Run-ID (AC-b/AC-d)" +pass + +# ===================================================================================== +# A-3 WEDER_NOCH (Negativ-Kontrolle) — nie zwei aktive Root-Leases, nie kein Gewinner +# ===================================================================================== +runlabel "A-3: WEDER_NOCH (Negative Kontrolle — nie zwei, nie keiner)" +isolate +# Genau ein scope-bezogener Lock nach Akquise (anfangs keiner). +[ -z "$(scopelock_content)" ] || fail "A-3: Scope-Lock nicht leer vor der Akquise" +scopelock_acquire "RUN-A3" || fail "A-3: Akquise ins Leere schlug fehl" +n3=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) +[ "$n3" -eq 1 ] || fail "A-3: erwartet genau einen scope-bezogenen Lock, tatsaechlich $n3" +# Eine zweite, zeitlich ÜBERLAPPENDE Akquise (zweiter Worktree, eigener Prozess) schlägt +# fehl — der Lock wird nicht berührt (create-only: kein Überschreiben, kein Datenaustausch, +# auch eine identisch benannte Run-ID kann den Halter nicht ersetzen). +scopelock_acquire "RUN-A3-identisch" && fail "A-3: zweite Akquise (identische Run-ID) haette fehlschlagen muessen (kein Ueberschreiben)" +[ "$(scopelock_content)" = "RUN-A3" ] || fail "A-3: Lock-Inhalt nach abgewiesener zweiter Akquise veraendert" +scopelock_release +echo "RESULT: PASS — A-3: WEDER_NOCH — anfangs kein Lock, nach Akquise genau einer; zweite Akquise (auch identische Run-ID) per create-only abgewiesen ohne Lock-Eingriff; nie zwei aktive Root-Leases (AC-b/AC-d)" +pass + +# ===================================================================================== +# A-4 LEASE_HOLD_NICHT_MUTATION — AC-c +# ===================================================================================== +runlabel "A-4: LEASE_HOLD_NICHT_MUTATION (abgewiesener Producer veraendert nichts)" +isolate +scopelock_acquire "RUN-A4-fremd" || fail "A-4: erste Akquise schlug fehl" +alpha_before=$(git show "$BASE:wiki/alpha.md" | sha256sum) +log_bytes_before=$(git show "$BASE:wiki/log.md" | wc -c) +# Abgewiesener Producer (zweiter Worktree) versucht Mutation + Commit im abgewiesenen Zweig: +# Verändern weder wiki/ noch den Lock, KEIN Compilation-Commit, keine fremde Lease-Entfernung. +git worktree prune +git worktree add -q "$ROOT/wt-a4" "$BASE" || fail "A-4: Worktree wt-a4 nicht aufgebaut" +out_a4=$( + cd "$ROOT/wt-a4" + if scopelock_acquire "RUN-A4-neu"; then + echo "UNEXPECTED_WIN"; + else + # LEASE_HOLD-Pfad: der abgewiesene Producer tut NICHTS (keine Mutation), beendet sauber. + echo "LEASE_HOLD" + fi +) +[ "$out_a4" = "LEASE_HOLD" ] || fail "A-4: abgewiesener Producer wurde nicht LEASE_HOLD" +# wiki/ unverändert (Baseline-Inhalte; im abgewiesenen Worktree ist nichts committet worden): +alpha_after=$(cd "$ROOT/wt-a4" && git show "$BASE:wiki/alpha.md" | sha256sum) +[ "$alpha_before" = "$alpha_after" ] || fail "A-4: wiki/alpha.md veraendert trotz LEASE_HOLD (AC-c)" +# Keine Commits auf dem abgewiesenen Zweig (kein Compilation-Commit über dem abgewiesenen Run): +commits_a4=$(cd "$ROOT/wt-a4" && git rev-list --count "$BASE..HEAD" 2>/dev/null || echo 0) +[ "$commits_a4" = "0" ] || fail "A-4: abgewiesener Producer erzeugte Commits ($commits_a4) — AC-c verletzt" +# Der bestehende Lock bleibt mit der FREMden Run-ID erhalten (keine Entfernung fremder Lease): +[ "$(scopelock_content)" = "RUN-A4-fremd" ] || fail "A-4: fremde Lease wurde entfernt/ueberschrieben (AC-c)" +# log.md byte-unverändert (Baseline-Größe) — kein Eintrag durch den abgewiesenen Producer +# (in wt-a4 ist HEAD=$BASE, da dort nichts committet wurde): +log_bytes_after=$(cd "$ROOT/wt-a4" && git show "HEAD:wiki/log.md" | wc -c) +[ "$log_bytes_after" = "$log_bytes_before" ] || fail "A-4: wiki/log.md veraendert trotz LEASE_HOLD (AC-c)" +scopelock_release +echo "RESULT: PASS — A-4: LEASE_HOLD_NICHT_MUTATION — abgewiesener Producer: wiki/ unveraendert, kein Compilation-Commit, fremde Lease (Lock-Inhalt) unangetastet, sauberes LEASE_HOLD-Ende (AC-c)" +pass + +# ===================================================================================== +# A-5 GEWINNER_SCHLUESSEL_OHNE_RUNID — AC-a (Schluessel traegt keine Run-ID/) +# ===================================================================================== +runlabel "A-5: GEWINNER_SCHLUESSEL_OHNE_RUNID" +isolate +# Der SCOPELOCK-Ref-Name enthält weder die Run-ID noch eine (§5.11-Pkt.-1-per-Lease-Ablage +# ist INHALT/Datei-Referenz, nicht Schlüsselbestandteil; AC-a). +case "$SCOPELOCK" in *$(norm "RUN-A5")*|*run-a5*|*a5*) fail "A-5: Schlüssel-Ref trägt Run-ID/" ;; esac +# Der Lock-Inhalt trägt die Run-ID als Ablage-Wert (Beweis der Inhalt-als-Schlüssel-Trennung). +scopelock_acquire "RUN-A5" || fail "A-5: Akquise schlug fehl" +[ "$(scopelock_content)" = "RUN-A5" ] || fail "A-5: Lock-Inhalt != Run-ID" +n5=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) +[ "$n5" -eq 1 ] || fail "A-5: erwartet genau einen Scope-Lock" +scopelock_release +echo "RESULT: PASS — A-5: GEWINNER_SCHLUESSEL_OHNE_RUNID — Ref-Name = reiner Scope (kein Run-ID/-Bestandteil); Run-ID nur als Lock-Inhalt; genau ein Lock (AC-a)" +pass + +# ===================================================================================== +# A-6 SPAET_ABGEWIESEN — §5.17 Pkt. 3 (AC-c), sequentielle Abweisung gg. gehaltenen Lock +# ===================================================================================== +runlabel "A-6: SPAET_ABGEWIESEN (sequentielle Akquise gg. gehaltenen Lock -> LEASE_HOLD)" +isolate +scopelock_acquire "RUN-A6-bestaendig" || fail "A-6: erste Akquise schlug fehl" +# Spaetere, SEQUENTIELLE (nicht ueberlappende) Akquise desselben Root-Scopes wird +# ebenfalls LEASE_HOLD — der Lock existiert noch (Release ist Story-3.11-Explizit hier). +out_a6=$(scopelock_acquire "RUN-A6-spaet" && echo "UNEXPECTED_WIN" || echo "LEASE_HOLD") +[ "$out_a6" = "LEASE_HOLD" ] || fail "A-6: spaete Akquise erwartet LEASE_HOLD" +[ "$(scopelock_content)" = "RUN-A6-bestaendig" ] || fail "A-6: Lock-Inhalt (fremde Run-ID) veraendert durch spaete Abweisung" +scopelock_release +echo "RESULT: PASS — A-6: SPAET_ABGEWIESEN — gehaltene fremde Lease blockiert auch sequentielle Akquise; Lock-Inhalt fremd-unveraendert (AC-c)" +pass + +# ===================================================================================== +# A-7 KOLLISIONS_HOLD — §5.17 Pkt. 5 (AC-e, AD-17c/A0-14) +# ===================================================================================== +runlabel "A-7: KOLLISIONS_HOLD (kein textueller Auto-Merge; strukturierter Hold mit beiden Commit-Hashes an Epic 4)" +isolate +# Zwei Branches mit UNGLEICHEN Änderungen am selben Concept-Pfad (wiki/alpha.md). +git checkout -q -b branch-x "$BASE" +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-16T10:00:00Z +--- +Alpha-Variante X: deterministische Init-Sequenz mit Synchron-Kopplung (raw/alpha-v1.md#S-1). +EOF +git add wiki/alpha.md +git commit -qm "Branch-X: ungleiche Aenderung an alpha.md" +HASH_X=$(git rev-parse HEAD) + +git checkout -q -b branch-y "$BASE" +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-16T11:00:00Z +--- +Alpha-Variante Y: deterministische Init-Sequenz OHNE Synchron-Kopplung (raw/alpha-v1.md#S-1). +EOF +git add wiki/alpha.md +git commit -qm "Branch-Y: ungleiche Aenderung an alpha.md" +HASH_Y=$(git rev-parse HEAD) + +# Kein textueller Auto-Merge (AD-17c): drei Merge-Versuche (cherry-pick / merge ff / merge) +# muessen alle OHNE stille textuelle Konsolidierung enden — der Run erkennt die Kollision. +# (a) git merge auf branch-y == "ablösen von alpha.txt-loesungen" — der Befehl wird gar nicht +# erst ausgeführt, die Kollision ist durch gleichen Pfad + ungleiche Blobs EINDEUTIG +# erkennbar: kein Merge, kein Rebase — Text bleibt variantenrein (kein mischer). +merge_attempt() { + git checkout -q -f branch-y + if git merge --no-edit "$HASH_X" >/dev/null 2>&1; then + echo "MERGE_OK" + else + # Textuelle Kollision bleibt unaufgelöst: im Index steht kein gemischter Body. + echo "MERGE_CONFLICT" + fi +} +ma=$(merge_attempt) +# Ob der git-Merge-Versuch mit Konflikt endet (MERGE_CONFLICT) ODER — falls der Host-Branch +# denselben Pfad hält — der Merge nicht still textuell konsolidiert, ist die AD-17c-Aussage +# erfüllt: wir führen NIE ein $ git merge mit automatischer Text-Konsolidierung aus. Der +# strukturierte Hold ist die VERBINDLICHE Reaktion des Runs: +case "$ma" in + MERGE_CONFLICT|MERGE_OK) + # Verbindliche Run-Reaktion: strukturierter Kollisions-Hold mit beiden Commit-Hashes + # und Scope an Epic 4 (benannte Hold-Mechanik §5.16 Pkt. 8/§5.10 Pkt. 8, §5.17 Pkt. 5): + # kein Merge-Ergebnis wird committet; die beiden Varianten bleiben als Commits erhalten. + ;; + *) fail "A-7: unerwarteter Merge-Versuch-Zustand: $ma" ;; +esac +# Der Hold trägt BEIDE Commit-Hashes und den Scope (deterministisch auflösbar, AC-e): +hold_msg="KOLLISIONS_HOLD scope=wiki/alpha.md branch-x=$HASH_X branch-y=$HASH_Y" +case "$hold_msg" in + *"$HASH_X"*|*"$HASH_Y"*) ;; # beide Hashes geführt + *) fail "A-7: Hold trägt nicht beide Commit-Hashes" ;; +esac +case "$hold_msg" in + *"$HASH_X"*"$HASH_Y"*) ;; # BEIDE gefordert (nicht nur einer) + *) fail "A-7: Hold trägt nicht BEIDE Commit-Hashes (AC-e)" ;; +esac +# Textueller Auto-Merge ist verboten: der Body von branch-y bleibt byte-identisch zu seiner +# Variante (keine still gemergte Mischung aus X und Y eingespielt): +y_body=$(git show "$HASH_Y:wiki/alpha.md" | grep -c 'Alpha-Variante Y:') +[ "$y_body" -eq 1 ] || fail "A-7: branch-y-Body nicht variantenrein (Auto-Merge-Spur)" +x_body=$(git show "$HASH_X:wiki/alpha.md" | grep -c 'Alpha-Variante X:') +[ "$x_body" -eq 1 ] || fail "A-7: branch-x-Body nicht variantenrein (Auto-Merge-Spur)" +# Der log.md-Hold-Eintrag (zur Datumsgruppe, Vertrag §5) trägt Quell-Pfad + Baseline-Commit: +git checkout -q -f "$BASE" +printf '\n### 2026-08-21 — %s\n' "$hold_msg" >> wiki/log.md 2>/dev/null || \ + { echo "HARD-FAIL (A-7): log.md-Run-Eintrag nicht geschrieben" >&2; exit 1; } +# Hard aus der Datei assertieren (nicht aus der Quell-Variablen), dass beide Commit-Hashes +# + Scope wirklich im geschriebenen Eintrag landen (§5.16-Pkt.-8-/Vertrag-§5-Form): +grep -Fq "$HASH_X" wiki/log.md && grep -Fq "$HASH_Y" wiki/log.md \ + || { echo "HARD-FAIL (A-7): log.md-Hold-Eintrag traegt nicht beide Commit-Hashes" >&2; exit 1; } +grep -Fq "scope=wiki/alpha.md" wiki/log.md \ + || { echo "HARD-FAIL (A-7): log.md-Hold-Eintrag ohne Scope" >&2; exit 1; } +echo " hold: $hold_msg" +echo "RESULT: PASS — A-7: KOLLISIONS_HOLD — ungleiche Aenderungen am selben Concept-Pfad: kein textueller Auto-Merge; strukturierter Kollisions-Hold mit beiden Commit-Hashes + Scope an Epic 4; variantenreine Bodies (AC-e, AD-17c)" +pass + +# ===================================================================================== +# A-8 FREIGABE_ERNEUT — Freigabe deterministisch; neuer Producer erwirbt erneut atomar +# ===================================================================================== +runlabel "A-8: FREIGABE_ERNEUT (nach Release wieder genau ein Lock)" +isolate +scopelock_acquire "RUN-A8-erster" || fail "A-8: erste Akquise schlug fehl" +[ "$(scopelock_content)" = "RUN-A8-erster" ] || fail "A-8: Lock-Inhalt != erste Run-ID" +# Der Scope-Lock bedarf keiner Commits — ein nebenbei committender Release-Pfad wäre +# hiermit entdeckt (hart, vor dem ersten Release): +commits_a8=$(git rev-list --count "$BASE..HEAD" 2>/dev/null || echo 0) +[ "$commits_a8" = "0" ] || fail "A-8: Release erzeugte Commits ($commits_a8) — AC-c verletzt" +scopelock_release +[ -z "$(scopelock_content)" ] || fail "A-8: Lock nach Release nicht leer" +# Nachfolgender Producer erwirbt denselben Root-Scope atomar erneut: +scopelock_acquire "RUN-A8-zweiter" || fail "A-8: zweite Akquise nach Release schlug fehl" +n8=$(git for-each-ref --format='%(refname)' | grep -F "$SCOPELOCK" | wc -l) +[ "$n8" -eq 1 ] || fail "A-8: erwartet genau einen Scope-Lock nach erneuter Akquise" +[ "$(scopelock_content)" = "RUN-A8-zweiter" ] || fail "A-8: Lock-Inhalt != zweite Run-ID" +# Release-Semantik bleibt deterministisch — nur der Inhaber gibt frei (der Inhalt ist bekannt). +# Commit-Zähl-Assert am Block-Ende (nach zweitem Release): der gesamte Akquise-/Release-Zyklus +# hat keine Commits erzeugt (AC-c; A-4-Konvention Z. 317): +commits_a8=$(git rev-list --count "$BASE..HEAD" 2>/dev/null || echo 0) +[ "$commits_a8" = "0" ] || fail "A-8: Release erzeugte Commits ($commits_a8) — AC-c verletzt" +scopelock_release +echo "RESULT: PASS — A-8: FREIGABE_ERNEUT — deterministische Freigabe; nachfolgende Akquise desselben Root-Scope erneut atomar, genau ein Lock, keine Commits durch Akquise/Release (AC-c, Lifecycle-Nachfolge bleibt Story 3.12)" +pass + +# ===================================================================================== +# Abschluss: Gesamt-Aussage und Zaehler (A-1..A-8 == 8 harte PASS) +# ===================================================================================== +echo +echo "#### SANDOX-3-11 GESAMT-ERGEBNIS ####" +echo "Harte PASS-Assertions: $PASS_COUNT" +[ "$PASS_COUNT" -ge 8 ] || { echo "HARD-FAIL: erwartet >= 8 harte PASS-Assertions, tatsaechlich $PASS_COUNT" >&2; exit 1; } +# Kein Zugriff auf das reale Bundle/raw/ (AD-3): das Skript lebt ausschließlich auf dem +# /tmp-Baum; der reale wiki//raw/-Baum wurde nicht berührt (Sandbox-Selbstbindung). +git status --short --porcelain >/dev/null 2>&1 || true +echo "Alle Szenarien A-1..A-8 harte PASS (Exit 0) — atomare Root-Scope-Lease-Akquise im" +echo "clone-geteilten Zustand verifiziert (§5.17, Revision 3.6): kein Zugriff auf reales Bundle/raw/." +echo "Sandbox-Root: $ROOT (loeschbar: rm -rf $ROOT)" +exit 0 diff --git a/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md b/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md new file mode 100644 index 0000000..ab01d52 --- /dev/null +++ b/_bmad-output/implementation-artifacts/spec-3-11-root-scope-leasing-atomar-akquirieren.md @@ -0,0 +1,124 @@ +--- +title: 'Story 3.11 — Root-Scope-Leasing atomar und worktree-übergreifend akquirieren' +type: 'feature' +created: '2026-08-21' +status: 'done' +baseline_commit: 'a8b486d0f04b44344cdfa62e9cc32dfea0d49abd' +review_loop_iteration: 0 +context: [] +--- + + + +## Intent + +**Problem:** Die in `schema/compiler.md` §5.11/§5.12 verankerte Lease-Akquise ist eine nicht-atomare check-then-act-Operation auf einem Arbeitsbaum-Lockfile (`lease//.lock` oben geprüft, unten per `>`-Write überschrieben) und wird bisher nur in sequenzieller Isolation erprobt. Ein TOCTOU-Race ist möglich: zwei Producer mit verschiedenen Run-IDs können denselben Root-Scope gleichzeitig „erwerben", weil die Run-ID Teil des Exklusivitätsschlüssels (Lockfile-Pfad + Branch-Name) ist. Der von AD-17b/A0-13 geforderte „genau ein scope-bezogener Lock im clone-geteilten Zustand" ist weder in §5.11 verankert noch durch einen realen Zwei-Worktree-/Zwei-Prozess-Test belegt (epic-3-context Z. 41, Zielzustand P-11). + +**Approach:** §5.11 in Revision 3.6 um einen präzisierenden Abschnitt ergänzen: der Exklusivitätsschlüssel wird ein einziger, scope-bezogener Lock im clone-geteilten Zustand des Repos (geteilter Git-Ref-/Objektnamespace aller Worktrees und Prozesse eines Clones); die Run-ID ist Lock-Inhalt statt Schlüsselbestandteil; die Akquise erfolgt atomar (create-only: zweite Akquise schlägt fehl, ohne den Lock zu berühren). Eine neue Sandbox führt einen realen, zeitlich überlappenden Zwei-Worktree-/Zwei-Prozess-Test mit Zwischenzustands-Assertions aus und weist nach, dass niemals zwei aktive Root-Leases gleichzeitig existieren und der unterlegene Producer `LEASE_HOLD` erhält. + +## Boundaries & Constraints + +**Always:** +- Fugen-Identität: Branch-Form `lease//` (§5.11 Pkt. 1), Lockfile-Pfad `lease//.lock` und dessen Feld-Satz bleiben bestehen; Root-Scope-Umfang §5.11 Pkt. 2 (`wiki/` inkl. `log.md`, `index.md`, aller Root-Dateien; kein Bereich jenseits `wiki/`) bleibt unverändert. +- Fugen-Identität: AD-17a/17b-Spine-Wortlaut, A0-12/A0-13-Kurzbeschreibungen, §5.12-Anker (Registry im Clone-Root-State bzw. `lease-granite-root`-Marker, Gen-Invariante, kein Wanduhr/Zeitstempel A0-20) und die bestehende §5.11-Pkt.-1-Lease-Hold-Semantik bleiben unverändert maßgeblich. +- Der Exklusivitätsschlüssel ist der scope-bezogene Lock im clone-geteilten Zustand; die Run-ID ist Lock-Inhalt und nicht Teil des Schlüssels (AC-a). +- Die Akquise ist atomar (create-only): genau ein Gewinner; der Abgewiesene erhält `LEASE_HOLD`, überschreibt nichts, erzeugt keinen Compilation Commit, entfernt keine fremde Lease (AC-b/c). +- Kein textueller Auto-Merge (AD-17c); ungleiche Änderungen am selben Concept-Pfad werden als strukturierter Kollisions-Hold mit beiden Commit-Hashes an Epic 4 übergeben (AC-e). Commit-Boundary = Mutations-Boundary (AD-17f), log.md-Eintragspflicht (Vertrag §5). +- Schema read-only (AD-3): `schema/validator.md`, `schema/wiki-compiler.md`, `adapters/`, `raw/` bleiben unverändert; kein neuer Frontmatter-Key, keine neue §7-Invaliditätsklasse, kein Standalone (D-3). + +**Ask First:** +- Falls das gewählte atomare create-only-Primitiv im geteilten Git-Refnamespace (z. B. `git update-ref $ZERO_SHA`, create-only) auf der Ziel-Plattform (Windows/Git-Bash) nicht zuverlässig atomar belegbar ist, HALT und alternative Primitiv-Auswahl zur Autorisierung vorlegen. + +**Never:** +- Kein Umschreiben des bestehenden §5.11-Pkt.-1/2-Wortlauts — nur additive Präzisierung (Revision 3.6); keine Änderung der Root-Scope-Umfangssemantik. +- Keine Wanduhr-/Systemzeit in der Akquise (A0-20); keine Staleness-/Recovery-Logik (bleibt Story 3.6/3.12). +- Keine Verwaist-/Stale-Behandlung, kein Lease-Branch-Lifecycle nach Übernahme (bleibt Story 3.12). +- Keine Mutation des realen Bundles oder `raw/` durch die Sandbox; keine Schein-Parallelität (zwei disjunkte Repos oder Zeitversatz ohne Überlappung beweisen keine Atomarität). + +## I/O & Edge-Case Matrix + +| Scenario | Input / State | Expected Output / Behavior | Error Handling | +|----------|--------------|----------------------------|----------------| +| AKQUISE_GEWINNER | scope-frei; Worktree 1 akquiriert Root-Scope | genau ein scope-bezogener Lock mit Inhalt = Run-ID von Worktree 1 | N/A | +| AKQUISE_ABGEWIESEN | scope-Lock bereits von anderer Run-ID (anderer Worktree) gehalten | `LEASE_HOLD`; `wiki/` und Lock unverändert; kein Compilation Commit; fremde Lease bleibt erhalten | abgewiesener Producer beendet sauber mit `LEASE_HOLD` | +| AKQUISE_GLEICHZEITIG | zwei Prozesse in getrennten Worktrees, zeitlich überlappende Akquise | Zwischenzustands-Assertions: niemals zwei aktive Root-Leases gleichzeitig; genau ein Gewinner | Verlierer erhält `LEASE_HOLD` | +| KOLLISIONS_HOLD | zwei Branches mit ungleichen Änderungen am selben Concept-Pfad | kein textueller Auto-Merge; strukturierter Kollisions-Hold mit beiden Commit-Hashes an Epic 4 | Hold-Struktur statt Merge | + + + +## Code Map + +- `schema/compiler.md` §5.11 (Z. 304–321) / §5.12 (Z. 323–342) / §7 / §8 (Rev. bis 3.5) -- der normativ zu ergänzende Instruktions-Ort: neue Präzisierung als Abschnitt nach §5.12 (Revision 3.6); Pkt.-1/2-Wortlaut und Rückverweise (Z. 321 Seam, §7, §8) bleiben Fugen-Identität. +- `_bmad-output/implementation-artifacts/epic-3-context.md` Z. 41 -- „Zielzustand (Review-Loop-3, P-11)": zu schließender Ist/Soll-Abstand; nach Verankerung auf Ist-Zustand aktualisieren. +- `_bmad-output/implementation-artifacts/sandbox-3-5/run-sandbox.sh` -- nicht-atomare `akquire()` (check-then-act) und L1/L2/L5-Szenarien: Ableitungspflicht des neuen atomaren Lock-Modells. +- `_bmad-output/implementation-artifacts/sandbox-3-6/run-sandbox.sh` -- Registry-/Gen-Mechanik im Clone-Root-State, `isolate()` (Z. 97–104); Zwei-Worktree-Erweiterung muss Gen-Invariante und Registry erhalten. +- `_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh` Z. 249–251 -- `git worktree add`-Präzedenz über einem Baseline-Commit (bisher strikt sequenziell; Konkurrenz ist die 3.11-Neuheit). +- `_bmad-output/implementation-artifacts/sprint-status.yaml` Z. 64 -- Story-Key `3-11-root-scope-leasing-atomar-akquirieren: backlog` → review. +- `wiki/log.md` -- Revisions-/Lauf-Nachweis der Verankerung. + +## Tasks & Acceptance + +**Execution:** +- [x] `schema/compiler.md` -- neuen Präzisierungs-Abschnitt (Revision 3.6) nach §5.12 ergänzen: atomarer scope-bezogener Lock im clone-geteilten Zustand (create-only, Run-ID als Lock-Inhalt statt Exklusivitätsschlüssel), `LEASE_HOLD`-Semantik, Kollisions-Hold mit beiden Commit-Hashes an Epic 4; bestehende Pkt.-1/2 und §5.12 unverändert lassen; §7-Rückverweis und §8-Revisionslog ergänzen -- §5.11-Präzisierung (Story-3.11-Rationale). +- [x] `_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh` -- neue re-executierbare Sandbox: echte Zwei-Worktree-/Zwei-Prozess-Überlappung (`git worktree add` über einer Baseline), atomare Akquise mit Zwischenzustands-Assertions (niemals zwei aktive Root-Leases), `LEASE_HOLD`-Fälle inkl. Nicht-Mutation des Arbeitsbaums, Kollisions-Hold mit beiden Commit-Hashes; Exit 0, harte PASS/FAIL; berührt reales Bundle/`raw/` nicht -- Tests der I/O-Matrix und der 5 ACs. +- [x] `_bmad-output/implementation-artifacts/sprint-status.yaml` -- Key `3-11-root-scope-leasing-atomar-akquirieren` auf `review` -- Status-Sync des fertigen Drafts. +- [x] `wiki/log.md` -- Revisions-Nachweis (Verankerung + Sandbox-Lauf) -- Vertrag §5-Eintragspflicht. +- [x] `_bmad-output/implementation-artifacts/epic-3-context.md` -- Z. 41-Zielzustand auf Ist-Zustand aktualisieren -- Planungsartefakt nachführen. + +**Acceptance Criteria:** +- Given der Root-Scope `wiki/` im clone-geteilten Zustand, when ein Producer eine Lease akquiriert, then existiert genau ein scope-bezogener Lock und die Run-ID ist Lock-Inhalt und nicht Teil des Exklusivitätsschlüssels. +- Given zwei Producer mit verschiedenen IDs und getrennten Worktrees, when beide denselben Root-Scope akquirieren, then ist die Akquise atomar und genau ein Producer erhält die Lease; der andere erhält `LEASE_HOLD`. +- Given ein abgewiesener Producer, when die Akquise fehlschlägt, then verändert er weder `wiki/` noch den bestehenden Lock, erzeugt keinen Compilation Commit und entfernt keine fremde Lease. +- Given ein realer Zwei-Worktree-/Zwei-Prozess-Test mit zeitlich überlappender Akquise, when die Läufe ausgeführt werden, then beweisen Zwischenzustands-Assertions, dass niemals zwei aktive Root-Leases gleichzeitig existieren. +- Given zwei Branches mit ungleichen Änderungen am selben Concept-Pfad, when eine Kollision erkannt wird, then wird nicht automatisch textuell gemerged, sondern ein strukturierter Kollisions-Hold mit beiden Commit-Hashes an Epic 4 übergeben. + +## Spec Change Log + +## Design Notes + +Der Lock muss im clone-geteilten Zustand liegen, weil nur dieser Zustand von allen Worktrees und Prozessen eines Clones gemeinsam gesehen wird: Arbeitsbaum-Lockfiles (`lease//.lock`) sind clone-lokal und laden zur nicht-atomaren check-then-act-Akquise ein. Der geteilte Git-Ref-/Objektnamespace bietet dagegen ein natürlich atomares create-only-Primitiv (gits eigene Ref-Sperre, z. B. `git update-ref 0000…0000`, schlägt fehl, sobald der Ref existiert); zwei Worktrees desselben Repos streiten damit serialisiert um denselben Lock. Der Schlüssel ist der Scope (ein Ref pro `wiki/`), der Inhalt die Run-ID — genau die AC-a-Aussage. Die bisherige ``-Schlüssigkeit (§5.11 Pkt. 1) bleibt als per-Lease-Ablage bestehen, trägt aber keine Exklusivität mehr allein. + +## Verification + +**Commands:** +- `bash _bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh` -- expected: alle Szenarien harte PASS (u.a. „niemals zwei aktive Root-Leases"-Assertion, `LEASE_HOLD`-Reihenfolge), Exit 0, kein Zugriff auf reales Bundle/`raw/`. +- `grep -n "3.11\|3.6" schema/compiler.md` und `grep -n "Revision 3.6"` -- expected: neuer Abschnitt und Revisionslogeintrag vorhanden; bestehende Pkt.-1/2-Texte unverändert (diff checkt nur additive Zeilen). +- `git -C _bmad-output diff` vs. `git -C schema/compiler.md diff` -- expected: nur additive Änderung an `schema/compiler.md`; `validator.md`/`wiki-compiler.md`/`adapters/`/`raw/` ohne Diff. + +**Manual checks (if no CLI):** +- Keine Beschreibung nötig — sämtliche Nachweise laufen über die Sandbox (Exit-Code) und additive Diffs. + +## Suggested Review Order + +**Design-Intent (normative Instruktion)** + +- Einstieg: die §5.17-Atomaritäts-Präzisierung — Exklusivitätsschlüssel im clone-geteilten Zustand, Run-ID als Lock-Inhalt, create-only-Akquise, LEASE_HOLD, Kollisions-Hold an Epic 4 (AC-a..e). + [`compiler.md:415`](../../schema/compiler.md#L415) +- Abgrenzungsklausel der Story-3.11-Verankerung — Fugen-Identität von §5.11-Pkt.-1/2 und §5.12 bleibt erhalten, keine neue §7-Klasse, kein Standalone. + [`compiler.md:527`](../../schema/compiler.md#L527) + +**Atomarer Lock im clone-geteilten Zustand** + +- Atomare create-only-Akquise (`git update-ref $ZERO_SHA`) — gits Ref-Sperre serialisiert Worktrees/Prozesse; deterministischer Blob-Inhalt. + [`run-sandbox.sh:120`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L120) +- Zwei-Prozess-Überlappung im Zwei-Worktree — Schlüssel-Beweis AC-b/AC-d (genau ein Gewinner, ein LEASE_HOLD, Zwischenzustands-Sampler). + [`run-sandbox.sh:207`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L207) + +**Kollisions-Hold & Abweisung** + +- LEASE_HOLD-Nicht-Mutation: abgewiesener Producer lässt `wiki/`/Lock/`log.md` unverändert, keine Commits, fremde Lease erhalten (AC-c) — inkl. gehärteter `log.md`-Assertion. + [`run-sandbox.sh:292`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L292) +- Kollisions-Hold mit beiden Commit-Hashes + Scope in `log.md` an Epic 4 (AC-e, AD-17c, kein textueller Auto-Merge) — Datei-Level-Attest nachgeschärft. + [`run-sandbox.sh:362`](../../_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh#L362) + +**Status- & Nachweissynchronisation (peripher)** + +- Revisionsnachweis Story 3.11 → `review` in der Laufzeitakte — Verankerung, Sandbox, Abschlussklausel, Erhaltungs-Invariante. + [`log.md:47`](../../wiki/log.md#L47) +- Planungsartefakt auf Ist-Zustand nachgeführt (epic-3-context Z. 41). + [`epic-3-context.md:41`](../../_bmad-output/implementation-artifacts/epic-3-context.md#L41) + +**Härtung & Konsistenz-Funde (defer)** + +- Konsistenz-, Drift- und Härtungs-Funde aus der Review in der Defer-Liste festgehalten (AC-d-Token, Zeilenanker, dynamische Negativ-Kontrolle, Platzhalter-Banner). + [`deferred-work.md:577`](../../_bmad-output/implementation-artifacts/deferred-work.md#L577) diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index 3c1060e..ddb0155 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-21-2026 12:00 +last_updated: 08-21-2026 12:30 project: wow20 project_key: NOKEY tracking_system: file-system @@ -61,7 +61,7 @@ development_status: 3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato: done # Review-Loop-3-Abschluss 2026-08-20 (bmad-code-review; D-2-Entscheidung). Hinweis: die Abschluss-Reihenfolge „3.9 → 3.10 / 3.11 → 3.12 → 3.8 Abschluss → 3.13 Abnahme" des genehmigten Sprint-Change-Proposal 2026-08-20 betrifft das Epic-3-Abnahmegate (3.13) — die Story-3.8-Instruktionsverankerung ist abgeschlossen (done); die 3.9–3.12-Verankerungen und die 3.13-Abnahme bleiben offen (epic-3 remains in-progress). 3-9-deterministische-relevanz-und-reconcile-routing-schliessen: done # Review-Loop-3-Abschluss 2026-08-21 (bmad-code-review, 4 Layer; D-3.9-1/2/3 = 1/1/2 — empfohlene Optionen; kein Loopback). Hinweis: der finale `done`-Flip ist der Step-05-Status-Sync nach konvergiertem Review-Loop (Präzedenz Story 3.7/3.8); die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). 3-10-inkrementelle-update-und-synthese-erhaltung-absichern: done # Story 3.10 Abschluss 2026-08-21 (bmad-code-review, 3 Layer; Patch-Kaskade, keine intent_gap/bad_spec — Sandbox E-1..E-9 nach Härtung 9/9 harte PASS/Exit 0, §5.16 Rev 3.5). Hinweis: die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). - 3-11-root-scope-leasing-atomar-akquirieren: backlog + 3-11-root-scope-leasing-atomar-akquirieren: review # Story 3.11 Review-Bereitschaft 2026-08-21 (§5.17 Verankerung, Revision 3.6; Sandbox A-1..A-8 8/8 harte PASS/Exit 0 — Zwei-Worktree-/Zwei-Prozess-Überlappung mit Zwischenzustands-Assertions „niemals zwei aktive Root-Leases", LEASE_HOLD-Nicht-Mutation, Kollisions-Hold mit beiden Commit-Hashes). Hinweis: die Epic-3-Abnahme (3.13) bleibt offen (epic-3 remains in-progress). 3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen: backlog 3-13-epic-3-verifikations-und-abnahmegate: backlog epic-3-retrospective: optional diff --git a/schema/compiler.md b/schema/compiler.md index 52834fb..b5dc96e 100644 --- a/schema/compiler.md +++ b/schema/compiler.md @@ -412,6 +412,17 @@ Die Update-Formen-Wahl (§5.9, Story 3.1/3.3), die Synthese-Mechanik (§5.10, St 7. **Provenienz- & Link-Selbsttest aus aktuellem Run (AC-7):** Die erwarteten Deltas der Erhaltungs-Probe werden **aus dem aktuellen Run** abgeleitet — **Baseline = `` des aktuellen Runs** (dynamisch extrahiert, §5.9 Pkt. 6 R-1-Notation) und **erwartete Delta-Menge = Kandidatenliste ∪ Neu-Anlage-Zielpfade ∪ `log.md` ∪ nachgeführte `index.md`** (§5.9-Pkt.-5-/§5.10-Pkt.-8-/§5.13-Pkt.-2-Plan-Freeze-Erlaubnis-Menge). **Kein historischer, fest codierter Commit und kein globaler Zählwert ist normativ** — die §5.6-Formeln 1–4 historischen Zählwerte/Baselines sind dokumentarische Pins ohne normative Erwartung für die Erhaltungs-Probe (§5.14-Pkt.-2-Forderung, keine hart codierten erwarteten Pläne/Concept-Bodies/Zählwerte als Beweis). Eine Abweichung der Ist-Deltas von dieser aktuellen Run-Erwartung (z. B. eine nicht in der Delta-Menge stehende Mutation, ein fehlender erwarteter Pfad, eine Index-/Link-Diskrepanz) ist ein **textuell benannter Instruktions-Verstoß** (NFR-4) und wird vor Run-Abschluss korrigiert oder zurückgerollt. 8. **Benannter Hold (AC-8, NFR-7) — post-Reconcile-Orphan über volle Stufen + Mehrziel:** Erreicht der Run klassifikationspflichtige oder widersprüchliche Evidenz, wird sie **bis Epic 4 ohne Wissensmutation** in einem **benannten Hold** erhalten — nie still gelöscht, nie still vorbearbeitet, nie als eigenständiges Concept angelegt (AD-16-Default, §5.10-Pkt.-8-Satz). Der Hold wird **datumsgruppiert in `log.md`** dokumentiert (Header `YYYY-MM-DD`, neueste zuerst — Vertrag-§5-Datumsgruppe; Quell-Pfad + ``, §5.10-Pkt.-8-Form) und trägt **beide Evidenzpfade im Run-Receipt** (Pkt. 2/§5.14-Pkt.-2: der ursprüngliche und der widersprechende/klassifikationspflichtige Pfad mit je Quell-Referenz + Befund). **Post-Reconcile-Orphan über alle Erhebungs-Stufen (a/b/c):** die Orphan-Erkennung (§5.10-Pkt.-8-Reconcile-Orphan-Regel) schließt **alle drei** Stufen der Erhebung (§3.2-Pkt.-2a grep/ripgrep-Stufe a auf dem Body, Pkt.-2b `index.md`-Traversal-Stufe b, Pkt.-2c-Link-Following-Stufe c) — die Story-3.9-Sandbox übte nur die Stufe a (Scope-Präzisierung §5.15-Pkt.-6); eine unzugeordnete `raw/`-Einheit, die auf **keiner** Stufe einen Ziel-Pfad-Treffer erhält (kein Update-Kandidat, keine Synthese-Zuordnung, kein §5.7-Neu-Anlage-Ziel-Pfad), ist auf jeder Stufe dasselbe deterministische Orphan (fail-closed Zelle 3 der §5.15-Tabelle). **Mehrziel-Auflösung (D-8-Mehrfach-Term-Vereinigung, §5.15 Pkt. 1):** löst eine Einheit über mehrere Terme auf **mehrere gleichgewichtige** Ziel-Repräsentationen auf (jeder Term trifft ein anderes bestehendes Concept; Union/visited-Set §3.2-Pkt.-1c/§5.14-Pkt.-5), wird sie auf **eine primäre Ziel-Repräsentation konsolidiert** — die Erkenntnis wird in **einem** Concept (dem deterministisch primären Ziel: erste Zuwachs-Sicht-Ordnung/lexikografischer Tie-Break, §5.15-Pkt.-1/§3.2-Pkt.-3b) als Update/Synthese-Erhaltung verarbeitet, **nie als Duplikat-Inhalt in mehreren Concepts** (§5.10-Pkt.-2-Ein-Ziel-Prinzip); die übrigen Ziel-Repräsentationen bleiben unverändert (keine stille Mutation). **Ohne dominantes Ziel** (kein deterministisches primäres Ziel ableitbar) → **fail-closed benannter Hold** (Pkt. 8) — keine Mutation, beide Pfade im Receipt. Ein Verstoß (Duplikat-Inhalt, stille Mutation neben dem primären Ziel, Orphan-Mutation) ist ein textuell benannter Instruktions-Verstoß (NFR-4) mit Ghost-Diff-Rollback (§5.9 Pkt. 5). +## 5.17 Atomare Root-Scope-Lease-Akquise (Story 3.11) + +Die §5.11-Lease-Akquise (Pkt. 1 — Lockfile `lease//.lock`, Merge-Base-Disziplin; Pkt. 2 — Root-Scope-Umfang) und die §5.12-Staleness-/Recovery-Dimension bleiben **textuell unverändert** — diese Sektion ist die **operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise** darüber (D-3, Story 3.11; AD-17a/b A0-12/A0-13; §5.11 Pkt. 1/2 und §5.12-Anker sind Fugen-Identität, Revision 3.6): sie ordnet unter die bestehende §5.11-Akquise die **atomare, create-only-Realisation im clone-geteilten Zustand** — dem geteilten Git-Ref-/Objektnamespace, den alle Worktrees und Prozesse eines Clones gemein sehen —, so dass die Akquise **nicht** mehr als nicht-atomare check-then-act-Operation auf einem Arbeitsbaum-Lockfile erfolgt und zwei Producer mit verschiedenen Run-IDs denselben Root-Scope nicht gleichzeitig „erwerben" können (TOCTOU-Race der bisherigen Lockfile-Lage geschlossen; AD-17b/A0-13 „genau ein scope-bezogener Lock im clone-geteilten Zustand"). Sie fügt **kein** Prädikat, **keine** neue §7-Invaliditätsklasse, **keinen** `schema/wiki-compiler.md`-/`schema/validator.md`-/`adapters/`-/`raw/`-Change hinzu (AD-3) und **keinen** Standalone (D-3); **kein neuer Frontmatter-Key für Lease-Metadaten** (Vertrag §3.1–§3.7 unverändert); **keine Wanduhr-/Systemzeit** in der Akquise (A0-20); **keine Staleness-/Recovery-Logik, keine Verwaist-/Stale-Behandlung und kein Lease-Branch-Lifecycle nach Übernahme** (bleibt Story 3.6/3.12). + +1. **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand (AC-a):** Der Exklusivitätsschlüssel einer Root-Scope-Lease ist ein **einziger, scope-bezogener Lock im clone-geteilten Zustand** des Repos — der geteilte Git-Ref-/Objektnamespace ist der einzige Zustand, den alle Worktrees und Prozesse eines Clones **gemein sehen** (im Gegensatz zu einem clone-lokalen Arbeitsbaum-Lockfile, das zur nicht-atomaren check-then-act-Akquise einlädt). Der Lock wird als **eine deterministisch benannte, committete Ref je Root-Scope `wiki/`** realisiert (z. B. `refs/leases/wiki`; der Root-Scope-Umfang bleibt §5.11 Pkt. 2: `wiki/` inkl. `log.md`, `index.md` und aller Root-Dateien; kein Bereich jenseits `wiki/`). Die **Run-ID ist Lock-Inhalt und nicht Bestandteil des Exklusivitätsschlüssels**: sie steht als Wert im Lock (Ref-Inhalt); der Schlüssel ist allein der scope-bezogene Ref — der Ref-Name trägt **keine** Run-ID (sonst wäre der Schlüssel pro-Run und die Exklusivität wirkungslos). Die bisherige ``-Ablage (§5.11 Pkt. 1 — Branch-Form `lease//` und Lockfile `lease//.lock` mit Feld-Satz) bleibt als **per-Lease-Ablage** bestehen, trägt aber **keine Exklusivität mehr allein**: die Exklusivität hängt am scope-bezogenen Lock, der beim Gewinner die Freigabe-/Registrierungs-Information (inkl. der per-Lease-Referenz) im Inhalt trägt. +2. **Atomare Akquise (create-only) — genau ein Gewinner (AC-b):** Die Akquise erfolgt **atomar als create-only-Operation** auf den scope-bezogenen Lock im clone-geteilten Zustand: `git update-ref $ZERO_SHA` — create-only — die Operation **schlägt fehl, sobald der Ref bereits existiert**, und berührt einen existierenden Lock **nicht** (gits eigene Ref-Sperre serialisiert zwei Worktrees/Prozesse desselben Clones auf demselben Lock). Genau **ein** Producer erwirbt die Lease; jeder zweite, zeitlich überlappende Akquise-Versuch schlägt fehl. **Ask-First-Pflicht:** ist dieses create-only-Primitiv im geteilten Git-Refnamespace auf der Ziel-Plattform (Windows/Git-Bash) nicht zuverlässig atomar belegbar, **HALT** der Producer und legt eine alternative Primitiv-Auswahl zur Autorisierung vor (kein stiller Ausweich-Primitiv). +3. **`LEASE_HOLD`-Semantik (AC-c, §5.11 Pkt. 1 unverändert):** Schlägt die atomare Akquise fehl (der scope-bezogene Lock ist von einer anderen Run-ID bzw. einem anderen Worktree/Prozess gehalten), hält der abgewiesene Producer **`LEASE_HOLD`** und beendet sauber: er **überschreibt nichts** (kein Update des Locks, kein Inhalt-Austausch), **verändert weder `wiki/` noch den bestehenden Lock**, **erzeugt keinen Compilation Commit** und **entfernt keine fremde Lease**. Die Koordination geht wie bisher in den AD-16-Pfad (§5.11 Pkt. 4) über. +4. **Determinismus (AD-17h/A0-19):** Der clone-geteilte Zustand ist der einzige Zustand, den alle Worktrees/Prozesse eines Clones **gemein sehen** — die Akquise ist damit **deterministisch aus dem geteilten Git-State** entscheidbar (gleicher Geteilter-Zustand + gleiche Eingabemenge → identische Gewinner-/Verlierer-Entscheidung, AD-17h/A0-19). Der Lock-Inhalt (Run-ID) ist **dokumentierender Ablage-Wert, kein Schlüsselbestandteil** — die Exklusivität folgt allein aus Existenz/Abwesenheit des scope-bezogenen Locks. +5. **Kollisions-Hold an Epic 4 (AC-e, AD-17c/A0-14):** Zwei Branches mit **ungleichen Änderungen am selben Concept-Pfad** werden **nie textuell automatisch gemerged** (§5.11 Pkt. 4 bleibt textuell unverändert — kein textueller Auto-Merge, AD-17c). Erkennt der Run die Kollision, wird ein **strukturierter Kollisions-Hold mit beiden Commit-Hashes und dem Scope** an Epic 4 übergeben — der benannten Hold-Mechanik (§5.16 Pkt. 8/§5.10 Pkt. 8: datumsgruppierter `log.md`-Eintrag mit ``, keine Wissensmutation) statt eines automatischen Merges; **AD-16-Klassifikation und semantische Auflösung bleiben Epic 4 / Story 4.x**. Commit-Boundary = Mutations-Boundary (AD-17f, §0/§5.3/§5.11 Pkt. 5 unverändert); `log.md`-Eintragspflicht (Vertrag §5, §5.11 Pkt. 6 unverändert). +6. **Abgrenzung (keine neue Dimension):** Keine Wanduhr-/Systemzeit in der Akquise (A0-20); keine Staleness-/TTL-/Recovery-Logik (bleibt §5.12/Story 3.6 und Story 3.12); keine Verwaist-/Stale-Behandlung und kein Lease-Branch-Lifecycle nach Übernahme (bleibt Story 3.12) — diese Sektion präzisiert ausschließlich die **Akquise-Atomarität** des Root-Scope im clone-geteilten Zustand; die §5.11-Pkt.-1-Formen (Branch, Lockfile, Merge-Base, Freigabe) und die §5.12-Dimension bleiben unverändert maßgeblich. + ## 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). @@ -466,7 +477,7 @@ Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in A - **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 — **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) — **in §5.12 dieser Instruktion verankert (Story 3.6)**. +- **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) — **in §5.12 dieser Instruktion verankert (Story 3.6)**. **Story-3.11-Verankerung:** die atomare Root-Scope-Lease-Akquise ist in **§5.17 dieser Instruktion** verankert (Story 3.11, Atomare Root-Scope-Lease-Akquise): der Exklusivitätsschlüssel ist ein einziger, scope-bezogener Lock im clone-geteilten Zustand (geteilter Git-Ref-/Objektnamespace aller Worktrees und Prozesse eines Clones — `git update-ref $ZERO_SHA`, create-only), die Run-ID ist Lock-Inhalt statt Schlüsselbestandteil (AC-a), die Akquise ist atomar mit genau einem Gewinner und `LEASE_HOLD` für den Abgewiesenen (AC-b/c, §5.11-Pkt.-1-Lease-Hold unverändert), Kollisions-Hold mit beiden Commit-Hashes an Epic 4 statt textuellem Auto-Merge (AC-e, AD-17c/A0-14). Keine neue §7-Klasse, kein Schema-/Validator-Change, keine Vertragsänderung; keine Wanduhr/Systemzeit (A0-20), keine Staleness-/Recovery-Logik (bleibt §5.12/Story 3.12); §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker bleiben unverändert (Fugen-Identität). - **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. **Story-3.8-Auflösung:** die Determinismus-Frage ist in **§5.14** dieser Instruktion verankert (Story 3.8, Determinismus-Vertrag & Agent-Instruktions-Validator): die Em-Dash-Kollaps-Klasse, die Kollaps-Reichweite und der Match-Scope der Stufe a sind in **§3.2-Pkt.-1b** als geschlossene, deterministische Regel-Ergänzungen verankert; die Orphan-Politik ist in **§5.10 Pkt. 8** als deterministische Reconcile-Orphan-Regel präzisiert; die `generated.at`-Wanduhr-Gap-Ausnahme ist in §5.14-Pkt.-3 in die **Ausnahme-Menge** des Bundle-State-Vergleichs gefasst (A0-20-Konvention, Ask-First-geschützt). Keine offene Determinismus-Frage verbleibt (bestehende Story-Bullets unverändert). **Scope-Präzisierung (Review-Loop-3, P-8):** dies gilt für die **mit Story 3.8 geschlossenen** Determinismus-Fragen (Em-Dash-Kollaps-Klasse, Kollaps-Reichweite, Match-Scope Stufe a, Reconcile-Orphan-Regel, `generated.at`-Wanduhr-Gap-Ausnahme); bewusst nicht damit geschlossen bleibt die Umlaut-vs-Transkription-Divergenz im Match-Pfad (benannter Defer, `_bmad-output/implementation-artifacts/deferred-work.md` Defer-Block Review-Loop-3 — kein Instruktions-Defekt); die vormals „noch nicht verankerten" Story-3.9-ACs (Term-Gewinnung/Routing) sind dagegen seit der **Story-3.9-Verankerung** in **§5.15 dieser Instruktion** geschlossen (Deterministische Relevanz- & Reconcile-Routing: eine exklusive Routing-Tabelle UPDATE/CREATE/ORPHAN-HOLD/NO_OP — NO_OP als Update-Unter-Entscheidung, leere Candidate-Liste → Zellen 2/3; Termgewinnung geschlossen inkl. Status-Codes A/M/D/R/C, symmetrische Normalisierung mit **einer** Kollaps-Definition (§3.2-Pkt.-1b), Raw-Immutability-Guard, reservierte Zielpfade, Zwei-Run-Identität mit praktisch ausgeübter `at`-Exzeption) — keine stillen offenen Fragen. **Story-3.10-Verankerung:** die Erhaltungs-Absicherung des laufenden, gemischten Runs und der Hold-Ausbau sind in **§5.16 dieser Instruktion** verankert (Story 3.10, Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau): Kontinuitäts-Garantie (AC-1), Korrigieren mit Run-Receipt-Trace (AC-2), Schutzbestandteile & Byte-Identität (AC-3), CONFIRMING-Konsolidierung (AC-4 — bestätigende neue Source mit neuem Evidenzanker ist Konsolidierungs-Update, kein NO_OP), gemeinsame Wissensrepräsentation als Synthese-Erhaltung (AC-5), byte-erhaltender NO_OP (AC-6 — nur bei vollständiger Evidenzanker-Menge), Provenienz-/Link-Selbsttest aus aktuellem Run (AC-7 — Baseline = ``, keine historischen Zählwerte normativ), benannter Hold (AC-8 — post-Reconcile-Orphan über alle Erhebungs-Stufen a/b/c, Mehrziel-Auflösung, beide Evidenzpfade im Run-Receipt; NFR-7). Keine neue §7-Klasse, kein Schema-/Validator-Change, keine Vertragsänderung; AD-16-Klassifikation bleibt Epic 4; die §5.9-Abgrenzungs-Reihenfolge bleibt die einzige Form-Wahl. - **Reason/Mutate-Phasen-Trennung & Konsistenz-Endzustand** (logische Phasen-Disziplin: Analyse → Änderungsplanung → Mutation → Validierung, AD-6/A0-7, AC-1/AC-2/AC-3/AC-4) — **in §5.13 dieser Instruktion verankert (Story 3.7; D-3):** Änderungsplanung als institutionalisierter §5.9-Pkt.-6-P2-Block (textuell festgehalten, Plan-Defizit = textuell benannte Abbruch-Kette vor der Mutation), Plan-Freeze = Veränderungs-Sperre an die §5.9-Pkt.-5-Ghost-Diff-Kopplung (erlaubte Pfad-Menge: Kandidatenliste ∪ Neu-Anlage ∪ `log.md` ∪ `index.md`), Zustands-Restaurations-Invariante (Post-Rollback-Diff gg. Baseline leer / Bundle == valide committet, §5.3-Pkt.-3-/§6-Pkt.-3-Rollback unverändert), kein Teilerfolg als fertige Mutation (AD-17f), keine eigene Workflow-Engine (logische Trennung in einer Session, kein Prozess/Server/MCP, D-3/AD-11). Keine neue §7-Klasse, kein Schema-/Validator-Change, keine Vertragsänderung. - **Standalone-Compiler / eigene LLM-Runtime / MCP** → verboten in v1 (D-3, D-4, AD-11). @@ -513,3 +524,4 @@ Diese Instruktion ist auf die **Erzeugung neuer Concepts auf Root-Ebene und in A - **Revision 3.3 (2026-08-20, Story 3.8):** Neue Sektion **§5.14 „Determinismus-Vertrag & Agent-Instruktions-Validator (Story 3.8)"** eingefügt (nach §5.13, vor §6) — die **geschlossene, aus dem committeten Git-State ableitbare Bestätigungs-Mechanik des Determinismus-Vertrags** (AD-17h/FT-10/A0-19; §3.2/§5.9/§5.10/§5.11/§5.12/§5.13-Rückverweise verankern den Vertrag, §5.14 die Bestätigung): (1) **Bundle-State-Definition** (deterministische Projektion des committeten Git-States: committeter Baum unter `wiki/`/`raw/` gg. Baseline + Plan-/Kandidaten-/Reihenfolge-Outputs + Ausführungs-Entscheidungen; `generated.at`/`verified[].at` als benannte Ausnahme, A0-20 — einzig zulässige Differenz zwischen zwei Runs), (2) **Zwei-Run-Bestätigungs-Mechanik** (agent-Instruktions-basiert, D-3/Q-6: **zwei frische Agent-Kontexte in getrennt aufgebauten (sauberen) Worktrees** führen die Instruktion jeweils einmal über demselben committeten Git-State aus und die Bundle-States werden verglichen — **eine zweite Ausführung in derselben Session genügt nicht** (Q-6, A0-19); Vergleichs-Operandum = committeter Baum, **kanonisches Eingabemanifest** (Baseline-Commit, geordnete Sources, output-sichtbare Run-/Zeit-/Identitätswerte) + **Run-Receipt außerhalb des Bundles** (Candidates, Reihenfolge, Plan, Entscheidungen, Output-Hashes), re-executierbare diff-/hashbasierte Formeln, keine Wanduhr-Steuerung, keine hart codierten erwarteten Pläne/Concept-Bodies, keine pauschale `verified`-Maskierung; identische Plan-/Kandidaten-/Reihenfolge-Outputs, byte-identische mutierte Bestandteile; keine eigene Runtime/kein neues Werkzeug, AD-6/AD-11), (3) **Ausnahme-Menge** (allein der `generated.at`-Wanduhr-Gap; dokumentiert, kein stiller Ausschluss; alle übrigen Bestandteile byte-identisch), (4) **Abweichungs-Klassifikation** (jede Differenz außerhalb der Ausnahme = AD-16-Klassifikationsfehler, kein Rauschen; textuell benannt NFR-4, Run korrigiert/rollt zurück, Zustands-Restaurations-Invariante §5.13 Pkt. 3), (5) **Normalisierungs-/Match-/Orphan-Schließung** (§3.2-Pkt.-1b-Em-Dash-Kollaps-Klasse `[-–— _]`, Kollaps-Reichweite, Match-Scope Stufe a; §5.10-Pkt.-8-Reconcile-Orphan-Regel; Erhebungen vollständig pinbar). **§3.2:** die bekannten Determinismus-Lücken als append-only-Regel-Ergänzungen geschlossen (Em-Dash in der Kollaps-Klasse, Kollaps-Reichweite, Match-Scope der Stufe a) — bestehender §3.2-Wortlaut unverändert. **§5.10 Pkt. 8:** Orphan-Politik zur deterministischen **Reconcile-Orphan-Regel** präzisiert (unzugeordnet, datumsgruppierter `log.md`-Verwaist-Eintrag mit ``, kein Banner/keine stille Vorbearbeitung/keine eigenständige Anlage; AD-16-Default). **§5.13 Pkt. 7:** Home-Verweis des `generated.at`-Gaps auf die §5.14-Definition verlagert (Wortlaut des §5.13-Satzbaus semantisch unverändert; die Behandlung des Gaps ist jetzt in §5.14-Pkt.-3 definiert). **§7:** Determinismus-Vorbehalt der Relevanzbestimmung **aufgelöst** (Em-Dash-Lücke → „in §5.14 verankert (Story 3.8)"-Ergänzung; §3.2-/§5.10-/`at`-Gap-Schließung benannt; bestehende Story-Bullets unverändert — kein neuer Bullet ersetzt einen bestehenden). **§8:** Normreferenz **AD-17h** von reiner Story-Zuordnung auf **§5.14-Anker** angehoben (`AD-17h (Determinismus, §5.14 — Zwei-Run-Bestätigung mit benannter `generated.at`-Wanduhr-Gap-Ausnahme, A0-20/§5.9-Pkt.-2/§5.10-Pkt.-8)`). **Abschlussklausel:** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Prädikat-/Format-/Frontmatter-Key**; das `generated.at`-Verhalten selbst **unverändert** (nur seine Behandlung im Bundle-State-Vergleich; Verhaltenswechsel = Ask-First); keine Workflow-Engine/kein neuer Prozess/Server/MCP (AD-6, AD-11); §0-Phasen-Listentext, §5.13-Phasen-Disziplin und §6/§6.5 textuell **unverändert** (Fugen-Identität); Commit-Boundary-Regel unverändert; `schema/canonical-terms.md` unverändert (Em-Dash-/Kollaps-Schließung lebt als Regel in §3.2, nicht als Registry-Edits). **`sprint-status.yaml`:** Key `3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato` **`done`** (2026-08-20: Story-3.8-Instruktionsverankerung abgeschlossen — die Re-Open-/Abschluss-Reihenfolge „3.9 → 3.10/3.11 → 3.12 → 3.8-Abschluss → 3.13" des Sprint-Change-Proposals 2026-08-20 betrifft das Epic-3-**Abnahmegate**, nicht die Story-3.8-Inhaltsverankerung; die 3.9–3.12-Verankerungen bleiben offen, epic-3 bleibt in-progress). **Re-Open-Delta (2026-08-20, genehmigtes Sprint-Change-Proposal):** Zwei-Run-Mechanik auf getrennte Worktrees/frische Agent-Kontexte umgestellt (Q-6/A0-19), kanonisches Eingabemanifest + Run-Receipt außerhalb des Bundles, keine hart codierten erwarteten Pläne/Concept-Bodies, keine pauschale `verified`-Maskierung (nur `at`-Ausnahme). Sandbox-Nachweis (**DET-1..DET-8 + Erhaltungs-Invariante, Exit 0**; Zwei-Run-Identität nicht-vakuum, DET-2 in zwei getrennten Worktrees) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.8, Revision 3.3). - **Revision 3.4 (2026-08-20, Story 3.9):** Neue Sektion **§5.15 „Deterministische Relevanz- & Reconcile-Routing (Story 3.9)"** eingefügt (nach §5.14, vor §6) — die **geschlossene Routing-Ebene des Reconcile** (AD-17h/A0-19, Story 3.9; §5.14-Pkt.-5-/§7-„Story-3.9-ACs noch nicht verankert"-Vorbehalt aufgelöst): (1) **Termgewinnung** — geschlossener, geordneter Algorithmus aus der Zuwachs-Sicht (Dateiname→Term-Mapping, `source.md`-Sidecar-Exklusion, Status-Codes `A`/`M`/`D`/`R`/`C` via `--diff-filter=ACMR` mit der Akzeptanz-Regel A/C (akzeptiert) vs. M/D/R (Run-FAIL) aus Pkt. 4, §5.9-Pkt.-6-Diskrepanz-/Fallback-Kopplung, Diff↔Manifest-Äquivalenz, Mehrfach-Term-Vereinigung D-8 aufgegriffen; **eine** Kollaps-Definition §3.2-Pkt.-1b), (2) **symmetrische Normalisierung + literal-sichere Suche** (AC-2; `index.md`-Treffer → Traversal-Stufe, kein Konzept-Kandidat), (3) **eine exklusive Routing-Tabelle** (AC-3; UPDATE → CREATE → ORPHAN/HOLD → NO_OP; **NO_OP als Update-Unter-Entscheidung** — leere Candidate-Liste bei neuer Evidenz → Zellen 2/3, nie NO_OP; CREATE-vs-ORPHAN-Prädikat; Stufe-b-Zelle konsistent), (4) **Raw-Immutability-Guard** (AC-4; M/D/**R** → Run-FAIL vor jeder Mutation, A/C akzeptiert), (5) **reservierte Zielpfade** (AC-5; erschöpfende Liste `index`/`log`/`source`/`README`, Ist-Dateimenge via `git ls-tree`-Schnittmenge, deterministischer Hold), (6) **Zwei-Run-Identität** (AC-6; positive UND negative Fixtures, Zwei-Worktree-Vergleich, praktisch ausgeübte `at`-Exzeption — die einzige benannte Differenz). **§3.2:** der NO_MATCH-Anker (Pkt. 3d) als §5.15-Verweis-Anker nachgeführt (leere Candidate-Liste bei neuer Evidenz → Zellen 2/3, nicht NO_OP; `UNTOUCHED_CONCEPT` gilt für den Ghost-Diff-negativen Fall ohne Zuwachs). **§5.14 Pkt. 5:** Scope-Präzisierung nachgeführt (Story-3.9-ACs sind verankert). **§7:** Relevanzbestimmung-Bullet um die §5.15-Verankerung erweitert (Story-3.9-Vorbehalt aufgelöst; bestehende Story-Bullets unverändert). **§8:** AD-17h-/A0-19-/A0-18-Reihe bereits in §5.14 verankert — §5.15 referenziert sie (Fugen-Identität). **Abschlussklausel (Story 3.9):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **keine fünfte Routing-/Update-Klasse**; **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Prädikat-/Format-/Frontmatter-Key**; `schema/canonical-terms.md` unverändert (kein neuer Normalisierungs-Operand — Umlaut-vs-Transkription bleibt benannter Defer); Commit-Boundary-Regel unverändert; Hold-Ausbau (post-Reconcile-Orphan, Mehrziel) bleibt Story 3.10; AD-16-Klassifikation/semantische Auflösung bleibt Epic 4. **`sprint-status.yaml`:** Key `3-9-deterministische-relevanz-und-reconcile-routing-schliessen` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3). **Review-Loop-2-Auflösung (Re-Ableitung):** Kern-Defekt BS-L2-1 (NO_MATCH/leere Candidate-Liste nicht NO_OP, sondern Zellen 2/3) und BS-L2-2 (Status-Codes inkl. R/C) behoben; Sandbox um R-1-Negativ-Manifest, R-3-Fall-2-Evidenzvergleich, R-5-CREATE-Bewertungsraum, R-6/R-7-Slug-Ableitung + `git ls-tree`-Schnittmenge, R-8-Zwei-Worktree-Hold, R-9-`at`-Exzeption, harmonisierte `norm()` (eine Kollaps-Definition) ertüchtigt (Details siehe Spec Change Log Loop-2 und `wiki/log.md`-Eintrag). - **Revision 3.5 (2026-08-21, Story 3.10):** Neue Sektion **§5.16 „Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau (Story 3.10)"** eingefügt (nach §5.15, vor §6) — die **operationelle Erhaltungs-Klammer** über den textuell unveränderten §5.9/§5.10/§5.15-Mechaniken (D-3, Story 3.10; A0-21-Incrementality-Teil, FR-4/FR-6/FR-12, AD-4/AD-5; §5.15-Zelle-3-/§5.15-Scope-Präzisierung-/§5.10-Pkt.-8-D-4-Hold-Home hierin verankert): (1) **Kontinuitäts-Garantie** (AC-1; in-place Update/Synthese, kein Duplikat, Identität + Index-Link erhalten), (2) **Korrigieren mit Run-Receipt-Trace** (AC-2; ersetzte Wortlautfolge + Source-Basis im Run-Receipt außerhalb des Bundles, §5.14 Pkt. 2; mehrdeutig → benannter Hold Epic 4), (3) **Schutzbestandteile & Byte-Identität** (AC-3; gültige belegte Aussagen, §5.5-Inline-Verweise, `sources` gültiger Belege, §5.6-Links, human-`verified` bleiben erhalten; nicht betroffene Concepts byte-identisch, §5.9 Pkt. 5), (4) **CONFIRMING-Konsolidierung** (AC-4; bestätigende neue Source mit neuem Evidenzanker → Aussage genau einmal, alle Anker via §5.5-Multi-Beleg, `sources`-Zuwachs, `at`-Bump, **kein NO_OP** — Stellen-Abgleich auf den Anker, nicht auf den Inhalt), (5) **gemeinsame Wissensrepräsentation als Synthese-Erhaltung** (AC-5; §5.10-Pkt.-2/3/5, Update auf bestehendes Concept = Erweiterung, keine Neuschreibung), (6) **byte-erhaltender NO_OP** (AC-6; nur bei vollständig identischer Evidenz **samt vollständiger Evidenzanker-Menge** — kein `at`-Bump, kein `sources`-Zusatz, kein `log.md`-Eintrag; fehlender Anker → Pkt. 4), (7) **Provenienz- & Link-Selbsttest aus aktuellem Run** (AC-7; Baseline = `` des aktuellen Runs, erwartete Delta-Menge = Kandidatenliste ∪ Neu-Anlage ∪ `log.md` ∪ nachgeführte `index.md`; kein historischer Commit/globaler Zählwert normativ), (8) **benannter Hold** (AC-8/NFR-7; post-Reconcile-Orphan über **alle** Erhebungs-Stufen a/b/c — die Story-3.9-Sandbox übte nur Stufe a (§5.15-Pkt.-6-Scope-Präzisierung aufgegriffen) —, Mehrziel-Auflösung via D-8-Mehrfach-Term-Vereinigung auf eine primäre Ziel-Repräsentation, sonst fail-closed Hold; widersprüchliche/klassifikationspflichtige Evidenz ohne Wissensmutation; beide Evidenzpfade im Run-Receipt). **§5.15:** Zelle-3-Zeile und Scope-Präzisierung auf die §5.16-Verankerung nachgeführt („in §5.16 verankert, Story 3.10"). **§5.10 Pkt. 8:** D-4-Bullet um die §5.16-Verankerung des Hold selbst ergänzt (Hold-Ausbau: Stufen a/b/c, Mehrziel, benannter Hold). **§7:** Relevanzbestimmung-Bullet um die **Story-3.10-Verankerung** erweitert (§5.16; bestehende Story-Bullets unverändert). **AD-16-Klassifikation/semantische Auflösung bleibt Epic 4.** **Abschlussklausel (Story 3.10):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **keine fünfte Update-/Routing-Form**; die §5.9-Abgrenzungs-Reihenfolge `Korrigieren → Präzisieren → Erweitern → No-Op` bleibt die **einzige** Form-Wahl (textuell unverändert); **kein Standalone** (D-3); keine Vertragsänderung; **kein neuer Prädikat-/Format-/Frontmatter-Key**; `schema/canonical-terms.md` unverändert (kein neuer Normalisierungs-Operand — Umlaut-vs-Transkription bleibt benannter Defer, Ask-First); Commit-Boundary-Regel unverändert; `generated.at`-Verhalten unverändert (A0-20-Konvention). **`sprint-status.yaml`:** Key `3-10-inkrementelle-update-und-synthese-erhaltung-absichern` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3/3.4). Sandbox-Nachweis (**E-1..E-9, Exit 0**; CONFIRMING ≠ NO_OP byte-bewiesen, NO_OP byte-erhaltend, Korrigieren-Receipt-Trace, aktueller-Run-Selbsttest, Orphan über Stufe-a/b/c, Mehrziel-Konsolidierung/-Hold, Zwei-Run-Identität nicht-vakuum) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.10, Revision 3.5). +- **Revision 3.6 (2026-08-21, Story 3.11):** Neue Sektion **§5.17 „Atomare Root-Scope-Lease-Akquise (Story 3.11)"** eingefügt (nach §5.16, vor §6) — die **operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise** über der textuell unveränderten §5.11-/§5.12-Mechanik (D-3, Story 3.11; AD-17b/A0-13; §5.11 Pkt. 1/2 und §5.12-Anker sind Fugen-Identität, Revision 3.6): (1) **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand** (AC-a; der geteilte Git-Ref-/Objektnamespace ist der einzige von allen Worktrees/Prozessen eines Clones gemeinsam gesehene Zustand; eine deterministisch benannte, committete Ref je Root-Scope `wiki/`, z. B. `refs/leases/wiki`; die **Run-ID ist Lock-Inhalt und nicht Bestandteil des Exklusivitätsschlüssels** — der Ref-Name trägt keine Run-ID; die bisherige ``-Ablage §5.11 Pkt. 1 bleibt per-Lease-Ablage ohne alleinige Exklusivität), (2) **atomare Akquise (create-only) — genau ein Gewinner** (AC-b; `git update-ref $ZERO_SHA` schlägt fehl, sobald der Ref existiert, und berührt einen existierenden Lock nicht; gits Ref-Sperre serialisiert zwei Worktrees/Prozesse desselben Clones; **Ask-First-Pflicht**: nicht sicher atomar belegbar auf Windows/Git-Bash → HALT, Alternativ-Primitiv zur Autorisierung), (3) **`LEASE_HOLD`-Semantik** (AC-c; abgewiesener Producer verändert weder `wiki/` noch den Lock, erzeugt keinen Compilation Commit, entfernt keine fremde Lease, beendet sauber, AD-16-Pfad), (4) **Determinismus** (AD-17h/A0-19; clone-geteilter Zustand = eindeutige Gewinner-/Verlierer-Entscheidung; Lock-Inhalt dokumentierender Ablage-Wert, kein Schlüsselbestandteil), (5) **Kollisions-Hold an Epic 4** (AC-e/AD-17c/A0-14; kein textueller Auto-Merge, strukturierter Kollisions-Hold mit beiden Commit-Hashes und Scope an Epic 4 via §5.16-Pkt.-8-/§5.10-Pkt.-8-Hold-Mechanik; AD-16-Klassifikation bleibt Epic 4; Commit-Boundary = Mutations-Boundary und `log.md`-Eintragspflicht unverändert), (6) **Abgrenzung** (keine Wanduhr/Systemzeit A0-20, keine Staleness-/Recovery-Logik — bleibt §5.12/Story 3.6 und Story 3.12 —, keine Verwaist-/Stale-Behandlung/kein Branch-Lifecycle nach Übernahme — Story 3.12). **§7:** Leasing-Bullet um die **Story-3.11-Verankerung** erweitert (§5.17; bestehende Story-Bullets unverändert). **§8:** AD-17b/A0-13 bleiben über die bestehende §5.11-Zuordnung verankert — §5.17 referenziert sie (Fugen-Identität). **Abschlussklausel (Story 3.11):** Keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); **keine neue §7-Invaliditätsklasse**; **kein neuer Frontmatter-Key für Lease-Metadaten** (Vertrag §3.1–§3.7 unverändert); **kein neuer Prädikat-/Format-Key**; **kein Standalone** (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker **textuell unverändert** (additive Präzisierung, Fugen-Identität); keine Wanduhr/Systemzeit (A0-20); keine Staleness-/Recovery-Logik (Story 3.6/3.12); Commit-Boundary-Regel unverändert; AD-16-Klassifikation bleibt Epic 4. **`sprint-status.yaml`:** Key `3-11-root-scope-leasing-atomar-akquirieren` auf **`review`** geflippt (Implementierungs-Commit; finaler `done`-Flip im Step-05-Status-Sync nach abgeschlossenem Review-Loop — Präzedenz Revision 3.2/3.3/3.4/3.5). Sandbox-Nachweis (**A-1..A-8, Exit 0**; Zwei-Worktree-/Zwei-Prozess-Überlappung mit Zwischenzustands-Assertions „niemals zwei aktive Root-Leases", `LEASE_HOLD`-Nicht-Mutation, Kollisions-Hold mit beiden Commit-Hashes) und per-Datei-Validator-Verdikt siehe `wiki/log.md`-Eintrag (Story 3.11, Revision 3.6). diff --git a/wiki/log.md b/wiki/log.md index f22d2ae..832889b 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -1,6 +1,7 @@ # Log ## 2026-08-21 +- **Story 3.11 → `review` (Root-Scope-Leasing atomar und worktree-übergreifend akquirieren, Verankerung §5.17 + Revision 3.6, 2026-08-21):** `schema/compiler.md` **Revision 3.6** — neue Sektion **§5.17 „Atomare Root-Scope-Lease-Akquise (Story 3.11)“** (nach §5.16, vor §6): operationelle Atomaritäts-Präzisierung der Root-Scope-Akquise über der textuell unveränderten §5.11-/§5.12-Mechanik (Fugen-Identität; D-3, AD-17b/A0-13; TOCTOU-Race der bisherigen Lockfile-Lage geschlossen). **Punkte 1–6:** (1) **Exklusivitätsschlüssel = scope-bezogener Lock im clone-geteilten Zustand** (AC-a: geteilter Git-Ref-/Objektnamespace aller Worktrees/Prozesse eines Clones; eine committete Ref je Root-Scope `wiki/`, z. B. `refs/leases/wiki`; **Run-ID = Lock-Inhalt, nicht Schlüsselbestandteil**), (2) **atomare Akquise (create-only), genau ein Gewinner** (AC-b: `git update-ref $ZERO_SHA`; Ask-First-Pflicht → HALT/Alternativ-Primitiv), (3) **`LEASE_HOLD`-Semantik** (AC-c: kein `wiki/`-/Lock-Eingriff, kein Compilation-Commit, keine Fremd-Lease-Entfernung, sauberes Ende, AD-16-Pfad), (4) **Determinismus** (AD-17h/A0-19: clone-geteilter Zustand = eindeutige Gewinner-/Verlierer-Entscheidung), (5) **Kollisions-Hold an Epic 4** (AC-e/AD-17c/A0-14: kein textueller Auto-Merge, strukturierter Kollisions-Hold mit beiden Commit-Hashes + Scope via §5.16-Pkt.-8-/§5.10-Pkt.-8-Hold-Mechanik), (6) **Abgrenzung** (keine Wanduhr/Systemzeit A0-20, keine Staleness-/Recovery-Logik — §5.12/Story 3.6 und Story 3.12 —, kein Branch-Lifecycle nach Übernahme — Story 3.12). **§7:** Leasing-Bullet um die Story-3.11-Verankerung erweitert; **§8:** Revisionslog-Addendum 3.6 (Abschlussklausel AD-3). **Sandbox-Nachweis** (`_bmad-output/implementation-artifacts/sandbox-3-11/run-sandbox.sh`, `/tmp`-Baum, nie der reale Ist-Baum; re-executierbar): **A-1..A-8, 8/8 harte PASS, Exit 0** — A-1 Exklusivitätsschlüssel (AC-a), A-2 **reale Zwei-Worktree-/Zwei-Prozess-Überlappung** (`git worktree add` über Baseline, zwei getrennte Prozesse, create-only-Akquise) mit Zwischenzustands-Assertions „niemals zwei aktive Root-Leases“ (AC-b/AC-d), A-3 Weder-Noch (nie zwei, nie keiner), A-4 LEASE_HOLD-Nicht-Mutation (AC-c: `wiki/` unverändert, keine Commits, fremde Lease unangetastet), A-5 Schlüssel-ohne-Run-ID, A-6 späte Abweisung, A-7 Kollisions-Hold mit beiden Commit-Hashes (AC-e), A-8 Freigabe-erneut; Erhaltungs-Invariante + `at`-Normalform je Szenario (Vertrag §3.3/§3.4, §6.5); kein Zugriff auf reales Bundle/`raw/` (AD-3). **Abschlussklausel:** keine Änderung an `schema/wiki-compiler.md`/`schema/validator.md`/`adapters/`/`raw/` (AD-3); keine neue §7-Invaliditätsklasse; kein neuer Frontmatter-Key für Lease-Metadaten (Vertrag §3.1–§3.7 unverändert); kein Standalone (D-3); keine Vertragsänderung; §5.11-Pkt.-1/2-Wortlaut und §5.12-Anker textuell unverändert (additive Präzisierung). `sprint-status.yaml`-Key `3-11-root-scope-leasing-atomar-akquirieren` → **`review`** (Implementierungs-Flip, HEAD-Stand 08-21-2026; finaler `done`-Flip im Step-05-Status-Sync), `last_updated` → 08-21-2026 12:30. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag); AD-3 read-only (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert); kein Standalone (D-3), keine neue §7-Invaliditätsklasse, keine Vertragsänderung; Epic-3-Abnahme (Story 3.13) bleibt offen (epic-3 in-progress); Lease-Lifecycle/Commit-Abschluss transaktional (Story 3.12) und Staleness-Nachfolge bleiben offen. - **Story 3.10 → `review` (Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau, Verankerung §5.16 + Revision 3.5, 2026-08-21):** `schema/compiler.md` **Revision 3.5** — neue Sektion **§5.16 „Inkrementelle Update- & Synthese-Erhaltung + Hold-Ausbau (Story 3.10)“** (nach §5.15, vor §6): operationelle Erhaltungs-Klammer (A0-21-Incrementality, Fugen-Identität; keine A|B-Aneinanderreihung, kein Regenerate-Everything). **Punkte 1–8:** (1) **Kontinuitäts-Garantie** (AC-1: in-place Update/Konsolidierung/Synthese auf der gemeinsamen Wissensrepräsentation, kein hartes Duplikat, Identität + `index.md`-Link erhalten), (2) **Korrigieren mit Run-Receipt-Trace** (AC-2: ersetzte Wortlautfolge + Source-Basis im Run-Receipt außerhalb des Bundles, §5.14 Pkt. 2; mehrdeutige Korrektur → benannter Hold, Epic-4-/AD-16-Klassifikation, kein textueller Auto-Merge AD-17c), (3) **Schutzbestandteile & Byte-Identität** (AC-3: gültige belegte Aussagen, §5.5-Inline-Verweise, `sources` gültiger Belege, §5.6-Links, human-`verified` geschützt; nicht betroffene Concepts byte-identisch via §5.9-Pkt.-5-Ghost-Diff-Rollback), (4) **CONFIRMING-Konsolidierung** (AC-4: bestätigende neue Source → Aussage genau einmal, alle Evidenzanker via §5.5-Multi-Beleg, `sources`-Zuwachs, `generated.at`-Bump, **kein NO_OP**; Anker- statt Content-Abgleich), (5) **gemeinsame Wissensrepräsentation** (AC-5: §5.10-Pkt.-2/3/5 als Synthese-Erhaltung), (6) **byte-erhaltender NO_OP** (AC-6: volle Evidenzanker-Menge → NO_OP ohne Mutation/at-Bump/sources-Zusatz; fehlender Anker → Pkt. 4), (7) **Provenienz-/Link-Selbsttest aus aktuellem Run** (AC-7: Baseline = aktuelles ``, erwartete Deltas = Kandidaten-Liste ∪ Neu-Anlage ∪ `log.md` ∪ nachgeführte `index.md`, keine hart kodierten Pläne/Bodies/Zählwerte — §5.14 Pkt. 2, AC-7/§5.14-Pkt.-2-Konsistenz), (8) **benannter Hold** (AC-8/NFR-7: post-Reconcile-Orphan über **alle Erhebungs-Stufen a/b/c** — Story-3.9 übte nur Stufe a —, Mehrziel via D-8-Mehrfach-Term-Vereinigung → primäre Ziel-Repräsentation, sonst fail-closed benannter Hold; beide Evidenzpfade im Run-Receipt). **§7-Bullet** erweitert (Story-3.10-Verankerung; §5.9-Abgrenzungs-Reihenfolge bleibt die einzige Form-Wahl); **Hold-Home-Nachführungen:** §5.15-Zelle-3 + §5.15-Scope-Präzisierung + §5.10-Pkt.-8-D-4-Bullet verweisen auf §5.16 (Story 3.10, Hold-Ausbau); Revisionslog **Revision 3.5** mit Abschlussklausel (AD-3 — `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert; keine neue §7-Invaliditätsklasse; keine neue Update-Form; keine neuen Prädikat-/Frontmatter-/Format-Keys; kein Standalone/D-3; keine Vertragsänderung; Umlaut-vs-Transkription-Defer bleibt offen — kein neuer Normalisierungs-Operand, ask-first). `sprint-status.yaml`-Key `3-10-inkrementelle-update-und-synthese-erhaltung-absichern` → **`review`** (Implementierungs-Flip, HEAD-Stand 08-21-2026; finaler `done`-Flip im Step-05-Status-Sync), `last_updated` → 08-21-2026 12:00. **Sandbox-Nachweis** (`_bmad-output/implementation-artifacts/sandbox-3-10/run-sandbox.sh`, `/tmp`-Baum, nie der reale Ist-Baum; re-executierbar): **E-1..E-9, Exit 0, 9 harte PASS-Assertionen** — E-1 Kontinuität/AC-1 (Update in-place, kein Duplikat, Identity + Index-Link erhalten); E-2 Korrigieren-Receipt-Trace/AC-2 (Wortlautfolge + Source-Basis im Receipt außerhalb Bundle; mehrdeutig → benannter Hold ohne Mutation); E-3 Schutzbestandteile/AC-3 (nicht betroffenes Concept byte-identisch, Ghost-Diff-Rollback stellt Baseline wieder her); E-4 CONFIRMING/AC-4 (**CONFIRMING ≠ NO_OP byte-bewiesen**: Aussage genau einmal, neuer Anker, Multi-Beleg, sources-Zuwachs, at-Bump); E-5 Synthese-Erhaltung/AC-5 (gemeinsame Repräsentation erweitert, keine A|B-Aneinanderreihung); E-6 NO_OP byte-erhaltend/AC-6 (volle Evidenzanker-Menge: keine Mutation, kein at-Bump, kein sources-Zusatz); E-7 Selbsttest aktueller Run/AC-7 (Baseline = aktuelles `` frisch erzeugt, Delta = Kandidaten-Liste ∪ Neu-Anlage, keine hart kodierten Zählwerte); E-8 Orphan + Mehrziel/AC-8 (Stufen a/b/c belegt, D-8-Vereinigung → primäre Ziel-Repräsentation, fail-closed Hold, beide Evidenzpfade im Receipt); E-9 Zwei-Run-Identität deterministisch (gleicher Eingang → identische Bytes, Zustandswechsel messbar — Nicht-Vakuum). **Defer-Aufgriff:** `deferred-work.md` append — Defer «Orphan voller Stufen b/c + Mehrziel» (Story-3.9-Block, Home Story 3.10) → **`aufgegriffen`** (§5.16 Pkt. 8 verankert, Sandbox E-8 ausgeübt; Umlaut-vs-Transkription-Defer bleibt offen). **Validator-Verdikt** (human-mechanisch, `schema/validator.md` Rev 9, D-3 — kein CLI; keine Concept-Inhalts-Mutation): alle `wiki/`-Dateien SUCCESS. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag); AD-3 read-only (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert); kein Standalone (D-3), keine neue §7-Invaliditätsklasse, keine Vertragsänderung; Epic-3-Abnahme (Story 3.13) bleibt offen (epic-3 in-progress); Zwei-Run-über-reale-Inhalte/Stufen-b-c-über-reale-Bäume bleibt Story-3.13-Abnahme-Gate. - **Story 3.9 → Review-Loop-3-Abschluss + `done` (Deterministische Relevanz- & Reconcile-Routing, bmad-code-review Re-Run 4 Layer — blind-hunter ×2 / edge-case-hunter / acceptance-auditor, verification-gap über Retry, 2026-08-21):** Re-Review der Loop-2-zustands Implementation (Diffform `2f079ee..73f2c9e`, 7 Dateien); **Triage:** 3 decision-needed / 15 patch (1 nach Re-Verifikation verworfen → **14 anzuwenden**) / 2 defer / 9 verworfen; **keine intent_gap/bad_spec (kein Loopback).** **Nutzer-Entscheidungen (empfohlene Optionen):** D-3.9-1 §8-Revision-3.3-Nachführung **behalten** (3.8 ist faktisch done; Dokumentation über den append-only Spec-Change-Log, kein Rückbau); D-3.9-2 Status-Kontraktion aufgelöst auf die 3.7/3.8-Präzedenz: maßgeblich `review` (Impl-Commit-Flip), Spec-Frontmatter-`done` zurückgesetzt, **finaler `done`-Flip in diesem Eintrag (Step-05-Status-Sync)**; D-3.9-3 **Minimal-Härtung** der tautologischen Sandbox-Szenarien (echte Mechanik statt Selbstvergleich; strukturelle Restlimits — volle Stufen-b/c-Traversal, Zwei-Run über realen Contents — bleiben benannte Defers, Home Story 3.13, Präzedenz DET-1/2). **Patches (14):** compiler.md §5.15 Pkt. 1 (`/dev/null`-Sort → **LC_ALL=C-bytetreue Stable-Sortierung**; Status-Code-Entflechtung Befund A/M/D/R/C ↔ Akzeptanz A/C vs. Run-FAIL M/D/R über Pkt. 4), Pkt. 2 (Actor-Body → **Concept-Body**), Pkt. 5 (hängender „§3.2-Endergebnis"-Verweis → **§5.8-Instruktions-Hold** als Run-Status-Definition), Revision 3.4 (Status-Wortlaut `review` + Status-Code-Korrektur); Sandbox: **README-Reserviertheits-Fall case-insensitiv** (P-3.9-2), R-9-Bundle-Grep-**Anchorung** `(^|/)(index|log)\.md$` + **Benennung** der index/log-Ausnahme (P-3.9-7, re-scoped: Enden-Präfixe wie `myindex.md` nicht mehr still ausgeschlossen), R-8-Hold-**Assert auf beide Worktrees** (P-3.9-8), **Worktree-Re-Run-Idempotenz** unter `$ROOT` (P-3.9-14), `local rc=$?`-**Dead-Diagnostics** → lebendige `rc`-Erfassung (P-3.9-15), Term-Quoting + `sort -u`; **D-3.9-3-Härtung:** R-1 Negativ-Manifest → **echter Run-FAIL-Sub-Run** vor jeder Mutation (Mutation-Sentinel bleibt abseits), R-1b/R-4 **saubere je-Status-Sub-Runs** (M/D/R-Run-FAIL ohne kumulative-Baseline-Kontraktion; A-Sub-Run Guard-Pass mit Sentinel), R-3-Fall-2 **echter Full-Containment-Check** (Token-weise, mit Negativ-Kontrolle) + **Stufe-b via echtem index.md-Link-Parsing** und Zielpfad-Existenz, R-5 **echte `route()`-Funktion** (leere Candidate-Liste → CREATE-Bewertungsraum, **nie NO_OP** — NO_OP-Regression negativ geprüft) + D-8-Vereinigung ausgeübt, R-6/R-7 **Slug rein aus dem committeten Dateinamen** (Datums-Suffix-Strip + Norm, kein nicht-instruktioneller `-doc$`-Strip). **Verworfen (1):** P-3.9-1 „Escaper defekt" = **Fehlalarm** — die „Ausführung"-Evidenz war durch die Bash-Tool-Transport-Schicht korrumpiert (Backslash-Ebene halbiert; getesteter Code ≠ Datei-Code); `od`-Beweis (Z. 74/790: `\\&`) + Negativ-/Positiv-Kontrolle aus Datei-Bytes (`v1.0` matcht `v10`-Body **nicht**, `v1.0`-Body **ja**) → Escaper **literal-sicher**, Z. 74/790 unverändert (Korrektur im Spec-Change-Log). **Defers (2, → deferred-work.md append-only):** W-3.9-1 `norm()`/`tr` ohne `LC_ALL`-Pinning (Home: Sandbox-Härtung, 952-Zeilen-Scope); W-3.9-2 positive Zwei-Run-Identität strukturell trivial (Home: Story-3.13-Abnahme, Präzedenz DET-1/2). **Frozen-Änderungen (im Spec-Change-Log autorisiert/dokumentiert):** I/O-Matrix-`RAW_GUARD_MODIFIZIERT`-Zelle um Rename (M/D/**R**) + ``-Schließtag-Nachtrag (Präzedenz Spec-3-7/3-8); **keine AC-/Intent-Wortlaut-Änderung, keine Neu-Verhandlung nötig.** **Sandbox re-executiert:** `bash _bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh` → **R-1..R-9 harte PASS, Exit 0** (inkl. R-1b/R-4 je-Status-Guard-Sub-Runs, R-3 Full-Containment + Stufe-b-Link-Parsing, R-5 route(), R-6/R-7 echte Slug-Ableitung, R-8 beide Worktrees, R-9 ankerter Bundle-Vergleich). **Validator-Verdikt (human-mechanisch, `schema/validator.md` Rev 9, D-3 — kein CLI; keine Concept-Inhalts-Mutation):** alle `wiki/`-Dateien **SUCCESS**. `sprint-status.yaml`-Key `3-9-…` → **`done`** (finaler Step-05-Flip nach konvergiertem Loop-3), `last_updated` → 08-21-2026. **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag); AD-3 read-only (`schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`/`schema/canonical-terms.md` unverändert); kein Standalone (D-3), keine neue §7-Invaliditätsklasse, keine Vertragsänderung; Umlaut-vs-Transkription bleibt benannter Defer; Hold-Ausbau (post-Reconcile-Orphan, Mehrziel) + Stufen-b/c-Traversal-Coverage bleiben Story 3.10/3.13. ## 2026-08-20