dream(flywheel-promotion): #287 wire withSequentialEvidence into run.ts + replay.ts (evaluated) - #288
Draft
ruvnet wants to merge 2 commits into
Draft
dream(flywheel-promotion): #287 wire withSequentialEvidence into run.ts + replay.ts (evaluated)#288ruvnet wants to merge 2 commits into
ruvnet wants to merge 2 commits into
Conversation
β¦s unreachable from run.ts/replay.ts `withSequentialEvidence` (sequential.ts) was fully built, exported, and unit-tested but had zero production call site: `runFlywheelGenerations` never populated `PromotionEvidence.pairedOutcomes` (the type didn't even have the field), so wiring it into a real FlywheelConfig always silently degraded to the plain frozen gate. Same gap independently found at verifyReplayBundle's ADR-235 gate re-execution by a fresh-subagent critic, closed in the same diff. Adds Score.itemWins (optional, additive) and threads it through both call sites via a shared pairedOutcomesFromItemWins helper. ADR-279 filed. 8 new tests, all confirmed non-vacuous by independently reverting each sub-fix. flywheel 77/77 (was 72/72), tsc clean, 0 regressions across every downstream @metaharness/flywheel consumer (evals-math/sql/toolcall/ servedmodel/hle/extract, autogenous). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EHW2MJiNYeYTb8nWHQYt89
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EHW2MJiNYeYTb8nWHQYt89
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.
Closes/tracks #287.
Hypothesis
Given a
FlywheelConfigwhose Evaluator reports per-itemitemWinsfor both baseline and candidate on thesame holdout, when
promotionRule: withSequentialEvidence(meetsPromotionRule)is supplied torunFlywheelGenerations, then a thin-margin win (few discordant items, e-value below the 1/alphathreshold) should be REJECTED even though the frozen base gate alone would promote it, and a strong-margin
win should be PROMOTED identically to the base gate β subject to: zero behavioral change for any Evaluator
that omits
itemWins;meetsPromotionRuleitself untouched; the same guarantee holding underverifyReplayBundle's independent replay, not just the live run. Frozen before implementation.Candidate
packages/flywheel/src/sequential.ts'swithSequentialEvidence()β an anytime-valid e-process gateagainst repeated-peeking false-commits β was fully built, exported, and unit-tested, but had zero
production call site:
runFlywheelGenerationsnever populatedPromotionEvidence.pairedOutcomes(thetype didn't even have the field), so wiring it into a real
FlywheelConfigalways silently degraded to theplain frozen gate. Same bug class as ADR-278 (Darwin Mode's Tier-2 sandbox never calling its own safety
gate), different domain.
Changes (4 source files, ~50 net lines + 1 new test file):
types.ts:Score.itemWins?: boolean[](optional, additive) +PromotionEvidence.pairedOutcomes?: PairedOutcome[](optional, additive;PairedOutcomerelocated here fromsequential.ts, re-exportedunchanged for API compatibility).
sequential.ts: new shared helperpairedOutcomesFromItemWins(baseline, candidate).run.ts: the live promotion loop now buildspairedOutcomesfrom the evaluated baseline/candidateScores and includes it on every gate call.
replay.ts: an independent adversarial critic (fresh subagent, not self-review) found the SAME gap at asibling call site β
verifyReplayBundle's ADR-235 gate re-execution never reconstructedpairedOutcomeseither, so replaying a sequential-gated promotion silently re-verified only the wrappedbase rule. Closed in this diff rather than deferred (same bug class, same package, ~10 line fix with its
own regression test).
meetsPromotionRule(the frozen default gate) is byte-for-byte untouched.Evaluation Receipt
8 new tests (
packages/flywheel/__tests__/sequential-wiring.test.ts), each confirmed non-vacuous byindependently reverting the corresponding sub-fix (
git stashonrun.tsalone, then onreplay.tsalone) and re-running:
runFlywheelGenerationscall (1 promotion, sanity-checked); the sequential-wrapped rule does not (0).Pre-fix (run.ts reverted): both promote β test fails exactly as predicted (
expected 0, got 1).itemWinsstill degrades to the base rule through thereal run path (not just a direct unit-level function call).
verifyReplayBundle's gate re-execution. Pre-fix (replay.tsreverted, run.ts fix kept): THIN sealed evidence incorrectly re-passes (
gateReExecutes: truewherefalseexpected) β confirmed live.Full suite: flywheel 77/77 (baseline 72/72),
tsc --noEmitclean. Downstream sweep, 0 regressions:evals-math 14/14, evals-sql 7/7, evals-toolcall 14/14, evals-servedmodel 12/12, evals-hle 7/7, evals-extract
7/7, autogenous 7/7. Build:
npm ci && npm run buildclean for the affected packages (no wasm/NAPI stepsneeded for this candidate).
Baseline Comparison
N/A in the model-eval sense β no live model calls, no benchmark corpus. "Baseline" here is the pre-fix
package (72/72 tests,
withSequentialEvidencereachable only from its own unit tests); "candidate" is thepackage after wiring (77/77 tests, the same function now reachable from
runFlywheelGenerationsandverifyReplayBundle).Darwin Lineage
Not applicable β this candidate is a structural fix to the flywheel's own infrastructure, not a tunable
policy genome. No Darwin generations run.
Flywheel Evidence
No flywheel receipt/lineage produced β the candidate IS flywheel infrastructure. See Evaluation Receipt
above for the direct test evidence instead.
Reward Hack Check
No test/benchmark weakened;
meetsPromotionRuleunchanged; no new caching or live model spend; fullydeterministic. Both new fields are additive. Independent critic explicitly checked for
cherry-picked/tautological tests and hand-verified the THIN-evidence math independently β see #287 for the
full critique summary (verdict: ACCEPT-WITH-CAVEATS, caveat = the
replay.tsgap it found, which this PRalso closes).
Security Review
Not a security-sensitive surface change. No new trust boundary;
pairedOutcomesFromItemWinsonly readsalready-sealed
Scorefields at both call sites; the receipt/signature model is untouched.Regression Analysis
0 regressions (see Evaluation Receipt). Every consumer of
@metaharness/flywheelin this repo re-testedgreen.
PairedOutcomerelocation fromsequential.tstotypes.tsis a pure move + re-export β noconsumer imports it from a path this PR changes the export of.
ADR
ADR-279
(new).
Research Gist
No gist-hosting tool available in this session; published locally instead:
docs/dream-cycle/2026-09-06-gist.md.Issue
#287
Witness
Merge Policy
Human review required. Do not self-merge. Do not autonomously promote any Flywheel state. This PR only
makes
withSequentialEvidencereachable from the flywheel's live and replay paths β it does not enablesequential-evidence gating anywhere by default (see Recommended Next Steps in #287 for the deliberately
deferred per-vertical rollout).
π€ Generated with Claude Code
https://claude.ai/code/session_01EHW2MJiNYeYTb8nWHQYt89
Generated by Claude Code