Files
wow20/_bmad-output/implementation-artifacts/spec-3-6-lease-staleness-recovery-basis-absichern.md

17 KiB
Raw Permalink Blame History

title, type, created, status, baseline_commit, review_loop_iteration, context
title type created status baseline_commit review_loop_iteration context
Story 3.6 — Lease-Staleness & Recovery-Basis absichern feature 2026-08-19 done 895b006f7f 0
_bmad-output/implementation-artifacts/epic-3-context.md

Intent

Problem: Ein abgebrochener Run hinterlässt eine Lease, die §5.11 (Lease-Hold) akquiriert, doch deren Freigabe (Release) nur nach committetem Run erfolgt. Ohne Staleness-Mechanik blockiert eine verwaiste Lease alle nachfolgenden Runs dauerhaft — Wissen bleibt blockiert (AD-17d/A0-15; §5.11 Pkt. 1 „verbleibt bis zum Staleness-/Recovery-Mechanismus der Story 3.6", §5.11 Pkt. 7-Seam: 3.6 = Zeit-/Umgebungs-Zustands-Frage, §7 verbleibendes 3.x-Thema).

Approach: Neue Sektion §5.12 „Lease-Staleness & Recovery-Basis (Story 3.6)" (nach §5.11, vor §6): TTL + Lease-Registrierung im Clone-Root-State deterministisch einführen — das TTL-Ablauf-Kriterium ist generationen-basiert (ohne Wanduhr, AD-17h-konform; die A0-20 zugelassene at-Notation bleibt dokumentierend) — plus Verwaist-Handling (Übernehmen/Stale-Markieren mit log.md-Protokollierung) und die raw/-Recovery-Basis (Zugriffs-/Consistency-Basis, AD-3 unverändert). Die vier Story-3.5-Defers mit Home 3.6 werden aufgegriffen (holder_id-Ableitung, baseline_commit-Diskrepanz-Regel, kumulative Registrierung über Runs, native git stash-Variante + Verwaist-Übungs-Thema). Verwaiste/hängende Leases werden dabei nie gelöscht (AD-17e) und raw/ nie verändert (AD-3).

Boundaries & Constraints

Always:

  • Nur schema/compiler.md (neue §5.12 + §7-Auflösung + §8 Revisionslog-Revision 3.1) mutiert (D-3); schema/validator.md, schema/wiki-compiler.md, adapters/, raw/ read-only (AD-3). Kein Standalone (D-3), keine neue §7-Invaliditätsklasse, kein Vertrags-Change.
  • Deterministisch aus dem committeten Git-State ableitbar (AD-17h/A0-19): Registrierungs-Aufbau, Ablauf-Kriterium, Verwaist-Klassifikation, log.md-Texte; kein Wanduhr-Timestamp im Lockfile- oder Registrierungs-Format (A0-20-Konvention, §5.11 D1).
  • raw/ ist die Zugriffs- und Consistency-Recovery-Basis (AD-17d/A0-15) und bleibt bei jedem Vorgang unverändert (AD-3).
  • Verwaiste/hängende Leases werden nie still gelöscht und fremde uncommittete Änderungen nie als Seitenwirkung entfernt (AD-17e).

Ask First:

  • Wanduhr-basierte TTL (Timeout nach Kalenderzeit) statt Generationen-Ablauf — wäre ein deterministischer Bruch, weil wanduhr-at von der Laufzeit abhängt; die A0-20-Konvention ließe einen dokumentierenden Zeitstempel zu, ein streng durchsetzendes Zeit-TTL wäre Ask-First.
  • Konflikt zweier gültiger Leases, die nicht per Generationen-Reihenfolge auflösbar ist (Older-wins außerhalb der definierten Klasse).

Never:

  • raw/-Inhalte verändern (AD-3); uncommittete fremde wiki/-Änderungen löschen (AD-17e); textuelle Auto-Merge bei Branch-Konvergenz (AD-17c); Leasing über lease/<area>/<id>-Branches hinaus; Zeitstempel/now-Wanduhr als Leasing-Steuer-Größe; neuer Frontmatter-Key für Lease-Metadaten (Vertrag §3.1–§3.7, §7); Prädikat-/Format-Erweiterung des Validators; EOF-# Log-eigener Stand in der Registry (wiki/log.md-Akkumulator ist alleiniger Aufzeichnungs-Ort, Vertrag §5).

I/O & Edge-Case Matrix

Scenario Input / State Expected Output / Behavior Error Handling
STALE_ABLAUF uncommittete Lease nach abgebrochenem Run; nachfolgender Run trifft auf sie Lease gilt als stale, blockiert nicht; Übernahme oder Stale-Markierung mit log.md-Eintrag verwaiste Lease nie gelöscht (AD-17e); Abbruch „published/committed Input erforderlich" (AD-17a, §5.11 Pkt. 3) unverändert
VERWAIST_UEBERNEHMEN neuer Run findet verwaiste Lease übernimmt die Lease gegen die erneute Merge-Base-Prüfung, protokolliert die Übernahme bei bestehendem Konflikt → AD-16-Pfad / menschliche Eskalation (AD-17g, §5.11 Pkt. 4)
VERWAIST_STALE_MARKIEREN verwaiste Lease, Übernahme nicht sinnvoll als stale markiert (Registry-Marker) und protokolliert; Blockade aufgehoben Registrierungs-Invariante (Gen > erzeugend oder gleiche Gen, hält den sichtbar höchsten Reg-Generator)
RECOVERY_RAW_BASIS uncommittete Änderungen aus abgebrochenem Run wiederherstellen raw/ (immutable, AD-3) als Zugriffs-/Consistency-Basis; Konformität re-bestätigt raw/ unverändert; kein git diff-/SHA-256-Beweis gegen raw/-Inhaltsebene auf dem realen Ist-Baum (Grenzen beachten: EC-1 auf sandbox-Evidenzwege beschränkt)
HOLD_GEGEN_HEAD Lease existiert; zu mutierender Bereich liegt nicht unter der akquirierten Lease Lease-Hold gegen HEAD; keine Mutation; kein Abbruch-Text §5.11 Pkt. 1 (Lease-Hold) unverändert
DIRTY_TREE_UNVERWAIST uncommittete fremde Änderung (Verdacht) ohne verwaiste Lease §5.11 Pkt. 3 (Schutz/Scratch-Zone, nie gelöscht) greift; keine Staleness-Marke textuell benannt (NFR-4); Restore-Weg dokumentiert

Code Map

  • schema/compiler.mdprimär mutiert (D-3): neue Sektion §5.12 „Lease-Staleness & Recovery-Basis (Story 3.6)" (nach §5.11, vor §6; §5.11-Seam-Kriterium S-1 und Pkt.-7-Text bleiben unverändert); §7 (:376-Bullet) Staleness/Recovery-Vorbehalt auflösen („in §5.12 verankert (Story 3.6)"); §8 Revisionslog Revision 3.1 mit Abschlussklausel; §8 Normreferenzen AD-17d/A0-15 von reiner Story-Zuordnung auf §5.12-Anker angehoben (AD-17d (Lease-Staleness, §5.12)); konsistente §5.12-Verweise in §5.11-Pkt.-1/Pkt.-7/§7 (nur Wortlaut, kein neuer Inhalt). Anker §5.12-Sektion: Z. nach §5.11-Ende (nach Z. 320); §7-Bullet Z. 376; §8-AD-17d Z. 387, A0-15 Z. 389; Revisionslog nach Z. 416.
  • wiki/log.mdappend (append-only, Vertrag §5): Story-3.6-Eintrag (Verankerung, Sandbox-Nachweis, Statuswechsel, Validator-Verdikt); bestehende Bullets unverändert.
  • _bmad-output/implementation-artifacts/sandbox-3-6/run-sandbox.shneu (re-executierbar, Muster sandbox-3-5, Exit 0): Szenarien STALE-1..STALE-6 (s. Design Notes), harte Pass/Fail-Assertionen, Erhaltungs-Invariante erzwungen, keine Berührung des realen Ist-Baums.
  • _bmad-output/implementation-artifacts/sprint-status.yamlmutiert: 3-6-… backlogin-progress; last_updated (Format MM-DD-YYYY HH:MM, HEAD-Präzision).
  • _bmad-output/implementation-artifacts/deferred-work.mdappend: erneut aufgreifen der vier Story-3.5-Defers Home 3.6 (holder_id, baseline_commit, Registry-Akkumulator, git-stash) + ggf. neue Story-3.6-Defers.
  • _bmad-output/implementation-artifacts/epic-3-context.md, spec-3-5-…mdread-only (continue-context; die epics-/spec-3-5-acme-Kette unverändert).

Tasks & Acceptance

Execution:

  • schema/compiler.md -- §5.12 einfügen (§5.11 Pkt. 1/7 + §7 + §8 + Revisionslog-3.1 + Abschlussklausel); Wortlaut nur, kein neuer Prädikat-/Format-Key
  • schema/compiler.md -- Revision 3.1 in §8 belegen (Anker-Zahlen + Abschlussklausel) und §5.11-/§7-Verweise §5.12-wortgleich
  • _bmad-output/implementation-artifacts/sandbox-3-6/run-sandbox.sh -- Szenarien STALE-1..6 + Erhaltungs-Invariante (vertraut auf §5.9-Pkt.-5-Probe-Muster), Exit 0
  • _bmad-output/implementation-artifacts/deferred-work.md -- vier Story-3.5-Defers Home 3.6 als aufgegriffen markieren + ggf. neue
  • wiki/log.md -- (Implementierung) Story-3.6-Eintrag, sprint-status.yaml → in-progress; Review-Abschluss done im Review-Schritt (Workflow-Konvention)

Acceptance Criteria:

  • Given ein abgebrochener Run, when uncommittete Leases hinterlassen wurden, then gelten sie als stale (TTL plus Lease-Registrierung im Clone-Root-State), blockieren keine nachfolgenden Runs, und raw/ bleibt Zugriffs-/Consistency-Basis (AD-17d, A0-15; AC-1/AC-2/AC-4).
  • Given ein neuer Run, when er eine verwaiste Lease vorfindet, then kann er sie übernehmen oder als stale markieren und protokollieren (AC-3; Alt-Branch nie gelöscht, AD-17e).
  • Given ein Story-3.5-Defer mit Home 3.6, when umgesetzt, then ist der Story-3.5-Defer-Bezug nachgezeichnet (holder_id/baseline_commit/Registry-Akkumulator/git-stash; Defer-### Aufgegriffen-Block-append).

Spec Change Log

Noch leer — wird von step-04 während der Review-Loops befüllt (append-only Konvention).

  • Review-Loop 1 (2026-08-19, Step-04-Review, 3 Layer, kein Loopback; review_loop_iteration bleibt 0): Stapel Autofix-Patches — Terminologie-Inversion „jünger→älter" (§5.12 Pkt. 1/3/6 + §8-Revisionslog-3.1-Text + log.md + Spec-Design-Notes; Gen kleiner = älter, ältere/niedrigere Erzeugungs-Generation = stale), Generations-Quellen-Präzedenz deterministisch gepinnt (§5.12 Pkt. 1: committeter lease-granite-root-Marker gewinnt, sonst lease/-Baumableitung, sonst Startwert gen = 0), STALE-1-kern generationen-basiertes TTL gegen dieselbe id (HOLD→stale→Akquise), STALE-3-Re-Akquise nach Stale-Markierung, STALE-5-Same-id-A/B (aktiv verweigert / stale-Markierung erlaubt), holder_id-genuine Ableitung (STALE-2), baseline_commit-Merge-Base-Diskrepanz real (Descendant-Commit, git merge-base gewinnt), STALE-4-lesender-raw/-Bind (Zugriffs-/Consistency-Basis, aufgelöste raw/-Ressourcen-Referenz), Marker-Idempotenz-Regex, STALE-6-Full-State-Invariante (Registry/Lockfiles/Lease-Branches/log.md SHA-256 byte-identisch), log_bullet-Datumsgruppen-Konvention; 1 neuer Defer (Branch-Ref-Schicksal nach Übernahme/Stale-Markierung → deferred-work.md). Sandbox re-executiert: Exit 0, 12 harte PASS; AD-3-Readonly + wiki/-Scope nur wiki/log.md verifiziert; alle Schritte der ## Verification-Sektion re-ausgeführt.

Design Notes

Warum §5.12 als eigene Sektion, nicht §5.11-Erweiterung? §5.11 (3.5) ist strikt committed-state-deterministisch (AD-17h) und hält das Seam-Kriterium S-1 explizit fest — 3.6 verlässt den committeten Zustand (Zeit-/Umgebungs-Zustands-Frage). Das nicht als Punkt an §5.11 anzuhängen, sondern als Eigen-Sektion zu verankern, spiegelt die gekoppelte Abschlussklausel (kein Leasing-Scope, Staleness → Story 3.6) und hält §5.11 als Denk-Basis des Reviews erreichbar.

Zeit ohne Wanduhr zwingend? (Beste alternative Bestätigung der Voranalyse): AD-17d nennt als erste Option „TTL + registration of the lease in the clone-root state". Wall-clock-TTL ist deterministisch unhaltbar (AD-17h/A0-19: identische Artifakte bei gleichem Git-State). A0-20 lebt die at-Notation als dokumentierendes Konzept (Master-Satz generated.at), nicht als steuerndes Leasing-Element; der at-Handoff wäre Ask-First. Deshalb: generationen-basiert — die Registrierung trägt einen monotonen Run-Generator (ein Highlight-generation-Zähler je Clone-Root, aus lease/-Baumableitung oder einem Mono-Commit-lease-granite-root-Marker), ein Run älterer (geringerer) Erzeugungs-Generation gilt als stale (TTL-Ablauf-Äquivalent, Gen kleiner = älter, §5.12 Pkt. 1), ohne Wanduhr.

Der Story-3.5-Seam (S-1) bleibt unbewegt: „3.5 = committed-state-deterministisch, 3.6 = Zeit-/Umgebungs-Zustands-Frage (TTL-Ablauf, verwaiste/hängende Leases, Registrierung, raw/-Recovery)". §5.12 greift ihn auf, ohne ihn zu ändern — die Review-Layer prüfen die Fuge.

Defer-Handoff (exakter Pfad): vier Einträge deferred-work.md (Z. 420437, Home Story 3.6): holder_id-Quelle (→ §5.12 Pkt. 2, deterministischer Default), baseline_commit-Merge-Base-Diskrepanz-Regel (→ §5.12 Pkt. 4, Vereinheitlichung), Sandbox-log-Akkumulator (→ §5.12 Pkt. 6, cumulative über Runs; kein eigener # Log-Stand), native git stash-Variante (→ §5.12 Pkt. 5-Recovery, als Sandbox-Doppel abgebildet). Neu-Defers möglich.

Sandbox (STALE-1..STALE-6, bash run-sandbox.sh, Exit 0):

  • STALE-1: abgebrochener Run erzeugt Lease + Registrierung ohne Release; nachfolgender Run findet sie → stale, kein Blockade-fail
  • STALE-2: verwaiste Lease übernehmen (± Merge-Base-Prüfung), Übernahme protokolliert
  • STALE-3: verwaiste Lease als stale markieren (Registry-Marker), Blockade aufgehoben, log.md-Eintrag
  • STALE-4: raw/-Recovery-Basis — Ablauf, der raw/-Inhalte unveränderlich lässt (Assertion), Konsistenz belegt
  • STALE-5: Registrierungs-Invariante (Gen vollständig, höchster-Reg-Invariant) — Verwaiste Kanten nie gelöscht, HOLD-Gegen-HEAD deterministisch
  • STALE-6: Determinismus Zwei-Run (AD-17h/A0-19) — gleicher Baum-Input → identische Registrierungs-/Markierungs-Outputs

(Code-/Zahlgenauigkeiten: Die obigen Szenario-Labels sind Fixierung der I/O-Matrix; die Implementierung trägt die harten Assertionen in der Sandbox.)

Verification

Commands (re-executierbar, ab Workspace-Root):

  1. bash _bmad-output/implementation-artifacts/sandbox-3-6/run-sandbox.sh — expected: STALE-1..STALE-6 harte PASS/Fail, Erhaltungs-Invariante erzwungen, Exit 0.
  2. grep -n "§5.12\|Revision 3.1" schema/compiler.md — liefert §5.12-Sektion + Revisionslog-Eintrag; grep -n "Lease-Staleness & Recovery-Basis" schema/compiler.md — die §5.12-Überschrift wortgleich (inkl. §5.11-Pkt.-7-Seam-Satz „Lease-Staleness/Recovery … TTL, Lease-Registrierung, verwaiste Leases, raw/-Recovery").
  3. Read-only (AD-3): git status --porcelain zeigt keinen Change an schema/validator.md/schema/wiki-compiler.md/adapters//raw/.
  4. Validator-Lauf: alle wiki/-Dateien SUCCESS (unverändert, keine Inhalts-Mutation).
  5. Auf den wiki/-Scope begrenzt (git status --porcelain -- wiki/): ausschließlich wiki/log.md (dieser Eintrag) — Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt; sprint-status.yaml/deferred-work.md/sandbox-3-6/ liegen außerhalb wiki/ und sind nicht Teil der Diff-Probe (wie §5.9 Pkt. 5-Doku, Story-3.5-Präzedenz).

Zu beachten (beim step-04-Review): (a) §5.11 Pkt. 1 „verbleibt bis Story 3.6" und Pkt. 7-Seam S-1 (sowie §7-Bullet) müssen textuell unverändert bleiben, wenn §5.12 auf sie verweist (Haltbarkeits-Fuge); (b) raw/-Berührung ist auf Sandbox-Evidenzwege beschränkt (kein realer Ist-raw/-Beweis nötig); (c) die vorhandene §8-Revisionslog-Umsetzungsnummer ist Revision 3.0 (Story 3.5); die Spec--Change-Log-Notiz „§8-Revision 3.1" der Story 3.5 (Review-Loop-1-Fix) wurde nicht real als eigener Revisionslog-Eintrag übernommen (compiler.md-Revisionslog enthält keine Revision 3.1; grep-verifiziert) — Revision 3.1 ist für Story 3.6 frei.

Suggested Review Order

§5.12-Leasing-Staleness-Instruktion

  • Einstieg: §5.12-Sektion — Staleness-/Recovery-Dimension, Kern der Story (Registrierung, TTL, Klassifikation). compiler.md:322
  • Registrierung & generationenbasiertes TTL mit gepinnter Quellen-Präzedenz (Marker/Baum/Startwert gen=0). compiler.md:326
  • Verwaist-Klassifikation — Übernehmen gg. erneute Merge-Base-Prüfung / Stale-Markieren, nie gelöscht (AD-17e). compiler.md:330
  • baseline_commit-Merge-Base-Diskrepanz-Regel — git-merge-base gewinnt, notierter SHA = Sekundär-Fingerprint. compiler.md:335
  • raw/-Recovery-Basis & native git stash-Variante — raw/ immutable (AD-3), EC-1-Grenze. compiler.md:337
  • Registry-Invariante & kumulativer Aufbau — Gen-Invariante, wiki/log.md alleiniger Aufzeichnungs-Ort. compiler.md:339
  • log.md-Eintragspflicht & Determinismus-Vertrag — datumsgruppiert, kein Wanduhr-Timestamp steuert. compiler.md:341

§7/§8-Nachweis

  • §7-Leasing-Enum-Bullet — Staleness/Recovery „in §5.12 verankert (Story 3.6)", §5.11-Rückverweis unverändert. compiler.md:397
  • §8-Revisionslog Revision 3.1 — Verankerung, Abschlussklausel, AD-17d/A0-15 auf §5.12-Anker. compiler.md:438

Sandbox-Nachweis

  • Sandbox STALE-1..STALE-6 — re-executierbar, harte PASS/Fail, Erhaltungs-Invariante §5.9 Pkt. 5 (Exit 0, 12 PASS). run-sandbox.sh:1

Story-Protokoll/Defers

  • log.md — Story-3.6-done-Eintrag (Review-Abschluss-Konvention). log.md:4
  • sprint-status.yaml — 3-6-… → done. sprint-status.yaml:59
  • deferred-work.md — 4 aufgegriffene Story-3.5-Defers + 1 neuer Story-3.6-Defer (Branch-Ref-Schicksal). deferred-work.md:417