125 lines
13 KiB
Markdown
125 lines
13 KiB
Markdown
---
|
||
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: []
|
||
---
|
||
|
||
<frozen-after-approval reason="human-owned intent — do not modify unless human renegotiates">
|
||
|
||
## 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/<area>/<id>.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/<area>/<id>` (§5.11 Pkt. 1), Lockfile-Pfad `lease/<area>/<id>.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 <ref> <wert> $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 |
|
||
|
||
</frozen-after-approval>
|
||
|
||
## 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/<area>/<id>.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 <ref> <wert> 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 `<id>`-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 <lock-ref> <wert> $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)
|