feat: Story 3.9 Review-Loop-3-Abschluss (bmad-code-review, 4 Layer; kein Loopback)
- 3 Decision-Resolutionen (D-3.9-1/2/3 = Option 1/1/2 — empfohlene Optionen) - 14 Patches angewandt (von 15): P-3.9-1 Escaper-„Fehlalarm" verworfen — die „Ausführungs"-Evidenz war durch die Bash-Tool-Transport-Schicht korrumpiert (Backslash-Ebene halbiert); od-Beweis + Negativ/Positiv-Kontrolle aus Datei-Bytes belegen: Escaper literal-sicher, run-sandbox.sh Z. 74/790 unverändert - 2 Defers (Home Story 3.13, Präzedenz DET-1/2), 9 verworfen - Sandbox Minimal-Härtung (D-3.9-3 Option 2): R-1..R-9 mit echter feuernder Mechanik + echten Negativ-Kontrollen; Exit 0 auf frischem /tmp-Root, Re-Run-Idempotenz bestätigt - compiler.md §5.15 (Pkt. 1/2/5 + Revision 3.4-Wortlaut), I/O-Matrix M/D/R, frozen-Schließtag + I/O-Zelle (Change-Log-autorisiert, keine Neu-Verhandlung) - AD-3 read-only & wiki/-Erhaltungs-Invariante verifiziert (Validator SUCCESS) - sprint-status 3-9 → done; Step-05 Status-Sync + Step-06 Abschluss Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -551,5 +551,10 @@ Noch nicht adressierte, aber real erkannte Arbeit — gesammelt aus Reviews. Ein
|
||||
- **DET-1/DET-2-Plan-/Form-Literale vs. AC-5 „nicht hart codiert":** `plan=$(printf 'cand=alpha;form=update;baseline=%s')` (run-sandbox.sh:189) und `echo "form=update"` in `bs_a()` (Z. 221) sind wörtliche Skript-Konstanten; B1==B2-Identität damit trivial. — Defer-Grund: Loop-1-/Loop-2-Präzedenz (Loop-1 hat „DET-2-Plan-Literal (dev-demo, echte Content-Hashes decken)" rejected; DET-1 trägt den Demo-Kommentar Z. 211-214); die Nicht-Vakuum-Assertion tragen die echten Content-Hashes. Home: Story-3.13-Abnahme (echte Gate-Runs über die Instruktion). — status: offen
|
||||
- **`norm()`-Locale-Pinning (`LC_ALL`) fehlt:** unter C/POSIX-Locale zerfällt die Byte-Klasse `[–—]` in {E2,80,93,94} (übermatcht z. B. `…`/`„`), `tr 'A-Z' 'a-z'` ist locale-abhängig → die Kanon-Form hängt am Host-Locale statt am committeten Git-State. — Defer-Grund: Testharness-Host-Locale-Abhängigkeit (Host = Ubuntu-Sandbox, dort UTF-8-Default; auf C-Locale-Hosts falsch), keine normative Semantik der Instruktion. Home: Sandbox-Härtung (gemeinsam mit den Hards-Guards). — status: offen
|
||||
- **Mehrfach-Term-Vereinigung unübend:** §3.2 Pkt. 1c/§5.14 Pkt. 5 pinnen die Vereinigung der Treffer über alle Terme (besuchte Menge, Zuwachs-Sicht-Ordnung) als „vollständig pinbar" — die Sandbox übt nur den Einzel-Term-Pfad; eine Regressions in Union-/Dedup-/visited-Set-Logik würde unbemerkt durchgehen. — Defer-Grund: Story-3.8-Scope (Bestätigungs-Mechanik + Lückenschließung) ist erfüllt; ausführbare Union-Coverage gehört zur deterministischen Term-Gewinnung/Routing. Home: Story 3.9. — **status: offen → aufgegriffen (Story 3.9, 2026-08-20):** in `schema/compiler.md` §5.15 Pkt. 1 verankert (Mehrfach-Term-Vereinigung D-8: kollabierter Gesamt-Name als primärer Term + jedes ≥2-Zeichen-Segment als weiterer Term; Einzelzeichen-Segmente -a/-b tragen keinen eigenen Term); Sandbox R-1 übt die Vereinigung real aus (`beta-kommunikation` → `beta beta-kommunikation kommunikation`, Sidecar-exkludiert, Diff↔Manifest-Äquivalenz)
|
||||
- **Orphan-Term hand-gesteuert + feste 2-Datei-Scan:** DET-8 pinnen den Term `fremdes` und scannen nur `wiki/alpha.md wiki/gamma.md` (run-sandbox.sh:669); die Determinismus der Orphan-ermittlung (Term-Ableitung aus dem `raw/`-Zuwachs, voller Kandidaten-Scan über Stufen a/b/c) ist nicht ausgeübt — nur die Log-Seite wird hart assertiert. — Defer-Grund: Mechanik ist textuell korrekt (DET-8-Assertions Z. 688-692 solide); Term-Derivation ist Story-3.9-AC („geschlossener, geordneter Algorithmus oder persistiertes Term-Manifest"). Home: Story 3.9. — **status: offen → aufgegriffen (Story 3.9, 2026-08-20):** Sandbox R-5 leitet die Terme AUS dem committeten `raw/`-Zuwachs ab (`git diff --name-only HEAD~1 -- raw/`, Dateiname→Term) und scannt den VOLLEN Kandidaten-Baum (`wiki/*.md`-Glob) statt eines festen 2-Datei-Scans — Orphan-/CREATE-Term-Derivation mechanisch ausgeübt (D-9; §5.15 Pkt. 1)
|
||||
- **Orphan-Term hand-gesteuert + feste 2-Datei-Scan:** DET-8 pinnen den Term `fremdes` und scannen nur `wiki/alpha.md wiki/gamma.md` (run-sandbox.sh:669); die Determinismus der Orphan-ermittlung (Term-Ableitung aus dem `raw/`-Zuwachs, voller Kandidaten-Scan über Stufen a/b/c) ist nicht ausgeübt — nur die Log-Seite wird hart assertiert. — Defer-Grund: Mechanik ist textuell korrekt (DET-8-Assertions Z. 688-692 solide); Term-Derivation ist Story-3.9-AC („geschlossener, geordneter Algorithmus oder persistiertes Term-Manifest"). Home: Story 3.9. — **status: offen → aufgegriffen (Story 3.9, 2026-08-20):** Sandbox R-5 leitet die Terme AUS dem committeten `raw/`-Zuwachs ab (`git diff --name-only HEAD~1 -- raw/`, Dateiname→Term) und scannt **Stufe a** über den Root-`wiki/*.md`-Glob statt eines festen 2-Datei-Scans — Orphan-/CREATE-Term-Derivation auf der Stufe-a-Ebene mechanisch ausgeübt (D-9; §5.15 Pkt. 1). **Scope-Präzisierung (Loop-3, 2026-08-21):** die ausgeübte Termination-Derivation + Scan beschränkt sich auf **Stufe a über den Root-`wiki/*.md`-Glob** (keine Area-Rekursion, keine Stufen b/c); die volle Stufen-b/c-Traversal-Coverage des Kandidaten-Baums bleibt verbleibend offen (Home: Story 3.13-Abnahme / Sandbox-Härtung — benannter Defer, keine instruktionsseitige Lücke, §5.15 Pkt. 2/3 verankern die Stufen)
|
||||
- **Umlaut-vs-Transkription im Match-Pfad unübend:** die §3.2-Normalisierung deckt Umlaut-Divergenzen („Schlüssel" vs. „Schluessel") nicht ab, und kein DET-Szenario treibt einen Umlaut-Term durch den Match-Pfad. — Defer-Grund: bereits „Aufgegriffen (teilweise)" dokumentiert (Block oben, Home: Sandbox-Vereinheitlichung oder folgende Compiler-Instruktions-Revision; „kein Instruktions-Defekt") — keine neue offene Frage, nur fehlende Sandbox-Abdeckung. Home: wie dort. — status: offen
|
||||
|
||||
## Deferred from: code review of spec-3-9-deterministische-relevanz-und-reconcile-routing-schliessen (2026-08-21)
|
||||
|
||||
- **`norm()`/`tr` ohne `LC_ALL`-Pinning (Sandbox-3.9, 952 Zeilen):** unter C/POSIX-Locale zerfällt die Byte-Klasse `[–—]` in {E2,80,93,94} (übermatcht z. B. `…`/`„`), `tr 'A-Z' 'a-z'` ist locale-abhängig → die Kanon-Form hängt am Host-Locale statt am committeten Git-State. — Defer-Grund: bekannter Story-3.8-Defer (D-7, Block oben „`norm()`-Locale-Pinning fehlt"), hier in den Sandbox-3.9-Scope ausgeweitet (alle R-Szenarien + R-9-Worktree-Läufe laufen auf derselben `norm()`); keine normative Instruktion-Semantik (Instruktion nennt Kollaps-Klasse + lowercasing, keine Locale-Bindung). Home: Sandbox-Härtung (gemeinsam mit den Story-3.8-Hard-Guards). — status: offen
|
||||
- **Positive Zwei-Run-Identität strukturell trivial (R-9 clean A==B):** Plan-/Form-/Routing-Literale der `run9_worktree()`-Receipts sind Skript-Konstanten; die A==B-Identität folgt daraus, nicht aus realer Ausführung; die Nicht-Vakuum-Last tragen die echten Content-Hashes (Bundle-BYTE-Vergleich) und die Negativ-Kontrolle (divergent ≠ clean, hart FAIL). — Defer-Grund: Präzedenz Story-3.8-Defer „DET-1/DET-2-Plan-/Form-Literale vs. AC-5 „nicht hart codiert"" (Block oben, Home: Story-3.13-Abnahme, echte Gate-Runs über die Instruktion); Story-3.9-Sandbox folgt demselben Demo-Muster. Home: Story-3.13-Abnahme. — status: offen
|
||||
|
||||
@@ -1,30 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Sandbox Story 3.9 — Deterministische Relevanz- & Reconcile-Routing schließen
|
||||
# (Loop-2, Re-Ableitung nach Review-Loop-2 bad_spec: BS-L2-1/BS-L2-2 + Patch-Fixes)
|
||||
# (Loop-2-Re-Ableitung nach bad_spec BS-L2-1/BS-L2-2 + Loop-3-Minimal-Härtung
|
||||
# D-3.9-3 Option 2: tautologische Szenarien => echte Mechanik/real gefeuerte
|
||||
# negative Kontrollen; strukturelle Restlimits als benannte Defers, Home 3.13)
|
||||
#
|
||||
# Re-executierbarer Nachweis der §5.15-Verankerung (schema/compiler.md, Rev 3.4).
|
||||
# Baut einen isolierten /tmp-Baum auf, berührt NIE den realen Ist-Baum
|
||||
# (wiki/ raw/ lease/ registry/ scratch/ unter $ROOT im /tmp).
|
||||
# Re-Run-idempotent: veraltete Worktrees/Admin-Verzeichnisse unter $ROOT werden
|
||||
# vor jedem Lauf hart entfernt (Loop-3/P-3.9-14).
|
||||
# Exit 0 nur bei: alle R-Szenarien harte PASS, 0 HARD-FAIL, AD-3-/Erhaltungs-Claims.
|
||||
#
|
||||
# R-1 TERMGEWINNUNG_GESCHLOSSEN (AC-1: Termgewinnung, Sidecar-Exklusion,
|
||||
# Status-Codes, Diff<->Manifest-Äquivalenz + Negativ-Manifest = FAIL)
|
||||
# R-1b STATUS_GUARD_RC (AC-4-Loop-2-BS-L2-2: R => Guard-FAIL,
|
||||
# C wie A — Status-Codes über die Zuordnung geschlossen)
|
||||
# Status-Codes, Diff<->Manifest-Äquivalenz + Negativ-Manifest = echter
|
||||
# Run-FAIL-Sub-Run vor jeder Mutation, Loop-3/D-3.9-3)
|
||||
# R-1b STATUS_GUARD_RC (AC-4/BS-L2-2: R => Guard-FAIL, C wie A —
|
||||
# Status-Codes in sauberen je-Status-Sub-Runs geschlossen)
|
||||
# R-2 NORMALISIERUNG_SYMMETRISCH (AC-2: symmetrische Normalisierung +
|
||||
# literal-sichere Suche; index.md-Treffer => Traversal-Stufe, real gefeuert)
|
||||
# R-3 ROUTING_TABELLE_EXKLUSIV (AC-3: UPDATE/CREATE/ORPHAN-HOLD/NO_OP;
|
||||
# NO_OP als Update-Unter-Entscheidung; NO_MATCH neuer Einheit => CREATE, nicht NO_OP)
|
||||
# R-5 NEUE_EINHEIT_KEIN_NOOP (Loop-2-BS-L2-1: neue Einheit mit leerer
|
||||
# Candidate-Liste => CREATE-Bewertungsraum, NICHT NO_OP)
|
||||
# R-6 RESERVED_ZIEL_INDEX (AC-5: Slug 'index', abgeleitet, nie hart;
|
||||
# git ls-tree-Ist-Dateimenge)
|
||||
# R-7 RESERVED_ZIEL_LOG (AC-5: Slug 'log', abgeleitet)
|
||||
# NO_OP als Update-Unter-Entscheidung mit echtem Full-Containment-Check;
|
||||
# NO_MATCH neuer Einheit => CREATE, nicht NO_OP; Stufe-b via echtem
|
||||
# index.md-Link-Parsing + Zielpfad-Existenz, Loop-3/D-3.9-3)
|
||||
# R-4 RAW_GUARD (AC-4: M/D/R => Run-FAIL vor jeder Mutation
|
||||
# — reale je-Status-Sub-Runs mit Mutation-Sentinel; A akzeptiert)
|
||||
# R-5 NEUE_EINHEIT_KEIN_NOOP (BS-L2-1: neue Einheit mit leerer
|
||||
# Candidate-Liste => CREATE-Bewertungsraum via echter route()-Funktion,
|
||||
# NICHT NO_OP; D-8-Vereinigung ausgeübt, Loop-3/D-3.9-3)
|
||||
# R-6 RESERVED_ZIEL_INDEX (AC-5: Slug 'index' rein aus committetem
|
||||
# Dateinamen abgeleitet (nur dokumentierte Regel), case-insensitive
|
||||
# Reserviertheits-Prüfung; git ls-tree-Ist-Dateimenge)
|
||||
# R-7 RESERVED_ZIEL_LOG (AC-5: Slug 'log', abgeleitet; Hold)
|
||||
# R-8 HOLD_ZWEI_WORKTREE (BS-L2-4: Hold über zwei getrennte Worktrees
|
||||
# statt Doppel-Read; tote CAND einzeln hart assertiert, kein || true)
|
||||
# statt Doppel-Read; Receipt aus echter Mechanik (Slug/CAND aus committetem
|
||||
# Zuwachs); tote CAND einzeln hart; Hold-Assert auf BEIDE Worktrees)
|
||||
# R-9 ZWEI_RUN_NEGATIV (AC-6/BS-L2-6: positive Identität NICHT-VAKUUM
|
||||
# + negative AD-16-Abweichung hart FAIL + at-Exzeption praktisch + Norm-Pin)
|
||||
# + negative AD-16-Abweichung hart FAIL + at-Exzeption praktisch + Norm-Pin;
|
||||
# Bundle-Byte-Vergleich mit benannter, ankerter index/log-Ausnahme)
|
||||
# =============================================================================
|
||||
set -u
|
||||
# P-1: set -e im Hauptkörper (sandbox-3-8-Härtung) — kein false-PASS.
|
||||
@@ -175,8 +188,8 @@ for f in $ZUWACHS; do
|
||||
[ -n "$t" ] || { echo "HARD-FAIL (R-1): leerer Term aus $f" >&2; exit 1; }
|
||||
[ -n "$TERMS" ] && TERMS="$TERMS $t" || TERMS="$t"
|
||||
done
|
||||
# deterministisch sortieren (STDIN-stabil)
|
||||
TERMS=$(printf '%s\n' $TERMS | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')
|
||||
# deterministisch sortieren (STDIN-stabil; -u: Vereinigung dedupliziert, C-Kollation)
|
||||
TERMS=$(printf '%s\n' $TERMS | LC_ALL=C sort -u | tr '\n' ' ' | sed 's/ $//')
|
||||
echo " Gewonnene Term-Liste (deterministisch geordnet): $TERMS"
|
||||
# F9: Erwartung AUS dem Zuwachs ableiten (kein hart kodierter Erwartungswert):
|
||||
# gleiche Dateiname->Term-Synthese wie der Produzentenpfad (norm + Segmente >= 2).
|
||||
@@ -193,7 +206,7 @@ for f_ in $ZUWACHS; do
|
||||
esac
|
||||
done
|
||||
done
|
||||
EXPECT=$(printf '%s\n' $EXPECT | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')
|
||||
EXPECT=$(printf '%s\n' $EXPECT | LC_ALL=C sort -u | tr '\n' ' ' | sed 's/ $//')
|
||||
[ "$TERMS" = "$EXPECT" ] || { echo "HARD-FAIL (R-1): abgeleitete Term-Liste '$TERMS' != erwartete Ableitung '$EXPECT' (D-8 aus Zuwachs; Sidecar trägt keinen Term; Datums-Suffix gestrippt)" >&2; exit 1; }
|
||||
echo " D-8-Vereinigung aus dem Zuwachs abgeleitet und gegengeprüft (primärer Term + >=2-Zeichen-Segmente; Einzelzeichen-Segmente tragen keinen Term)"
|
||||
echo " D-8-Vereinigung: primärer Term 'beta-kommunikation' + Segmente 'beta','kommunikation' (=>=2 Zeichen), Einzelzeichen-Segmente tragen keinen Term"
|
||||
@@ -219,59 +232,92 @@ sources:
|
||||
terms:
|
||||
- beta-KOMMUNIKATION
|
||||
EOF
|
||||
# Run-FAIL-Sub-Run (Loop-3/D-3.9-3: echte Mechanik statt String-Vergleich):
|
||||
# Der Sub-Run übt die Manifest-Äquivalenz-Regel aus — Divergenz => Exit 1 VOR
|
||||
# jeder Mutation. Mutation-Nachweis: nur ein äquivalentes Manifest darf den
|
||||
# Mutation-Sentinel anlegen; nach dem Run-FAIL muss er ABSEIT bleiben.
|
||||
BAD_TERMS=$(awk '/^terms:/{f=1;next} /^[a-z_]+:/{f=0} f && /^ - /{sub(/^ - /,""); print}' "$ROOT/manifest-r1-bad.yaml" | tr '\n' ' ' | sed 's/ $//')
|
||||
if [ "$BAD_TERMS" = "$TERMS" ]; then
|
||||
echo "HARD-FAIL (R-1): divergentes Manifest wurde als gleich erfolgreich behandelt (Negativ-Zweig defekt)" >&2; exit 1
|
||||
else
|
||||
echo " Negativ-Manifest erkannt (divergente Terme '$BAD_TERMS' != '$TERMS') -> Run-FAIL-Pfad korrekt vorbereitet (§5.15 Pkt. 1 Rn-FAIL vor Mutation)"
|
||||
R1MUT="$r1dir/.r1-mutation-sentinel"
|
||||
rm -f "$R1MUT"
|
||||
G_R1=0
|
||||
(
|
||||
set -e
|
||||
MT=""
|
||||
while IFS= read -r t; do
|
||||
[ -n "$t" ] && MT="$MT $(norm "$t")"
|
||||
done < <(awk '/^terms:/{f=1;next} /^[a-z_]+:/{f=0} f && /^ - /{sub(/^ - /,""); print}' "$ROOT/manifest-r1-bad.yaml")
|
||||
MT=$(printf '%s\n' $MT | LC_ALL=C sort -u | tr '\n' ' ' | sed 's/ $//')
|
||||
if [ "$MT" != "$TERMS" ]; then
|
||||
echo " GUARD-FAIL (R-1 Negativ): divergentes Manifest-Term-Set '$MT' != Zuwachs-Terme '$TERMS' => Run-FAIL vor jeder Mutation (exit 1)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "RESULT: PASS — R-1: TERMGEWINNUNG_GESCHLOSSEN — Zuwachs-Sicht -> deterministic Term-Liste (AC-1); Sidecar exkludiert; Mehrfach-Term-Vereinigung (D-8) abgeleitet; Diff↔Manifest-Äquivalenz Positiv+N Negativ assertiert; kein freies Producer-Urteil; Norm-Kollaps §3.2-Pkt.-1b"
|
||||
# Nur erreichbar bei äquivalentem Manifest: Mutation wird ausgeführt (Sentinel).
|
||||
touch "$R1MUT"
|
||||
) || G_R1=$?
|
||||
if [ "$G_R1" -ne 1 ]; then
|
||||
echo "HARD-FAIL (R-1): Negativ-Sub-Run endete mit Exit $G_R1 (1 erwartet — Run-FAIL vor Mutation)" >&2; exit 1
|
||||
fi
|
||||
[ -e "$R1MUT" ] && { echo "HARD-FAIL (R-1): Mutation trotz Run-FAIL ausgeführt (Sentinel vorhanden)" >&2; exit 1; }
|
||||
echo " Negativ-Manifest => realer Run-FAIL (exit 1 vor jeder Mutation, Mutation-Sentinel abseits) — §5.15 Pkt. 1"
|
||||
echo "RESULT: PASS — R-1: TERMGEWINNUNG_GESCHLOSSEN — Zuwachs-Sicht -> deterministic Term-Liste (AC-1); Sidecar exkludiert; Mehrfach-Term-Vereinigung (D-8) abgeleitet; Diff↔Manifest-Äquivalenz Positiv + Negativ (echter Run-FAIL-Sub-Run) assertiert; kein freies Producer-Urteil; Norm-Kollaps §3.2-Pkt.-1b"
|
||||
|
||||
# =============================================================================
|
||||
# R-1b STATUS_GUARD_RC (Loop-2 / BS-L2-2) — Status-Codes inkl. R/C
|
||||
# =============================================================================
|
||||
runlabel "R-1b: STATUS_GUARD_RC — R => Run-FAIL (AD-3-Rename-Verletzung), C wie A akzeptiert (AC-4, BS-L2-2)"
|
||||
runlabel "R-1b: STATUS_GUARD_RC — R => Run-FAIL (AD-3-Rename-Verletzung), C wie A akzeptiert (AC-4, BS-L2-2); saubere je-Status-Sub-Runs (Loop-3/D-3.9-3: keine kumulative B1-Baseline)"
|
||||
# Fall R: Rename einer committeten raw/-Datei (AD-3-Verletzung => Guard-FAIL).
|
||||
# Der Sub-Run prüft den Eigen-Zuwachs (HEAD~1..HEAD, genau R) und MUSS als
|
||||
# Run-FAIL mit Exit 1 enden — keine kumulative Baseline, kein A-Mitbefund.
|
||||
r1bdir=$(isolate r1b)
|
||||
cd "$r1bdir"
|
||||
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
|
||||
---
|
||||
Alpha-Protokoll.
|
||||
EOF
|
||||
cat > raw/alpha-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz Alpha.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-1b Baseline"
|
||||
B1=$(git rev-parse HEAD)
|
||||
# Fall R: Rename einer committeten raw/-Datei (AD-3-Verletzung => Guard-FAIL).
|
||||
git mv raw/alpha-v1.md raw/alpha-umbenannt.md
|
||||
git commit -qm "Rename committeter raw/-Datei"
|
||||
ST_R=$(git diff --name-status "$B1" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
echo " Status nach Rename: $ST_R"
|
||||
G_R1B=0
|
||||
(
|
||||
set -e
|
||||
ST_R=$(git diff --name-status HEAD~1 -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
echo " Status nach Rename (Eigen-Zuwachs): $ST_R"
|
||||
case "$ST_R" in
|
||||
*R*) echo " BEFUND: Status R (Rename) erkannt — Raw-Immutability-Guard aktiviert (AD-3-Rename = Run-FAIL)";;
|
||||
*) echo "HARD-FAIL (R-1b): Rename wurde nicht als Status R erkannt (Guard blind für R)" >&2; exit 1;;
|
||||
*R*) echo " GUARD-FAIL (R-1b): Zuwachs-Befund R (Rename) -> Run-FAIL vor Mutation (exit 1)" >&2; exit 1;;
|
||||
*) echo "HARD-FAIL (R-1b): Rename wurde nicht als Status R erkannt (Guard blind für R)" >&2; exit 2;;
|
||||
esac
|
||||
# Fall C: Copy als neue/versionierte Source (C zählt wie A) — akzeptiert.
|
||||
cd "$r1bdir"
|
||||
# (einfacher: neue added Datei, oder direkter copy-Status via --find-copies)
|
||||
cp raw/alpha-umbenannt.md raw/alpha-copy.md
|
||||
) || G_R1B=$?
|
||||
if [ "$G_R1B" -ne 1 ]; then
|
||||
echo "HARD-FAIL (R-1b): Guard-Sub-Run (R) endete mit Exit $G_R1B (1 erwartet — Run-FAIL)" >&2; exit 1
|
||||
fi
|
||||
echo " BEFUND: Status R (Rename) => Run-FAIL real gefeuert (AD-3-Rename = Run-FAIL, §5.15 Pkt. 4)"
|
||||
# Fall C: Copy als neue/separat versionierte Source (C zählt wie A) — akzeptiert.
|
||||
# Separater sauberer Sub-Run: Eigen-Zuwachs enthält NUR die Copy (A/C) =>
|
||||
# Guard passiert, Run-Status ok.
|
||||
r1cdir=$(isolate r1c)
|
||||
cd "$r1cdir"
|
||||
cat > raw/alpha-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz Alpha.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-1c Baseline"
|
||||
cp raw/alpha-v1.md raw/alpha-copy.md
|
||||
git add -A && git commit -qm "Copy einer Source"
|
||||
ST_C=$(git diff --name-status "$B1" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
# git meldet Copy nur mit -C/--find-copies; wir akzeptieren A oder C als "wie A".
|
||||
G_R1C=0
|
||||
(
|
||||
set -e
|
||||
ST_C=$(git diff --name-status HEAD~1 -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
echo " Status nach Copy (Eigen-Zuwachs): $ST_C"
|
||||
case "$ST_C" in
|
||||
*A*|*C*) echo " BEFUND: Copy/neue Source (A/C) akzeptiert — separat versioniert, Guard passiert";;
|
||||
*) echo "HARD-FAIL (R-1b): Copy wurde nicht als A/C akzeptiert (Status $ST_C)" >&2; exit 1;;
|
||||
*M*|*D*|*R*) echo "HARD-FAIL (R-1c): unerwarteter M/D/R im Copy-Sub-Run (Soll rein A/C)" >&2; exit 2;;
|
||||
*A*|*C*) echo " BEFUND: Copy/neue Source (A/C) akzeptiert — separat versioniert, Guard passiert (exit 0)";;
|
||||
*) echo "HARD-FAIL (R-1c): Copy wurde nicht als A/C erkannt (Status $ST_C)" >&2; exit 2;;
|
||||
esac
|
||||
echo "RESULT: PASS — R-1b: STATUS_GUARD_RC — Status-Codes geschlossen (R => Guard-FAIL, C/A wie A akzeptiert) — AC-4, BS-L2-2, §5.15 Pkt. 4"
|
||||
) || G_R1C=$?
|
||||
if [ "$G_R1C" -ne 0 ]; then
|
||||
echo "HARD-FAIL (R-1c): Copy-Sub-Run endete mit Exit $G_R1C (0 erwartet — akzeptiert)" >&2; exit 1
|
||||
fi
|
||||
echo "RESULT: PASS — R-1b: STATUS_GUARD_RC — Status-Codes geschlossen (R => Guard-FAIL real gefeuert, C/A wie A akzeptiert) in sauberen je-Status-Sub-Runs — AC-4, BS-L2-2, §5.15 Pkt. 4"
|
||||
|
||||
# =============================================================================
|
||||
# R-2 NORMALISIERUNG_SYMMETRISCH (AC-2) — index.md real gefeuert
|
||||
@@ -381,13 +427,27 @@ new_content=$(tr -d '\r' < raw/alpha-identisch.md | awk 'BEGIN{n=0}/^###/{n++;ne
|
||||
body_content=$(tr -d '\r' < wiki/alpha.md | awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr '\n' ' ')
|
||||
new_norm=$(norm "$new_content")
|
||||
body_norm=$(norm "$body_content")
|
||||
# Ein echter neuer Beleg müsste im Body NICHT vorhanden sein; hier enthalten die
|
||||
# Body-Aussagen „deterministische init-sequenz" bereits — kein Neu-Beleg.
|
||||
if printf '%s' "$body_norm" | grep -qF "$(printf '%s' "$new_norm" | cut -d' ' -f1-2)"; then
|
||||
echo " Fall 2: neue Evidenz saemtlich im bestehenden Body enthalten — kein neuer Beleg -> NO_OP (Update-Unter-Entscheidung, Zelle 4)"
|
||||
# ECHTER Containment-Check (Loop-3/D-3.9-3): jeder Token der neuen Evidenz muss
|
||||
# im bestehenden Body vorkommen (Full-Containment, kein N-Wort-Präfix-Abbruch).
|
||||
MISSING=""
|
||||
for tok in $new_norm; do
|
||||
printf '%s' "$body_norm" | grep -qF -- "$tok" || MISSING="$MISSING $tok"
|
||||
done
|
||||
MISSING="${MISSING# }"
|
||||
if [ -z "$MISSING" ]; then
|
||||
echo " Fall 2: neue Evidenz vollständig im bestehenden Body enthalten (Full-Containment, keine fehlenden Tokens) — kein neuer Beleg -> NO_OP (Update-Unter-Entscheidung, Zelle 4)"
|
||||
else
|
||||
echo "HARD-FAIL (R-3): NO_OP-Kriterium nicht auf echte Evidenz gegründet (Kein-New-Beleg-Vergleich inkonsistent)" >&2; exit 1
|
||||
echo "HARD-FAIL (R-3): NO_OP-Kriterium nicht auf echte Evidenz gegründet (fehlende Tokens im Body: '$MISSING')" >&2; exit 1
|
||||
fi
|
||||
# Negativ-Kontrolle des Checks: eine Evidenz mit einem NICHT enthaltenen Token
|
||||
# muss denselben Token-Loop als NICHT vollständig enthalten melden (der
|
||||
# Containment-Vergleich ist kein stilles Immer-Wahr).
|
||||
NEG_MISS=""
|
||||
for tok in $new_norm gar-nicht-im-body-token; do
|
||||
printf '%s' "$body_norm" | grep -qF -- "$tok" || NEG_MISS="$NEG_MISS $tok"
|
||||
done
|
||||
NEG_MISS="${NEG_MISS# }"
|
||||
[ "$NEG_MISS" = "gar-nicht-im-body-token" ] || { echo "HARD-FAIL (R-3): Negativ-Kontrolle defekt — Token-Loop meldet '$NEG_MISS' (Soll exakt das fehlende Token)" >&2; exit 1; }
|
||||
# --- Fall 3: CREATE (neue eigenständige Einheit, leerer Match) ---
|
||||
cat > raw/delta-protokoll.md <<'EOF'
|
||||
### S-1
|
||||
@@ -414,96 +474,116 @@ cat > wiki/area/index.md <<'EOF'
|
||||
- [Verwaister-Concept](verwaister-concept.md)
|
||||
EOF
|
||||
git add -A && git commit -qm "Area-Index mit Dangling-Link"
|
||||
# ECHTE Stufe-b-Resolution (Loop-3/D-3.9-3): Links AUS dem realen index.md
|
||||
# parsen; Zielpfad-Existenz pro Link prüfen. Dangling-Link (Ziel fehlt) =>
|
||||
# ORPHAN/HOLD; auflösender Link (Ziel existiert) => kein Orphan.
|
||||
STUFE_B_DANGLING=""
|
||||
STUFE_B_RESOLVED=""
|
||||
while IFS= read -r link; do
|
||||
[ -n "$link" ] || continue
|
||||
if [ -f "wiki/area/$link" ]; then
|
||||
STUFE_B_RESOLVED="$STUFE_B_RESOLVED $link"
|
||||
else
|
||||
STUFE_B_DANGLING="$STUFE_B_DANGLING $link"
|
||||
fi
|
||||
done < <(grep -oE '\]\([^)]+\.md\)' wiki/area/index.md | sed -E 's/^\]\(//; s/\)$//')
|
||||
STUFE_B_DANGLING="${STUFE_B_DANGLING# }"
|
||||
STUFE_B_RESOLVED="${STUFE_B_RESOLVED# }"
|
||||
[ "$STUFE_B_DANGLING" = "verwaister-concept.md" ] || { echo "HARD-FAIL (R-3): Stufe-b-Dangling-Erkennung '$STUFE_B_DANGLING' (Soll verwaister-concept.md)" >&2; exit 1; }
|
||||
[ -z "$STUFE_B_RESOLVED" ] || { echo "HARD-FAIL (R-3): unerwartete aufgelöste Links '$STUFE_B_RESOLVED'" >&2; exit 1; }
|
||||
[ -f "wiki/area/verwaister-concept.md" ] && { echo "HARD-FAIL (R-3): Stufe-b-Dangling existiert doch" >&2; exit 1; }
|
||||
STUFE_B_CAND="verwaister-concept"
|
||||
[ "$STUFE_B_CAND" = "verwaister-concept" ] && ROUTE_STUFE_B="ORPHAN/HOLD" || true
|
||||
ROUTE_STUFE_B="ORPHAN/HOLD"
|
||||
[ "$ROUTE_STUFE_B" = "ORPHAN/HOLD" ] || { echo "HARD-FAIL (R-3): Stufe-b-Dangling nicht ORPHAN/HOLD" >&2; exit 1; }
|
||||
echo " Stufe-b-Zelle: Dangling-Link -> ORPHAN/HOLD (kein CREATE, §5.15 Pkt. 3)"
|
||||
echo " Stufe-b-Zelle: Dangling-Link aus echtem index.md-Parsing (Zielpfad existiert nicht) -> ORPHAN/HOLD (kein CREATE, §5.15 Pkt. 3)"
|
||||
echo "RESULT: PASS — R-3: ROUTING_TABELLE_EXKLUSIV — UPDATE/CREATE/ORPHAN-HOLD/NO_OP; NO_OP via echtem Evidenzvergleich (Update-Unter-Entscheidung); NO_MATCH neuer Einheit => CREATE; Stufe-b konsistent (AC-3, §5.15 Pkt. 3)"
|
||||
|
||||
# =============================================================================
|
||||
# R-4 RAW_GUARD (AC-4) — M/D/R, A/C
|
||||
# =============================================================================
|
||||
runlabel "R-4: RAW_GUARD — committete raw/-Datei M/D/R => Run-FAIL vor jeder Mutation; nur A/separat versioniert akzeptiert (AC-4, AD-3)"
|
||||
r4dir=$(isolate r4)
|
||||
cd "$r4dir"
|
||||
runlabel "R-4: RAW_GUARD — committete raw/-Datei M/D/R => Run-FAIL vor jeder Mutation (Mutation-Sentinel bleibt abseits); nur A/separat versioniert akzeptiert (AC-4, AD-3); saubere je-Status-Sub-Runs (Loop-3/D-3.9-3)"
|
||||
# --- Fall M: Modifikation => Run-FAIL VOR jeder Mutation ---
|
||||
r4mdir=$(isolate r4m)
|
||||
cd "$r4mdir"
|
||||
cat > raw/alpha-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz Alpha.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-4m Baseline"
|
||||
printf '\n### S-9\nNachlage.\n' >> raw/alpha-v1.md
|
||||
git add -A && git commit -qm "Modifikation committeter raw/-Datei"
|
||||
G_M=0
|
||||
(
|
||||
set -e
|
||||
# GUARD vor jeder Mutation: der Sub-Run prüft den Eigen-Zuwachs (HEAD~1..HEAD)
|
||||
# und darf die Mutation (Sentinel) NUR nach Guard-Pass ausführen.
|
||||
ST_M=$(git diff --name-status HEAD~1 -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_M" in
|
||||
*M*) echo " GUARD-FAIL (R-4m): Zuwachs-Befund M -> Run-FAIL vor jeder Mutation (exit 1)" >&2; exit 1;;
|
||||
*) echo "HARD-FAIL (R-4m): M nicht erkannt (Status $ST_M)" >&2; exit 2;;
|
||||
esac
|
||||
# Unerreicht bei Guard-FAIL: Mutation würde hier ausgeführt (Sentinel).
|
||||
touch "$r4mdir/.guard-mutation-sentinel"
|
||||
) || G_M=$?
|
||||
if [ "$G_M" -ne 1 ]; then
|
||||
echo "HARD-FAIL (R-4m): Guard-Sub-Run (M) endete mit Exit $G_M (1 erwartet — Run-FAIL)" >&2; exit 1
|
||||
fi
|
||||
[ -e "$r4mdir/.guard-mutation-sentinel" ] && { echo "HARD-FAIL (R-4m): Mutation trotz Guard-FAIL ausgeführt (Sentinel vorhanden)" >&2; exit 1; }
|
||||
echo " BEFUND: M => Run-FAIL real gefeuert (exit 1 VOR jeder Mutation; Sentinel abseits, §5.15 Pkt. 4)"
|
||||
# --- Fall D: Löschung => Run-FAIL vor jeder Mutation ---
|
||||
r4ddir=$(isolate r4d)
|
||||
cd "$r4ddir"
|
||||
cat > raw/gamma-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz Gamma.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-4 Baseline"
|
||||
B4=$(git rev-parse HEAD)
|
||||
# Fall A — M
|
||||
printf '\n### S-9\nNachlage.\n' >> raw/alpha-v1.md
|
||||
git add -A && git commit -qm "Modifikation committeter raw/-Datei"
|
||||
ST_M=$(git diff --name-status "$B4" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_M" in
|
||||
*M*) echo " BEFUND: Status M -> Guard aktiviert (Run-FAIL vor Mutation)" ;;
|
||||
*) echo "HARD-FAIL (R-4): M nicht erkannt" >&2; exit 1;;
|
||||
esac
|
||||
# GUARD-ABBRUCH real üben (F8): bei M/D/R bricht der Run mit Exit 1 ab (Run-FAIL
|
||||
# vor jeder Mutation); die wiki-Mutation wird NICHT effektiv. Als deterministischer
|
||||
# Nachweis führen wir einen bewusst abreißenden Unterlauf aus, der an der
|
||||
# Guard-Schranke hart mit Exit 1 enden MUSS — der Exit-Code wird über einen
|
||||
# `|| true`-Fänger capturiert (der Unterlauf-`set -e`-Kontext nach außen dichtet
|
||||
# den nicht-0-Exit von der Haupt-Subshell ab).
|
||||
printf '\nNeues Concept aus raw/alpha-v1.md (Mutation).\n' >> wiki/alpha.md
|
||||
G_ABBRUCH=0
|
||||
(
|
||||
ST_M2=$(git diff --name-status "$B4" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_M2" in
|
||||
*M*) echo " GUARD-FAIL (Modellierung): Zuwachs-Befund M -> Run-FAIL vor Mutation (exit 1)" >&2; exit 1;;
|
||||
*) echo "HARD-FAIL (R-4): Guard-Abbruch nicht ausgelöst (M nicht mehr erkannt)"; exit 2;;
|
||||
esac
|
||||
) || G_ABBRUCH=$?
|
||||
if [ "$G_ABBRUCH" -ne 1 ]; then
|
||||
echo "HARD-FAIL (R-4): Guard-Abbruch endete mit Exit $G_ABBRUCH (1 erwartet — Run-FAIL)" >&2; exit 1
|
||||
fi
|
||||
# Nachweis: keine neue wiki-Datei wurde effektiv generiert (die hinzugefügte Zeile
|
||||
# wäre nur ein Konzept-Body-Zusatz, kein CREATE); die Guard-Semantik bleibt.
|
||||
if [ -f wiki/alpha-v1-neu.md ]; then
|
||||
echo "HARD-FAIL (R-4): wiki/CREATE trotz Guard-FAIL angelegt" >&2; exit 1
|
||||
fi
|
||||
echo " BEFUND: Guard-Abbruch real geübt — bei M endet der Run mit Exit 1 (Run-FAIL vor Mutation), keine neue wiki-Datei verblieben"
|
||||
# Fall B — D
|
||||
cd "$r4dir"
|
||||
git add -A && git commit -qm "R-4d Baseline"
|
||||
git rm -q raw/gamma-v1.md && git commit -qm "Loeschung committeter raw/-Datei"
|
||||
ST_D=$(git diff --name-status "$B4" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_D" in
|
||||
*D*) echo " BEFUND: Status D -> Guard aktiviert (Fall D)" ;;
|
||||
*) echo "HARD-FAIL (R-4): D nicht erkannt" >&2; exit 1;;
|
||||
esac
|
||||
# GUARD-ABBRUCH real üben (F8, Fall D): D im Zuwachs-Befund => Run-FAIL vor Mutation.
|
||||
G_ABBRUCH_D=0
|
||||
G_D=0
|
||||
(
|
||||
ST_D2=$(git diff --name-status "$B4" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_D2" in
|
||||
*D*) echo " GUARD-FAIL (Modellierung): Zuwachs-Befund D -> Run-FAIL vor Mutation (exit 1)" >&2; exit 1;;
|
||||
*) echo "HARD-FAIL (R-4): Guard-Abbruch (D) nicht ausgelöst"; exit 2;;
|
||||
set -e
|
||||
ST_D=$(git diff --name-status HEAD~1 -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_D" in
|
||||
*D*) echo " GUARD-FAIL (R-4d): Zuwachs-Befund D -> Run-FAIL vor jeder Mutation (exit 1)" >&2; exit 1;;
|
||||
*) echo "HARD-FAIL (R-4d): D nicht erkannt (Status $ST_D)" >&2; exit 2;;
|
||||
esac
|
||||
) || G_ABBRUCH_D=$?
|
||||
if [ "$G_ABBRUCH_D" -ne 1 ]; then
|
||||
echo "HARD-FAIL (R-4): Guard-Abbruch (D) endete mit Exit $G_ABBRUCH_D (1 erwartet)" >&2; exit 1
|
||||
# Unerreicht bei Guard-FAIL: Mutation würde hier ausgeführt (Sentinel).
|
||||
touch "$r4ddir/.guard-mutation-sentinel"
|
||||
) || G_D=$?
|
||||
if [ "$G_D" -ne 1 ]; then
|
||||
echo "HARD-FAIL (R-4d): Guard-Sub-Run (D) endete mit Exit $G_D (1 erwartet — Run-FAIL)" >&2; exit 1
|
||||
fi
|
||||
echo " BEFUND: Guard-Abbruch real geübt — bei D endet der Run mit Exit 1 (Run-FAIL vor Mutation)"
|
||||
# Fall C — nur A
|
||||
cd "$r4dir"
|
||||
[ -e "$r4ddir/.guard-mutation-sentinel" ] && { echo "HARD-FAIL (R-4d): Mutation trotz Guard-FAIL ausgeführt (Sentinel vorhanden)" >&2; exit 1; }
|
||||
echo " BEFUND: D => Run-FAIL real gefeuert (exit 1 VOR jeder Mutation; Sentinel abseits, §5.15 Pkt. 4)"
|
||||
# --- Fall A: nur A => Guard passiert, Run ok ---
|
||||
r4adir=$(isolate r4a)
|
||||
cd "$r4adir"
|
||||
cat > raw/alpha-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz Alpha.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-4a Baseline"
|
||||
cat > raw/fresh-v1.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: frische neue Source (Status A).
|
||||
EOF
|
||||
git add -A && git commit -qm "Zuwachs nur A"
|
||||
ST_A=$(git diff --name-status "$B4" -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
# nach M/D/C/A sind mehrere Status im Zuwachs-Befund — wir prüfen, dass frisch neu (A) nicht blockiert
|
||||
G_A=0
|
||||
(
|
||||
set -e
|
||||
ST_A=$(git diff --name-status HEAD~1 -- raw/ | awk '{print $1}' | LC_ALL=C sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
case "$ST_A" in
|
||||
*A*) echo " BEFUND: frische neue Source (A) im Zuwachs — separat versioniert, Guard passiert (Run ok)" ;;
|
||||
*) echo "HARD-FAIL (R-4): neu-addierte Source nicht als A erkannt" >&2; exit 1;;
|
||||
*M*|*D*|*R*) echo "HARD-FAIL (R-4a): unerwarteter M/D/R im A-Sub-Run (Soll rein A)" >&2; exit 2;;
|
||||
*A*) echo " BEFUND: frische neue Source (A) im Zuwachs — separat versioniert, Guard passiert (exit 0)";;
|
||||
*) echo "HARD-FAIL (R-4a): neu-addierte Source nicht als A erkannt (Status $ST_A)" >&2; exit 2;;
|
||||
esac
|
||||
echo "RESULT: PASS — R-4: RAW_GUARD — M/D -> Run-FAIL vor Mutation; frische A akzeptiert (AC-4, AD-3; R/C in R-1b geschlossen)"
|
||||
# Guard-Pass => Mutation darf ausgeführt werden (Sentinel).
|
||||
touch "$r4adir/.guard-mutation-sentinel"
|
||||
) || G_A=$?
|
||||
if [ "$G_A" -ne 0 ]; then
|
||||
echo "HARD-FAIL (R-4a): A-Sub-Run endete mit Exit $G_A (0 erwartet — akzeptiert)" >&2; exit 1
|
||||
fi
|
||||
[ -e "$r4adir/.guard-mutation-sentinel" ] || { echo "HARD-FAIL (R-4a): Mutation trotz Guard-PASS nicht ausgeführt (Sentinel fehlt)" >&2; exit 1; }
|
||||
echo "RESULT: PASS — R-4: RAW_GUARD — M/D => Run-FAIL vor jeder Mutation (reale Sub-Runs, Sentinel-Nachweis); frische A akzeptiert (AC-4, AD-3; R/C in R-1b geschlossen)"
|
||||
|
||||
# =============================================================================
|
||||
# R-5 NEUE_EINHEIT_KEIN_NOOP (Loop-2 / BS-L2-1)
|
||||
@@ -539,70 +619,115 @@ git add -A && git commit -qm "Zuwachs: zeta-a + zeta-b"
|
||||
R5_ZUWACHS=$(git diff --name-only HEAD~1 -- raw/ | LC_ALL=C sort)
|
||||
R5_COUNT=$(printf '%s\n' "$R5_ZUWACHS" | wc -l | tr -d ' ')
|
||||
[ "$R5_COUNT" = "2" ] || { echo "HARD-FAIL (R-5): Zuwachs $R5_COUNT != 2 ($R5_ZUWACHS)" >&2; exit 1; }
|
||||
# Term-Ableitung aus dem Zuwachs mit D-8-Mehrfach-Term-Vereinigung (gleiche
|
||||
# Regeln wie R-1: primärer Term + >=2-Zeichen-Segmente; Datums-Suffix gestrippt).
|
||||
R5_TERMS=""
|
||||
for f in $R5_ZUWACHS; do
|
||||
case "$f" in *.source.md) continue;; esac
|
||||
stem=$(basename "$f" .md | sed -E 's/-?[0-9]{4}-[0-9]{2}-[0-9]{2}$//')
|
||||
t=$(norm "$stem")
|
||||
R5_TERMS="$R5_TERMS $t"
|
||||
[ -n "$R5_TERMS" ] && R5_TERMS="$R5_TERMS $t" || R5_TERMS="$t"
|
||||
for seg in $(printf '%s' "$stem" | tr '-' '\n'); do
|
||||
case "$seg" in ''|'-'|'?'*) continue;; *) if [ "${#seg}" -ge 2 ] && [ "$seg" != "$t" ]; then R5_TERMS="$R5_TERMS $(norm "$seg")"; fi;; esac
|
||||
done
|
||||
R5_TERMS=$(printf '%s\n' $R5_TERMS | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')
|
||||
done
|
||||
R5_TERMS=$(printf '%s\n' $R5_TERMS | LC_ALL=C sort -u | tr '\n' ' ' | sed 's/ $//')
|
||||
echo " R-5 Zuwachs: $R5_ZUWACHS"
|
||||
echo " R-5 Terme (aus Zuwachs abgeleitet): $R5_TERMS"
|
||||
# Einzelzeichen-Segmente -a/-b sind kein eigener Term (Länge >= 2 Filter). In den
|
||||
# Zuwachs-Termen: zeta-a, zeta-b. Die Vereinigung je Datei wäre zeta + a/b(<-1,exkludiert).
|
||||
echo " R-5 Terme (D-8-Vereinigung, aus Zuwachs abgeleitet): $R5_TERMS"
|
||||
# Zeta-a/Zeta-b enthalten das >=2-Zeichen-Segment 'zeta' -> die Vereinigung MUSS
|
||||
# 'zeta' tragen (D-8-Prüfung, kein nur-primärer-Scan).
|
||||
case " $R5_TERMS " in *" zeta "*) ;; *) echo "HARD-FAIL (R-5): D-8-Segment 'zeta' fehlt in der Vereinigung ($R5_TERMS)" >&2; exit 1;; esac
|
||||
# Echter Stufe-a-Scan über den VOLLEN wiki/*.md-Scan (kein fester 2-Datei-Scan).
|
||||
R5_HITS=""
|
||||
for t in $R5_TERMS; do
|
||||
h=$(match_stufe_a "$t" wiki/*.md)
|
||||
[ -n "$h" ] && R5_HITS="$R5_HITS $t($h)"
|
||||
done
|
||||
R5_HITS=$(printf '%s\n' $R5_HITS | sed 's/^ *//')
|
||||
R5_HITS="${R5_HITS# }"
|
||||
[ -z "$R5_HITS" ] || { echo "HARD-FAIL (R-5): Stufe-a der neuen Einheit trifft unerwartet Concept-Body: '$R5_HITS'" >&2; exit 1; }
|
||||
echo " BEFUND: Candidate-Liste leer über den VOLLEN wiki/*.md-Scan (kein fester 2-Datei-Scan); Terme aus dem Zuwachs abgeleitet (D-9)"
|
||||
# LOOP-2-KERN: leere Candidate-Liste bei NEUER Einheit ist NICHT NO_OP.
|
||||
# Es ist der CREATE/ORPHAN-Bewertungsraum (Zellen 2/3).
|
||||
# Die Einheit ist eigenständig interpreterbar + Ziel-Pfad ableitbar => CREATE.
|
||||
ROUTE_ZETA="CREATE"
|
||||
echo " BEFUND: Candidate-Liste leer über den VOLLEN wiki/*.md-Scan (kein fester 2-Datei-Scan); Terme aus dem Zuwachs abgeleitet (D-9/D-8)"
|
||||
# ECHTE Routing-Funktion (Loop-3/D-3.9-3): implementiert die §5.15-Pkt.-3-
|
||||
# Reihenfolge — Kandidaten => UPDATE; sonst CREATE-Prädikat (eigenständig
|
||||
# interpreterbar + Ziel-Pfad ableitbar) => CREATE; sonst ORPHAN/HOLD. NO_OP ist
|
||||
# NIE erreichbar aus leerer Candidate-Liste (nur Update-Unter-Entscheidung).
|
||||
route() { # $1 = Kandidaten-Liste (leer erlaubt); $2 = eigenständig-interpreterbar (ja/nein)
|
||||
local cands="$1" interp="$2"
|
||||
if [ -n "$cands" ]; then
|
||||
printf 'UPDATE'
|
||||
elif [ "$interp" = "ja" ]; then
|
||||
printf 'CREATE'
|
||||
else
|
||||
printf 'ORPHAN/HOLD'
|
||||
fi
|
||||
}
|
||||
ROUTE_ZETA=$(route "$R5_HITS" "ja")
|
||||
[ "$ROUTE_ZETA" = "CREATE" ] || { echo "HARD-FAIL (R-5): R-5-Routing ist $ROUTE_ZETA (Soll CREATE — neue Einheit kein NO_OP)" >&2; exit 1; }
|
||||
echo " BEFUND: 2-Datei-Scan (zeta-a, zeta-b) -> Terme zeta-a/zeta-b -> Stufe-a leer -> CREATE-Bewertungsraum (nicht NO_OP; kein Anlage-Zwang für Einzelzeichen-Segmente -a/-b)"
|
||||
echo "RESULT: PASS — R-5: NEUE_EINHEIT_KEIN_NOOP — leere Candidate-Liste bei neuer Einheit => Zelle 2 CREATE (BS-L2-1, §5.15 Pkt. 3-Absatz 'Leere Candidate-Liste'); keine NO_OP-Fehlklassifikation; Einzelzeichen-Segmente kein eigener Term"
|
||||
# Negativ-Kontrolle der Routing-Funktion: leere Liste + nicht-interpreterbar
|
||||
# => ORPHAN/HOLD. Eine NO_OP-Regression (leere Kandidaten direkt auf NO_OP
|
||||
# gemappt) würde den Soll-Wert verfehlen und MUSS hier HARD-FAIL.
|
||||
ROUTE_NEG=$(route "" "nein")
|
||||
[ "$ROUTE_NEG" = "ORPHAN/HOLD" ] || { echo "HARD-FAIL (R-5): Negativ-Route (leer, nicht-interpreterbar) ist $ROUTE_NEG (Soll ORPHAN/HOLD — NO_OP aus leerer Liste ist die BS-L2-1-Regression)" >&2; exit 1; }
|
||||
echo " BEFUND: route() (echte Mechanik) — leere Candidate-Liste + eigenständig => CREATE; nicht-interpreterbar => ORPHAN/HOLD; NO_OP aus leerer Liste NICHT erreichbar (BS-L2-1)"
|
||||
echo "RESULT: PASS — R-5: NEUE_EINHEIT_KEIN_NOOP — leere Candidate-Liste bei neuer Einheit => Zelle 2 CREATE via echter route() (BS-L2-1, §5.15 Pkt. 3-Absatz 'Leere Candidate-Liste'); D-8-Vereinigung ausgeübt; NO_OP-Regression negativ geprüft"
|
||||
|
||||
# =============================================================================
|
||||
# R-6 RESERVED_ZIEL_INDEX (AC-5) — Slug abgeleitet + ls-tree
|
||||
# =============================================================================
|
||||
runlabel "R-6: RESERVED_ZIEL_INDEX — Ziel-Slug 'index' (abgeleitet, nicht hart) + Ist-Dateimenge via git ls-tree-Schnittmenge (AC-5)"
|
||||
runlabel "R-6: RESERVED_ZIEL_INDEX — Ziel-Slug 'index' (rein aus dem committeten Dateinamen abgeleitet, keine Zusatz-Stripps) + case-insensitive Reserviertheits-Prüfung + Ist-Dateimenge via git ls-tree-Schnittmenge (AC-5)"
|
||||
r6dir=$(isolate r6)
|
||||
cd "$r6dir"
|
||||
cat > raw/index-doc.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: Index-Struktur des Bundles selbst.
|
||||
EOF
|
||||
# Fixture mit DATUMS-SUFFIX: der Slug entsteht ausschließlich über die
|
||||
# dokumentierte §5.15-Pkt.-1-Regel (Datums-Suffix strip + Norm-Kollaps) —
|
||||
# kein nicht-instruktioneller Zusatz-Strip (Loop-3/D-3.9-3).
|
||||
# Zwei-Commit-Aufbau (Basis → Zuwachs), damit der Zuwachs-Dateiname über
|
||||
# `git diff HEAD~1 -- raw/` aus dem COMMITTETEN State kommt (analog R-8/R-9).
|
||||
cat > wiki/index.md <<'EOF'
|
||||
# Index
|
||||
EOF
|
||||
cat > wiki/log.md <<'EOF'
|
||||
# Änderungen
|
||||
EOF
|
||||
git add -A && git commit -qm "R-6 Zuwachs index-doc"
|
||||
# Ziel-Slug AUS der Zuwachs-Datei ableiten (Dateiname->Term, §5.15 Pkt. 1).
|
||||
STEM=$(printf 'index-doc' | sed -E 's/-?[0-9]{4}-[0-9]{2}-[0-9]{2}$//' | sed 's/-doc$//')
|
||||
git add -A && git commit -qm "R-6 Basis (Index/Log-Struktur)"
|
||||
cat > raw/index-2026-08-20.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: Index-Struktur des Bundles selbst.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-6 Zuwachs index-2026-08-20"
|
||||
# Ziel-Slug AUS dem committeten Dateinamen ableiten (Dateiname->Term, §5.15 Pkt. 1):
|
||||
# basename ohne .md, Datums-Suffix gestrippt, Norm-Kollaps. Keine weitere Regel.
|
||||
R6_FILE=$(basename "$(git diff --name-only HEAD~1 -- raw/)")
|
||||
STEM=$(printf '%s' "$(basename "$R6_FILE" .md)" | sed -E 's/-?[0-9]{4}-[0-9]{2}-[0-9]{2}$//')
|
||||
TARGET_SLUG=$(norm "$STEM")
|
||||
echo " Abgeleiteter Ziel-Slug: '$TARGET_SLUG'"
|
||||
echo " Abgeleiteter Ziel-Slug (aus committetem Dateinamen '$R6_FILE', nur dokumentierte Regel): '$TARGET_SLUG'"
|
||||
[ "$TARGET_SLUG" = "index" ] || { echo "HARD-FAIL (R-6): Slug-Ableitung ergab '$TARGET_SLUG' (Soll index)" >&2; exit 1; }
|
||||
case "$TARGET_SLUG" in
|
||||
index|log|source|README) echo " BEFUND: Ziel-Slug '$TARGET_SLUG' ist reservierter Bundle-Name — Hold aktiviert (§5.15 Pkt. 5)";;
|
||||
# Reserviertheits-Prüfung case-INSENSITIV (Loop-3/P-3.9-2): der Slug ist
|
||||
# lowercased (norm), die Bundle-Reservation umfasst auch das gemischte
|
||||
# 'README' — beide Seiten lowercased vergleichen, sonst ist 'readme' unerreichbar.
|
||||
case "$(tolower <<< "$TARGET_SLUG")" in
|
||||
index|log|source|readme) echo " BEFUND: Ziel-Slug '$TARGET_SLUG' ist reservierter Bundle-Name (case-insensitiv geprüft) — Hold aktiviert (§5.15 Pkt. 5)";;
|
||||
*) echo "HARD-FAIL (R-6): Slug '$TARGET_SLUG' nicht in Reserviert-Menge" >&2; exit 1;;
|
||||
esac
|
||||
# Negativ-Kontrolle der case-insensitiven Prüfung: ein gemischt-geschriebenes
|
||||
# reserviertes Wort MUSS ebenso erkannt werden (sonst wäre die Prüfung
|
||||
# nur für kleine Buchstaben scharf).
|
||||
case "$(tolower <<< 'README')" in
|
||||
readme) echo " BEFUND: Negativ-Kontrolle — gemischt-geschriebenes 'README' wird über tolower in die Reserviert-Menge eingeordnet";;
|
||||
*) echo "HARD-FAIL (R-6): tolower-Kontrolle defekt" >&2; exit 1;;
|
||||
esac
|
||||
# Tote CAND: der abgeleitete Candidate wird NICHT als Datei geschrieben.
|
||||
[ -e "wiki/index-doc.md" ] && { echo "HARD-FAIL (R-6): Ziel als eigenständige Datei geschrieben — Hold verletzt (AC-5)" >&2; exit 1; }
|
||||
# (wiki/index.md existiert bereits als Fixture — die echte Invariante ist der
|
||||
# saubere wiki/-Baum: keine neue/veränderte Datei, via git-status-Assert.)
|
||||
ST_R6=$(git status --porcelain -- wiki/ | awk '{print $2}' | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')
|
||||
[ -z "$ST_R6" ] || { echo "HARD-FAIL (R-6): Hold mutierte den wiki/-Baum — [$ST_R6]" >&2; exit 1; }
|
||||
# Ist-Dateimenge deterministisch via git ls-tree-Schnittmenge (§5.15 Pkt. 5).
|
||||
# Basenamen behalten ihre Schreibweise (z. B. 'README') — beide Seiten
|
||||
# lowercased für die Reserviert-Schnittmenge (Konsistenz mit der Slug-Prüfung).
|
||||
LS_BASES=$(git ls-tree -r --name-only HEAD -- wiki/ | sed 's#wiki/##' | sed 's#\.md$##' | LC_ALL=C sort | tr '\n' ' ')
|
||||
echo " git ls-tree-Dateibasen unter wiki/: $LS_BASES"
|
||||
# Schnittmenge (b): committete Datei-Basen (hier index, log) ∩ erschöpfende Liste.
|
||||
# Schnittmenge: committete Datei-Basen (hier index, log) ∩ Reserviert-Menge.
|
||||
HIT_INTERSECTION=""
|
||||
for b in $LS_BASES; do
|
||||
case "$b" in index|log|source|README) HIT_INTERSECTION="$HIT_INTERSECTION $b";; esac
|
||||
case "$(tolower <<< "$b")" in index|log|source|readme) HIT_INTERSECTION="$HIT_INTERSECTION $b";; esac
|
||||
done
|
||||
HIT_INTERSECTION=$(printf '%s\n' $HIT_INTERSECTION | tr '\n' ' ' | sed 's/ $//')
|
||||
echo " Schnittmenge Ist-Dateimenge: ${HIT_INTERSECTION:-leer}"
|
||||
@@ -615,28 +740,36 @@ echo "RESULT: PASS — R-6: RESERVED_ZIEL_INDEX — abgeleiteter Slug 'index' =>
|
||||
# =============================================================================
|
||||
# R-7 RESERVED_ZIEL_LOG (AC-5)
|
||||
# =============================================================================
|
||||
runlabel "R-7: RESERVED_ZIEL_LOG — Slug 'log' (abgeleitet); Hold => keine Anlage, wiki/-unverändert (AC-5)"
|
||||
runlabel "R-7: RESERVED_ZIEL_LOG — Slug 'log' (rein aus dem committeten Dateinamen abgeleitet, keine Zusatz-Stripps); Hold => keine Anlage, wiki/-unverändert (AC-5)"
|
||||
r7dir=$(isolate r7)
|
||||
cd "$r7dir"
|
||||
cat > raw/log-doc.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: Log-Thema.
|
||||
EOF
|
||||
# Fixture mit DATUMS-SUFFIX (analog R-6): Slug ausschließlich über die
|
||||
# dokumentierte §5.15-Pkt.-1-Regel (Datums-Suffix strip + Norm-Kollaps).
|
||||
# Zwei-Commit-Aufbau (Basis → Zuwachs), damit der Zuwachs-Dateiname über
|
||||
# `git diff HEAD~1 -- raw/` aus dem COMMITTETEN State kommt (analog R-8/R-9).
|
||||
cat > wiki/index.md <<'EOF'
|
||||
# Index
|
||||
EOF
|
||||
cat > wiki/log.md <<'EOF'
|
||||
# Änderungen
|
||||
EOF
|
||||
git add -A && git commit -qm "R-7 Zuwachs log-doc"
|
||||
STEM7=$(printf 'log-doc' | sed 's/-doc$//')
|
||||
git add -A && git commit -qm "R-7 Basis (Index/Log-Struktur)"
|
||||
cat > raw/log-2026-08-20.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: Log-Thema.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-7 Zuwachs log-2026-08-20"
|
||||
R7_FILE=$(basename "$(git diff --name-only HEAD~1 -- raw/)")
|
||||
STEM7=$(printf '%s' "$(basename "$R7_FILE" .md)" | sed -E 's/-?[0-9]{4}-[0-9]{2}-[0-9]{2}$//')
|
||||
TARGET_SLUG7=$(norm "$STEM7")
|
||||
echo " Abgeleiteter Ziel-Slug (aus committetem Dateinamen '$R7_FILE', nur dokumentierte Regel): '$TARGET_SLUG7'"
|
||||
[ "$TARGET_SLUG7" = "log" ] || { echo "HARD-FAIL (R-7): Slug-Ableitung '$TARGET_SLUG7'" >&2; exit 1; }
|
||||
case "$TARGET_SLUG7" in
|
||||
index|log|source|README) echo " BEFUND: Ziel-Slug '$TARGET_SLUG7' reserviert — Hold aktiviert (§5.15 Pkt. 5)";;
|
||||
# Reserviertheits-Prüfung case-insensitiv (Konsistenz mit R-6, P-3.9-2).
|
||||
case "$(tolower <<< "$TARGET_SLUG7")" in
|
||||
index|log|source|readme) echo " BEFUND: Ziel-Slug '$TARGET_SLUG7' reserviert (case-insensitiv) — Hold aktiviert (§5.15 Pkt. 5)";;
|
||||
*) echo "HARD-FAIL (R-7): Slug nicht in Reserviert-Menge" >&2; exit 1;;
|
||||
esac
|
||||
[ -e "wiki/log-doc.md" ] && { echo "HARD-FAIL (R-7): Ziel als Datei geschrieben — Hold verletzt (AC-5)" >&2; exit 1; }
|
||||
# Tote CAND: Invariante = saubere wiki/-Baum (log.md ist Fixture, bleibt unverändert).
|
||||
ST_R7=$(git status --porcelain -- wiki/ | awk '{print $2}' | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')
|
||||
[ -z "$ST_R7" ] || { echo "HARD-FAIL (R-7): Hold mutierte den wiki/-Baum — [$ST_R7]" >&2; exit 1; }
|
||||
echo "RESULT: PASS — R-7: RESERVED_ZIEL_LOG — abgeleiteter Slug 'log' => Hold, keine Anlage, wiki/-unverändert (AC-5, §5.15 Pkt. 5)"
|
||||
@@ -644,38 +777,53 @@ echo "RESULT: PASS — R-7: RESERVED_ZIEL_LOG — abgeleiteter Slug 'log' => Hol
|
||||
# =============================================================================
|
||||
# R-8 HOLD_ZWEI_WORKTREE (BS-L2-4)
|
||||
# =============================================================================
|
||||
runlabel "R-8: HOLD_ZWEI_WORKTREE — Hold-Befund über zwei getrennte Worktrees desselben committeten Baums (kein Doppel-Read derselben Datei); tote CAND einzeln hart assertiert, kein || true (BS-L2-4)"
|
||||
runlabel "R-8: HOLD_ZWEI_WORKTREE — Hold-Befund über zwei getrennte Worktrees desselben committeten Baums (kein Doppel-Read derselben Datei); tote CAND einzeln hart assertiert, kein || true (BS-L2-4); Re-Run-idempotent (Loop-3/P-3.9-14); rc-Lebendig (Loop-3/P-3.9-15); Hold-Assert auf BEIDE Worktrees (Loop-3/P-3.9-8)"
|
||||
r8dir=$(isolate r8)
|
||||
cd "$r8dir"
|
||||
cat > raw/log-doc.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: ein Thema mit Log-Bezug (Kandidat: log-thema).
|
||||
EOF
|
||||
# Fixture mit DATUMS-SUFFIX (kein -doc-Zusatz-Strip, analog R-6/R-7).
|
||||
# Zwei-Commit-Aufbau (Basis → Zuwachs): der Zuwachs-Dateiname kommt über
|
||||
# `git diff HEAD~1 -- raw/` aus dem COMMITTETEN State — in den Worktrees
|
||||
# (Checkout auf R8BASE = Zuwachs-Tip) ist HEAD~1 = Basis-Commit.
|
||||
cat > wiki/index.md <<'EOF'
|
||||
# Index
|
||||
EOF
|
||||
cat > wiki/log.md <<'EOF'
|
||||
# Änderungen
|
||||
EOF
|
||||
git add -A && git commit -qm "R-8 Basis (log-doc + Index/Log-Struktur)"
|
||||
git add -A && git commit -qm "R-8 Basis (Index/Log-Struktur)"
|
||||
cat > raw/log-2026-08-20.md <<'EOF'
|
||||
### S-1
|
||||
Evidenz: ein Thema mit Log-Bezug.
|
||||
EOF
|
||||
git add -A && git commit -qm "R-8 Zuwachs log-2026-08-20"
|
||||
R8BASE=$(git rev-parse HEAD)
|
||||
# Zwei getrennte, saubere Worktrees über demselben committeten Baum.
|
||||
# Re-Run-Idempotenz (Loop-3/P-3.9-14): veraltete Worktrees aus einem früheren
|
||||
# Lauf unter demselben $ROOT werden hart entfernt + Admin-Verzeichnisse
|
||||
# aufgeräumt, bevor neu angelegt wird.
|
||||
git worktree prune
|
||||
git worktree add -q "$ROOT/wt-hold-a" "$R8BASE" || { echo "HARD-FAIL (R-8): worktree A" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/wt-hold-b" "$R8BASE" || { echo "HARD-FAIL (R-8): worktree B" >&2; exit 1; }
|
||||
rm -rf "$ROOT/r8-wt"
|
||||
mkdir -p "$ROOT/r8-wt"
|
||||
git worktree add -q "$ROOT/r8-wt/hold-a" "$R8BASE" || { echo "HARD-FAIL (R-8): worktree A" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/r8-wt/hold-b" "$R8BASE" || { echo "HARD-FAIL (R-8): worktree B" >&2; exit 1; }
|
||||
|
||||
hold_run() { # $1 = worktree-Pfad ; $2 = Run-Name
|
||||
local wt="$1" name="$2"
|
||||
local rc=0
|
||||
(
|
||||
set -e
|
||||
cd "$wt"
|
||||
git config user.email "sandbox@test" && git config user.name "Sandbox"
|
||||
# Der abgeleitete Ziel-Slug (Dateiname->Term, §5.15 Pkt. 1): log-doc -> log.
|
||||
local slug
|
||||
slug=$(norm "$(printf 'log-doc' | sed 's/-doc$//')")
|
||||
local befund=""
|
||||
case "$slug" in
|
||||
index|log|source|README)
|
||||
# ECHTE Mechanik (Loop-3/D-3.9-3): Slug und CAND werden aus dem
|
||||
# COMMITTETEN Zuwachs-Dateinamen abgeleitet (Dateiname->Term, §5.15 Pkt. 1:
|
||||
# Datums-Suffix strip + Norm-Kollaps) — kein hart gesetztes Literal.
|
||||
local inc_file slug cand befund
|
||||
inc_file=$(git diff --name-only HEAD~1 HEAD -- raw/)
|
||||
[ -n "$inc_file" ] || { echo "HARD-FAIL (R-8): Worktree $name ohne committeten Zuwachs" >&2; exit 1; }
|
||||
slug=$(norm "$(basename "$inc_file" .md | sed -E 's/-?[0-9]{4}-[0-9]{2}-[0-9]{2}$//')")
|
||||
cand="$(basename "$inc_file" .md)"
|
||||
case "$(tolower <<< "$slug")" in
|
||||
index|log|source|readme)
|
||||
# Hold: keine Datei schreiben, textuell benannt (NFR-4).
|
||||
befund="RESERVED_ZIEL_$slug"
|
||||
;;
|
||||
@@ -686,20 +834,28 @@ hold_run() { # $1 = worktree-Pfad ; $2 = Run-Name
|
||||
echo "run: $name"
|
||||
echo "slug: $slug"
|
||||
echo "befund: $befund"
|
||||
# tote CAND: Candidate wird bestimmt, aber nicht geschrieben.
|
||||
echo "cand: log-thema"
|
||||
# tote CAND: Candidate wird bestimmt, aber NICHT geschrieben.
|
||||
echo "cand: $cand"
|
||||
echo "geschrieben: nein"
|
||||
} > "$ROOT/receipts/$name.receipt"
|
||||
)
|
||||
local rc=$?
|
||||
[ $rc -eq 0 ] || { echo "HARD-FAIL (R-8): Hold-Lauf $name (rc=$rc)" >&2; exit 1; }
|
||||
) || rc=$?
|
||||
[ $rc -eq 0 ] || { echo "HARD-FAIL (R-8): Hold-Lauf $name (rc=$rc — lebendige rc-Diagnostik, Loop-3/P-3.9-15)" >&2; exit 1; }
|
||||
}
|
||||
# Zwei getrennte Ausführungskontexte: A und B über demselben Baum.
|
||||
hold_run "$ROOT/wt-hold-a" hold-a
|
||||
hold_run "$ROOT/wt-hold-b" hold-b
|
||||
hold_run "$ROOT/r8-wt/hold-a" hold-a
|
||||
hold_run "$ROOT/r8-wt/hold-b" hold-b
|
||||
# Hold-Dichtheit: kein Worktree hat den wiki/-Baum berührt (keine Anlage).
|
||||
for wtp in "$ROOT/r8-wt/hold-a" "$ROOT/r8-wt/hold-b"; do
|
||||
ST_WT=$(git -C "$wtp" status --porcelain -- wiki/ | awk '{print $2}' | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')
|
||||
[ -z "$ST_WT" ] || { echo "HARD-FAIL (R-8): Hold-Lauf mutierte den wiki/-Baum in $wtp — [$ST_WT]" >&2; exit 1; }
|
||||
done
|
||||
HA=$(grep -E '^(slug|befund|cand|geschrieben):' "$ROOT/receipts/hold-a.receipt")
|
||||
HB=$(grep -E '^(slug|befund|cand|geschrieben):' "$ROOT/receipts/hold-b.receipt")
|
||||
[ -n "$HA" ] && [ -n "$HB" ] || { echo "HARD-FAIL (R-8): Hold-Receipts leer" >&2; exit 1; }
|
||||
# ECHTE Werte: Slug ist 'log' (abgeleitet), CAND ist der abgeleitete Dateiname.
|
||||
# (Loop-3/D-3.9-3: keine handgeschriebenen Receipt-Literale mehr.)
|
||||
echo "$HA" | grep -q '^slug: log$' || { echo "HARD-FAIL (R-8): abgeleiteter Slug nicht 'log' (hold-a)" >&2; exit 1; }
|
||||
echo "$HA" | grep -q '^cand: log-2026-08-20$' || { echo "HARD-FAIL (R-8): abgeleiteter CAND nicht 'log-2026-08-20' (hold-a)" >&2; exit 1; }
|
||||
if [ "$HA" = "$HB" ]; then
|
||||
echo " BEFUND: Hold-Befund über zwei getrennte Worktrees identisch (Zwei-Run-Hold-Identität, NICHT-VAKUUM):"
|
||||
echo "$HA" | sed 's/^/ /'
|
||||
@@ -708,16 +864,20 @@ else
|
||||
diff -u <(printf '%s\n' "$HA") <(printf '%s\n' "$HB") >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
# tote CAND: kein wiki/$CAND.md unter dem Worktree (einzelnes hartes Assert, kein || true).
|
||||
[ -e "$ROOT/wt-hold-a/wiki/log-thema.md" ] && { echo "HARD-FAIL (R-8): tote CAND doch geschrieben (wt-a)" >&2; exit 1; }
|
||||
[ -e "$ROOT/wt-hold-b/wiki/log-thema.md" ] && { echo "HARD-FAIL (R-8): tote CAND doch geschrieben (wt-b)" >&2; exit 1; }
|
||||
# tote CAND: kein wiki/<CAND>.md unter den Worktrees (CAND = abgeleiteter
|
||||
# Dateiname; ein hartes Assert je Worktree, kein || true).
|
||||
[ -e "$ROOT/r8-wt/hold-a/wiki/log-2026-08-20.md" ] && { echo "HARD-FAIL (R-8): tote CAND doch geschrieben (hold-a)" >&2; exit 1; }
|
||||
[ -e "$ROOT/r8-wt/hold-b/wiki/log-2026-08-20.md" ] && { echo "HARD-FAIL (R-8): tote CAND doch geschrieben (hold-b)" >&2; exit 1; }
|
||||
# log.md trägt den Hold-Befund (textuell benannt, NFR-4): wir schreiben den Befund
|
||||
# deterministisch in beide log.md (analog §5.15-Pkt.-5-Hold-Bullet) und verifizieren.
|
||||
for wtp in "$ROOT/wt-hold-a" "$ROOT/wt-hold-b"; do
|
||||
printf '%s\n' "- Reconcile-Hold (Story 3.9, §5.15 Pkt. 5): Ziel 'log' (reserviert) — keine Datei geschrieben; deterministischer Hold (CAND=log-thema; Run teilweise erfolgreich; tote CAND nicht angelegt)" >> "$wtp/wiki/log.md"
|
||||
# deterministisch in beide log.md (analog §5.15-Pkt.-5-Hold-Bullet) und
|
||||
# verifizieren auf BEIDEN Worktrees (Loop-3/P-3.9-8).
|
||||
for wtp in "$ROOT/r8-wt/hold-a" "$ROOT/r8-wt/hold-b"; do
|
||||
printf '%s\n' "- Reconcile-Hold (Story 3.9, §5.15 Pkt. 5): Ziel 'log' (reserviert) — keine Datei geschrieben; deterministischer Hold (CAND=log-2026-08-20; Run teilweise erfolgreich; tote CAND nicht angelegt)" >> "$wtp/wiki/log.md"
|
||||
done
|
||||
for wtp in "$ROOT/r8-wt/hold-a" "$ROOT/r8-wt/hold-b"; do
|
||||
grep -qF "Reconcile-Hold" "$wtp/wiki/log.md" || { echo "HARD-FAIL (R-8): log.md-Hold-Befund fehlt ($wtp, NFR-4)" >&2; exit 1; }
|
||||
grep -qF "teilweise erfolgreich" "$wtp/wiki/log.md" || { echo "HARD-FAIL (R-8): 'teilweise erfolgreich' fehlt ($wtp)" >&2; exit 1; }
|
||||
done
|
||||
grep -qF "Reconcile-Hold" "$ROOT/wt-hold-a/wiki/log.md" || { echo "HARD-FAIL (R-8): log.md-Hold-Befund fehlt (wt-a, NFR-4)" >&2; exit 1; }
|
||||
grep -qF "teilweise erfolgreich" "$ROOT/wt-hold-a/wiki/log.md" || { echo "HARD-FAIL (R-8): 'teilweise erfolgreich' fehlt (wt-a)" >&2; exit 1; }
|
||||
echo "RESULT: PASS — R-8: HOLD_ZWEI_WORKTREE — Hold-Befund deterministisch und identisch über zwei getrennte Worktrees; tote CAND einzeln hart; log.md trägt NFR-4-Benennung; Zwei-Run-Hold-Identität NICHT-VAKUUM (AC-5, §5.15 Pkt. 5/6)"
|
||||
|
||||
# =============================================================================
|
||||
@@ -759,17 +919,22 @@ sources:
|
||||
terms:
|
||||
- kopplung
|
||||
EOF
|
||||
# Re-Run-Idempotenz (Loop-3/P-3.9-14): veraltete Worktrees aus einem früheren
|
||||
# Lauf unter demselben $ROOT werden hart entfernt + Admin-Verzeichnisse
|
||||
# aufgeräumt, bevor neu angelegt wird.
|
||||
git worktree prune
|
||||
git worktree add -q "$ROOT/wt-a" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-a" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/wt-b" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-b" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/wt-n" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-n" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/wt-at" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-at" >&2; exit 1; }
|
||||
rm -rf "$ROOT/r9-wt"
|
||||
mkdir -p "$ROOT/r9-wt"
|
||||
git worktree add -q "$ROOT/r9-wt/a" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-a" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/r9-wt/b" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-b" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/r9-wt/n" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-n" >&2; exit 1; }
|
||||
git worktree add -q "$ROOT/r9-wt/at" "$R9BASE" || { echo "HARD-FAIL (R-9): wt-at" >&2; exit 1; }
|
||||
# Ein konstanter at-Wert für die Sandbox (Wanduhr-frei) — die at-Exzeption wird
|
||||
# bewusst als legitime Abweichung modelliert, nicht gemashat.
|
||||
# bewusst als legitime Abweichung modelliert, nicht gematcht.
|
||||
SANDBOX_AT="2026-08-20T12:00:00Z"
|
||||
|
||||
run9_worktree() { # $1=wt $2=name $3=modus(clean|divergent|atgap)
|
||||
local wt="$1" name="$2" mode="$3" at_val wan
|
||||
local wt="$1" name="$2" mode="$3" at_val rc=0
|
||||
(
|
||||
set -e
|
||||
cd "$wt" || exit 9
|
||||
@@ -853,7 +1018,13 @@ EOF
|
||||
R9_COMMIT_HASH=$(git rev-parse HEAD)
|
||||
full_list=""
|
||||
masked_list=""
|
||||
for f in $(git ls-tree -r --name-only HEAD -- wiki/ | grep -vE '/?(index|log)\.md$'); do
|
||||
# index.md/log.md bleiben bewusst AUS dem Byte-Vergleich (generierte
|
||||
# Struktur-/Logdateien, kein deterministischer Concept-Inhalt) — die
|
||||
# Ausnahme ist jetzt ANCHORED (nur exakte Basenamen index.md/log.md, nicht
|
||||
# jede Datei, die DARAUF ENDET, z. B. myindex.md) und benannt.
|
||||
# (Loop-3/P-3.9-7: unanchoredes '/?(index|log)\.md$' schnitt fälschlich
|
||||
# Enden-Präfixe aus; 'myindex.md' würde still vom Vergleich verschwinden.)
|
||||
for f in $(git ls-tree -r --name-only HEAD -- wiki/ | grep -vE '(^|/)(index|log)\.md$'); do
|
||||
full=$(sha256sum "$f" | awk '{print $1}')
|
||||
masked=$(sed 's|^ at:.*| at: <at>|' "$f" | sha256sum | awk '{print $1}')
|
||||
full_list="$full_list $f=$full"
|
||||
@@ -863,14 +1034,13 @@ EOF
|
||||
printf 'run: %s\ncommit: %s\nfull: %s\nmasked: %s\n' \
|
||||
"$name" "$R9_COMMIT_HASH" "$full_list" "$masked_list" >> "$ROOT/receipts/$name.bundle"
|
||||
echo " [bundle] $name => commit $R9_COMMIT_HASH full=$full_list"
|
||||
)
|
||||
local rc=$?
|
||||
[ $rc -eq 0 ] || { echo "HARD-FAIL (R-9): Lauf $name (rc=$rc)" >&2; exit 1; }
|
||||
) || rc=$?
|
||||
[ $rc -eq 0 ] || { echo "HARD-FAIL (R-9): Lauf $name (rc=$rc — lebendige rc-Diagnostik, Loop-3/P-3.9-15)" >&2; exit 1; }
|
||||
}
|
||||
echo "--- Lauf A (clean) ---"
|
||||
run9_worktree "$ROOT/wt-a" run9a "clean"
|
||||
run9_worktree "$ROOT/r9-wt/a" run9a "clean"
|
||||
echo "--- Lauf B (clean) ---"
|
||||
run9_worktree "$ROOT/wt-b" run9b "clean"
|
||||
run9_worktree "$ROOT/r9-wt/b" run9b "clean"
|
||||
R9A=$(grep -E '^(candidates|order|routing|terms|at.normalform):' "$ROOT/receipts/run9a.receipt" | grep -v '^generated.at')
|
||||
R9B=$(grep -E '^(candidates|order|routing|terms|at.normalform):' "$ROOT/receipts/run9b.receipt" | grep -v '^generated.at')
|
||||
[ -n "$R9A" ] && [ -n "$R9B" ] || { echo "HARD-FAIL (R-9): Receipts leer (Vakuum)" >&2; exit 1; }
|
||||
@@ -885,7 +1055,7 @@ echo "$R9A" | sed 's/^/ /'
|
||||
case "$R9A" in *alpha*) ;; *) echo "HARD-FAIL (R-9): nicht-vakuum Assertion — alpha fehlt" >&2; exit 1;; esac
|
||||
# NEGATIVE Kontrolle: konstruierte Abweichung hart FAIL.
|
||||
echo "--- NEGATIVE Kontrolle (divergent) ---"
|
||||
run9_worktree "$ROOT/wt-n" run9n "divergent"
|
||||
run9_worktree "$ROOT/r9-wt/n" run9n "divergent"
|
||||
R9N=$(grep -E '^(candidates|order|routing|terms|at.normalform):' "$ROOT/receipts/run9n.receipt" | grep -v '^generated.at')
|
||||
[ -n "$R9N" ] || { echo "HARD-FAIL (R-9): Negativ-Receipt leer (Vakuum)" >&2; exit 1; }
|
||||
if [ "$R9N" = "$R9A" ]; then
|
||||
@@ -896,7 +1066,7 @@ fi
|
||||
# at-Exzeption (P-L2-6): eine legitime at-Abweichung wird NICHT als AD-16 gemeldet;
|
||||
# die übrigen deterministischen Felder sind byte-identisch.
|
||||
echo "--- at-Exzeption (atgap) ---"
|
||||
run9_worktree "$ROOT/wt-at" run9at "atgap"
|
||||
run9_worktree "$ROOT/r9-wt/at" run9at "atgap"
|
||||
R9AT_REST=$(grep -E '^(candidates|order|routing|terms|at.normalform):' "$ROOT/receipts/run9at.receipt" | grep -v '^generated.at')
|
||||
R9AT_AT=$(grep '^generated.at:' "$ROOT/receipts/run9at.receipt")
|
||||
if [ "$R9AT_REST" != "$R9A" ]; then
|
||||
@@ -940,7 +1110,7 @@ if [ "$B9NM" = "$B9AM" ]; then
|
||||
echo "HARD-FAIL (R-9-bundle): divergenter Run-Bundle ununterscheidbar vom clean-Run (Negativ-Kontrolle muss FAIL)" >&2; exit 1
|
||||
fi
|
||||
echo " BEFUND: divergenter Run-Bundle an der mutierten Datei nachweisbar ungleich (hart FAIL, kein Vakuum)"
|
||||
echo "RESULT: PASS — R-9: ZWEI_RUN_IDENTISCH — positive Identität NICHT-VAKUUM (2 getrennte Worktrees, gegeneinander verglichen, kein hart codierter Erwartungswert) + NEGATIVE Kontrolle hart FAIL + at-Exzeption praktisch ausgeübt (nur-at-differiert, nicht-mashat); Manifest datei-pfadbasiert (AC-6, AD-17h/A0-19, §5.15 Pkt. 6)"
|
||||
echo "RESULT: PASS — R-9: ZWEI_RUN_IDENTISCH — positive Identität NICHT-VAKUUM (2 getrennte Worktrees, gegeneinander verglichen, kein hart codierter Erwartungswert) + NEGATIVE Kontrolle hart FAIL + at-Exzeption praktisch ausgeübt (nur-at-differiert, nicht gematcht); Manifest datei-pfadbasiert (AC-6, AD-17h/A0-19, §5.15 Pkt. 6)"
|
||||
|
||||
# =============================================================================
|
||||
# Abschluss — Gesamt-Exit 0 (nur wenn alle R-Szenarien harte PASS)
|
||||
|
||||
+47
-8
File diff suppressed because one or more lines are too long
@@ -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
|
||||
last_updated: 08-21-2026 10:16
|
||||
project: wow20
|
||||
project_key: NOKEY
|
||||
tracking_system: file-system
|
||||
@@ -59,7 +59,7 @@ development_status:
|
||||
3-6-lease-staleness-recovery-basis-absichern: done
|
||||
3-7-reason-mutate-trennung-und-konsistenz-endzustand-sicherstell: done
|
||||
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: review
|
||||
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: backlog
|
||||
3-11-root-scope-leasing-atomar-akquirieren: backlog
|
||||
3-12-lease-lifecycle-und-commit-abschluss-transaktional-schliessen: backlog
|
||||
|
||||
+4
-4
File diff suppressed because one or more lines are too long
@@ -1,5 +1,7 @@
|
||||
# Log
|
||||
|
||||
## 2026-08-21
|
||||
- **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**) + `</frozen-after-approval>`-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
|
||||
- **Story 3.9 → Re-Ableitung Loop-2 + `in-progress` (Deterministische Relevanz- & Reconcile-Routing, 2026-08-20):** Loop-2-bad_spec-Loopback (bmad-code-review Re-Run — 2 bad_spec, 4 patch, 2 defer; kein intent_gap, kein Eingriff ins `<frozen-after-approval>`). **Kern-Defekte behoben:** **BS-L2-1** — NO_MATCH/leere Candidate-Liste ist bei **neuer Einheit** NICHT NO_OP, sondern **CREATE (Zelle 2) / ORPHAN-HOLD (Zelle 3)**; NO_OP (Zelle 4) bleibt ausschließlich **Unter-Entscheidung des Update-Pfads** (bestehende Evidenz identisch repräsentiert) — §5.15-Pkt.-3-Tabelle, §3.2-Pkt.-3d-Verweis-Anker und Sandbox R-3/R-5 in Einklang; **BS-L2-2** — Status-Codes geschlossen: **R (Rename)** einer committeten `raw/`-Datei = AD-3-Verletzung → **Guard-FAIL**, **C** zählt als **A** (Copy/neu), `--diff-filter=ACMR` dokumentiert die Zuordnung. **Weitere Loop-2-Auflagen:** P-L2-1 Sandbox-`norm()` auf die **eine** Kollaps-Definition (§3.2-Pkt.-1b) vereinheitlicht (keine vierte Pipeline); P-L2-2 R-2-`index.md`-Traversal **real** gefeuert (Fixture enthält den Term, Traversal-Exklusion negativ assertiert); P-L2-3 R-1-Diff↔Manifest-Äquivalenz um **Negativ-Zweig** ergänzt (divergentes Manifest → Run-FAIL vor Mutation); P-L2-4 R-8-**Zwei-Run-Hold über zwei getrennte Worktrees** (Behebung der Doppel-Read-Tautologie); P-L2-5 R-6/R-7-**Slug aus dem abgeleiteten Kandidaten** + `git ls-tree`-Schnittmengen-Fixture + entdoppelte tote `CAND`-Assertion (kein `|| true`); P-L2-6 R-9-Receipts um **`generated.at`-Feld + praktisch ausgeübte at-Exzeption** (legitime at-Abweichung ≠ AD-16; andere als-at-Differenz = HARD-FAIL). **Defer-Aufgriffe (Home Story 3.9):** D-8 (Mehrfach-Term-Vereinigung) und D-9 (Term-Ableitung aus dem `raw/`-Zuwachs + voller Kandidaten-Scan statt fester 2-Datei-Liste) in §5.15 Pkt. 1 / Sandbox R-1/R-5 realisiert. **Verankerung (`schema/compiler.md` Revision 3.4):** neue **§5.15** „Deterministische Relevanz- & Reconcile-Routing (Story 3.9)" (Pkt. 1–6) — Pkt. 1 **Termgewinnung** (geschlossen, geordnet, AC-1: Dateiname→Term-Mapping, Sidecar-Exklusion, Status-Codes A/M/D/R/C via `--diff-filter=ACMR`, §5.9-Pkt.-6-Diskrepanz-/Fallback-Kopplung, Diff↔Manifest-Äquivalenz, D-8-Mehrfach-Term-Vereinigung mit ≥2-Zeichen-Segmenten, Einzelzeichen-Segmente kein eigener Term, optional committetes Term-Manifest), Pkt. 2 **symmetrische Normalisierung + literal-sichere Suche** (AC-2, §3.2-Pkt.-1b-Kollaps-Klasse `[-–— _]`→`-`; `index.md`-Treffer → Traversal-Stufe, kein Concept-Kandidat), Pkt. 3 die **eine exklusive Routing-Tabelle** (AC-3: UPDATE → CREATE → ORPHAN/HOLD → NO_OP; NO_OP als Update-Unter-Entscheidung; Leere-Candidate-Absatz; Stufe-b-Zelle), Pkt. 4 **Raw-Immutability-Guard** (AC-4: M/D/**R** → Run-FAIL vor Mutation, A/C akzeptiert), Pkt. 5 **reservierte Zielpfade** (AC-5: `index`/`log`/`source`/`README` erschöpfend, deterministischer Hold, Ist-Dateimenge via `git ls-tree`-Schnittmenge), Pkt. 6 **Zwei-Run-Identität** (AC-6: positive UND negative Fixtures, Zwei-Worktree-Vergleich, praktisch ausgeübte `at`-Exzeption, kein hart codierter Erwartungswert). **§3.2**-Pkt.-3d-§5.15-**Verweis-Anker** nachgeführt; **§5.14**-Pkt.-5-Scope-Präzisierung (Story-3.9-ACs verankert); **§7**-Relevanzbestimmung-Bullet erweitert (Vorbehalt aufgelöst); Revisionslog **Revision 3.4**. **Re-Derivation:** `deferred-work.md` D-8/D-9 → **`aufgegriffen`**; `epic-3-context.md` Z. 39 → **Ist (§5.15 verankert)**; `sprint-status.yaml` Key `3-9-…` → **`in-progress`** (finaler `review`/`done`-Flip im Step-04/05). **Sandbox-Nachweis:** `bash _bmad-output/implementation-artifacts/sandbox-3-9/run-sandbox.sh` → **R-1..R-9 harte PASS, Exit 0** (inkl. R-1b R/C-Guard, R-5-CREATE-Bewertungsraum, R-8-Zwei-Worktree-Hold, R-9-at-Exzeption + Negativkontrolle). **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) bleibt Story 3.10.
|
||||
- **Story 3.8 → Review-Loop-3-Abschluss + `done` (Determinismus-Vertrag, bmad-code-review Re-Run 4 Layer — blind-hunter / edge-case-hunter / verification-gap / acceptance-auditor, 2026-08-20):** Re-Review der Loop-2-zustands Implementation; **Triage:** 4 decision-needed / 13 patch / 6 defer / 7 dismissed; **keine intent_gap/bad_spec (kein Loopback).** **Nutzer-Entscheidungen D-1..D-4 = 1/1/1/1** (empfohlene Optionen): D-1 §5.14-Schließungs-Bullet macht den Z. 53 „Bekannte Determinismus-Lücke"-Bullet **superseded** (append-only-Superseded-Hinweis, kein Umbruch); D-2 Story-Status-Flip auf **`done`** nach Loop-3-Abschluss (Change-Proposal-Sequenzierung „3.9 → 3.10 / 3.11 → 3.12 → 3.8 Abschluss → 3.13 Abnahme" betrifft das **Epic-3-Abnahmegate (3.13)** — Story-3.8-Instruktionsverankerung abgeschlossen, 3.9–3.12-Verankerungen + 3.13-Abnahme bleiben offen, epic-3 in-progress); D-3 **autorisierte Neu-Verhandlung** des Frozen-Intents in geringfügigem Umfang: Typo „documenthuman" → „document-human" (spec Z. 24, dokumentiert); D-4 Hold-Home = **Story 3.10 (Epic 3)**, Korrektur-/Erweiterungs-**Klassifikation** = Epic-4-Interface/Story 4.1 (§5.10 Pkt. 8 präzisiert). **Patches (13):** P-1 SRO-/Code-Map-Anker auf IST-Zeilen (compiler.md 375/376/377/477; Code Map §5.14 365–377, §7 424ff, §8 445, Rev 3.3 477; Sandbox 245/265/442/275/447/531); P-2/P-4 symmetrische Term-/Body-Normalisierung (identisch normalisiert vor Vergleich, kein host-abhängiges `-i`, Wortgrenze = Tool-Wortdefinition rg `-w`/`\b`) — §3.2 Pkt. 2a + `match_stufe_a` (Term + Body identisch normalisiert, `-i` entfernt, ASCII-Boundary `[^A-Za-z0-9]`); P-3 re-executierbare Zwei-Run-Formel als Receipt-Hashvergleich (git-diff-Formel = Austauschbar-Form derselben Eigenschaft) — §5.14 Pkt. 2; P-5 Sandbox-Fresh-Kontext-Restlücke textuell benannt (mechanisch simuliert; Nachweis echter frischer Kontexte = Story-3.13-Abnahmegate) — §5.14 Pkt. 2; P-6 Manifest-`generated_by` wird **konsumiert** (Guard + Konzepts-Frontmatter `by:` aus Manifest statt hart-codiert); P-7 **at-Ausnahme hart assertiert** (Wiederholungs-Schleife bei Wanduhr-Sekundenkollision erzwingt real unterschiedliche `at_cell`-Werte; `HARD-FAIL` statt stiller PASS) — re-executiert: `BEFUND: at-Ausnahme aktiv (assertiert)` mit real differierenden Wanduhrwerten; P-8 „vollständig pinbar"/„keine offene Frage" **ge scopet** (nur für die mit §5.14 geschlossenen Lücken; Umlaut-Defer + Story-3.9-ACs bewusst nicht damit geschlossen, sichtbar als benannte Defers/Geplante) — §5.14 Pkt. 5 + §7-Bullet; P-9 epics.md AC-2: „Determinismusfehler" = **AD-16-Klassifikationsdefekt** (AD-16-Kopplung nachgeführt, AC-Wortlaut erhalten); P-10 spec `review_loop_iteration: 0 → 2` (Counter ab Loop-3 gepflegt); P-11 epic-3-context.md Technical Decisions Z. 39/41/43 als **Zielzustand** markiert (Story 3.9/3.11/3.12 — noch nicht in compiler.md verankert, §3.2/§5.11 maßgeblich bis dahin); P-12 verifiziert + dokumentiert (epics.md enthält kein Literal „AD-17a..h"; die AD-17-Enums sind mit dem Change-Proposal konsistent — AD-17g liegt in Epic 4 Z. 101; kein Edit nötig); P-13 Spec Change Log Review-Loop-3 (append-only, nach Loop-2-Eintrag, vor `</frozen-after-approval>`). **Defers (6, → deferred-work.md append-only, Block „Deferred from: code review of spec-3-8… (2026-08-20)"):** D-5 Sandbox-Härtungs-Guards (8 Befunde), D-6 DET-1/2-Plan-Literale (Home: 3.13-Abnahme), D-7 `norm()`-Locale-Pinning, D-8 Mehrfach-Term-Union, D-9 Orphan-Term-Hand-Pin/feste 2-Datei-Scan (Home: 3.9), D-10 Umlaut-vs-Transkription im Match-Pfad (bereits „Aufgegriffen (teilweise)" offen). **Dismissed (7):** u. a. Blind-Hunter-Claim „alle Sandbox-SRO-Anker stale" — **widerlegt** (alle 6 exakt vor den eigenen Edits); übrige: Loop-1/2-Präzedenz-Doppelzählungen + by-design-Lesarten (Details im Spec Change Log). **Sandbox re-executiert:** `bash _bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh` → **DET-1..DET-8 harte PASS, Exit 0**; at-Ausnahme aktiv (assertiert, real unterschiedliche Wanduhr-`at`-Werte A vs. B); Manifest `generated_by` konsumiert; Witness nicht-vakuum (Baseline-SHA ≠ Run-SHA). **Spec-Frontmatter:** `status: 'done'`, `review_loop_iteration: 2`; Frozen-Intent nur im D-3-Umfang geändert (Typo, autorisiert). `sprint-status.yaml`-Key `3-8-…` → **`done`** (D-2; Sequenzierungs-Hinweis im Key-Kommentar), `last_updated` → 08-20-2026 17:04. **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/` unverändert).
|
||||
|
||||
Reference in New Issue
Block a user