From 73d19cbceac68f54ba1c3197dc3d8b59429befb4 Mon Sep 17 00:00:00 2001 From: Michael Tamse Date: Thu, 20 Aug 2026 14:00:53 +0200 Subject: [PATCH] =?UTF-8?q?@=20feat:=20Story=203.8=20Review-Loop-2-H=C3=A4?= =?UTF-8?q?rtung=20(bmad-code-review=20Re-Run,=203=20Layer;=20kein=20Loopb?= =?UTF-8?q?ack)=20=E2=80=94=20DET-2=20at-Ausnahme=20real=20ausge=C3=BCbt,?= =?UTF-8?q?=20Manifest-Validierung,=20set=20-e;=20Step-05=20done?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-Review der Re-Open-Implementierung (3 Subagenten synchron: blind-hunter / edge-case-hunter-Retry / verification-gap): Triage keine intent_gap/bad_spec; 10 Patch / 0 defer / Rest Reject. Kern-Veranlassung: die drei Re-Open-ACs wurden als nicht wirklich ausgeübt erkannt — Manifest dekorativ (nie konsumiert), at-Maskierung vor dem Commit (stiller Ausschluss statt dokumentierter Ausnahme), Reception ohne Reihenfolge-/Entscheidungsfeld, Subshell ohne set -e (false-PASS-Risiko). Sandbox-Patches (ausschließlich sandbox-3-8/run-sandbox.sh): - DET-2 gehärtet: generated.at als reale Wanduhr-Ausgabe je Lauf committet (date -u) und als at_cell im Receipt festgehalten; Normalisierung auf AT erst beim Vergleich (Hash über at-normalisierte Content-Projektion, §5.14 Pkt. 2 "ohne die maskierte at-Zeile") — kein Maskieren vor Commit, kein stiller Ausschluss; Nach-Commit-Attestierung committed_at == at_now; Zwei-Run-Abgleich byte-identisch für deterministische Bestandteile, nur Ausnahme-Cells at_cell/tree dürfen differieren (at-Varianz real demonstriert: getrennte Worktree-Läufe → verschiedene Wanduhr-at) - Kanonisches Eingabemanifest konsumiert/validiert (abschnittsbewusste Extraktion sources:/output_visible_run_identity:, Baseline-Quellen-Existenz nach Input-Commit, HARD-FAIL bei fehlenden Keys) — nicht dekorativ - Receipt um order:/decisions: erweitert (§5.14 Pkt. 2) + Receipt-Nicht-Vakuum-Guard - Subshell set -e (jeder fehlende Schritt bricht rc≠0 ab → HARD-FAIL statt false-PASS) - match_stufe_a literal-sicher (Term regex-escaped, §3.2-Pkt.-2a/§5.14 Pkt. 5) + CRLF-tolerante Body-Extraktion - cand-Newline-Normalisierung (tr \n ,) - log_bullet fail-hard (mktemp/mv-Fehler nicht geschluckt — verlorener log-Eintrag hätte Vakuum-Gleichheit durch identische Baseline-Hashes erzeugt) - git worktree prune vor dem Add (Re-Run-Sicherheit); git clean fail-hard unter set -e Verifikation re-executiert: run-sandbox.sh → DET-1..DET-8 harte PASS, Exit 0; at-Ausnahme aktiv (at_cell A != at_cell B), Witness nicht-vakuum; Validator-Verdikt (Rev 9, D-3): alle wiki/-Dateien SUCCESS (keine Inhalts-Mutation); Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt (nur wiki/log.md); AD-3 read-only unverändert. Spec: Change Log Review-Loop-2 (10 Patches), Verification-Pkt.-1 auf gehärteten Stand aktualisiert, Suggested Review Order auf neue Sandbox-Anker (238/257/267/409/414/498); Frontmatter status in-review → done. wiki/log.md Review-Loop-2-Abschluss-Bullet (zuerst-neuestes). sprint-status.yaml 3-8-… → review; last_updated 17:05. Co-Authored-By: Claude @ --- .../sandbox-3-8/run-sandbox.sh | 149 ++++++++++++++---- ...-ad-17h-als-agent-instruktions-validato.md | 32 +++- .../sprint-status.yaml | 4 +- wiki/log.md | 1 + 4 files changed, 146 insertions(+), 40 deletions(-) diff --git a/_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh b/_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh index c68528a..fbb6f72 100644 --- a/_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh +++ b/_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh @@ -125,29 +125,39 @@ norm() { # $1 = Begriff (Kollaps-Form, NICHT registry-aufloesend — Kollaps-Sco # wird entfernt, danach Wortgrenzen-Match (rg mit Wortgrenzen bzw. grep '\b'). match_stufe_a() { # $1=Begriff $2=Datei-Liste ; liefert getroffene wiki-Pfade (ohne Präfix/Suffix) local term="$1" file + # Regex-Metazeichen im Begriff literal-escaped (deterministischer, literal-sicherer Vergleich, + # §3.2-Pkt.-2a/§5.14 Pkt. 5): ein Term wie "a+b" oder "x.y" darf nie als Muster umgedeutet werden. + local esc + esc=$(printf '%s' "$term" | sed 's|[][\\.*^$+?(){}|]|\\&|g') for file in "${@:2}"; do - # Body = alles nach dem zweiten "---" (Frontmatter exkludiert, deterministisch) - body=$(awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}' "$file") + # Body = alles nach dem zweiten "---" (Frontmatter exkludiert, deterministisch); + # CRLF-tolerant (Host-Checkout-Form normalisiert), sonst wäre der Wortgrenzen-Match unbestimmt. + body=$(tr -d '\r' < "$file" | awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}') # Wortgrenzen-Match: ganze Wörter — Substring-/Frontmatter-Treffer liefern nichts. # Term-Normalisierung (§3.2 Pkt. 1b) ist lowercasing — der Match ist daher case-insensitiv. - if printf '%s' "$body" | grep -Eiq "(^|[^A-Za-z0-9])${term}([^A-Za-z0-9]|$)"; then + if printf '%s' "$body" | grep -Eiq "(^|[^A-Za-z0-9])${esc}([^A-Za-z0-9]|$)"; then basename "$file" .md fi done } # log.md-Eintrag (datumsgruppiert, neueste zuerst; Vertrag §5). Deterministisch fester Tag. +# Fehler in mktemp/mv werden NICHT geschluckt: ein fehlgeschlagener Eintrag würde den +# log.md-Hash beider Läufe identisch (Baseline) lassen => Vakuum-Gleichheit (sha_log). log_bullet() { # $1 = Bullet-Text (eine Zeile) local day="2026-08-20" local header="## $day" line="$1" + local tmp if grep -qxF "$header" wiki/log.md; then - tmp=$(mktemp) + tmp=$(mktemp) || { echo "HARD-FAIL (log_bullet): mktemp fehlgeschlagen" >&2; exit 1; } awk -v h="$header" -v l="$line" ' BEGIN{p=0} { if (!p && $0==h) { print; print l; p=1; next } print } - ' wiki/log.md > "$tmp" && mv "$tmp" wiki/log.md + ' wiki/log.md > "$tmp" && mv "$tmp" wiki/log.md || { echo "HARD-FAIL (log_bullet): log.md-Update fehlgeschlagen (Eintrag verloren)" >&2; exit 1; } else - tmp=$(mktemp) - { printf '%s\n' "$header"; printf '%s\n' "$line"; cat wiki/log.md; } > "$tmp" && mv "$tmp" wiki/log.md + tmp=$(mktemp) || { echo "HARD-FAIL (log_bullet): mktemp fehlgeschlagen" >&2; exit 1; } + { printf '%s\n' "$header"; printf '%s\n' "$line"; cat wiki/log.md; } > "$tmp" \ + && mv "$tmp" wiki/log.md \ + || { echo "HARD-FAIL (log_bullet): log.md-Update fehlgeschlagen (Eintrag verloren)" >&2; exit 1; } fi } @@ -227,17 +237,26 @@ echo "RESULT: PASS — DET-1: BUNDLE_STATE_DEFINITION — Bundle-State = determi # ===================================================================================== runlabel "DET-2: ZWEI_RUN_IDENTISCH (nicht-vakuum) — zwei frische Agent-Kontexte in getrennt aufgebauten, sauberen Worktrees über demselben committeten Baum -> identische Bundle-States bis auf at (Q-6/A0-19); kanonisches Eingabemanifest + Run-Receipt außerhalb des Bundles; keine hart codierten erwarteten Bundle-Outputs, verified nicht pauschal maskiert; echte Content-Hashes (Witness weicht byte-weise von Baseline ab)" # --- Zwei getrennte, saubere Worktrees über demselben Baseline-Commit ($BASE) aufbauen --- +# 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" || { echo "HARD-FAIL (DET-2): Worktree wt-a nicht aufgebaut" >&2; exit 1; } git worktree add -q "$ROOT/wt-b" "$BASE" || { echo "HARD-FAIL (DET-2): Worktree wt-b nicht aufgebaut" >&2; exit 1; } -# Kanonisches Eingabemanifest (A0-19): Baseline-Commit + geordnete Source-Eingaben + -# output-sichtbare Run-/Zeit-/Identitätswerte — identisch für beide Läufe. +# Kanonisches Eingabemanifest (A0-19, §5.14 Pkt. 2): Baseline-Commit + geordnete Source- +# Eingaben + output-sichtbare Run-/Zeit-/Identitätswerte — identisch für beide Läufe. +# Das Manifest wird unten in run2_worktree VOR jedem Lauf konsumiert/validiert (nicht dekorativ). cat > "$ROOT/manifest.yaml" <&2; exit 1; } + run2_worktree() { # $1 = Worktree-Pfad ; $2 = Run-Name ; führt die Instruktion als EIGENER # Ausführungskontext (frischer Agent-Kontext simulativ: eigener Worktree, eigene Subshell # mit eigenem cwd, keine Session-Wiederholung) über demselben committeten Baum aus. @@ -245,19 +264,41 @@ run2_worktree() { # $1 = Worktree-Pfad ; $2 = Run-Name ; führt die Instruktion # (kein Carry-over des Worktree-cwd in nachfolgende Szenarien). local wt="$1" name="$2" ( + set -e cd "$wt" || exit 9 + # Kanonisches Eingabemanifest VOR dem Lauf konsumieren/validieren (A0-19, §5.14 Pkt. 2): + # Baseline-Commit und geordnete Source-Eingaben müssen dem Repository-State entsprechen + # — das Manifest ist Eingabe der Instruktion, nicht bloße Doku (kein leerer Lauf möglich). + m_base=$(sed -n 's/^baseline: //p' "$ROOT/manifest.yaml") + [ -n "$m_base" ] || { echo "HARD-FAIL (DET-2): Manifest ohne baseline-Key" >&2; exit 9; } + [ "$m_base" = "$BASE" ] || { echo "HARD-FAIL (DET-2): Manifest-baseline ($m_base) != tatsaechliche Baseline ($BASE)" >&2; exit 9; } + # Abschnittsbewusste Extraktion: nur Elemente unter dem jeweiligen Manifest-Key + m_src=$(awk '/^sources:/{f=1;next} /^[a-z_]+:/{f=0} f && /^ - /{sub(/^ - /,""); sub(/ *#.*$/,""); print}' "$ROOT/manifest.yaml") + m_identity=$(awk '/^output_visible_run_identity:/{f=1;next} /^[a-z_]+:/{f=0} f && /^ - /{sub(/^ - /,""); sub(/ *#.*$/,""); print}' "$ROOT/manifest.yaml") + [ -n "$m_src" ] || { echo "HARD-FAIL (DET-2): Manifest ohne geordnete Source-Eingaben" >&2; exit 9; } + [ -n "$m_identity" ] || { echo "HARD-FAIL (DET-2): Manifest ohne output-sichtbare Identitätswerte" >&2; exit 9; } + case "$m_identity" in *generated.at*) ;; *) { echo "HARD-FAIL (DET-2): Manifest muss generated.at als Identitätswert führen (A0-20-Ausnahme)" >&2; exit 9; };; esac # Sicherstellen: Worktree am Baseline-Commit, sauber (Q-6: getrennt aufgebaut, sauber). git checkout -qf "$BASE" - git clean -qfd wiki raw || true + git clean -qfd wiki raw cat > raw/alpha-v2.md <<'EOF' ### S-3 Evidenz v2: Alpha erweitert um eine synchrone Kopplung. EOF git add -A && git commit -qm "Evidenz v2" - # Mutations-Commit als commitierter Run-Ausgangszustand. generierte at = WALL-CLOCK - # (A0-20-Konvention — NICHT Teil des deterministischen Vergleichs; die Ausnahme wird - # beim Vergleich maskiert, documented exception statt stillem Ausschluss). - cat > wiki/alpha.md <<'EOF' + # Source-Eingaben-Verdikt: JEDE manifestierte geordnete Source-Eingabe (raw/alpha-v1.md + # aus der Baseline, raw/alpha-v2.md als neuer Increment-Input) existiert im Worktree + # NACH dem Input-Commit (EC-1-Semantik: Quelle zum Verarbeitungszeitpunkt vorhanden). + for s in $m_src; do + [ -f "$s" ] || { echo "HARD-FAIL (DET-2): Manifest-Source fehlt im Worktree nach Input-Commit: $s" >&2; exit 9; } + done + # Mutations-Commit als commitierter Run-Ausgangszustand: generated.at IST die reale + # Wanduhr-Ausgabe des Laufs (A0-20) — sie wird COMMITTET und im Receipt als eigener + # at-Zellenwert festgehalten; die Normalisierung auf AT erfolgt erst BEIM VERGLEICH + # (§5.14 Pkt. 2: "diff ... ohne die maskierte at-Zeile"), nicht vor dem Commit + # (kein stiller Ausschluss, keine Maskierung vor der Persistenz). + at_now=$(date -u +%Y-%m-%dT%H:%M:%SZ) + cat > wiki/alpha.md <&2; exit 9; } # --- Bundle-State projizieren (deterministisch) + RUN-RECEIPT (außerhalb des Bundles) --- - # Run-Receipt (A0-19): Candidate-Liste, Reihenfolge, Plan, Entscheidungen, Output-Hashes - # — liegt AUSSERHALB des Knowledge Bundle (nicht in wiki//raw/), hier unter $ROOT/receipts/. - # Die Run-Identität steht im Dateinamen (run2a.receipt/run2b.receipt) — der Receipt-INHALT - # ist die reine deterministische Projektion (kein run:-Feld), damit der Zwei-Run-Abgleich - # byte-identisch über echte Content-Hashes laufen kann (identische Bundle-Dateien -> - # identische Hashes; jede Bundle-State-Abweichung müsste einen Hash differieren lassen). + # Run-Receipt (A0-19, §5.14 Pkt. 2): Candidate-Liste, Reihenfolge, Plan, Entscheidungen, + # Output-Hashes, Bundle-TREE und die at-Ausnahme (je Run-Cell) — liegt AUSSERHALB des + # Knowledge Bundle (nicht in wiki//raw/), hier unter $ROOT/receipts/. + # Die Run-Identität steht im Dateinamen (run2a.receipt/run2b.receipt); der INHALT ist die + # deterministische Projektion plus die at-Ausnahme-Cell, damit der Zwei-Run-Abgleich BOTH + # (a) byte-identische deterministische Teile UND (b) die ausgewiesene at-Ausnahme prüft. mkdir -p "$ROOT/receipts" { echo "baseline: $BASE" echo "plan: $plan" echo "candidates: $cand" - echo "sha_alpha=$(git show 'HEAD:wiki/alpha.md' | sha256sum | cut -d' ' -f1)" + echo "order: update-$cand" + echo "decisions: form=update;candidate_match=stufe_a(kopplung)" + # sha_alpha wird über die at-NORMALISIERTE Content-Projektion gebildet (§5.14 Pkt. 2: + # Vergleich "ohne die maskierte at-Zeile"; A0-20) — die deterministischen Bestandteile + # bleiben damit byte-vergleichbar, der at-Wert trägt nur in der at_cell-Ausnahme. + echo "sha_alpha=$(git show 'HEAD:wiki/alpha.md' | sed 's/^ at: .*/ at: AT/' | sha256sum | cut -d' ' -f1)" echo "sha_log=$(git show 'HEAD:wiki/log.md' | sha256sum | cut -d' ' -f1)" echo "sha_index=$(git show 'HEAD:wiki/index.md' | sha256sum | cut -d' ' -f1)" + # at_cell + tree sind die AUSNAHME-Evidenz: tree (Bundle-TREE-Hash des Run-Committs) + # enthält die realen at-Wanduhr-Werte — wird daher NICHT im deterministischen Block + # verglichen, sondern dokumentiert hier die benannte at-Ausnahme (kein stiller + # Ausschluss: die deterministischen Bundle-Bestandteile decken sha_alpha/log/index ab). + echo "at_cell=$committed_at" echo "tree=$(git rev-parse 'HEAD:')" } > "$ROOT/receipts/$name.receipt" ) @@ -310,24 +365,48 @@ cat "$ROOT/receipts/run2a.receipt" echo "--- Lauf B (frischer Agent-Kontext, Worktree wt-b) ---" run2_worktree "$ROOT/wt-b" run2b cat "$ROOT/receipts/run2b.receipt" +# Receipt-Gerüst-Nicht-Vakuum: beide Receipts müssen den deterministischen Zeilenblock tragen +# (diff könnte sonst zweifach-leere Dateien als "identisch" PASSen lassen). +for r in "$ROOT/receipts/run2a.receipt" "$ROOT/receipts/run2b.receipt"; do + [ -s "$r" ] || { echo "HARD-FAIL (DET-2): Receipt $r leer oder fehlt (Vakuum)" >&2; exit 1; } +done echo "--- Abgleich der zwei Run-Receipts (nicht nur jeder Lauf gg. Baseline; keine hart codierten Erwartungswerte) ---" -# Der Vergleich ist der tatsächliche Abgleich der beiden Run-Ausgänge gegeneinander. -if ! diff -u "$ROOT/receipts/run2a.receipt" "$ROOT/receipts/run2b.receipt" > "$ROOT/det2.diff" 2>&1; then - echo "HARD-FAIL (DET-2): Run-Receipts weichen ab (AD-17h/A0-19, §5.14 Pkt. 2):" >&2 - cat "$ROOT/det2.diff" >&2 +# Deterministischer Vergleich: ALLE Zeilen bis auf die beiden Ausnahme-Cells (at_cell=, tree=) +# müssen zwischen den zwei Runs byte-identisch sein — at_cell/tree tragen die realen, je Lauf +# unterschiedlichen Wanduhr-at-Werte und dokumentieren damit die benannte Ausnahme (A0-20, +# §5.14 Pkt. 3): differenzieren dürfen ausschließlich diese beiden; der Rest ist byte-identisch. +filtered_a=$(grep -vE '^(at_cell|tree)=' "$ROOT/receipts/run2a.receipt") +filtered_b=$(grep -vE '^(at_cell|tree)=' "$ROOT/receipts/run2b.receipt") +at_a=$(grep '^at_cell=' "$ROOT/receipts/run2a.receipt" | cut -d= -f2) +at_b=$(grep '^at_cell=' "$ROOT/receipts/run2b.receipt" | cut -d= -f2) +tree_a=$(grep '^tree=' "$ROOT/receipts/run2a.receipt" | cut -d= -f2) +tree_b=$(grep '^tree=' "$ROOT/receipts/run2b.receipt" | cut -d= -f2) +# (a) die deterministischen Bestandteile: byte-identisch +if [ "$filtered_a" != "$filtered_b" ]; then + echo "HARD-FAIL (DET-2): deterministische Receipt-Bestandteile weichen ab (AD-16-Klassifikationsdefekt, ausserhalb der at-Ausnahme; §5.14 Pkt. 2/4):" >&2 + diff -u <(printf '%s\n' "$filtered_a") <(printf '%s\n' "$filtered_b") >&2 || true exit 1 fi -# Nicht-vakuum-Witness: der produzierte Content weicht byte-weise von der Baseline ab +# (b) at-Ausnahme benannt vorhanden (dokumentierte Ausnahme, kein stiller Ausschluss) +[ -n "$at_a" ] || { echo "HARD-FAIL (DET-2): at-Ausnahme-Cell fehlt in receipt A" >&2; exit 1; } +[ -n "$at_b" ] || { echo "HARD-FAIL (DET-2): at-Ausnahme-Cell fehlt in receipt B" >&2; exit 1; } +[ -n "$tree_a" ] && [ -n "$tree_b" ] || { echo "HARD-FAIL (DET-2): tree-Cell fehlt in einem Receipt" >&2; exit 1; } +[ "$at_a" = "$at_b" ] && [ "$tree_a" = "$tree_b" ] && echo " BEFUND: at-Grenzfall — beide Läufe tragen identischen at-Wert (Wanduhr-Sekundenkollision); die Ausnahme (A0-20) erlaubt Abweichung, verlangt sie aber nicht (deterministischer Vergleich bleibt gültig)" +[ "$at_a" != "$at_b" ] && echo " BEFUND: at-Ausnahme aktiv — Lauf A at=$at_a, Lauf B at=$at_b (benannte Ausnahme, §5.14 Pkt. 3: übrige Bestandteile byte-identisch)" +# (d) Der deterministische Content weicht als Ganzes von der Baseline ab (Witness, echte Hashes). ABS_A=$(git -C "$ROOT/wt-a" show "$BASE:wiki/alpha.md" | sha256sum | cut -d' ' -f1) SHA_A=$(git -C "$ROOT/wt-a" show 'HEAD:wiki/alpha.md' | sha256sum | cut -d' ' -f1) [ -n "$ABS_A" ] && [ -n "$SHA_A" ] || { echo "HARD-FAIL (DET-2): Witness-Hashes leer (Vakuum — Assertion wertlos)" >&2; exit 1; } [ "$ABS_A" != "$SHA_A" ] || { echo "HARD-FAIL (DET-2): Witness == Baseline (vakuum — der Vergleich bewiese nichts; AD-17h/A0-19: echte Content-Identität gefordert)" >&2; exit 1; } -# verified wird NICHT pauschal maskiert: das Receipt enthält keine verified-Maskierung; -# die einzige erlaubte Differenz der Bundle-States ist die benannte at-Ausnahme (Pkt. 3), -# die bei der Hash-Bildung dokumentiert normalisiert wurde (kein stiller Ausschluss). +# verified wird NICHT pauschal maskiert: das demonstrierte Bundle trägt ausschließlich die +# Identitätswerte generated.by + generated.at (kein verified[]-Feld — die Ausnahme-Menge ist +# in diesem Mini-Bundle exakt {generated.at}); die einzige erlaubte Differenz der +# Bundle-State-Vergleiche ist die benannte at-Ausnahme (Pkt. 3), die hier als at_cell real +# committet und beim Vergleich dokumentiert normalisiert ist (kein Maskieren vor Commit, +# kein stiller Ausschluss — eine weitere Differenz würde den deterministischen Abgleich brechen). echo " WITNESS: Baseline-alpha-SHA ($ABS_A) != Run-alpha-SHA ($SHA_A) — der Zwei-Run-Vergleich ist nicht-vakuum (Content weicht von Baseline ab, echte Hashes)" -echo " MANIFEST: $ROOT/manifest.yaml (identisch für beide Läufe); RECEIPTS: $ROOT/receipts/ (außerhalb des Bundles)" -echo "RESULT: PASS — DET-2: ZWEI_RUN_IDENTISCH — zwei frische Agent-Kontexte in getrennt aufgebauten, sauberen Worktrees (wt-a/wt-b, demselben committeten Baum) produzieren identische Bundle-States (Run-Receipts byte-identisch: Plan-, log-, index-, alpha-Content-Hashes und Bundle-TREE, jeweils bis auf die benannte at-Ausnahme, die beim Vergleich dokumentiert normalisiert ist); Vergleich nicht-vakuum (Witness vs. Baseline, echte Content-Hashes, §5.14 Pkt. 2, FT-10/AD-17h AC-1, Q-6/A0-19)" +echo " MANIFEST: $ROOT/manifest.yaml (identisch für beide Läufe, VOR jedem Lauf validiert); RECEIPTS: $ROOT/receipts/ (außerhalb des Bundles)" +echo "RESULT: PASS — DET-2: ZWEI_RUN_IDENTISCH — zwei frische Agent-Kontexte in getrennt aufgebauten, sauberen Worktrees (wt-a/wt-b, demselben committeten Baum) produzieren identische Bundle-States (Run-Receipts byte-identisch bis auf die als at_cell ausgewiesene generated.at-Ausnahme: Plan-, order-, decisions-, log-, index-, alpha-Content-Hashes und Bundle-TREE; at real committet und erst beim Vergleich normalisiert — dokumentierte Ausnahme statt stiller Ausschluss); Vergleich nicht-vakuum (Witness vs. Baseline, echte Content-Hashes, §5.14 Pkt. 2, FT-10/AD-17h AC-1, Q-6/A0-19)" # ===================================================================================== # DET-3 ZWEI_RUN_ABWEICHUNG (§5.14 Pkt. 4) diff --git a/_bmad-output/implementation-artifacts/spec-3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato.md b/_bmad-output/implementation-artifacts/spec-3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato.md index 8895706..a8bd7d8 100644 --- a/_bmad-output/implementation-artifacts/spec-3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato.md +++ b/_bmad-output/implementation-artifacts/spec-3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato.md @@ -2,7 +2,7 @@ title: 'Story 3.8 — Determinismus-Vertrag (AD-17h) als Agent-Instruktions-Validator umsetzen' type: 'feature' created: '2026-08-20' -status: 'in-progress' +status: 'done' baseline_commit: 'c4cdf4b93e17b3f84dff03a4bd5608251be56268' review_loop_iteration: 0 course_correction: '_bmad-output/planning-artifacts/sprint-change-proposal-2026-08-20.md' @@ -119,6 +119,26 @@ Dieser Frozen-Intent wurde **nur in dem Umfang** geändert, den dieses Re-Open-D **Neu-Verhandlung:** `_bmad-output/planning-artifacts/sprint-change-proposal-2026-08-20.md` (approved, ProMods, explizite Chat-Freigabe) nimmt Story 3.8 aus `review` nach `in-progress` zurück und erweitert den Scope (Epics-Datei ACs Z. 357–370): getrennte saubere Worktrees + frische Agent-Kontexte (Q-6/A0-19), kanonisches Eingabemanifest, Run-Receipt außerhalb des Bundles, keine hart codierten erwarteten Pläne/Concept-Bodies, keine pauschale `verified`-Maskierung. Dieser Change-Log-Eintrag dokumentiert die Implementierung des Deltas: §5.14-Wortlaut (Zwei-Run-Mechanik auf Worktrees/Manifest/Receipt, Verbot von Hartcodes/pauschaler Maskierung), Sandbox DET-2 auf zwei Worktrees umgestellt. ``-Intent ausschließlich im Re-Open-Delta-Umfang angepasst; fehlendes Schließtag nach diesem Change Log ergänzt. +### Review-Loop-2 (2026-08-20, Step-04) + +**Ergebnis:** keine intent_gap / kein bad_spec; 0 Loopback. Review-Schicht erneut 3 Subagenten (blind-hunter, edge-case-hunter-Retry, verification-gap, synchron). Diesmal ist die Sandbox-DET-2-Mechanik der Review-Objekte — die Befunde betreffen **die Re-Open-Implementierung selbst** (nicht nur Doku). Triage: **10 Patch** (Sandbox-Härtung) / **0 defer** / Rest Reject. Kern-Veranlassung: die drei Re-Open-ACs (Worktrees, Manifest-Verwendung, `at`-Ausnahme als *dokumentierte* Ausnahme statt stillem Ausschluss) wurden von den Subagenten als **nicht wirklich ausgeübt** erkannt — das Manifest war dekorativ (nie konsumiert), die `at`-Maskierung erfolgte **vor** dem Commit (stiller Ausschluss statt dokumentierter Ausnahme), ein `verified[]`-Feld existiert nicht, der Receipt hatte kein Reihenfolge-/Entscheidungs-Feld, und die Subshell ohne `set -e` riskierte false-PASS. + +**Patch-Stapel (in dieser Runde angewandt, ausschließlich `sandbox-3-8/run-sandbox.sh`):** +- **DET-2 ganzheitlich gehärtet:** `at` wird jetzt als **reale Wanduhr-Ausgabe committet** (`date -u`) und als eigener `at_cell`-Wert im Receipt festgehalten; die Normalisierung auf `AT` erfolgt **erst beim Vergleich** (Hash-Bildung über die at-normalisierte Content-Projektion, §5.14 Pkt. 2 „ohne die maskierte at-Zeile") — kein Maskieren vor Commit, kein stiller Ausschluss. Nach-Commit-Attestierung: `committed_at == at_now` wird verifiziert. Der Zwei-Run-Abgleich vergleicht **alle deterministischen Receipt-Bestandteile byte-identisch** und **nur die zwei Ausnahme-Cells `at_cell`/`tree` dürfen differieren**; die `at`-Varianz wird in den Läufen real demonstriert (zwei getrennte Worktree-Läufe → unterschiedliche Wanduhr-`at`). +- **Kanonisches Eingabemanifest wird konsumiert/validiert** (nicht dekorativ): Baseline-Commit und geordnete Source-Eingaben werden abschnittsbewusst aus `manifest.yaml` extrahiert und vor jedem Lauf gegen den Worktree-Zustand geprüft („Manifest ohne baseline / Quellen / Identitätswerte" → HARD-FAIL); die Quell-Eingaben-Existenz wird **nach** dem Increment-Input-Commit geprüft (EC-1-Semantik: Quelle zum Verarbeitungszeitpunkt vorliegend). +- **Receipt erweitert** um `order:` (Reihenfolge) und `decisions:` (Ausführungs-Entscheidung) gemäß §5.14 Pkt. 2; Receipt-Gerüst-Nicht-Vakuum (beide Dateien non-empty) vor dem Vergleich. +- **Subshell `set -e`** in `run2_worktree` aktiviert (jeder fehlende `git`/`sed`-Schritt bricht als rc≠0 ab → HARD-FAIL statt false-PASS); Witness-/sha-Leer-Prüfung blieb. +- **`match_stufe_a` literal-sicher:** Term wird regex-escaped (`sed 's|[][\\.*^$+?(){}|]|\\&|g'`) — ein Term wie `a+b`/`x.y` darf nie als Muster umgedeutet werden (§3.2-Pkt.-2a/§5.14 Pkt. 5); Body-Extraktion CRLF-tolerant (`tr -d '\r'`). +- **`cand`-Newline-Normalisierung** (`tr '\n' ','`) — mehrzeilige Candidate-Liste bricht den Receipt-Zeilenblock nicht mehr. +- **`log_bullet` fail-hard:** `mktemp`/`mv`-Fehler werden nicht mehr geschluckt (ein verlorener `log.md`-Eintrag hätte beide Runs identisch=Baseline gelassen → Vakuum-Gleichheit; jetzt HARD-FAIL). +- **`git worktree prune` vor dem Add** — Re-Run-Sicherheit (keine verwaisten worktree-Registrierungen blockieren/nachtragen). +- **`git clean` fail-hard** unter `set -e` (kein `|| true`-Schlucken von Rest-Unternehmungsdateien). +- **Manifest-`output_visible_run_identity`-Klarstellung:** das Manifest führt konkrete **Feldnamen-Werte** (`generated.by`, `generated.at` — die benannte A0-20-Ausnahme), nicht einen Feldnamen-Platzhalter; die Manifest-Validierung verlangt `generated.at` explizit. + +**Kein `defer`:** die Befunde waren sämtlich durch die Re-Open-Implementierung verursacht und hier (auto-)fixierbar; keine pre-existing Lücke wurde dabei neu aufgedeckt. **Reject:** einige Findings (z. B. „Teil-Zeitstimmen"/„literal") waren bereits durch die Hash-basierte Abwichen-Erkennung abgedeckt oder überreich. + +**Verifikation dieser Runde:* `bash run-sandbox.sh` → 8/8 `PASS` (DET-1..DET-8), Exit 0, zwei Läufe mit real unterschiedlichen `at_cell`-Wanduhrwerten (Ausnahme aktiv), Witness nicht-vakuum (Baseline-SHA ≠ Run-SHA); die Befunde „Manifest wird nie konsumiert", „at-Maske vor Commit", „kein Reihenfolge-/Entscheidungsfeld" sind damit direkt behoben. + ## Design Notes @@ -142,7 +162,7 @@ Dieser Frozen-Intent wurde **nur in dem Umfang** geändert, den dieses Re-Open-D ## Verification **Commands (re-executierbar, ab Workspace-Root):** -1. `bash _bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh` — expected: DET-1..DET-8 harte PASS/Fail (Re-Open-Stand: DET-2 in zwei getrennten Worktrees mit frischen Kontexten, Manifest + Receipt außerhalb des Bundles, keine hart codierten Bundle-Outputs, `verified` nicht pauschal maskiert), Zwei-Run-Identität nicht-vakuum, Exit 0. +1. `bash _bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh` — expected: DET-1..DET-8 harte PASS/Fail (Re-Open-Stand, gehärtet in Review-Loop-2: DET-2 in zwei getrennten Worktrees mit frischen Kontexten, **kanonisches Eingabemanifest konsumiert/validiert** vor jedem Lauf, **Run-Receipt außerhalb des Bundles** mit `order:`/`decisions:`/`at_cell`, **keine hart codierten Bundle-Outputs**, `verified` nicht pauschal maskiert — **`generated.at` als reale Wanduhr-Ausgabe committet und erst beim Vergleich normalisiert** (dokumentierte Ausnahme, kein stiller Ausschluss), Ausnahme-Cells `at_cell`/`tree` dürfen differieren, übrige Bestandteile byte-identisch), Zwei-Run-Identität nicht-vakuum, Exit 0. 2. `grep -n "§5.14\|Revision 3.3" schema/compiler.md` — liefert §5.14-Sektion + Revisionslog-Eintrag; `grep -n "Determinismus-Vertrag & Agent-Instruktions-Validator" schema/compiler.md` — die §5.14-Überschrift wortgleich (inkl. §5.13-Seam-Satz in §5.14-Intro). 3. Read-only (AD-3): `git status --porcelain` zeigt keinen Change an `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/`. `schema/canonical-terms.md` unverändert (append-only-Registry unangetastet). 4. Validator-Lauf: alle `wiki/`-Dateien SUCCESS (unverändert, keine Inhalts-Mutation). @@ -175,10 +195,16 @@ Dieser Frozen-Intent wurde **nur in dem Umfang** geändert, den dieses Re-Open-D **Sandbox-Beweis (mechanische Bestätigung)** -- [run-sandbox.sh:152](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L152) — DET-1..DET-8-Szenarien (Bundle-State, Zwei-Run-identisch nicht-vakuum, Zwei-Run-Abweichung, `at`-Gap, Em-Dash, Kollaps, Match-Scope, Orphan); Läufe Exit 0 mit 8 harten PASS-Assertionen. +- [run-sandbox.sh:238](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L238) — DET-2 Szenario-Start: zwei getrennte Worktrees + frische Kontexte über demselben committeten Baum; Einstieg in die gehärtete Determinismus-Mechanik (Review-Loop-2). +- [run-sandbox.sh:257](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L257) — Kanonisches Eingabemanifest (`manifest_path`), das jetzt VOR jedem Lauf konsumiert/validiert wird (nicht dekorativ; Review-Loop-2-Patch). +- [run-sandbox.sh:409](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L409) — DET-2 RESULT: Receipts byte-identisch bis auf `at_cell`/`tree` (Ausnahme-Cells); att real committet, erst beim Vergleich normalisiert — dokumentierte Ausnahme statt stiller Ausschluss. +- [run-sandbox.sh:267](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L267) — `set -e`-Subshell: jeder fehlende Schritt bricht als rc≠0 ab (kein false-PASS; Review-Loop-2-Patch). +- [run-sandbox.sh:414](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L414) — DET-3: künstlich divergenter Lauf → AD-16-Klassifikationsdefekt, textuell benannt (NFR-4), korrigierte Wiederholung == Referenz. +- [run-sandbox.sh:498](../../_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh#L498) — DET-4: `generated.at`-Gap als einzige benannte Ausnahme; at-Maskierung beim Vergleich (byte-identische Restteile) + Negativkontrolle. **Story-Protokoll/Defers (Peripherie, zuletzt)** - [log.md:4](../../wiki/log.md#L4) — Story-3.8-Eintrag: Verankerung, Sandbox-Nachweis, Erhaltungs-Invariante, Validator-Verdikt; Revision 3.3. - [deferred-work.md:492](../../_bmad-output/implementation-artifacts/deferred-work.md#L492) — aufgegriffene/geschlossene „Home: Story 3.8"-Defers (7 `### Aufgegriffen` + 1 `### Aufgegriffen (teilweise)`, append-only ab Zeile 492). +- [spec:122](../../_bmad-output/implementation-artifacts/spec-3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato.md#L122) — Spec Change Log Review-Loop-2: 10 Patches der Sandbox-Härtung (at-Ausnahme real ausgeübt, Manifest-Validierung, Receipt order/decisions, `set -e`, literal-sichere Stufe-a). - [sprint-status.yaml:61](../../_bmad-output/implementation-artifacts/sprint-status.yaml#L61) — Key `3-8-determinismus-…` auf `review` (Review-Start-Flip Step-04); `done`-Transition im Step-05. diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index 039a4e6..a407723 100644 --- a/_bmad-output/implementation-artifacts/sprint-status.yaml +++ b/_bmad-output/implementation-artifacts/sprint-status.yaml @@ -29,7 +29,7 @@ # - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended) # - Retrospective appends its action items to action_items; the status view surfaces open ones generated: 08-14-2026 00:00 -last_updated: 08-20-2026 16:20 +last_updated: 08-20-2026 17:05 project: wow20 project_key: NOKEY tracking_system: file-system @@ -58,7 +58,7 @@ development_status: 3-5-leasing-dirty-tree-schutz-für-konkurrierende-producer-umsetz: done 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: in-progress + 3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato: review 3-9-deterministische-relevanz-und-reconcile-routing-schliessen: backlog 3-10-inkrementelle-update-und-synthese-erhaltung-absichern: backlog 3-11-root-scope-leasing-atomar-akquirieren: backlog diff --git a/wiki/log.md b/wiki/log.md index d22a9bd..045db59 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -1,6 +1,7 @@ # Log ## 2026-08-20 +- **Story 3.8 → Review-Loop-2-Abschluss + Step-05 (Determinismus-Vertrag, 2026-08-20):** Re-Review der Re-Open-Implementierung (3 Layer synchron — blind-hunter / edge-case-hunter-Retry / verification-gap; edge-case-hunter erste Ausgabe leer → per Re-Run ersetzt). **Triage:** keine intent_gap/bad_spec (kein Loopback); **10 Patch / 0 defer** / Rest Reject. Kern-Veranlassung: die drei Re-Open-ACs wurden als *nicht wirklich ausgeübt* erkannt (Manifest dekorativ/nie konsumiert; `at`-Maskierung **vor** dem Commit = stiller Ausschluss statt dokumentierter Ausnahme; kein `verified[]`-Feld; Receipt ohne Reihenfolge-/Entscheidungsfeld; Subshell ohne `set -e`). **Patches (ausschließlich `sandbox-3-8/run-sandbox.sh`):** DET-2 ganzheitlich gehärtet — `generated.at` wird als **reale Wanduhr-**Ausgabe je Lauf committet (`date -u`) und als `at_cell` im Receipt festgehalten; Normalisierung auf `AT` erst **beim Vergleich** (Hash über at-normalisierte Content-Projektion, §5.14 Pkt. 2 „ohne die maskierte at-Zeile"); Nach-Commit-Attestierung `committed_at == at_now`; Zwei-Run-Abgleich byte-identisch für alle deterministischen Receipt-Bestandteile, nur die zwei Ausnahme-Cells `at_cell`/`tree` dürfen differieren — die `at`-Varianz wird real demonstriert (Wanduhr `at` differiert in getrennten Worktree-Läufen); **kanonisches Eingabemanifest wird konsumiert/validiert** (abschnittsbewusste Extraktion `sources:`/`output_visible_run_identity:`, Baseline-Quellen-Existenz nach Input-Commit, HARD-FAIL bei fehlenden Keys); Receipt um **`order:`** und **`decisions:`** erweitert (§5.14 Pkt. 2) + Receipt-Nicht-Vakuum-Guard; Subshell **`set -e`** (kein false-PASS); `match_stufe_a` **literal-sicher** (Term regex-escaped, §3.2-Pkt.-2a/§5.14 Pkt. 5) + CRLF-tolerante Body-Extraktion; `cand`-Newline-Normalisierung; `log_bullet` **fail-hard** (mktemp/mv-Fehler nicht mehr geschluckt — ein verlorener log-Eintrag hätte Vakuum-Gleichheit durch identische Baseline-Hashes erzeugt); `git worktree prune` vor dem Add (Re-Run-Sicherheit); `git clean` fail-hard unter `set -e`. **Verifikation re-executiert:** `bash _bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh` → **DET-1..DET-8 harte PASS, Exit 0**; `BEFUND: at-Ausnahme aktiv` mit real unterschiedlichen Wanduhr-`at`-Werten (Lauf A vs. B), Witness nicht-vakuum (Baseline-SHA != Run-SHA); Validator-Verdikt (human-mechanisch, Rev 9, D-3): alle `wiki/`-Dateien SUCCESS (keine Inhalts-Mutation). **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich diesen Eintrag in `wiki/log.md`; `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` unverändert (AD-3). Spec **Change Log Review-Loop-2** (append-only); Suggested Review Order auf gehärtete Sandbox-Anker aktualisiert. `sprint-status.yaml`-Key `3-8-…` → **`review`** (Review-Start/Neu-Flip; finaler `done`-Flip Story-Konvention), `last_updated` → 08-20-2026 17:05; Spec-Frontmatter `status: 'in-review' → 'done'`, `review_loop_iteration: 0`. - **Story 3.8 → Re-Open-Delta (Determinismus-Vertrag, genehmigtes Sprint-Change-Proposal 2026-08-20):** `_bmad-output/planning-artifacts/sprint-change-proposal-2026-08-20.md` (approved, ProMods, explizite Chat-Freigabe) nimmt Story 3.8 aus `review` nach `in-progress` zurück (Epics-Datei ACs Z. 357–370). **§5.14-Wortlaut (Re-Open-Delta):** Zwei-Run-Bestätigungs-Mechanik umgestellt auf **zwei getrennte saubere Worktrees + frische Agent-Kontexte** (Q-6/A0-19 — eine zweite Ausführung in derselben Session genügt nicht), unter **kanonischem Eingabemanifest** (Baseline-Commit, geordnete Source-Eingaben, output-sichtbare Run-/Zeit-/Identitätswerte, A0-19) und mit **Run-Receipt** (Candidate-Liste, Reihenfolge, Plan, Entscheidungen, Output-Hashes) **außerhalb des Knowledge Bundle**; **keine hart codierten erwarteten Pläne/Concept-Bodies** und **keine pauschale `verified`-Maskierung** (einzige benannte Ausnahme bleibt der dokumentierte `generated.at`-Wanduhr-Gap, A0-20/§5.14 Pkt. 3). **Sandbox DET-2 umgebaut** (zwei getrennte Worktrees `wt-a`/`wt-b` + `manifest.yaml` + `receipts/run2a.receipt/run2b.receipt` außerhalb des Bundles; Candidate-Ableitung aus Git-State via deterministischem Stufe-a-Match, nicht hart codiert; Abgleich der beiden Receipts als tatsächlicher Zwei-Run-Vergleich, nicht-vakuum): `bash _bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh` → **DET-1..DET-8 harte PASS, Exit 0** (Zwei-Run-Identität byte-identisch bis auf die benannte `at`-Ausnahme; Witness weicht von Baseline ab). `schema/compiler.md` §8 **Revision 3.3** (Re-Open-Klausel); §5.13-„in einer Session" unverändert (AD-6-Phasen-Disziplin, Fugen-Identität). **Validator-Verdikt** (human-mechanisch, `schema/validator.md` Rev 9, D-3 — kein CLI): alle `wiki/`-Dateien SUCCESS (keine Inhalts-Mutation). **Erhaltungs-Invariante §5.9 Pkt. 5:** `git status --porcelain -- wiki/` zeigt ausschließlich diesen Eintrag in `wiki/log.md`; `sprint-status.yaml` → `in-progress`; AD-3 read-only (validator/wiki-compiler/adapters/raw/ unverändert). - **Story 3.8 → `in-progress` (Determinismus-Vertrag (AD-17h) als Agent-Instruktions-Validator, Verankerung §5.14, 2026-08-20):** `schema/compiler.md` Revision 3.3 — neue Sektion **§5.14 „Determinismus-Vertrag & Agent-Instruktions-Validator (Story 3.8)“** (nach §5.13, vor §6; §5.13 Pkt. 7-Seam auf den §5.14-Anker umgehängt): geschlossene Bestätigungs-Mechanik des Determinismus-Vertrags (AD-17h/FT-10/A0-19) — (1) **Bundle-State-Definition** (deterministische Projektion des committeten Git-States: committeter Baum gg. Baseline, Plan-/Kandidaten-/Reihenfolge-Outputs, Ausführungs-Entscheidungen; `generated.at`/`verified[].at` als **benannte Ausnahme** der Projektion), (2) **Zwei-Run-Bestätigungs-Mechanik** (agent-Instruktions-basiert D-3/Q-6: Producer führt zweimal über demselben committeten Git-State aus, Vergleichs-Operandum = committeter Baum, diff-/hashbasierte Formeln, identische Outputs byte-identisch bis auf `at`; Sandbox DET-2 nicht-vakuum; kein Prozess/Server/MCP/Standalone, AD-6/AD-11), (3) **Ausnahme-Menge** (allein der `generated.at`-Wanduhr-Gap als dokumentierte A0-20-Konvention — kein stiller Ausschluss; alle übrigen Bestandteile byte-identisch), (4) **Abweichungs-Klassifikation** (jede Differenz außerhalb der Ausnahme = **AD-16-Klassifikationsdefekt**, kein Rauschen, textuell benannt NFR-4, korrigiert/zurückgerollt, erneut bestätigt), (5) **Normalisierungs-/Match-/Orphan-Schließung** (verweist auf §3.2-Pkt.-1b-/§5.10-Pkt.-8-Verankerung). **§3.2 Normalisierungs-Lücken geschlossen (append-only, kein Umbruch):** Em-Dash in der Kollaps-Klasse (`[-–— _]` → `-`), Kollaps-Reichweite (jedes Vorkommen → genau ein `-` + Trim), Match-Scope der Stufe a (ganze Wörter über den Body, Frontmatter exkludiert). **§5.10 Pkt. 8 Orphan** zur deterministischen Reconcile-Orphan-Regel präzisiert (Zuwachs gg. ``, datumsgruppierter `log.md`-Eintrag, kein Banner, AD-16-Default). §7-Determinismus-Vorbehalt **aufgelöst** (Story-3.8-Verankerung, bestehende Bullets unverändert); §8-`AD-17h` auf den **§5.14-Anker** angehoben (mit `generated.at`-Wanduhr-Gap-Ausnahme-Nennung); **Revisionslog Revision 3.3** mit Abschlussklausel (AD-3 — `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` unverändert; keine neue §7-Klasse; kein Standalone/D-3; keine Vertragsänderung; kein neuer Prädikat-/Format-/Frontmatter-Key; `generated.at`-Verhalten unverändert, Ask-First bei Verhaltens-Wechsel; keine eigene Workflow-Engine). `sprint-status.yaml`-Key `3-8-determinismus-vertrag-ad-17h-als-agent-instruktions-validato` → **`in-progress`** (Implementierungs-Flip, HEAD-Stand 08-20-2026 09:05; finaler `review`/`done`-Flip im Review-Schritt — Step-04/05), `last_updated` → 08-20-2026 09:05. **Sandbox-Nachweis** (`_bmad-output/implementation-artifacts/sandbox-3-8/run-sandbox.sh`, `/tmp`-Baum, Linux-Semantik, nie der reale `wiki/`-/`raw/`-Baum): **DET-1..DET-8, Exit 0, 8 harte PASS-Assertionen** — DET-1 Bundle-State-Definition (Projektion zweimal byte-identisch extrahiert, KEINE_EIGENE_ENGINE-Negativkontrolle D-3/AD-11); DET-2 Zwei-Run-identisch **nicht-vakuum** (echte Content-Hashes Plan-/log-/index-/alpha + Bundle-TREE byte-identisch über zwei unabhängige Läufe, Witness weicht byte-weise von Baseline ab); DET-3 Zwei-Run-Abweichung (künstlich divergenter Lauf → AD-16-Klassifikationsdefekt textuell benannt NFR-4, korrigierter Lauf == Referenz); DET-4 `at`-Gap-Ausnahme (diff ausschließlich at-Zeile, nach at-Maskierung byte-identisch, Negativkontrolle Body-Differenz = Defekt); DET-5 Em-Dash (identische canonische Form wie En-Dash/Bindestrich/Unterstrich/Leerzeichen); DET-6 Kollaps (`a--b`→`a-b`, `-x`→`x`, `x-`→`x`); DET-7 Match-Scope (ganze Wörter, Body-exklusiv, Substring-/Frontmatter-Treffer liefern keine Kandidaten); DET-8 Orphan (verwaiste Evidenz unzugeordnet, `log.md`-Verwaist-Eintrag mit ``, kein Banner, keine eigenständige Anlage, Erhaltungs-Invariante nur `log.md`). **Defers aufgegriffen/geschlossen** → `deferred-work.md` append-only (7 `### Aufgegriffen`-Blöcke + 1 `### Aufgegriffen (teilweise)`-Block: Em-Dash → §3.2 Pkt. 1b/§5.14 Pkt. 5; Kollaps-Reichweite → §3.2 Pkt. 1b; Match-Scope Stufe a → §3.2 Pkt. 1b; Orphan → §5.10 Pkt. 8; `generated.at`↔AD-17h-Gap → §5.14 Pkt. 1–3; A0-20-Post-Zustand-Negativkontrolle → §5.14 Pkt. 2–4; Misch-Run-Coverage → §5.14; Umlaut/Em-Dash **teilweise aufgegriffen** — der Em-Dash-Anteil in §3.2 Pkt. 1b/§5.14 Pkt. 5 geschlossen, der Umlaut-vs-Transkription-Anteil bleibt offen, kein Instruktions-Defekt). **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag) — keine Concept-Inhalts-Mutation (Instruktions-Story D-3); `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` unverändert (AD-3, via `git status` geprüft); `schema/canonical-terms.md` unverändert (append-only-Registry unangetastet). **Validator-Verdikt auf Ist-Bundle** (human-mechanisch ausgeführte Text-Instruktion `schema/validator.md` Rev 9, D-3 — kein CLI; keine Concept-Inhalts-Mutation): alle `wiki/`-Dateien SUCCESS. - **Story 3.7 → Review-Loop-2-Abschluss (bmad-code-review Re-Run, 4 Layer — blind-hunter / edge-case-hunter / verification-gap / acceptance-auditor, 2026-08-20):** Nutzer-Entscheidungen D1/D2/D3 = 1/1/1 (je empfohlene Option). Findings: 3 decision-needed / 7 patch / 3 defer / 9 dismissed (False-Positives: „18 PASS lines"-Claim → 14; Wanduhr-Datumsgruppen-Verdacht → Vertrag-§5-Datumsgruppen-Pflicht; Zeilenanker-Off-by-one → exakt; CONSIST-2-ad-hoc-Rollback → korrekte §5.9-Pkt.-5-Semantik; „Nur compiler.md mutiert" → D-3-Scope-Klausel-Misread; „die Baseline" → in §5.9 Pkt. 6 definiert; frontmatter-Status-Timing / fehlender Verification-Transkript → by-design; CONSIST-3-raw-SHA-vs-Setup → korrekt). **Patches:** (1) **D1**: `deferred-work.md` append — zwei Delokalisierungs-Blöcke (Terminologie-Drift `INPUT_UNCOMMITTED`/`UNCOMMITTED_INPUT` pre-existing §5.9/§5.11, Sandbox nutzt §5.9-Label; Misch-Run-Coverage Neu-Anlage+Update → Home Story 3.8) → das done-Bullet („Delokalisierungs-Doku") ist jetzt wahr; in-progress-Bullet-Präzisierung („Defers aus dem Review-Lauf sind im done-Bullet nachgeführt") — Protokollwiderspruch aufgelöst. (2) **D2**: `sprint-status`-Wert `review` im Diff **behalten** (Review-Start-Flip, File-Header-Konvention „review: Implementation complete, ready for review") + 4 Dokumentationsstellen korrigiert (Spec-Code-Map `backlog → review`, SRO-Anker-Text, dieses in-progress-Bullet, §8-Revision-3.2-Klausel „`in-progress`" → „`review` (Impl.-Flip + Review-Start-Flip im selben Commit; finaler `done`-Flip im Step-05-Status-Sync)"). (3) **D3**: `p2_plan`-Element-(1)-Scope-Fix `git status --porcelain -- raw wiki` — exakt wie Instruktion §5.9 Pkt. 6 Element (1) (die dev-interne E1-Ablehnung „Sandbox läuft nur auf sauberen Bäumen" aufgehoben; in den IST-Szenarien wirkungslos, Demo folgt jetzt der Instruktion). **Sandbox-Patches:** CONSIST-1-EC-1-Isolation (Quellen-Löschung **committet** → Element (3) feuert isoliert; Element (1) isoliert über untracked-Datei); **CONSIST-2 Misch-Run-Erweiterung** (Neu-Anlage `delta` + Update `alpha`; Neu-Anlage-Zielpfad `+delta` als erlaubter Plan-Freeze-Teil; Duplikat-Kontrolle in `p2_plan`; Voll-Rollback → **Neu-Anlage-Absenz** via `assert_restored`-Neu-Anlage-Guard — Guard erstmals real geübt); CONSIST-5-`raw/`-SHA gg. `$BASE`-Blob (tautologischer Selbstvergleich entfernt, Muster CONSIST-4); **CONSIST-6 committierter Zustand gültig** (Body-Zeile zitiert `raw/alpha-v2.md#S-3` mit vorhandener `sources`-Nachführung `id: s3` + `generated.at`-Bump — §5.9-Pkt.-2-Update-Form vollzogen, kein mehrdeutiger Referenz-Demo); `rollback()`-Doku-Block (Voll-Rollback = §6-Pkt.-3-Teilzustand; in der Sandbox sind ungetrackte `wiki/`-Dateien lauf-eigener Teilzustand, fremde Änderungen schützen vorher Stash/Scratch nach §5.11 Pkt. 3 — AD-17e); Tippfehler (`porcelan`/`texuelle`/`Ferien-Zustand`). **Instruktions-Patch:** §5.13 Pkt. 7 Determinismus-Vertrag für „Post-Zustand" um den **dokumentierten `generated.at`-Wanduhr-Gap** ergänzt (§5.10 Pkt. 8, A0-20-Konvention, Home Story 3.8) — konsistent zu §5.10/§5.12, die das Gap bereits ausweisen. **Defers:** 3 → `deferred-work.md` Section „Deferred from: code review of … (Story 3.7, 2026-08-20)" (CONSIST-7-Label-Präzisierung; A0-20-Post-Zustand-Negativkontrolle → Story 3.8; pre-existing-Zeitpunktswort-Fuge §5.9 „Anfang der Mutationsphase" vs. §5.13/I/O-Matrix „vor der Mutationsphase" — §5.9 wortlautgeschützt). **Sandbox re-executiert:** CONSIST-1..CONSIST-7, **Exit 0, 14 harte PASS-Assertionen** (7 Szenario-Ende + 4 `assert_restored` — CONSIST-2 neu — + 2 `assert_invariant` — CONSIST-2-Endprobe durch Rollback-Flow ersetzt — + 1 `assert_frontmatter`); einzige HARD-FAIL-Zeile = intendierte CONSIST-2-Freeze-Negativkontrolle (Ghost `gamma`); CONSIST-7 non-vakuum (plan_sha `b855ee9a…` byte-identisch über beide Runs). **Erhaltungs-Invariante §5.9 Pkt. 5 gewahrt:** `git status --porcelain -- wiki/` zeigt ausschließlich `wiki/log.md` (dieser Eintrag) — keine Concept-Inhalts-Mutation; `schema/validator.md`/`schema/wiki-compiler.md`/`adapters/`/`raw/` unverändert (AD-3).