From b4451527c377e986b7cdfad88bdbac0b4b3eeba1 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Fri, 29 May 2026 09:49:09 +0100 Subject: [PATCH] =?UTF-8?q?builder:=20clean-tree-before-claim=20discipline?= =?UTF-8?q?=20(git=20status=20must=20be=20clean=20=E2=80=94=20Adversary=20?= =?UTF-8?q?cold-verifies=20from=20git)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cheap guard against the deploy/git divergence: a fix built locally but uncommitted/un-pushed is a guaranteed Adversary cold-build mismatch. Added to the builder prompt claim discipline + plan.md §6.1. (Lighter than binding the deploy to a git rev — iteration speed + the Adversary's cold-from-git verify is the real safety net.) Co-Authored-By: Claude Opus 4.8 (1M context) --- cc-ci-plan/plan.md | 4 ++++ cc-ci-plan/prompts/builder.md | 1 + 2 files changed, 5 insertions(+) diff --git a/cc-ci-plan/plan.md b/cc-ci-plan/plan.md index e92d118..8500ced 100644 --- a/cc-ci-plan/plan.md +++ b/cc-ci-plan/plan.md @@ -648,6 +648,10 @@ its own pacing. To make concurrent writes conflict-free: Builder. So the prefixes are **load-bearing** — a gate claim MUST be a `claim(...)` commit and a verdict MUST be a `review(...)` commit, or the counterpart isn't promptly woken (it falls back to its slower self-poll). STATUS/REVIEW remain the durable source of truth; the prefix is the signal. + - **Clean tree before claim.** The Builder runs `git status` before claiming — the working tree + must be clean (everything committed AND pushed). The Adversary cold-verifies from a fresh clone, + so an uncommitted/un-pushed change that only exists on the Builder's host (e.g. a locally-built + fix) is a guaranteed cold-verify mismatch. Commit + push first, then claim. - **DONE handshake.** Builder may write `## DONE` to `STATUS.md` **only** when `REVIEW.md` shows a PASS dated within 24h for every D1–D10. The Adversary can write `## VETO ` to `REVIEW.md` at any time, which forbids DONE until cleared. diff --git a/cc-ci-plan/prompts/builder.md b/cc-ci-plan/prompts/builder.md index 8a6ff68..ce93e06 100644 --- a/cc-ci-plan/prompts/builder.md +++ b/cc-ci-plan/prompts/builder.md @@ -10,6 +10,7 @@ You run as a SEPARATE process from the Adversary loop and coordinate ONLY throug - Write ONLY your files: source/config, STATUS.md, JOURNAL.md, DECISIONS.md, and the "## Build backlog" section of BACKLOG.md. Treat REVIEW.md and "## Adversary findings" as read-only — the Adversary owns them. - ARTIFACT-LAYER ISOLATION (facts in STATUS, reasoning in JOURNAL). STATUS.md **MUST** give the Adversary everything it needs to verify your claim — withholding verification context defeats the verification: **WHAT** is claimed (gate id, DoD items), **HOW** to verify it (the exact command/check the Adversary can re-run from its own clone), the **EXPECTED** outcome (build hashes, file contents, status codes, leaf fingerprints, command exit), and **WHERE** the inputs live (commit shas, paths). If something is essential for the Adversary to verify, put it in STATUS. STATUS **MUST NOT** include rationalisations / "I think this passes because…" / design narrative / dead-ends explored / design choices and their justification — those go in JOURNAL.md, which the Adversary is instructed not to read before forming its verdict (anti-anchoring), so keeping reasoning out of STATUS preserves that. The line: **WHAT + HOW + EXPECTED + WHERE = STATUS; WHY = JOURNAL.** DECISIONS.md is for SETTLED design decisions (joint authority), not in-the-moment rationale. - At each milestone gate, set "Gate: CLAIMED, awaiting Adversary" in STATUS.md and work other unblocked items; do NOT advance past the gate until REVIEW.md shows its PASS. +- CLEAN TREE BEFORE CLAIM: run `git status` before you claim — the working tree MUST be clean (everything committed AND pushed). The Adversary cold-verifies from a fresh git clone, so any uncommitted/un-pushed change that only exists on your host (e.g. a fix you built locally but didn't commit) is a guaranteed Adversary cold-build/verify mismatch. Commit + push it first, then claim. - INBOX side-channel (§6.1). For non-gate messages to the Adversary (heads-up, "I'm starting a long e2e," "please cold-verify this while I keep going," etc.), write/append `machine-docs/ADVERSARY-INBOX.md` in your clone and push — the watchdog edge-pings the Adversary on appearance. To receive a message from the Adversary, look for `machine-docs/BUILDER-INBOX.md`; process it, then DELETE the file (commit + push) — deletion is the "consumed" signal. Do NOT use the inbox for formal gate claims or verdicts — STATUS.md / REVIEW.md still own those. - INBOX — for non-gate cross-loop messages (heads-ups, requests for early-look, "I refactored X please re-verify Y", "starting a 25-min e2e"), write `machine-docs/ADVERSARY-INBOX.md` in your clone and push. The watchdog edge-triggers and pings the Adversary. The Adversary deletes the file on consumption. If you receive `machine-docs/BUILDER-INBOX.md` (Adversary side-channel to you), read+process+`git rm` it+push — deletion is the "consumed" signal. Use the inbox for things that aren't a formal gate claim or a verdict; CLAIMS still live in STATUS.md and verdicts in REVIEW.md (the inbox is a side-channel, not a replacement). - PACING for long-running tasks (e2e / deploy / nixos-rebuild / heavy test): POLL every ~5 min, not a single big ScheduleWakeup that matches the expected runtime. A 25-min e2e gets ~5 short cache-warm polls so you see failures as they happen — never a 25-min cache-cold blackout. (plan.md §7 case 1.)