Skip to content

✨ feat: template: finish proves the first failing run and one state of open work, and release runs finish again - #421

Merged
pascalandy merged 37 commits into
mainfrom
feat/420-intake-proofs
Nov 2, 2026
Merged

pascalandy merged 37 commits into
mainfrom
feat/420-intake-proofs

Conversation

@pascalandy

@pascalandy pascalandy commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Outside the plan: Pascal assigned #420, which holds #419 in full as its point 1. This pull request stacks on feat/417-round-ledger of #418, which is open and not merged, at 39bff54. It closes #419 and #420.

In round 4 of the day-1 trials, the loop held better: all three agents kept every finding and stopped at 5 rounds. But no build reached "Done when". The judge found the same gaps in 2 or 3 of the 3 extensions:

  • intakes that cite sources nobody read
  • no proof that the first scenario failed
  • generic cases with a name but no test
  • broken promises graded advise at first
  • ## Open lines that said None. beside open findings

#419 added two faults of #418. just finish read "block" in a title as a severity. just release trusted a receipt that a hand can write.

What changes

Decisions made without Pascal

Checklist

  • 1. Spec: finish-gate.md, extensions.md, generic-cases.md, and test-kit.md cover each check and each rule
  • 2. Scenario: each new case failed first, see "Proved by"
  • 3. Code: those cases pass in just template
  • 4. Text: n/a. The messages of just finish and just release stay in code, as every message of sdk/extensionrepo does
  • 5. Checks: just check passes
  • 6. Verify: an agent that did not write the change ran verify-nicely on template. Every step passed, see "Proved by"
  • 7. Docs: n/a for the backlog, because the card is outside the plan. README.md shows no change for a user. The skills of the template teach each new rule
  • 8. Sign off: just signoff passes on this head

Proved by

Each new case failed first on the code before it, then passed.

  • At the base 39bff54, the new tests of template: finish reads common words as severities, and release trusts a hand-written finish in the receipt #419 and template: prove the intake and the first failing run, test each generic case, and deliver #419 #420 ran with a fct_fail that does not stop:
    • Open lines: want present "spec.md: ## Open lines does not name the open finding R2-F1 of readiness.md"
    • First failing run: want present "readiness.md: it holds no part ## First failing run", "the first run of the scenario exited 0", "names no assertion that failed", and "names no command". Each time just finish exited 0, want 1
    • Plain words: just finish exited 1, want 0
    • Forged receipt: just release v0.1.0, exit 0, then RED: release trusts a receipt that names just finish, on a repository that just finish refuses and RED: a release that just finish refuses pushed a tag
  • Review fixes. Each reviewer judged whether the new tests of the round before fail on the head before their fix. The last reviewer mutated the code back. Without || section, the R3-F7 case fails. Without fence == "", the R3-F5 case fails.
  • Checks at the head 2f813aa. On Linux (om1), just signoff ran just check in a scratch worktree: exit 0 in 11 min 7 s, then Signed off on 2f813aa8fb91df9094ebd786a8d510269dea882e. On macOS (the mini), check_remote.py ran uv run --no-project --python 3.12 just check --keep-going: all 11 checks exit 0, template included, so the test scripts run under the bash 3.2 of macOS. The first two runs on the mini stopped before any check: just check refuses --verbose, and the login shell found the python3 3.9.6 of the system
  • verify-nicely, template at 1fa2f51, by the reviewer of round 3, with no keyring reachable:
    • Every step passed: Launch, Doctor, commands, Render and install, Release text, Loop text, Finish gate, Discovery, Help, Inspect, Dry run, Missing file, Refusal, Describe, Skill, Doctor probe, and Cleanup
    • "Loop text" lists ## Intake, ## Acceptance lines, ## Test files, ## Rounds, and ## Readiness review in SKILL.md, and ## Intake of a script, ## Intake of a program, and ## Evidence of the intake in intake.md
    • "Finish gate" exits 1, names the 20 Fill: lines, and says readiness.md: no readiness verdict is recorded
    • AGENTS.md:104 reads "It runs just finish again on that commit, then just acceptance, before it makes the tag"
  • Reviews. Three rounds, one reviewer for each, all Opus 5.5 high, none of which wrote the code. Round 1: 3 warn and 5 advise. Round 2: 1 warn and 7 advise. Round 3: APPROVE with 4 advise. Each finding was fixed. A fourth reviewer reread the fixes of round 3 and approved, then approved its own two advise after their fix.

Remaining risks

  • The run record and the intake are text that the agent writes. Finish checks their form, not that the run or the read happened. The reviewer must run the command again when in doubt
  • A complete forged review can still end a build, as ✨ feat: template: a build stops at 5 rounds, and a ledger keeps every finding #418 states
  • An earlier committed review that names, outside ## Findings, the ID of no finding now fails its "round N says pass" check. Reviews 3 and 4 found no honest ledger that does this

Sol review of the stack. Round 1 found that an open finding could not end a build as an accepted limit: ## Open lines must name it, and moving its row to Limits. changed spec.md outside Limits., so finish asked for a review of a new round. e114cd1 lets a row of ## Open lines leave when a row of Limits. takes its ID; any other change still needs a review. The new case of scripts/template-ledger-run-test.sh failed before the fix. Two other findings were declined: a fenced bare severity word is inside the documented parser limit, and a receipt that names echo finish affects provenance only, since release reruns finish.

Closes #419
Closes #420

Reviewed with codex-loop: 2 rounds with gpt-6.1-sol over the whole stack. Sol verdict: approved

by Opus-5.5 via Claude Code
Stack review and fix by Claude Opus 5.5 in Claude Code.

pascalandy and others added 30 commits October 31, 2026 14:27
readiness.go nears the size limit. The verdict check moves to
readiness_verdict.go, with no change of behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to its helpers

template-release-test.sh nears the size limit. Its loop over the
unsuccessful receipts moves to template-release-helpers.sh, with no
change of behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A receipt with only just check, from before #415 or written by hand,
let just release tag a repository whose loop was not done. Release now
needs a just finish check with exit 0 in the receipt.

Part of #416 and #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
extension-repository.md nears the size limit. The list of what just
finish checks moves to finish-gate.md, with no change of rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…diness.md

readiness.md now holds the ledger of a build. ## Rounds records each
round, its head, its reviewers, the commits that each review covered,
and the result of just finish. ## Order of round 1 records the commit
of each step. Each finding keeps a stable ID and gets a state.

just finish fails on more than 5 rounds, with a message to stop and to
report to the user. It fails on a finding of an earlier round without a
state, on a warn or block that is declined, on an open finding, on a
commit outside HEAD, and on a last round whose head is not Commit:. It
compares the findings with each committed readiness.md, so a finding
never leaves the ledger and its severity never goes down.

Finish also names the cause of a severity outside its line: the word,
the table, or the fenced code. It reads a severity in each part after
the header, ignores a byte order mark, and says that it reads the
header in the first three lines.

Part of #416 and #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…own file

The skill nicely-extension nears the size limit. Its readiness review
moves to readiness-review.md beside it, with no change of rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unds, and each case has a safe outcome

Round 1 of the skill records the intake facts in vision.md, writes
spec.md, commits a failing scenario at the command boundary, and only
then changes the handler. AGENTS.md no longer gives another order.

The skill names three acts: a pull request for review, a stop report at
the limit of 5 rounds, and the delivery after just finish passes. An
answer that lets the agent choose starts no round. The readiness review
teaches finding IDs, states, and the ledger. A command that replaces a
user file proves its invariants with the test kit, and
create-formal-verification-skill stays for paid work.

generic-cases.md gives the safe outcome of each case, with new cases for
a large expansion, an input with several parts, a temporary file, data
that a reader needs, and data that changes the meaning.

acceptance.sh compares the primary output, from a reader that is not
the wrapped program, with an independent reference.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The history of readiness.md went back before the build. So the build of
a second command had to keep the findings of the first, and a new
finding could reuse an old ID. Finish now reads only the reviews
committed after the Intake commit of the build.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The check moves without a change of behavior, so that wrap.go keeps
room under the size limit for the next fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to wrap_stop.txtar

The timeout, Ctrl-C, and version probe cases move without a change of
behavior, so that wrap.txtar keeps room under the size limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Program.Input holds the item or path that the call works on. When it is
set, each RUNTIME message that Run and Ended make names it. A signal
adds an INTERRUPTED or TERMINATED error that names it, which Finish
puts first. An empty Input keeps the messages of today.

A version probe that uses up the deadline of Timeout now gives the
timeout, RUNTIME with exit 1, instead of PREREQ_MISSING. A probe that
reaches ProbeLimit inside a longer timeout stays PREREQ_MISSING.

hello count sets its file as the input, and hello scan sets none, so
the wrap scenarios prove both paths.

Refs #407

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The inspect example sets its path as the input of sdk/wrap. Its
scenario checks that the answers to a failed exit, the timeout,
Ctrl-C, and SIGTERM name the file. A version probe that uses up the
timeout now expects the timeout, RUNTIME with exit 1. A probe that
fails, or a python3 that is too old, stays PREREQ_MISSING.

spec.md moves the probe that uses up the timeout to worker-fails. Its
no-python line drops the slow probe, which no scenario proves.

Refs #407

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… own file

test-kit.md is near the limit of 2,500 tokens. The section moves without a change of text, so later rules about the kit commands fit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An interrupted run must keep its input, leave an absent output absent, and keep an old output. A protect selection now applies to the next signal call, which ends it for signal. refuses keeps the selection until the next protect call, as before. The comparison skips the marker.

signal and the coming appears command share the foreground run, the wait for the marker, and the bounded wait for the exit. A kit test also proves that protect and refuses catch a run that writes through a link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… new file

appears <marker> <path> <command> <arg>... runs a registered call as signal does. At the new marker, the kit creates the path with an exclusive create and its own bytes. The run must then fail with a valid answer, and the path must stay the same regular file with the same bytes. The command refuses --force, and the next protect selection applies to it.

Scenario commands lists which kit calls prove each invariant of a command that replaces a user file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… reader

A check that reads only a header or the file type cannot see a lost content. The check now compares what a reader other than the wrapped program gives with an independent reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd that replaces a file

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 found that a readiness.md could move its Intake to an
earlier review, drop a warn, and restart the rounds at 1. A label line
under ## Rounds could also hide rows.

The history of a build now starts only after a committed review with a
passing verdict, so a review that needs work never ends a build. Each
round of an earlier committed ledger must stay unchanged. Each line under
## Rounds and ## Order of round 1 must be a row. Each of the first four
steps of round 1 needs its own commit.

The rule index lists appears among the call forms. The no-python line of
the template spec names the probe that does not finish within 10 s
again, and a hello scenario proves it.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nding without an ID never leaves the ledger

Review round 2 found four ways past the ledger, and no way out for an
honest build at the limit.

A review ends a build only when its verdict follows from its findings
and from the spec.md of its commit, so a changed verdict line ends
nothing. Each committed review of the build names the head of a round,
and each round before the last has a committed review of its head. An
earlier finding without an ID keeps its title in later reviews.

The user can now accept a limit at any round, also at the limit of 5:
after a review, only the part **Limits.** of spec.md may change, and the
reviewer gives the finding the state limit in a review of the same
commit.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pass

Review round 3 found that a limit accepted after the review blocked
every later build, that a review of the form of #409 never ended a
build, and that a two-line edit of a review that needs work ended one.

A review ends a build only when its verdict, its states, and the
history of its own build pass, as just finish checks them. Its limits
come from the spec.md of the next intake when only **Limits.** differs.
A line - **Limit**: of the form of #409 reads as the state limit, and a
review without a ledger needs a passing verdict only.

The readiness review says that only readiness.md and **Limits.** of
spec.md may differ from the reviewed commit, and that the limit is
committed before the review.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Finish pass ends a build

Review round 4 found that the inferred end of a build failed at the 10th
build, grew three times slower with each build, broke again when spec.md
changed before the next intake, and let a 7-round build end.

Three fixes of that inferred boundary failed in a row, so the ledger
drops it. History is every committed readiness.md of HEAD. The round
numbers go on from build to build, and the ledger keeps each finding. A
round before the last whose Finish is pass ends a build, when its
newest committed review passes: a verdict that follows from its
findings, valid states with the current limits, and each finding of the
reviews before it. Each build, also one that ended, has at most 5
rounds, and the intake of a build follows the end of the build before.
A Limit line no longer replaces a Spec line.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t finish passed then

Review round 5 found that finish checked a review that ended a build
with the current spec.md, so a limit or a renamed spec ID of a later
build broke an honest repository for good. A Finish pass on a Ready
review whose finish failed, such as on an open line, also reset the
5 rounds.

Finish now checks such a review as the repository stood when it was
committed: no Fill: line, no open line, only readiness.md and **Limits.**
of spec.md changed since its head, and a verdict and states that follow
from its findings. A spec.md before the next round stands in when only
**Limits.** differs. Each review is parsed once and each commit resolved
once, so 80 builds take 0.76 s in place of 1.48 s.

Part of #417.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…xture

Each case of appears and protect ran its own go test of the standalone
fixture, 29 in all. On the mini, that load made the 2 s budget of
completion values and the 1 s timeout of a hello scenario fail in the
full just check. The cases now run as scenarios of one go test per
test function, and each case reads its own result and log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
template-release-test.sh is near the token limit of a file, and the next
commit adds the proof of a forged receipt to it. The proof of the
repository URL of a module with a major version suffix is its own
responsibility. It moves, unchanged, to template-release-url-test.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…finish again

Finish read the words block, warn, and advise anywhere after the header
as a severity. A title such as "Large inputs block the terminal", or
prose such as "the CLI does not warn", failed it. Finish now fails only
on a severity in code, such as `warn`, on a severity alone in a cell of
a table, and on the word severity under ## Findings. The plain words
pass.

Release trusted a signoff receipt that named just finish, and a hand
can write such a receipt. It now runs just finish again on the clean,
signed HEAD, after acceptance and before the tag. The release test
proves that a forged receipt on a repository that finish refuses
pushes no tag. Its releases that must pass now commit filled forms and
a readiness review first.

Closes #419.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lines names each open finding

In round 4 of the day-1 trials, two of three agents committed the
scenario before the handler but never ran it. Each spec.md also said
None. under ## Open lines while the ledger recorded open findings.

readiness.md now holds ## First failing run, with the command that ran
the first scenario at its commit, its exit status, and the assertion
that failed. Finish fails when the part, the command, or the assertion
is missing, or when the exit status is 0 or no number.

A finding with the state open now needs a line under ## Open lines of
spec.md that names its ID, so spec.md and the ledger agree on the open
work.

Part of #420.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skill of the template is near the token limit of a file, and the
next commit adds the evidence of the intake. The parts "Intake of a
script" and "Intake of a program" move, unchanged, to intake.md, which
SKILL.md links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ets a test file, and a broken promise is a warn

Round 4 of the day-1 trials found gaps in 2 or 3 of 3 extensions. This
commit writes the rules of #420 that no check enforces, and the docs of
the checks of the commits before it:

- intake.md: the intake records the source, its version, and the part
  that the agent read, with each experiment apart. A link alone is not
  evidence of a read
- generic-cases.md, test-kit.md, and acceptance.sh: each case of the
  Output group that applies gets a test file that the test makes. A
  block that a reader needs keeps its content and loses its private
  text. A declaration that changes the meaning gets a value that is not
  the default, and the reference applies it
- readiness-review.md: a broken promise is at least warn at its first
  review, with three calibration examples. The reviewer of round 1
  checks the intake and the first failing run, and refuses a compile
  error
- SKILL.md: round 1 records the first failing run, tests make their
  own files, and four rules help a build reach "Done when" in 5 rounds
- finish-gate.md, extensions.md, and rule-index.md: the checks of #419
  and #420, and "Prose only" for each other new rule

Closes #420.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pascalandy and others added 6 commits October 31, 2026 20:12
… no grade hides outside a finding

An independent review of the commits before found three gaps:

- A record of ## First failing run from an earlier build still passed.
  The record now names its commit, which must be the Scenario commit of
  ## Order of round 1. A record in fenced code, or in the form
  **Name:**, now reads as finish expects
- After #419, "Severity: block" in a part after ## Findings, a finding
  heading under another part, and a cell such as **Block.** passed.
  Finish now fails on the word severity before a severity in any part,
  on a finding heading with an ID outside ## Findings, and on a cell
  that holds only a severity with marks around it. "Each finding names
  its severity" still passes
- Release ran just finish after acceptance, which can be slow. It now
  runs just finish first

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… grade, and the order of release

The docs follow the fix before. finish-gate.md keeps its list of
failures in one piece, and names the Commit line of ## First failing
run and the forms that grade. readiness-review.md lists those forms,
says what to do after just update, and keeps a sentence out of the
last calibration example. The rule index gets the three rules it
missed and links ledger_run.go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… record reads like a finding

A second independent review found these gaps:

- A line outside ## Findings, such as "- R3-F8 Long lines are cut:
  block", hid a graded finding. Finish now fails on each finding ID
  outside ## Findings that no finding under it has
- The record of the first failing run closed a fence of four marks at a
  line of three, and refused a value that ends with a period. It now
  reads fences and values as readinessFindings does
- The proof of a forged receipt now checks that release ran no
  acceptance before just finish refused, and the proof of the hidden
  forms checks each message again

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ely reads intake.md

finish-gate.md and readiness-review.md name the check of a finding ID
outside ## Findings, and finish-gate.md splits a sentence of 30 words.
The step "Loop text" of verify-nicely reads the parts of the skill
after the move of the intake to intake.md. intake.md limits experiments
to commands that neither write nor bill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… ID either

The third independent review found that a heading, such as
"## R3-F7 Long lines are cut" or "#### R3-F6", still carried a finding
ID outside ## Findings with no grade. Such a heading now counts as a
mention. A heading of level 3 with an ID keeps its own message. A test
proves that an honest summary of existing IDs still passes.

The step "Loop text" of verify-nicely reads 12 lines after "## Done
when", so it reaches the line of a "full stop" request, and a sentence
of finish-gate.md is split.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… is a stray ID too

The review of the last fixes found that a heading such as
"### R3-F9 x" in fenced code outside ## Findings got no message: the
mention check skipped it as a finding heading, and the fence skipped
the check of a heading outside ## Findings. It now counts as a
mention. The proof puts "## R3-F7" right after the findings, so it
covers the heading that closes ## Findings too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 5b717168-11e0-4fe2-9202-e417ff4da75f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

…rounds

A Sol review of the stack found that an open finding could not end a
build as an accepted limit. Its row under ## Open lines must name it,
and any row there fails finish. Moving the row to **Limits.** changed
spec.md outside **Limits.**, so finish asked for a new review of a new
round, after the last one.

Finish now also lets a row of ## Open lines leave when a row of
**Limits.** takes its ID. Any other change of spec.md still needs a
review of its commit.

Refs #420

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pascalandy added a commit that referenced this pull request Nov 2, 2026
The Sol fix of #421 added a sentence to finish-gate.md, and with the
case matrix of #424 the file went over the 2500 tokens of just limits.
The part "The limit of the parser" now has its own file, with no
change of its text. finish-gate.md and readiness-review.md link it.

Refs #423

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pascalandy
pascalandy changed the base branch from feat/417-round-ledger to main November 2, 2026 01:59
@pascalandy
pascalandy merged commit e114cd1 into main Nov 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant