feat(ce-optimize): held-out confirmation, judge validity gate, and text-target guidance - #1707
Merged
cursor[bot] merged 4 commits intoSep 15, 2026
Conversation
…xt-target guidance Phase 1 accepts the harness only when it orders known-good above known-bad exemplars and does not reward a trivial shortcut; a judge primary also needs a human-labeled calibration sample (or an explicit waiver) before the run leaves Phase 1. A held-out set (measurement.holdout.command or metric.judge.confirmation_seed) is scored only before a keep and at final confirmation: decide.mjs answers a would-be keep with next_measurement: holdout until the pair is supplied, and a holdout that disagrees withholds the keep. Judge items carry a required feedback string that the digest groups into failure themes for hypothesis generation; identical items are judged once per run via a content-hash cache; per-experiment cost and per-case regressions are logged, report only. New references/text-targets.md and example-text-target-spec.yaml cover instruction-text targets: the eval-set coverage rule, model roles, hypothesis moves, and saturation. The judge model enum becomes capability tiers (cheap|strong) with legacy haiku/sonnet read as aliases. Co-authored-by: Kieran Klaassen <kieranklaassen@users.noreply.github.com>
…idance Co-authored-by: Kieran Klaassen <kieranklaassen@users.noreply.github.com>
Co-authored-by: Kieran Klaassen <kieranklaassen@users.noreply.github.com>
cursor
Bot
force-pushed
the
cursor/feat/ce-optimize-eval-discipline-01d6
branch
from
September 14, 2026 18:23
d28a236 to
6d7057f
Compare
cursor
Bot
changed the base branch from
main
to
cursor/ce-optimize-long-runs-54a9
September 14, 2026 18:27
Co-authored-by: Kieran Klaassen <kieranklaassen@users.noreply.github.com>
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.
Stacked on #1708 (
cursor/ce-optimize-long-runs-54a9); merge that first.Summary
Implements "Proposal I" (eval discipline) for
ce-optimize: the DSPy-style checks around the existing loop. Nothing about what counts as an improvement changes; what changes is whether the harness is trusted before the baseline, whether a keep is confirmed on data the loop never selected from, and what the judge hands back for the next hypotheses.Rebased onto
cursor/ce-optimize-long-runs-54a9and targeted at it. The diff here is only the eval-discipline content; the tick loop, state root, and approval record are #1708's. Reconciled against #1708: holdout is required by the same wake after turn end condition #1708 defines (not a second term); the holdout rule sits beside #1708's unattended judge-cost-cap rule without duplicating it;judge-cache.yamlis now a row in #1708'spersistence.mdfile table and the log schema names its location as<state-root>/judge-cache.yaml.What changed
Phase 1 metric validity gate (
measurement.md1.2,spec.mdstep 2, logharness_validation). The harness is accepted when it orders the user's known-good exemplars above the known-bad ones and does not reward a trivial shortcut (empty / constant / copied output). Fortype: judge, additionally when the judge agrees with a human-labeled sample (20-50 items with reasoning) atmetric.judge.calibration.min_agreement(default 0.8), or the user explicitly waives calibration; a judge run with neither does not leave Phase 1. Failure direction: stop before the baseline, report which probe failed. The approval presentation gains one evidence-quality line.Held-out confirmation (
optimize-spec-schema.yaml,decide.mjs,loop.md3.3/3.4,wrap-up.md).measurement.holdout.command, ormetric.judge.confirmation_seeddistinct fromsample_seed. Scored only before a keep and at final confirmation; never used to select or generate hypotheses.decide.mjsowns the gate mechanically: a would-be keep returnsnext_measurement: holdoutuntil the payload carries aholdoutsnapshot pair, and a holdout that disagrees returnsrevertorinconclusive. Required fortype: judgeand when the run waits between ticks through a wake after turn end (#1708's term); otherwise optional, with the approval presentation stating plainly that selection and reporting share one sample.Judge feedback -> hypotheses (
judge-prompt-template.md,loop.md3.3/3.5, logjudge.items[].feedback). A required per-itemfeedbackstring; the digest gains a "Failure themes" section built from it; Phase 3.5 generates at most one hypothesis per theme, not a rule per failing item. The template also asks for repeatable scores (same item, same score), which is what makes the cache and calibration valid.Judge cache and per-experiment diagnostics (
loop.md3.3, log schema). Judge results cached by content hash injudge-cache.yamlbeside the log for the run;cost(usd / tokens / latency) recorded when reported.Per-case regressions (
measurement.per_case,decide.mjs,wrap-up.md). When the harness emits acasesmap,decide.mjsreturnsregressions(cases the reference passed and the candidate fails). Report only; the decision is unchanged.references/text-targets.md(new) +example-text-target-spec.yaml(new). For targets that are instruction text: eval set from recorded failures (four fields, 5-10 floor); the coverage rule "every rule you want preserved needs a case that fails without it"; hypothesis moves as categories; task model pinned by the harness, proposer may be stronger; a ceiling score is "eval too easy", stop and say so; an external optimizer as one experiment, capability phrasing, no library named. Pointed to fromspec.mdandmeasurement.md(SKILL.md body untouched, at 7,778 bytes it is near the Codex cap).Portability fix while the block was touched: judge
model: haiku|sonnet->cheap|strongcapability tiers, harness resolves the concrete model; legacy values read as aliases.example-judge-spec.yamlupdated (tier,confirmation_seed,calibration).Design choices made where the doc did not decide
decide.mjsas a ladder step (next_measurement: holdout) rather than as prose alone. The script already owns the ladder next step; prose would have left the gate to the model's discretion.revertwhen the holdout regressed,inconclusivewhen it did not confirm) rather than a new outcome enum. Closest to today's log shape.measurement.holdout.commandstill works for judge runs that have a separate set.tests/skills/ce-optimize-decide.test.ts(which already carries the ce-optimize schema/skill pins) instead of creatingtests/skills/ce-optimize-contract.test.ts; that file does not exist onmainyet and is on the other worker's file list, so keeping out of it avoids an add/add conflict at rebase.docs/solutions/learning. The coverage rule and the "script owns the gate" reasoning are stated intext-targets.md, the schema description, and thedecide.mjsheader; they fail the AGENTS.md counterfactual.Left as follow-up (untouched blocks, not brought to the standard)
measurement.md1.2-1.3 still read as numbered procedures around the new condition paragraphs; only the added blocks are stated as conditions.loop.md3.2 Codex env-var check is unchanged (the long-run branch restates it).bun run test:skill-eval-cell) was not run: neitherclaudenorcodexis on PATH in this environment. Scenarios worth running before merge: (a) judge spec without labels or waiver stops in Phase 1; (b) hard spec withmeasurement.holdoutcollects the holdout only whendecide.mjsasks; (c) plain hard spec with no holdout behaves as before.Validation
bun test tests/skills/ce-optimize-decide.test.ts: 99 pass after the rebase (10 new decide tests for holdout / regressions, 7 new pin tests, plus feat(ce-optimize): long-running optimization stack (tick loop, eval discipline, remote backend) #1708's).bun run test(after rebase): 4107 pass, 14 timeouts intests/skills/ce-work-unit-workspace-fallback.test.tsandtests/ce-code-review-mechanics.test.ts(files this branch does not touch) under a loaded 4-worker VM; both files pass in 9s and 2s when run alone.bun run release:validate: in sync (35 skills, no count change).bun run plugin:validate: not run,claudeis not on PATH here.Security Disclosure
No security-relevant changes.
decide.mjsgains a pure-function path over an additional JSON snapshot pair and acasesobject; no new shell execution, path handling, or dependency.Agent Disclosure
Cursor cloud agent · Claude Fable