feat: Story 3.11 — Root-Scope-Leasing atomar und worktree-übergreifend akquirieren (Revision 3.6, Verankerung §5.17)
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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/<area>/<id>`, 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/<area>/<id>`, 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 <ref> <wert> $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.
|
||||
|
||||
@@ -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
|
||||
# <ref> <wert> $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-/<id>-Bestandteil im Schlüssel); die per-Lease-<id>-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/<id>)
|
||||
# =====================================================================================
|
||||
runlabel "A-5: GEWINNER_SCHLUESSEL_OHNE_RUNID"
|
||||
isolate
|
||||
# Der SCOPELOCK-Ref-Name enthält weder die Run-ID noch eine <id> (§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/<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/<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
|
||||
+124
@@ -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: []
|
||||
---
|
||||
|
||||
<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)
|
||||
@@ -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
|
||||
|
||||
+13
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user