diff --git a/skills/old-coder/SKILL.md b/skills/old-coder/SKILL.md index 966fc6e..4a527e7 100644 --- a/skills/old-coder/SKILL.md +++ b/skills/old-coder/SKILL.md @@ -58,6 +58,9 @@ implementation files: reviews after the fact. - The spec is append-only during the task. If implementation reveals the spec was wrong, say so explicitly and revise it visibly — never silently drift. +- **Declare the isolation mechanism** (worktree / branch / none, and why) in the + spec, so the human can see and veto it before work starts. Pick it with the + detection chain in `references/setup.md`. ### 2. RED — prove each test can fail @@ -161,7 +164,7 @@ such excuse: you chose them, so choose real bugs. ### 6. EVIDENCE — the only thing the human reads after code End with a report the human can trust without opening a single source file -(template in `references/gauntlet.md`): +(template in `references/templates.md`): - The approved spec, with each behavior mapped to the test that verifies it. - Each gauntlet layer: the command run, and its actual result (pasted numbers, @@ -268,7 +271,40 @@ until that file has been read in full and executed; missing or unreadable → `not performed` finalizes only as a declared downgrade, like an unapproved spec. On Tier 3 it needs no apology — say so and claim less. -## Setup +## Setup and configuration + +Optional per-repo config lives in `.old-coder.toml` — `isolation`, `install`, +`commit`, `commit_args`, `tracker`, `artifacts`, `[commands]`. **Never block on +it.** Absent, use restrictive defaults (permission keys = `propose`, +`isolation` = `auto`, `artifacts` = `.old-coder`) and mention +`references/setup.md` once. It is gitignored by default so *grants* stay local; +a **tracked** copy is honored only where it tightens (`propose` yes, `allow` and +`isolation = "none"` ignored) — otherwise cloning a repo would hand its config +authority over your machine. + +**Use the project's configured or detected commands**, not the ecosystem tables +in `references/gauntlet.md` — those are fallbacks for when nothing is found. A +guessed command produces confident, wrong evidence, which is the one failure +mode this skill exists to prevent. + +The permission rule, once: **an operation proceeds if policy permits it AND (it +is reversible OR an approver is present).** Policy can grant standing +permission; it cannot manufacture a human. Writing tests and running the +gauntlet are reversible and proceed unattended. Installs, commits, and tracker +posts are not: they need the matching key set to `allow`, or an in-task +approval. **With `propose` and no approver present, skip the operation, record +the consequence in EVIDENCE, and continue** — never block on a human who is not +there. A run that halts on configuration produces neither code nor evidence. + +**Isolation.** The invariant, not the mechanism: *do not mutate the user's +working tree to do your work.* Branch or worktree — pick with the detection +chain in `references/setup.md`, declare it in the SPEC. The trap: **a fresh +worktree contains no gitignored content**, so the gauntlet often cannot run +there until dependencies are rebuilt. Rebuild, or fall back to a branch and +record why. Never report green from a tree that never ran the suite — and where +the isolated tree and the tree the change lands in differ by ignored or +untracked content, say so in EVIDENCE, because a green run in a tree missing the +main tree's `.env` or build outputs is not evidence about the main tree. If the project has no test runner, no linter, or no type checking, set up the minimal standard toolchain for the language **first** (see diff --git a/skills/old-coder/references/gauntlet.md b/skills/old-coder/references/gauntlet.md index 72abd77..a19464e 100644 --- a/skills/old-coder/references/gauntlet.md +++ b/skills/old-coder/references/gauntlet.md @@ -166,77 +166,7 @@ into a vacuous pass. Prove each home-grown check can fail with a one-off negative control (feed it a known-bad fixture; make its input unreadable) and record the control in EVIDENCE's honest notes. -## Gherkin scenario template (for the SPEC step) - -```gherkin -Feature: - Scenario: - Given - When - Then - - Scenario: - Given ... - When - Then -``` - -Each scenario maps 1:1 to at least one automated test; name the test after the -scenario so the evidence report's spec→test mapping is mechanical. - -## Evidence report template (for the EVIDENCE step) - -```markdown -## Evidence Report — (Tier <1|2|3>) - -- Spec approval: -- Source state: — persist the - computation as a script (e.g. tools/source_state.sh); a hash recipe written - in prose is working-directory-sensitive and will fail to reproduce -- Toolchain: -- Entry point: -- Independent verification: - **against the final source state** — a state no verifier saw is - `not performed` however many rounds preceded it (Tier 3; protocol in - `verifier.md`) - -### Spec → Test mapping -Status is one of: **pass / fail / unverified / n-a**. A row mapped to -"skipped: " must carry unverified or n-a — never pass. - -| Scenario | Test | Status | -|---|---|---| -| | :: | pass | -| Must NOT: | | pass \| unverified | +## Templates -### Gauntlet (final fresh run) -| Layer | Command | Result | -|---|---|---| -| Tests | | passed, 0 failed | -| Types | | 0 errors | -| Lint | | 0 warnings | -| Changed-line coverage | | / changed lines (list any misses) | -| Mutation | | / killed | -| Property-based | | properties, examples each | -| Real execution | | | -| Supply chain | | 0 known vulns; new deps: none (or list, each ↔ SPEC justification) | -| Suite health | | randomized order (seed ), all passed | - -### Independent verification (never omit; see verifier.md) -- Verifier: ; fresh context; which inputs it received; - what correlation that breaks and what it does not. -- Rounds: (cap ); verdict per round, each against the state it saw. -- Grading: who classified each finding behavioural vs description, and who - approved stopping. -- Attacked: . -- Findings: behavioural (fixed, then re-verified in a new context) vs - description/mapping (fixed and disclosed, no new round). -- Fixed after the last verified state, therefore unverified: . - -### Skipped layers -- : (or "none") - -### Honest notes -- -``` +The Gherkin scenario template, the `SPEC.md` template, the `EVIDENCE.md` +template, and the tracker roll-up live in `templates.md`. diff --git a/skills/old-coder/references/setup.md b/skills/old-coder/references/setup.md new file mode 100644 index 0000000..993a9fb --- /dev/null +++ b/skills/old-coder/references/setup.md @@ -0,0 +1,298 @@ +# One-Time Setup: `.old-coder.toml`, Isolation, Artifacts + +This procedure configures the skill for a repo once, and can be re-run any time. +It **detects and proposes, then confirms** — it does not interrogate the human +with questions whose answers are already visible in the repo. + +Nothing here is a precondition. **Missing config is never a blocker**: run with +the restrictive defaults below and mention in one line that setup exists. A +skill that stops to be configured deadlocks every unattended run on a fresh +repo, which is worse than running conservatively. + +## The config file + +Written at the repo root as `.old-coder.toml`: + +```toml +isolation = "auto" # auto | worktree | branch | none +install = "propose" # propose | allow +commit = "propose" # propose | allow +commit_args = [] # flags the repo mandates on every commit, e.g. ["-S"] +tracker = "propose" # propose | allow — posting the roll-up to an issue +artifacts = ".old-coder" # dir for per-task SPEC/EVIDENCE/logs; absolute when the config is local + +[commands] +test = "..." # detected from package.json scripts / Makefile / pyproject / CI config +lint = "..." +types = "..." +``` + +| Key | Meaning | Default when absent | +|---|---|---| +| `isolation` | how work is kept out of the user's working tree | `auto` — run the detection chain below | +| `install` | is the skill permitted to install packages/tools without in-task approval? | `propose` — put it in the SPEC's setup plan and wait | +| `commit` | is the skill permitted to create checkpoint commits without in-task approval? | `propose` | +| `commit_args` | flags the repo *mandates* on every commit — signing (`-S`), a trailer, a sign-off. Policy says **whether** you are permitted to commit; this says **how** the repo requires it done | `[]` — but detect: a repo rule or CI check requiring signed commits is a mandate the skill must honor, not a preference | +| `tracker` | is the skill permitted to post the completion roll-up to the issue the SPEC names, without in-task approval? | `propose` — write the note into the artifact directory and let the human post it | +| `artifacts` | root directory for per-task SPEC, EVIDENCE, and logs. Repo-relative, or **absolute** when the config is gitignored — see "Which tree each artifact is written in" | `.old-coder` at the repo root | +| `commands.test` / `.lint` / `.types` | the project's real commands | detect; if detection finds nothing, fall back to the ecosystem tables in `gauntlet.md` | + +Values are only ever these spellings. Use the same key names verbatim in SPEC +and EVIDENCE when you cite them. + +## Procedure (idempotent) + +1. **Read the existing config** if there is one. Re-running setup is a normal + operation: show the current value of every key and let the human change one + without restating the rest. +2. **Detect**, don't ask: + - commands: `package.json` scripts, `Makefile` targets, `pyproject.toml` + (`[tool.pytest]`, script entries), `justfile`, `.mise.toml` tasks, and the + CI workflow — CI is the most reliable source, because it is the invocation + the project actually gates merges on. + - isolation: whether this is a git repo, and whether the tree is dirty. + - artifacts: whether a directory already exists from a previous run. + - `commit_args`: repo rules and CI checks that mandate a commit style — + required signatures, required trailers. +3. **Propose the whole file** as a diff-shaped block, each value annotated with + where it came from ("test: from package.json scripts.test"). +4. **Confirm once.** The human accepts, or corrects individual lines. + **Write nothing before this point — including `.old-coder.toml` itself.** + Setup proposes a config that grants the skill permissions; writing it and + then asking inverts the gate. If nobody is present to confirm, do not write + the file: run with the restrictive defaults and say so in EVIDENCE. +5. **Write `.old-coder.toml` and add it to `.gitignore`**, together with + `/*/logs/` (see "Gitignored by default" and "Tracked or + ignored?"). Skip the second entry when `artifacts` points outside the repo — + there is nothing for git to track. +6. **Report** what was written; do not re-propose on later tasks unless asked or + unless detection now disagrees with the recorded commands. + +## Gitignored by default + +Add `.old-coder.toml` to `.gitignore` when writing it. This is not tidiness: it +makes every permission **grant** local by construction. A grant that lives in +the repo is a grant to every agent run by everyone who clones it. + +If the human explicitly wants the file tracked — a team standardizing the +commands — that is fine, subject to the next rule. + +## Restrict-only asymmetry + +Check whether it is tracked — do not assume: + +```sh +git ls-files --error-unmatch .old-coder.toml # exit 0 = tracked, non-zero = not +``` + +If `.old-coder.toml` is **tracked by git**, honor only the settings that +*tighten* permissions, and ignore the ones that *loosen* them: + +| Setting | Tracked file is permitted to set it to | Ignored if tracked | +|---|---|---| +| `install` | `propose` | `allow` | +| `commit` | `propose` | `allow` | +| `tracker` | `propose` | `allow` | +| `isolation` | `worktree`, `branch`, `auto` | `none` | +| `artifacts`, `commit_args`, `[commands]` | any value — these grant nothing | an **absolute** `artifacts` path: it names one machine's filesystem, so fall back to the default and say so in EVIDENCE | + +Rationale: a committed grant silently authorizes agents run by anyone who +clones the repo, including on an untrusted fork or a PR branch you did not +write. Tightening carries no such risk, so tightening travels with the repo and +loosening stays local. When you ignore a loosening setting, say so once in +EVIDENCE (`install = allow ignored: config is tracked`) rather than silently. + +## The permission combining rule + +State it once, apply it everywhere: + +> An operation proceeds if **policy permits it AND (it is reversible OR an +> approver is present)**. Policy can grant standing permission; it cannot +> manufacture a human. + +- **Reversible work proceeds unattended**: writing test files, running the + suite, running the gauntlet, writing SPEC/EVIDENCE artifacts. +- **Installs, commits, and tracker posts are not reversible in the same cheap + way**, so they need either standing policy permission (`install = "allow"` / + `commit = "allow"` / `tracker = "allow"`) or an in-task approver. With + `propose` and nobody there, do not do it — record the consequence in EVIDENCE + and continue. + +A tracker post is the one operation here that can reach beyond the repo: on a +hosted tracker it notifies people and cannot be un-sent. That is why it is +gated, and why `propose` means *write the note, do not post it*. The skill ends +at EVIDENCE; `tracker = "allow"` is the human moving that boundary themselves, +for one tracker, on one machine, in a file that is not committed. + +## Isolation detection chain + +The invariant, not the mechanism, is what matters: + +> **Never mutate the user's working tree to do your work, and verify in the +> tree that will actually receive the merge.** + +With `isolation = "auto"`, choose by detection. Declare the chosen mechanism in +the SPEC so the human can see and veto it. + +| Condition | Isolation | +|---|---| +| Not a git repo | `none` — propose `git init` in the SPEC's setup plan | +| Git repo, parallel agents running or the user is actively working in the tree | `worktree` | +| Git repo, exclusive access | `branch` is sufficient | +| Worktree created but the gauntlet cannot run there | fall back to `branch`, and record why in EVIDENCE | + +That last row is the common one, and it is not obvious: **a fresh worktree +contains no gitignored content.** No `node_modules`, no `.venv`, no build +outputs, no local `.env`. In many projects the gauntlet simply cannot run in a +new worktree until the dependency tree is rebuilt, which can cost minutes per +task. Two acceptable outcomes, and no third: + +1. Rebuild the dependencies in the worktree and run the gauntlet there. +2. Fall back to a branch in the main tree, and write in EVIDENCE: + `isolation: branch (worktree lacked and could not run the gauntlet)`. + +**Never report green from a tree that never ran the suite.** "Isolation +succeeded" is not a gauntlet result. + +Whenever the isolated tree and the tree the change lands in differ by ignored or +untracked content, say so in EVIDENCE. A suite that passed in a worktree lacking +the main tree's `.env`, build outputs, or installed dependencies has not been run +against the tree that will actually receive the change. + +## Artifacts layout + +One directory **per task**, not per session — a session runs several tasks and +they would collide. Name it at SPEC time and keep using it for the whole task: + +``` +/-/ + SPEC.md + EVIDENCE.md + ROLLUP.md # only when the SPEC names a tracker issue + logs/ + tests.log + types.log + ... +``` + +- `logs/` is created at the start of the gauntlet run, before any redirect. A + redirect into a directory that does not exist runs the command not at all — + no log, no result, and an EVIDENCE row citing a path that was never written. +- Timestamp is **UTC** (`date -u +%Y%m%d-%H%M%S`). Local time can produce two + identical directory names across a DST fall-back. +- **No colons** anywhere in the name — illegal in Windows paths. +- Slug is lowercased and reduced to `[a-z0-9-]`, capped at roughly 40 + characters, so the full path stays inside path-length limits. + +Per-task **outputs** live in this directory. Reusable **scripts** +(`tools/mutants.py`, `tools/gauntlet.sh`) stay at repo level, because EVIDENCE +promises the human can rerun them later; a script inside a dated task directory +is an output, not a tool. + +Both scripts are **files the SPEC's setup plan must name by path**. That is what +turns "EVIDENCE promises the human can rerun them" into something that happens: +an unnamed, unauthorized script gets replaced under time pressure by a throwaway +edit in a scratch directory, and EVIDENCE ends up honestly reporting a gap +instead of citing a command. If the repo already has them from a previous task, +say so in the setup plan instead — reuse is the cheap case, silence is the +failure case. + +### Tracked or ignored? + +**Track `SPEC.md` and `EVIDENCE.md`; ignore `logs/`.** That is the default, and +the first half of it is not a preference. + +**Gitignoring the artifact directory silently disables the spec-drift +mechanism.** The skill's enforcement for "the spec is append-only, never +silently drift" is: commit `SPEC.md` at approval, so any later divergence is a +`git diff`. A gitignored `SPEC.md` can never be committed, so there is nothing +to diff against — the rule survives as an instruction the agent may follow, and +loses the mechanism that made it checkable. Nothing warns you: the skill keeps +running, EVIDENCE keeps claiming append-only, and the guarantee is gone. + +So the honest cost table: + +| Choice | Audit trail | "Reproducible from the repo alone" | Spec-drift detection | +|---|---|---|---| +| Track `SPEC.md` + `EVIDENCE.md`, ignore `logs/` | travels with the repo | true, except log paths are local | **intact** | +| Track everything | travels with the repo | literally true | intact | +| Ignore the whole directory | local only | false | **gone** | + +Ignoring the whole directory is defensible only where the evidence reaches +reviewers by some other durable route (pasted into a review, attached to a +ticket) *and* the owner accepts losing drift detection. If you choose it, say +both things in EVIDENCE — "artifacts gitignored; spec-drift detection not +available this run" — because a reader cannot infer it. + +Whichever is in effect, state it in EVIDENCE. When `logs/` is ignored, note that +the log paths EVIDENCE cites are local only. + +### Which tree each artifact is written in + +Under `isolation = "worktree"` the tracked/ignored split above also decides +*where* the file is written. A worktree is deleted when the task ends, and +nothing gitignored inside it is committed, merged, or recoverable — it dies with +the directory. + +| Artifact | Tracked? | Written in | +|---|---|---| +| `SPEC.md`, `EVIDENCE.md`, `ROLLUP.md` | yes | the **worktree** — they are committed with the change and reach the human through the merge | +| `logs/`, and anything else the repo ignores | no | the **durable root** (below) — it outlives the task | +| the whole task directory, when `artifacts` is gitignored | no | the **durable root** | + +Both errors are silent. A tracked file written outside the worktree becomes an +uncommitted change in the human's working tree — the exact mutation isolation +exists to prevent. An ignored file written into the worktree is deleted, unread, +at cleanup, and EVIDENCE goes on citing its path. + +Resolve the durable root from the **shared git directory**, not from the CWD or +the worktree's parent: + +```bash +dirname "$(git rev-parse --path-format=absolute --git-common-dir)" +git check-ignore -q # exit 0 = ignored → durable root, not the worktree +``` + +In an ordinary repo that is the main checkout (`.git`'s parent). In a bare + +worktrees layout it is the container directory holding `.bare/` and the +checkouts — not itself a working tree, which is harmless: only gitignored files +go there, and durability is the whole requirement. + +Do **not** take `git worktree list`'s first entry as "the main checkout". In a +bare layout the first entry is the bare repo, and the remaining entries are peer +worktrees in registration order with no canonical one among them. + +Use the **same** `-` directory name in both places, so the +two halves are recognizable as one task. + +This applies to worktree isolation only. Under `branch` or `none` there is one +tree and everything goes in it; when `artifacts` already points outside the repo +the whole directory is durable and there is nothing to split. + +When the halves are split, say so in EVIDENCE and cite the moved paths +**absolutely** (`/home/you/proj/main/.old-coder//logs/tests.log`) — a path +relative to the worktree does not exist there and will not exist anywhere once +the worktree is gone. + +### Or skip the split: an absolute `artifacts` path + +`.old-coder.toml` is gitignored by default, and a local config may hold a +machine-local value. So set `artifacts` to an **absolute path** and the whole +task directory is durable by construction — one location, resolved identically +from every worktree, nothing to compute, nothing lost at cleanup. Prefer this +when the repo already ignores the artifacts directory: it is the same outcome as +the table above, minus the two-place bookkeeping. + +Two conditions, both hard: + +- **Only in a gitignored config.** An absolute path in a tracked `.old-coder.toml` + names one machine's filesystem and is wrong on every other clone — ignore it + per the restrict-only table. +- **Only where you have already accepted losing spec-drift detection.** Nothing + outside the repo can be committed, so `SPEC.md` is never a commit and later + divergence is never a `git diff` ("Tracked or ignored?", row 3). Keeping that + mechanism means a repo-relative `artifacts` and the split. + +That is the real choice, and it is not about paths: **durable-and-unverifiable +versus verifiable-and-split.** State which one is in effect in EVIDENCE — the +reader cannot infer it from a path. diff --git a/skills/old-coder/references/templates.md b/skills/old-coder/references/templates.md new file mode 100644 index 0000000..25306be --- /dev/null +++ b/skills/old-coder/references/templates.md @@ -0,0 +1,233 @@ +# SPEC and EVIDENCE Templates + +The two artifacts the human actually reads. Both live in the task's artifact +directory (naming and layout in `setup.md`); the layers they reference are +defined in `gauntlet.md`. + +## SPEC template (for the SPEC step) + +`SPEC.md` is written into the task's artifact directory (see `setup.md`) at +SPEC time, before any implementation file is touched. + +```markdown +# SPEC — + +- Tier: <1|2|3> +- Issue: +- Artifact dir: /-/ +- Isolation: +- Setup plan: + - Tools to install: + - Git: + - Files the gauntlet will add, **by path**: `tools/mutants.py` (mutation + layer), `tools/gauntlet.sh` (entry point) — mark either "already exists, + reused" — plus any fixture or harness file + - New dependencies: + +## Scenarios + + +## Must NOT +- + +## Revisions +- +``` + +Commit `SPEC.md` at approval (subject to the `commit` setting). Once the +approved spec is a commit, later drift is literally a `git diff` — that is what +turns "append-only" and "revise it visibly" from promises into mechanisms. +Without a durable spec, a compaction loses the approved contract while the code +it authorized remains, and nobody can check whether a scenario was quietly +dropped from the EVIDENCE mapping. + +**If the human rejects the spec**, keep the directory and the file: revise +`SPEC.md` in place, add the reason to `## Revisions`, and re-request approval. +Do not delete it and start clean — what the human turned down, and why, is the +most useful thing in the file. Nothing is committed until a spec is approved, so +a rejected spec costs one directory and no history. + +### Gherkin scenario template + +```gherkin +Feature: + Scenario: + Given + When + Then + + Scenario: + Given ... + When + Then +``` + +Each scenario maps 1:1 to at least one automated test; name the test after the +scenario so the evidence report's spec→test mapping is mechanical. + +## Evidence report template (for the EVIDENCE step) + +Written to `EVIDENCE.md` in the task's artifact directory, alongside the +`SPEC.md` it answers. + +```markdown +## Evidence Report — (Tier <1|2|3>) + +- Spec: //SPEC.md () +- Spec approval: +- Source state: > — persist + the computation as a script (e.g. tools/source_state.sh); a hash recipe + written in prose is working-directory-sensitive and will fail to reproduce +- Isolation: <; fallback reason if a worktree could + not run the gauntlet> +- Config: <.old-coder.toml values in effect; note any tracked-file loosening + that was ignored> +- Toolchain: +- Entry point: +- Independent verification: + **against the final source state** — a state no verifier saw is + `not performed` however many rounds preceded it (Tier 3 option; protocol in + `verifier.md`) +- Gauntlet cost: +- Logs: //logs/ +- Tracker: + +### Spec → Test mapping +Status is one of: **pass / fail / unverified / n-a**. A row mapped to +"skipped: " must carry unverified or n-a — never pass. + +| Scenario | Test | Status | +|---|---|---| +| | :: | pass | +| Must NOT: | | pass \| unverified | + +### Gauntlet (final fresh run) +Every command was redirected to the log named in the last column; the numbers +here are read from those logs. Cite only logs that were actually written — where +one command covers several layers, repeat that log on each row; where no script +can run the layer, write `manual`. A path to a file that does not exist is a +fabricated citation. + +**Status is one of five, and the vocabulary is closed:** + +| Status | Means | Required detail | +|---|---|---| +| `PASSED` | the layer's own instrument ran and was satisfied | the numbers | +| `FAILED` | it ran and was not satisfied | verbatim failure; you are not done | +| `N-A` | this project has no such surface — nothing to run, ever | why the surface does not exist | +| `UNAVAILABLE` | the surface exists, the tool does not | which tool, and that nothing was run in its place | +| `SUBSTITUTED` | something else was run instead of the specified instrument | what ran, **and what it cannot detect** | + +`SUBSTITUTED` may never be written as a pass. Two repeat runs in place of +randomized order is not "suite health: stable" — it is +`SUBSTITUTED (2 repeat runs + 3-module cross-order — cannot detect whole-suite +order dependence)`. A reader who cannot tell a substitute from the real layer +will read "found nothing" where the truth is "did not look with that +instrument". `N-A` and `UNAVAILABLE` are likewise distinct: three `N-A` layers +describe the project, not a degraded run, and EVIDENCE should say so rather than +leaving a reader to count empty rows. + +| Layer | Command | Status + result | Wall-clock | Log | +|---|---|---|---|---| +| Tests | | PASSED — passed, 0 failed | | logs/tests.log | +| Types | | PASSED — 0 errors (or `N-A: no type checker in this project — untyped codebase, no CI job`) | | logs/types.log | +| Lint + format | | PASSED — 0 warnings | | logs/lint.log | +| Changed-line coverage | | PASSED — / changed lines (list any misses) | | logs/coverage.log | +| Mutation | **required: the command**, e.g. `python tools/mutants.py` | PASSED — / killed | | logs/mutation.log | +| Property-based | | PASSED — properties, examples each | | logs/property.log | +| Complexity budget | | PASSED — | | logs/complexity.log \| manual | +| Real execution | | PASSED — | | logs/run.log | +| Supply chain & secrets | | PASSED — 0 known vulns; new deps: none (or list, each ↔ SPEC justification) | | logs/supply-chain.log | +| Suite health | | PASSED — randomized order (seed ), all passed (or `SUBSTITUTED: — cannot detect `) | | logs/suite-health.log | + +The **mutation row has no prose form.** "12/12 killed, mutants listed below for +manual re-application" is an incomplete row, not a passing one — the command is +part of the claim. If no script was persisted, the honest status is +`SUBSTITUTED (hand-applied edits — the score is not re-runnable)`. + +Wall-clock is per layer, from the log or a wrapper timer, so the tier map can be +tuned by evidence rather than by feel. An estimate marked as one is fine; a +blank column is not. + +† Unlike every other log here, `review.log` is written by the agent under +review, not by a tool. It records what the reviewer reported; it is not +independent evidence that a reviewer ran. Weight this layer below the +tool-generated ones, and ask for the reviewer's full transcript if its findings +matter to your decision. + +If the change was **abandoned** after round 2, every other layer reads +`n-a: change abandoned`. An abandoned change has no green result; report the +findings that drove the decision and stop. + +### Independent verification (omit only when it was not run at all; see verifier.md) +This is not a gauntlet layer and gets no row in the table above — it is prose a +human graded. Keep it out of the layer table and record it here. +- Verifier: ; fresh context; which inputs it received; + what correlation that breaks and what it does not. +- Rounds: (cap ); verdict per round, each against the state it saw. +- Grading: who classified each finding behavioural vs description, and who + approved stopping. +- Attacked: . +- Findings: behavioural (fixed, then re-verified in a new context) vs + description/mapping (fixed and disclosed, no new round). +- Fixed after the last verified state, therefore unverified: . + +### Layers not run as specified +Split by status, because they mean different things to a reader: +- **N-A (this project has no such surface):** +- **UNAVAILABLE (tool missing):** +- **SUBSTITUTED:** +- (or "none") + +### Dismissed review findings +Fixes are self-evidencing; dismissals are not. One line each: +- — dismissed because . +- (or "none — every finding was fixed or accepted as a known limit") + +### Structural blind spot +- + +### Honest notes +- +- +``` + +## Tracker roll-up (only when the SPEC names an issue) + +Tracker linkage is **bidirectional and tracker-agnostic**: the SPEC header +carries an issue ID, and on completion a short roll-up goes back to that issue. +No hard dependency on any particular tracker — if the SPEC's `Issue` field says +`none`, this step does not exist. + +Write it to `ROLLUP.md` in the task's artifact directory. Post it to the issue +only if `tracker = "allow"` or an approver says so in-task; with `propose` and +nobody present, leave it in the directory and say so in EVIDENCE. A hosted +tracker notifies people and cannot be un-sent, so it gets the same gate as a +commit. + +```markdown +- Built: +- Left undone: +- Traps for the next task: +- Evidence: // (SPEC.md, EVIDENCE.md, logs/) +``` + +**Why it is short, and why it is not a copy of EVIDENCE.** The two serve +different readers, and keeping them distinct is what stops them drifting into +rival sources of truth: + +| | Reader | Obligation | +|---|---|---| +| EVIDENCE | the human reviewing **this** change | complete — every layer, every number, every limit | +| Tracker roll-up | whoever picks up the **next** task | short — what changed the ground under them, and where to find the rest | + +A tracker whose notes are append-only by API gives the spec's no-silent-drift +property for free: an earlier note cannot be quietly rewritten to match a later +story. Where the tracker permits editing, that property is not there and the +git-commit-at-SPEC mechanism remains the enforcement — the roll-up is a +convenience for the next reader, never the authoritative record.