feat(campaign): runLineageLoop — Lineage DAG live seams#322
Merged
Conversation
…rovement loop (multi-track, merge, governor)
tangletools
approved these changes
Jul 7, 2026
tangletools
left a comment
Contributor
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 8cc567da
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-07T17:33:42Z
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.
Wires the just-merged Lineage DAG primitive (
src/campaign/lineage.ts—Lineage,runLineage,Governor,heuristicGovernor) to the real improvement machinery so the multi-track, multi-parent improvement DAG can run live.What this adds
src/campaign/presets/run-lineage-loop.ts—runLineageLoop, a thin additive adapter that suppliesrunLineage's two abstract seams:step= ONESurfaceProposer.proposefrom the track tip (a single GEPA reflective generation, small population) + one scoringrunCampaignper candidate. Elitist: the tip stays in the pool so a step never regresses below its parent (mirrorsrunOptimizationkeeping the winner as baseline when no candidate beats it). Best-scoring candidate becomes the new DAG node.merge= the same proposer driven withctx.paretoParentsset to the 2+ parent surfaces, which firesgepaProposer's GEPA combine-complementary-lessons crossover, then one scoring campaign on the merged surface.The default governor is
heuristicGovernor(); seed scores come from an initial scoring pass of each seed surface.Integration choice
Single gepa-propose + one scoring campaign per step — not a full
runImprovementLoopper DAG step. A full improvement loop (baseline campaign + optimization + two holdout campaigns + gate + optional PR) per single node would be enormously heavy; the DAGGovernoris what controls breadth across steps (extend / branch / merge / prune), so the inner step is intentionally one small generation.Injectable seams (unit-testable without a live model)
Both machinery halves are overridable:
proposer— defaults togepaProposer(needsllm+model); tests inject a pure stub.scoreSurface— defaults to arunCampaignpass overholdoutScenarios ?? scenarios(the "agent" =dispatchWithSurface, judges =judges); tests inject a deterministic function, or supply a stubdispatchWithSurface+judgesand exercise the realrunCampaignpath.Tests
src/campaign/presets/run-lineage-loop.test.ts(5 tests, all green) drives the loop with a deterministic stub agent + judge (surfaces encode their own fitness; no LLM, no sandbox) and asserts: it seeds N visioned tracks, produces a multi-node merge DAG,best()is the max score, re-running is bit-identical, the merge seam drives the crossover proposer, and required-seam validation throws. The defaultscoreSurfaceruns the realrunCampaignpath via an in-memory storage stub.Observed live DAG: 3 visioned roots → a 3-parent merge node → the solve track climbs 0.11→0.31→0.51→0.71→0.9 via the real propose+campaign step seam, then plateaus and stops.
Additive: no changes to
lineage.ts,run-optimization.ts, orgepa.ts.tsc --noEmitclean, biome clean, 29/29 lineage+loop tests pass.