Skip to content

feat(ready): judge whether a change is finished before it is pushed (0.2.17) - #146

Merged
chrispezza merged 2 commits into
mainfrom
claude/push-readiness-93
Oct 12, 2026
Merged

chrispezza merged 2 commits into
mainfrom
claude/push-readiness-93

Conversation

@chrispezza

Copy link
Copy Markdown
Contributor

A push-readiness check (#93): the first consumer built for what a judgment model is for, taking a review pass off a reasoning model, and not for the safety gate.

What it does

bouncer ready [--base ref] [--enforce] [--backend …] [--policy path] [--json]

Reads the commits ahead of the base branch and asks four questions in two sets (policy/push.yaml):

set asked of questions
push the whole change, once message_mismatch, untested_behaviour
push_file each changed file worth reading, one at a time debug_leftover, unfinished

Prints READY, or HOLD with the file and the question that fired, in the question's own words. /bouncer:ready is the slash command for it.

How it is built

  • A consumer, not a branch in the engine (ADR-008). src/io/git.ts reads the change, src/push.ts turns it into plain items for the existing item state builder, and src/commands/ready.ts runs the existing judge runner over two policy sets. Nothing below src/commands/ learns what a push is.
  • Because the items are plain items, the rest is free. The fixtures are the same shape, so calibrate scores these questions and measure can compare them with a reasoning model with no new code.
  • Countable things are computed. tests_changed, docs_only, line counts and file kinds are fields. The model is asked only what is left over, per the classifier's documented limits.
  • One file per request. Accuracy falls as unrelated content grows, so a question about a file is shown that file.

Behaviour worth reviewing

  • It sends content. Commit messages and diff text go to the backend after redaction. This is the judge's rule (ADR-009 decision 4), not the gate's. This is new data leaving the machine, only when the command is run. --backend mock sends nothing.
  • It observes. Exit 0 unless --enforce, where a HOLD exits 1.
  • It never holds on its own failure. No repository, no base, no key, an unanswered request: said, exit 0, with or without --enforce.
  • It names what it did not read. Lockfiles, generated files, test data, docs, binaries, and any diff longer than one item (judge: chunk documents longer than the state cap (needs an ADR) #53).
  • Real runs append to readiness.jsonl in the data directory: head commit, verdict, answers, no diff text. Mock runs are not recorded.

Evidence, and its limits

  • Live on the fixtures (jev-1.13.0, answers committed): the verdict matched the label on 25 of 26. The miss is a commit called "tidy the upload settings" that changes two behavioural constants; untested_behaviour read 0.31. Left as a miss rather than tuned until one fixture passed. docs/calibration/2026-10-12-push-1.md.
  • Those fixtures were written with the questions, so that is a check on wording and nothing more.
  • Run on this PR's own branch. First run: one HOLD, a false positive. debug_leftover fired at 0.96 on fixtures/push-file.jsonl, whose contents are console.log lines. Fixed in the second commit by treating fixture and test-data directories as a path fact. Second run: READY, having read 8 of 20 files. The other 12 are listed, including test/ready.test.ts and the bundle, which are too long for one item.
  • No evidence on real pushes exists. That is what readiness.jsonl against CI is for.

Checks

  • Suite: 1611 passed (60 new), including a real repository built in a temp directory and the built bundle end to end.
  • bench --against the base bundle, six paired runs: medians −0.9 to +0.6 ms on a noisy machine. Bundle 543.5 → 558.2 KB (The hook pays for CLI-only code: bundle size is now a measurable per-call cost #134).
  • No change to the hook, the gate or policy/default.yaml.
  • Cost: one CI run; the live runs were under a cent of Jev.

Refs #93

🤖 Generated with Claude Code

chrispezza and others added 2 commits October 12, 2026 14:58
…0.2.17)

`bouncer ready` reads the commits ahead of the base branch and asks
four questions in two sets: of the whole change, whether the messages
describe it and whether behaviour changed with no test; of each file,
whether a debugging statement or an unfinished marker was added.
Countable facts are computed and handed over as fields.

It observes: exit 0 unless --enforce, and never a hold on its own
failure. It sends commit messages and diff text to the backend after
redaction, which the gate never does, and lists every file it did not
read. Real runs go to readiness.jsonl with the head commit, for a later
comparison with CI.

A consumer of the engine, not a part of it: plain items for the item
state builder and a policy file of its own (policy/push.yaml).

Refs #93

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found by running the check on its own change: the debug_leftover
fixtures are lines of console.log, and the question fired on the file
at 0.96.

Refs #93

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chrispezza
chrispezza merged commit 1a83d5d into main Oct 12, 2026
2 checks passed
@chrispezza
chrispezza deleted the claude/push-readiness-93 branch October 12, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant