perf(review): overlap the completeness judge with the fleet, make its PASS intent-sticky, cap 6 - #360
Conversation
… PASS intent-sticky, cap 6 Three latency/cost changes to the ship gate chain, driven by telemetry (~/.devkit/telemetry/gate-events.jsonl): 1. Review concurrency default 3 -> 6. The correctness lens split schedules ~8 judge tasks on a backend commit; at 6 they run in at most two waves, so the fleet makespan approaches the slowest single lens instead of a 3-slot packing. The bound is subscription slots, not CPU/memory. 2. Parallel completeness prewarm (ship path). The sc-1442 message file already reaches pre-commit, so the review hook fragment now launches guard-review completeness alongside the fleet, applies the commit-msg fragment's exact exit contract, and lets the commit-msg gate re-judge from cache. The fleet blocking the commit kills the judge instead of waiting. Interactive commits (no message file) and review mode (same env, different meaning) are excluded. The verdict store merges under a lock, so the two concurrent writers cannot clobber each other. 3. Intent-sticky completeness PASS (cost ruling). The gate judges the MESSAGE's claims, so a retry whose diff was reshaped to satisfy another reviewer -- same branch, same message -- is not re-judged: a confident PASS is saved under a branch+message+brief key (version-salted) beside the exact-bytes key. FAILs are never sticky. normalizeCommitMessage() converges the ship temp file with git's cleanup=whitespace output so the two hooks compute identical keys. Net: opus completeness is paid once per branch+message across a retry chain, and a passing attempt's judged path drops from fleet+completeness serial to max(fleet-at-6, completeness). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe completeness gate now normalizes commit messages, caches intent-scoped PASS results, and prewarms during ship commits. The Husky hook handles completeness outcomes separately from reviewer verdicts. Review concurrency defaults and related tests now use six concurrent judges. ChangesCompleteness cache and normalization
Ship-commit orchestration
Review concurrency
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant precommit as .husky/pre-commit
participant fleet as reviewer fleet
participant completeness as completeness judge
participant gate as review gate
precommit->>fleet: Start reviewer fleet
precommit->>completeness: Start completeness judge for known ship message
fleet-->>gate: Return reviewer verdict
alt Reviewer fleet passes or is inconclusive
gate->>completeness: Wait for completeness result
completeness-->>gate: Return completeness exit code
gate-->>precommit: Allow or block commit
else Reviewer fleet blocks
gate->>completeness: Terminate and reap completeness judge
gate-->>precommit: Block commit
end
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
gate-engine/review/__tests__/run-review.test.mts (1)
1951-1988: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover the remaining sticky-cache invalidators.
The sticky
completeness-intentkey usesDEVKIT_SHIP_BRANCH, the commit message (message), and the reviewer brief (body). The version salt is in the judge cache key, but the intent sticky cache reuses the same cached PASS without re-judging when any sticky-key component changes. Add cases that change the branch and the completeness agent brief, and reassert thatexecis invoked again.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@gate-engine/review/__tests__/run-review.test.mts` around lines 1951 - 1988, Extend the sticky completeness tests around runCompleteness to cover changes to DEVKIT_SHIP_BRANCH and the reviewer brief body: after an initial PASS, alter each component while keeping the other sticky-key inputs unchanged, then assert the result remains PASS and exec is invoked again. Use the existing msg helper and run-review test setup, and preserve the current message-change and diff-retry assertions.Source: Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cli/lib/husky/husky-block.mts`:
- Around line 92-99: After terminating the tracked completeness process in
cli/lib/husky/husky-block.mts#L92-L99 and .husky/pre-commit#L163-L170, wait for
"$comp_pid" before returning so the process is reaped. Update
cli/__tests__/husky-block-exec.test.mts#L194-L199 to use a completeness stub
that waits for a signal, then verify the fleet-failure path both terminates and
reaps it.
---
Nitpick comments:
In `@gate-engine/review/__tests__/run-review.test.mts`:
- Around line 1951-1988: Extend the sticky completeness tests around
runCompleteness to cover changes to DEVKIT_SHIP_BRANCH and the reviewer brief
body: after an initial PASS, alter each component while keeping the other
sticky-key inputs unchanged, then assert the result remains PASS and exec is
invoked again. Use the existing msg helper and run-review test setup, and
preserve the current message-change and diff-retry assertions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 36e91b10-3afe-449d-a779-f2c8fb2744cf
⛔ Files ignored due to path filters (4)
dist/cli/lib/husky/husky-block.mjsis excluded by!**/dist/**dist/gate-engine/review/completeness.mjsis excluded by!**/dist/**dist/gate-engine/review/run-review.mjsis excluded by!**/dist/**dist/gate-engine/review/telemetry/timing.mjsis excluded by!**/dist/**
📒 Files selected for processing (7)
.husky/pre-commitcli/__tests__/husky-block-exec.test.mtscli/lib/husky/husky-block.mtsgate-engine/review/__tests__/run-review.test.mtsgate-engine/review/completeness.mtsgate-engine/review/run-review.mtsgate-engine/review/telemetry/timing.mts
…just be signalled CodeRabbit flagged the kill path as signal-without-reap. Investigating it found the deeper cause: `__dk_no_git_env` is a shell FUNCTION, so backgrounding it forked a subshell — $! was that wrapper, and the judge ran on as an orphaned grandchild. Signalling the wrapper killed nothing that mattered, and `wait` alone would have reaped the wrapper just as harmlessly. Proven with a probe: after kill+wait the judge was still in `pgrep`. Backgrounding a SIMPLE command instead (DK_NO_GIT_ENV_INLINE, one env -u prefix built from the same GIT_ENV_VARS as the function) makes the shell fork-and-exec directly, so $! IS the judge; kill then reaches it and wait reaps it before the hook returns. That matters beyond tidiness: the judge inherits git's stdout/stderr, and a survivor holds the ship capture pipeline's read end open — commit-with-gate-capture.sh's R3 hang — while still spending opus on a verdict nobody will read. Test coverage this PR was thin on, now added: - the reap contract itself, with a stub that releases the inherited pipe first (so the assertion measures the HOOK's return, not the pipe drain) and delays inside its TERM handler (so 'returned' and 'reaped' are separable). Verified failing against the unfixed hook. - the same for a fleet exit 3, not just exit 1 — every block path. - review mode does not prewarm; a missing message-file path arms nothing. - sticky-key components proven to re-open the gate one at a time: branch (isolated with a moving diff, since the exact-bytes key is legitimately branch-independent) and reviewer brief. - the prewarm handoff end to end: ship temp file then git-cleaned message is ONE judgement, which is what normalizeCommitMessage exists for. - a sticky hit emits cache_hit + a fully-cached gate_timing, never a silent skip. - DEVKIT_SHIP_BRANCH added to the suite's env-hygiene list (the sticky key reads it, so a suite run during a ship would otherwise be steered). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (3)
cli/__tests__/husky-block-exec.test.mts (2)
68-74: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe backgrounded
sleep 30outlives the stub.The TERM trap exits the stub, but it does not kill the
sleep 30child. That process stays alive for up to 30 seconds after each of the twoCOMP_SLOW_TERMtests. It cannot hangexecFileSync, becauseexec >/dev/null 2>&1runs before the fork and stdin isignore. It only leaves stray processes in the test host.Kill the child in the trap, or shorten the sleep.
♻️ Proposed cleanup of the background sleep
if [ -n "\${COMP_SLOW_TERM:-}" ]; then exec >/dev/null 2>&1 - trap 'sleep 1; echo reaped > "$HOME/comp-reaped"; exit 143' TERM echo running > "$HOME/comp-running" sleep 30 & + slp=$! + trap 'kill $slp 2>/dev/null; sleep 1; echo reaped > "$HOME/comp-reaped"; exit 143' TERM wait $! fi🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/__tests__/husky-block-exec.test.mts` around lines 68 - 74, Update the COMP_SLOW_TERM stub around the background sleep and TERM trap so the trap terminates the spawned sleep process before exiting. Preserve the existing reaped marker and exit status, and ensure the child PID is available to the trap.
220-227: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe test title claims more than the assertions check.
The title states that review mode "exports the same env for its reviewer intent file". The body only asserts that
guard-review --gateruns and thatguard-review completenessdoes not run. It never checks the exported message-file path. Either assert the export, or narrow the title to the prewarm exclusion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/__tests__/husky-block-exec.test.mts` around lines 220 - 227, Update the test named “review mode does NOT prewarm — it exports the same env for its reviewer intent file” so its assertions match the title: verify that the reviewer intent file export uses the expected message-file path in addition to the existing guard invocation checks. Alternatively, narrow the test title to describe only the prewarm exclusion if that export is not intended to be tested.gate-engine/review/__tests__/run-review.test.mts (1)
2019-2030: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueIsolate the brief component of the sticky key.
This test keeps the diff unchanged between the two calls. The brief is also part of the exact-bytes key, because
wrapCompleteness(body, ...)puts it in the prompt. A second judgement therefore happens even if the sticky key stopped including the brief. The test proves "an edited brief re-judges", but it does not prove the sticky key is brief-scoped.Apply the same moving-diff technique used in the branch test at Line 1996 to isolate the component.
♻️ Proposed change to isolate the sticky-key brief component
it('an edited reviewer brief re-judges — a new judge is not covered by the old verdict', async () => { const repo = consumerRepo({ backend: true }); vi.spyOn(console, 'error').mockImplementation(() => {}); const exec = mkExec(async () => 'VERDICT: PASS'); expect(await runCompleteness(msg(repo, 'feat: add db layer'), repo, { exec })).toBe(0); + // Reshape the diff so the exact-bytes key cannot hit: only the sticky key is under test. + writeFileSync(join(repo, 'src', 'main', 'db.ts'), 'export const q = 2;\n'); + execSync('git add .', { cwd: repo }); writeFileSync( join(repo, '.claude', 'agents', 'feature-completeness-reviewer.md'), '---\nname: feature-completeness-reviewer\n---\nBrief for feature-completeness-reviewer. Also check migrations.', ); expect(await runCompleteness(msg(repo, 'feat: add db layer'), repo, { exec })).toBe(0); expect(exec).toHaveBeenCalledTimes(2); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@gate-engine/review/__tests__/run-review.test.mts` around lines 2019 - 2030, Update the test around the second run of the edited reviewer brief to use a changed diff, matching the moving-diff technique from the branch test near line 1996. Keep the reviewer brief edit and assertions intact, while ensuring the changed diff prevents prompt-byte differences from independently triggering re-judgment and isolates the sticky key’s brief-scoped behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cli/__tests__/husky-block-exec.test.mts`:
- Around line 68-74: Update the COMP_SLOW_TERM stub around the background sleep
and TERM trap so the trap terminates the spawned sleep process before exiting.
Preserve the existing reaped marker and exit status, and ensure the child PID is
available to the trap.
- Around line 220-227: Update the test named “review mode does NOT prewarm — it
exports the same env for its reviewer intent file” so its assertions match the
title: verify that the reviewer intent file export uses the expected
message-file path in addition to the existing guard invocation checks.
Alternatively, narrow the test title to describe only the prewarm exclusion if
that export is not intended to be tested.
In `@gate-engine/review/__tests__/run-review.test.mts`:
- Around line 2019-2030: Update the test around the second run of the edited
reviewer brief to use a changed diff, matching the moving-diff technique from
the branch test near line 1996. Keep the reviewer brief edit and assertions
intact, while ensuring the changed diff prevents prompt-byte differences from
independently triggering re-judgment and isolates the sticky key’s brief-scoped
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f1f6a5c8-55b5-4750-b89f-8da19ce4d29b
⛔ Files ignored due to path filters (2)
dist/cli/lib/husky/husky-block.mjsis excluded by!**/dist/**dist/cli/lib/husky/review-fragments.mjsis excluded by!**/dist/**
📒 Files selected for processing (5)
.husky/pre-commitcli/__tests__/husky-block-exec.test.mtscli/lib/husky/husky-block.mtscli/lib/husky/review-fragments.mtsgate-engine/review/__tests__/run-review.test.mts
🚧 Files skipped from review as they are similar to previous changes (2)
- cli/lib/husky/husky-block.mts
- .husky/pre-commit
…tion it answers (#361) Records the ruling behind #360, which shipped without its why. New axis judge-verdict-cache-scope: completeness judges the commit MESSAGE's claims, so its confident PASS is keyed on branch + normalised message + brief rather than the staged bytes — a retry that reshapes the diff for a DIFFERENT reviewer is not re-judged. The Negative is on the record: a retry that guts claimed functionality under an unchanged message is not re-caught, and the message is the only guard. Filed as its own axis rather than a note under ship-gates-converge-not-restart: that axis rules that retries converge, this one rules what a verdict is scoped TO. Cross-linked both ways. Also notes the prewarm on review-gate-in-chain (placement, not scope): completeness now starts in parallel with the fleet at pre-commit on the ship path, and commit-msg re-judges from cache. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bump 0.48.0 -> 0.49.0 and rebuild dist from a clean origin/main worktree. Ships the review-latency work (#360) to consumers: completeness prewarmed in parallel with the reviewer fleet on the ship path, its PASS intent-scoped to branch + message so a retry does not re-pay opus, the cancelled judge actually killed and reaped, and review concurrency defaulting to 6. The ruling behind the sticky verdict is on the record in #361. Also drops dist/cli/commands/migrate.mjs, a stale artifact no build has produced since #68 deleted its source (cli/commands/migrate.mts). It was force-added at v0.33.0 and has shipped to consumers in every release since — dead code for a command that no longer exists. Found by rebuilding dist from EMPTY and diffing the result against the index in both directions; the release check until now only asked whether a built file was missing from the index, never whether an indexed file was still built. Note for the first ship after upgrading: cacheKey salts on the devkit VERSION, so every reviewer and completeness verdict earned under 0.48.0 is invalidated by design (sc-1437 / #353). That first attempt re-judges from scratch; the convergence shows up from the second attempt on. Gates bypassed at the maintainer's request (--no-verify). Release smoke checks ran: built bin reports 0.49.0, a from-empty rebuild is byte-identical to the index in both directions, and all four shipped behaviours are present in dist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bump 0.48.0 -> 0.49.0 and rebuild dist from a clean origin/main worktree. Ships the review-latency work (#360) to consumers: completeness prewarmed in parallel with the reviewer fleet on the ship path, its PASS intent-scoped to branch + message so a retry does not re-pay opus, the cancelled judge actually killed and reaped, and review concurrency defaulting to 6. The ruling behind the sticky verdict is on the record in #361. Also drops dist/cli/commands/migrate.mjs, a stale artifact no build has produced since #68 deleted its source (cli/commands/migrate.mts). It was force-added at v0.33.0 and has shipped to consumers in every release since — dead code for a command that no longer exists. Found by rebuilding dist from EMPTY and diffing the result against the index in both directions; the release check until now only asked whether a built file was missing from the index, never whether an indexed file was still built. Note for the first ship after upgrading: cacheKey salts on the devkit VERSION, so every reviewer and completeness verdict earned under 0.48.0 is invalidated by design (sc-1437 / #353). That first attempt re-judges from scratch; the convergence shows up from the second attempt on. Gates bypassed at the maintainer's request (--no-verify). Release smoke checks ran: built bin reports 0.49.0, a from-empty rebuild is byte-identical to the index in both directions, and all four shipped behaviours are present in dist. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bump 0.49.1 -> 0.50.0 and rebuild dist from a clean origin/main worktree. Minor, not patch: judge_exec gains a new shape. Every judge now records input_tokens, output_tokens, cache_creation, cache_read, cost_usd and session_id (sc-1527, #368), which makes per-ship cost answerable for the first time — the whole reason the review-latency work in #360 could only ever be justified on wall clock. Verified against a REAL claude spawn on the merged code, not the fake used in tests: a haiku judge returned clean verdict text and booked input=10 output=49 cache_creation=17652 cache_read=17822 cost_usd=0.0373 with its session_id — so the join back into the usage tracker exists too. Note for the first ship after upgrading: cacheKey salts on the devkit VERSION, so every reviewer and completeness verdict earned under 0.49.1 is invalidated by design (sc-1437). That attempt re-judges from scratch — which incidentally is the run that will carry the first full cost picture. Gates bypassed at the maintainer's request (--no-verify). Release smoke checks ran: built bin reports 0.50.0, dist byte-consistent with the index in BOTH directions (0 stale, 0 untracked), and the capture is present in the compiled output. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…371) ## What `devkit ship` printed six biome findings into the gate log and passed the commit anyway (the v0.50.0 ship). The deterministic runner was working correctly — `biome check .` exits **0** when every diagnostic is warn-severity, and `--extra "lint=bun run lint"` is only ever as hard as the script it names. devkit’s own `lint` script is now `biome check --error-on-warnings .`, and the six pre-existing warnings are cleared so the gate starts green. ## The six that were passing | file | rule | | --- | --- | | `cli/__tests__/husky-block.test.mts:418,440` | `noTemplateCurlyInString` | | `cli/__tests__/self-host.test.mts:147` | `noTemplateCurlyInString` | | `gate-engine/coverage/__tests__/produce.test.mts:123` | `noNonNullAssertion` | | `gate-engine/decisions/__tests__/recall-scoring.test.mts:255` | `noNonNullAssertion` | | `skills/correctness/scripts/checklist.mjs:65` | `useOptionalChain` | The three `noTemplateCurlyInString` sites assert literal POSIX-sh `${VAR:-default}` text — suppressed with the same `biome-ignore` line this repo already uses at six other sites. The two non-null assertions are **removed** rather than suppressed: one becomes a real precondition check, the other hoists the fixture literal so no assertion is needed. The optional chain is the rule’s own fix. ## Scope: devkit’s own gate only The consumer emitter (`cli/lib/install/package-json.mts`) and the overlay biome gate (`cli/lib/husky/husky-block.mts`) keep a bare `biome check` on purpose. `biome/base.jsonc` holds `noConsole` at `"warn"` deliberately for consumers, while devkit’s root config turns it off across its whole authored surface — so the flag costs devkit nothing and would cost a consumer every `console.log`. Making consumers strict is a separate decision. ## Regression test `cli/__tests__/self-host.test.mts` now asserts the repo’s real `package.json` lint script carries `--error-on-warnings`, because the strictness lives in a script string that no hook-text assertion can reach. ## Also in the diff - `docs/decisions/gate-opt-out-is-visible-and-detectable.md` — note recording the reverse failure mode: not a gate that silently opts out, but one that prints its findings and exits 0. - `.devkit/skills-manifest.json` — `devkit sync-skills` refreshed the correctness-checklist hash and bumped a stale `devkitRef` v0.49.1 → v0.50.0. ## Deliberately NOT in the diff `cli/lib/husky/husky-block.mts:35` still documents the gate as `biome check .`, which is now stale by one line. Correcting that comment was in the first attempt and the ship blocked: the file is **560 lines against a 510-line size baseline on `origin/main`** (`eslint/baselines/size-lines.json:7`), so `guard-size` rejects any commit that touches it. That debt is pre-existing — it arrived via #360, #348 and #286 without a baseline refresh — and paying it (a file split, or a `guard-size freeze` that launders 50 lines) does not belong in this PR. The load-bearing documentation of the command lives in `cli/lib/husky/self-host.mts`, next to `SELF_HOST_EXTRAS`, and that one is updated. ## Verification `biome check --error-on-warnings .` → 0 · `tsc -p tsconfig.json --noEmit` → 0 · `eslint cli gate-engine` → 0 · `vitest run` → 3681 passed / 1 failed, the failure being `cli/__tests__/review.test.mts` “preserves timeout exit 124” returning 143 (SIGTERM) — a wall-clock-bounded test losing its 1s race under a loaded machine, unrelated to this diff.
What
Three latency/cost changes to the ship gate chain, driven by the gate telemetry (
~/.devkit/telemetry/gate-events.jsonl): review is ~95% of a ship attempt's wall clock, the correctness lens split dominates the fleet makespan, and completeness (straight opus, mean ~4 min, max 30 min) ran serially at commit-msg on every landed attempt.Review concurrency default 3 → 6 (
timing.mts). The lens split schedules ~8 judge tasks on a backend commit; at 6 they run in at most two waves, so the fleet makespan approaches the slowest single lens instead of a 3-slot packing. The bound is subscription slots, not CPU/memory — if this ever needs lowering, watch judge timeout rates, not RSS.Parallel completeness prewarm on the ship path (
husky-block.mtsreview fragment). The sc-1442 composed-message file already reaches pre-commit, so the review fragment now launchesguard-review completenessalongside the fleet and applies the commit-msg fragment's exact exit contract, just earlier. A confident PASS lands in the shared verdict store (merge-under-lock, so concurrent writers are safe) and the commit-msg gate re-judges it as a cache hit. If the fleet blocks the commit, the judge is killed rather than awaited. Interactive commits (no message file) are unchanged;devkit reviewis excluded (it exports the same env var as its reviewer intent file).normalizeCommitMessage()mirrors git'scleanup=whitespaceso the ship temp file and git's cleanedCOMMIT_EDITMSGcompute identical cache keys.Intent-sticky completeness PASS. The gate judges the message's claims against the delivered change, so a retry whose diff was reshaped to satisfy another reviewer — same branch, same message — is not re-judged: a confident PASS is additionally saved under a branch+message+brief key (version-salted). What re-opens the gate: an amended message, a different branch, a changed brief, or a devkit upgrade. FAILs are never sticky. The sticky lookup runs before targets retrieval and diff assembly, so a hit costs ~1s.
Net effect: opus completeness is paid once per branch+message across a retry chain (telemetry: ~4.5 attempts per landed ship), and a passing attempt's judged path drops from fleet + ~4 min serial completeness to max(fleet-at-6, completeness).
Trade-off (deliberate, user-ruled)
The sticky PASS trades a re-judgement for cost. If a retry genuinely guts claimed functionality — e.g. an agent deletes a feature to appease the correctness reviewer — while keeping the same commit message, completeness will not re-catch it on that branch. The commit message is the guard: changing the claim re-judges, and a FAIL always re-judges. We accepted this because the flip data shows completeness verdicts on reshaped-but-same-intent diffs almost never change, while the re-runs were the single largest opus line item (~200 calls/week, ~14 h of opus).
Secondary trade-off: the prewarm starts completeness on every ship attempt rather than only on attempts that survive pre-commit review. The sticky pass neutralises the repeat cost (first attempt pays, later attempts hit the key even when blocked mid-chain), and a fleet block kills the in-flight judge — but a first attempt that is blocked before completeness finishes does pay for a partial judge run that today costs nothing. Worst case is bounded at one completeness run per branch+message, same as the status quo's best case.
Verification
run-review.test.mts119/119 (3 new sticky tests, 1 key-normalisation test, concurrency assertions moved to 6)husky-block-exec.test.mts26/26 (7 new prewarm branch tests: armed/unarmed, FAIL/outage/object-fault/fail-open, fleet-block attribution)self-host.test.mtsparity green —.husky/pre-commitregenerated from the updated fragmentCommitted
--no-verifyby request; CI runs the full suite. Follow-up at ship time: record the intent-scoped-verdict ruling viaguard-decisions.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Performance
Bug Fixes