harness: rate-check.sh — N-draw refusal-rate check on full-document fixtures, release step 4b (closes #320) - #323
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
rate-check.sh currently references an unset $SUMMARY variable (fails under set -u), and the README examples use an inconsistent invocation path relative to the preceding cd instructions.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (3)
What changed in this PR
Adds a local, multi-draw “refusal-rate” check (rate-check.sh) to measure how often full-document fixtures are rejected by the structural-parity guard, addressing the limitation that the existing GitHub-based harness gate observes only one draw per scenario.
Changes:
- Add
tool-test-action-on-github/rate-check.shto run N draws per (fixture × language), summarize refusal rates/reasons, and fail above a threshold. - Document the new “Phase 1b” rate-check step in the harness README and add release checklist step 4b in
AGENTS.md. - Add an
[Unreleased]changelog entry describing the new tool.
| File | Description |
|---|---|
tool-test-action-on-github/rate-check.sh |
New script that repeatedly runs the CLI against full-document fixtures, logs draws, and summarizes refusal counts with a pass/fail verdict. |
tool-test-action-on-github/README.md |
Adds “Phase 1b” documentation and example invocations for the new rate-check script. |
AGENTS.md |
Adds release checklist step 4b to run the rate-check at the tag before moving floating tags. |
CHANGELOG.md |
Records the addition of rate-check.sh under [Unreleased]. |
.dev/log/2026-09-23-close-out.md |
Session log documenting the decision and validation results for the new rate-check step. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| echo "✗ A cell is over the threshold. One draw per scenario would have passed this at ~$((100 - 100 * MAX_REFUSALS / DRAWS))% or better; the gate cannot see it — do not release on the gate alone." | ||
| exit 1 | ||
| fi | ||
| echo "✓ Every cell within threshold. Summary: $SUMMARY" |
There was a problem hiding this comment.
Fixed in 7a2c3d1 — a real bug, thank you. SUMMARY had become a local inside summarize_run when the tally moved into a function, and the closing line still read the global, so under set -u a passing full run would have exited 1. It is set globally in the function now. My earlier validation only re-ran --summarize after that refactor, which exits before this line; this time the full-run path was exercised with one real draw (--languages ml --draws 1): 0/1, closing line printed, exit 0.
…4d74; round-4 arm (#319) * dev: v0.29.2 released — §4a gate completed, @v0 = 5f74d74; round-4 numpy arm at v0.29.2 Gate 84/84 sync, 28/28 delivery + 28/28 engineVersion 0.29.2 verdicts per lane; scenario 17 on .ml delivered. Round 4 regenerated at @v0: three draws archived, draw 1 sent with one disclosed ml_repair.py comma. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * dev: STATE.md — 2026-09-23 close-out (#322 for #321, #323 for #320) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * arm: note the garbage token in round-4 draw 2 (left as generated; a lint gap, #301) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…nt fixtures (release step 4b) The gate takes one draw per scenario and passed a ~40% defect three times. This runs the CLI at a tag or checkout N times per full-document fixture and language, prints refusals per cell with reasons, and fails above a threshold. Validated: v0.29.2 0/12, v0.29.0 4/12 (FAIL) on game-theory.md for ml. Closes #320. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
a8d8f66 to
a8fbe61
Compare
…d 1 under set -u), --summarize in the synopsis, README paths match the cd above Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* chore: release v0.29.3 Patch: fr glossary v1.2 (#328) from the French editor's second review round, which reaches French syncs only once @v0 moves; plus the harness reset fix (#322) and the release rate check (#323, step 4b), both of which first run on this gate. No source change in this commit; dist-action/ rebuilds byte-identical. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * dev: STATE.md — wrap the v0.29.3 entry to the file's style Raised by Copilot review on #329. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Directory-rename detection moved the six .dev/ files main added since the branch point (two decision records, three log entries, the #319 arm references) into .qe/dev/. Conflicts resolved: - .qe/dev/STATE.md: main's re-verified page (#330), with its one .dev/ path mention updated and the #314 In-flight bullet replaced by a Recently-landed entry for the move itself. - src/language-config.ts: main's ml rules (#315/#317) with the four decision-record path comments pointed at .qe/dev/decisions/. - dist-action/index.js: rebuilt; differs from main only by those comments. Also carried through: rate-check.sh (#323, merged after this branch) wrote its logs to .dev/scratch/rate-check/, which would recreate an in-tree scratch folder that is no longer git-ignored. Logs now go to ${TMPDIR:-/tmp}/action-translation-rate-check/<stamp>/ per D-2026-09-21-no-scratch-in-tree; its README line updated to match. npm test 1590/1590, lint and format:check clean, check-dev-refs: 168 .qe/ references resolve. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>


Closes #320 — Matt's decision of 2026-09-23 (recorded on the issue): keep the gate as it is and add a local N-draw rate check as release checklist step 4b.
Why
The gate takes one action-path draw per scenario. Scenario 17's new document was refused by the structural-parity guard on about 40% of draws from v0.28.0 to v0.29.0 and passed three release gates; v0.29.1's gate caught it only because the rate had risen to ~90%. One draw cannot see a rate. Twelve can.
What
tool-test-action-on-github/rate-check.sh [--ref <tag|branch>] [--draws N] [--languages …] [--fixtures …] [--parallel J] [--max-refusals K] [--model M] [--summarize DIR]init -f <fixture> --localize none) N times (default 12) per full-document fixture and language, from a two-file source dir (fixture + a generated_toc.yml). A draw is refused when no output file is written — the parity guard's fail-closed behaviour.--max-refusals(default 1). Writesmeta.txtandsummary.txtunder.dev/scratch/rate-check/<stamp>-<pid>/;--summarize DIRre-reads a run without new draws.--refcompiles the requested version in a temporary worktree and runs the CLI from it, so that version's own glossary is used — an old release can be measured. Languages derive from the main script'sLANGUAGESarray; fixtures default togame-theory.md, the only file the scenarios introduce as a whole new document today (scenario 20 is agit mvwith unchanged content).AGENTS.md gains step 4b; the tool README a "Phase 1b" section; CHANGELOG under
[Unreleased]. Session log.dev/log/2026-09-23-close-out.md.Validated
game-theory.md,ml, 12 draws--ref, worktree)source [none] vs output [exercise-start], 1×[exercise]That is the defect that passed three gates, read off in one command. The first v0.29.0 run printed FAIL and then exited 0: the verdict flag was being set inside a
{ … } | teepipeline — a subshell. The tally is now a function run in the current shell, and--summarizeon the same two run directories reproduced both exit codes without new draws.Not adopted
The in-action retry on a parity refusal. It is a production behaviour change, and it would hide exactly the rate this step exists to see (a 40% defect passes a two-retry gate at ~6%). If wanted for delivery it is its own decision under W1 (#259) / #260.
Notes for merging
Rebased onto
mainafter #322 merged (2026-09-23);[Unreleased]now carries this PR's### Addedabove #322's### Fixed.bash -nand shellcheck clean.🤖 Generated with Claude Code