Repository navigation
feat(improve): advisory LLM selector among harnesses that passed the gate - #980
Merged
Merged
Conversation
LinuxDevil
force-pushed
the
s20-selector
branch
6 times, most recently
from
November 8, 2026 22:19
966355f to
6903811
Compare
…gate Adds select: true. The gate judges every candidate (composite and proposals, or seq checkpoints) instead of stopping at the first pass; when two or more pass, a blind read-only selector session picks one by its training answers, with labels shuffled by a seed from the cycle and Harness2's rubric order. A failure or invalid choice keeps the cheapest passer. ImproveResult gains selection; ProbeRun gains answer. The selector never sees a rejected harness or a held-out case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shows the selector the last assistant answer of a transcript without tool calls, leaves out unscored runs, caps each candidate file, accepts a lower-case choice, gives a reason when none was given, types selection.chosen as a gate label, shows the selection on the card, and documents fallback, cost and budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The M4 improve modules brought the packed entry count to 1041, one over the 1040 budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LinuxDevil
force-pushed
the
s20-selector
branch
from
November 8, 2026 22:25
6903811 to
78dae0d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
M4 ticket S20 (Harness² rows 13 and 14). Harness² uses a blind LLM selector with a rubric (
harness2/core/selection.py:71-153,harness2/core/prompts.py:1040-1104). The M3 plan dropped it as an authority, because hidden checks beat an LLM reading outputs. This adds it back only as an advisory tie-break among harnesses that already passed the gate. It checks output quality that a binary check can't see. The gate stays the authority, and the selector can't choose anything that failed. Per decision 5 (section 7 of the M4 plan) it is opt-in and off by default, so cost and behaviour are unchanged. Builds on S18 (#974) and S19 (#978).Changes
ImproveOptions.select?: boolean(defaultfalse).agg, or each checkpoint inseq.src/improve/select.ts. With two or more passers:ImproveRun.ask: fs read tools only, on an in-memory workspace) readscontext/candidates/<id>.md.ProbeRun.answerwhen the probe returns one; otherwise the last assistant message of the transcript, without tool calls;unmarked;selectPromptfollows Harness²'s rubric order: delivery, conformance, fidelity, consistency, fitness, finish. It replies with<why>and achoicefence.ImproveResult.selection?: { chosen; why; fallback }.whypasses throughplain(), whichaudit.tsnow exports internally, andchosenis aGateVerdict['label'].ProbeRun.answer?: string.winningNotesfollowsselection.chosen, sochangescarries the chosen editor's reasons.formatImproveResultadds a## Selectionsection.docs/improve.md, covering what the selector sees, the fallback, and the extra held-out runs and budget. The API report is updated.Acceptance. With
selectoff, the result is unchanged. A test comparesselect: undefinedwithselect: falseand pins the exact reason and gate list. Every existing S18 and S19 test, including the k = 1 snapshot, passes unchanged.Testing
TDD: new
src/improve/select.test.ts(14 tests), written first and failing. It covers the ticket's four cases:with one passer no selector runslabels are shuffled deterministicallyan invalid choice falls back to the cheapestthe selector never sees a rejected harness or a held-out case(no rejected answer, held-out answer, held-out id or provenance label reaches it)It also covers:
why;<why>;seqcheckpoints;changesfollowing the chosen editor.A new
format.test.tscase covers the card.npx vitest run src/improve src/cli/improve: 532 passed after rebasing onto feat(improve): applyProposal, the one writer #976, feat(improve): rollbackHarness and the revisions, rollback and audit commands #981, fix(forge): split LabelsDialog under the fallow complexity limit #988, fix(forge): templates screens under the fallow limits #991, feat(improve): regression corpus store and growth #987 and feat(improve): corpus guard #989 (plain()keeps feat(improve): rollbackHarness and the revisions, rollback and audit commands #981's control-character stripping). Coverage onsrc/improveis 98.4% of lines, withselect.tsat 97%.The first CI run failed
pack-smoke: 1041 tarball entries against a 1040 cap. Main has since raised the cap to 1150 in feat(improve): rollbackHarness and the revisions, rollback and audit commands #981, so this PR no longer changesscripts/pack-smoke.ts.A CI run failed
size-check: 19,771,956 bytes unpacked against a 19,768,292 budget. feat(improve): corpus guard #989 (S14) has since raised the budget to 20,760,183, above that measurement, so this PR doesn't changescripts/size-budget.jsoneither.Standard checks pass:
api:update/api:check,docs:llms/docs:llms:checkanddocs:verify-snippets -- --skip-build;docs:ratchet, at the 1724 baseline;src/improve, thennpx fallow audit --base origin/main: no issues.An independent review found no High issues. It confirmed that the selector can't override the gate, sees no held-out data or provenance labels, and that select off is unchanged in both modes. Fixed:
<why>, and an exact select-off result.whyon a valid choice.read_file's cap.selection.chosenis now typed as a gate label.Declined: using the gate's
costOnPassingCasesfor "cheapest". It isn't defined when no case passes under both harnesses. Tokens per training run is, and the docs now name it.🤖 Generated with Claude Code