# Proofwarden — build kickoff brief

**From:** Bassam · **To:** the implementer (Claude Code, local) · **Status:** design closed, ready to build
**Read with:** `proofwarden_spec_v0_1.md` (the authoritative contract) and `proofwarden_console_wireframe.html` (the reference prototype — open it; the warden, leases, streaming logs, the refused double-run, history, and CI watch-link are all real behaviour, the data is mock).

---

## 0. TL;DR

I need a second local web, sibling to mgf-fed-web — this one for **testing and CI**. Per project, I want to: browse the available tests (category → group → individual test), see and optionally tweak each test's config, run them, watch them live (streaming logs + progress), see everything that ran before with full context, and start + watch CI (watch opens the Woodpecker host).

The rule that defines this product: **a given test can never run twice at once** — no matter how it was launched (command line, this website, the AI agent, or CI). Testing has **central authority**. So this isn't a dashboard with a run button bolted on; it's built around a single entry point that *cannot* be bypassed. Every project has a **test supervisor** — I'm calling it the **warden** — that is the **sole executor**: everyone submits run *requests* to it; nothing else ever spawns a test. The website, like mgf-fed-web, stays read-mostly — it submits intent, it never runs tests itself.

This is the build handoff. The spec is the contract; this brief is the why and the shape. Decisions I haven't pinned are confirm-lines in spec §7 — I already chose defaults for the load-bearing ones.

---

## 1. The authority — single-flight, end-to-end (the heart)

This has to be **locked down and clear end-to-end**, for both local runs and CI. The way I want it enforced:

- **The warden is the only thing that runs a test.** CLI, web, agent, CI pipeline → all call the warden. None execute tests directly. If the warden is down, **nothing runs** (fail-closed) — because running outside it would defeat the single entry point.
- **An atomic lease registry is the single source of truth for "what's running."** The web *reads* it; it never decides run-state from its own guess. One run at a time per project by default (the rest queue) — that kills the whole class of two-runs-fighting-over-a-board/port/file that makes tests flaky. A test proven independent can opt into parallel.
- **When the same test is launched again while it's running, the warden coalesces** — it attaches the new caller to the in-flight run instead of starting a second. That directly kills the "agent kicks it while it's already going" case, and it beats a flat reject. A *different* test on a busy project queues.
- **Leases, not bare locks.** A lock file leaks if the test crashes — blocked forever. A lease has a heartbeat + TTL; if the holder dies, the warden reclaims it with an **audited** "stale lease reclaimed" event — never a silent steal. This covers the other failure cases I worried about.
- **Every acquire / coalesce / queue / reclaim / refusal is recorded** as an event and in the run-record. So "did the authority actually stop a collision" is *checkable after the fact* — a correctly-refused double-launch becomes visible proof the lock works, not something I have to take on faith.
- **CI joins the same lease.** The Woodpecker pipeline calls the warden (`testctl run --from-ci`), so a CI run and a local run of the same test can't collide. This fully holds when Woodpecker is reachable from the warden (self-hosted, same host/network — my assumption); if CI is remote and can't call back, CI single-flight is advisory and the web surfaces the conflict **loudly** rather than pretending it's safe.

The prototype demonstrates all of this — open Running, start a test, then hit **"Sim agent double-launch"** (watch it coalesce, not double-run) and **"Sim holder crash"** (watch the audited reclaim after TTL).

---

## 2. Three data concerns (reusing the mgf-fed-web spine)

It plugs into the same `fed-resources/` directory and the same patterns:

- **Catalog** — `generated/test_catalog.json`: the test tree + each test's config + config-schema. **Generated-not-asserted and freshness-gated**, so the test list I see is provably the real suite, never a stale hand-maintained list.
- **Lease registry** — the warden's live authority state, read via `testctl status`. Ephemeral runtime truth, not gated.
- **History + live logs** — **all local runs stream their logs to local storage** as append-only NDJSON (`live/runs/…`), which the web consumes to show live progress *and* past runs; each finished run also writes a durable, gated **run-record** (`generated/runs/…`) with the effective config + the full lease audit. Live log = ephemeral telemetry; run-record = the verifiable record. Never conflated.

New surface: a **`testctl`** CLI, sibling to `fedres` — `catalog`, `status`, `run`, `watch`, `cancel`, `ci start`, `serve` (the warden). The web reaches the warden through it (or a local socket). Spec §2.

---

## 3. Configs — shown on demand, editable per run

Tests have configurations, and the site should surface them — **not by default**, but as something that **expands** to show them, and the user can adjust parameters before a run. Committed defaults stay **read-only**; my edits ride with the run request as an **overlay**, and the run-record stores the **effective config** that actually produced the result — so every result is traceable to the exact parameters. Never a mutation of the committed defaults. (Prototype: expand "config" on any test row, edit, run — the effective config shows in the live log and the history record.)

---

## 4. CI

Start a Woodpecker pipeline from the web; **watch via a link that opens the Woodpecker host.** The pipeline joins the same lease (§1) so it participates in single-flight. The web also lists recent CI runs with status and a Watch deep-link.

---

## 5. Non-negotiables

Single entry point **by construction** (warden = sole executor, never politeness); single-flight via the atomic lease registry; **fail-closed** when the authority is down; lease with heartbeat + TTL + **audited** reclaim, never a bare lock; every refusal/coalesce/reclaim **recorded as visible proof**; catalog **generated + gated** (the shown test list is provably real); configs are a **per-run overlay**, defaults read-only, **effective config recorded**; **all local runs stream logs to local storage**; live logs ephemeral + gitignored + **never gated** + never styled as provenance; the web is **read-mostly** (submits run requests, never executes, never edits state); honest-absence everywhere (warden-down, stale-catalog, idle-stream are real, shown states — never blanks or fabricated passes); everything printable.

---

## 6. What I need you to confirm

I've chosen the load-bearing defaults — **serialize-by-default** (parallel opt-in for independent tests), **resident daemon warden, fail-closed**, **coalesce same-test / queue different-test**, **run-records exempt from the reproduce-gate**, and **assume Woodpecker is reachable from the warden** (advisory + loud surfacing if remote). The rest are smaller and fine to settle in round 1 (spec §7): the family naming (`Proofwarden`/`warden`/`testctl` vs descriptive), the Woodpecker trigger + status mechanism (**D-CI-2**), lease TTL/heartbeat values (**D-TTL**), queue policy details (**D-RUN-3**), config types + whether overrides can be saved as presets (**D-CFG**), and the per-project runner adapters — `zig build test` for the kernel, `pytest` for the forge GUI, shell, mixed (**D-RUNNERS**). Build the milestones in order (spec §6: M0 schemas+validator → **M1 the warden + single-flight, the core** → M2 catalog+web → M3 run+live logs → M4 history+configs → M5 CI → M6 package mode); M1's acceptance bar is exactly the single-flight proof (two concurrent launches → one execution + one coalesced record; killing a holder → audited reclaim; warden down → refuse). Dogfood on soothfast first. Raise concerns through the same feedback loop and commit to the resolution.
