What is missing
A campaign that runs out of budget dies instead of resuming, and nothing carries a campaign's stopping point into the next round's input. Two related capabilities:
1. Cross-window succession. When a campaign question settles without closing its objective, mint exactly ONE successor branched from the just-settled run, carrying a monotonic generation counter, so a sharded or multi-round campaign resumes across budget windows. With a hard stop-guard: N consecutive successors that move nothing — the run banked no result AND the objective did not advance — pause the campaign and surface it, so the N+1th is never burned. A run that produced no branchable state is deferred, never emitted as a row that would refuse every cycle forever.
2. A per-arm frontier record. One durable record per campaign arm that survives budget windows, process restarts, and machine crashes: the current objective, what is banked, what is ruled out, the generation counter, the unmoved streak, and the snapshot each successor is measured against. Movement on it is the round's grade, on an ordered scale: closed, advanced, ruled-out, unmoved. Two rules make it honest — the record is a SIBLING file, never a field inside the queue; and every banked or ruled-out claim must RESOLVE to a real artifact reference, so a campaign cannot self-grade its own movement.
Where it lives today
discovery-lab/tools/campaign-succession.mjs 343 lines.
discovery-lab/tools/frontier.mjs 212 lines.
Where it belongs
src/campaign/run-campaign.ts:225 — export async function runCampaign(, which owns a campaign's lifecycle within one window and has no successor concept.
src/campaign/parent-selection.ts:49 — export function crowdedFrontierParent(, which selects a parent WITHIN a generation. Succession is the same selection across windows.
src/campaign/search-ledger.ts — SearchCandidateLineage (:83), SearchPlannedOperation (:108), and SearchCandidateSlot (:113) already model lineage and planned work; the durable per-arm frontier and the generation counter are the missing records beside them.
Grepped across src/campaign/*.ts: successor and barren return nothing, and every resume hit belongs to the external-optimizer subprocess path (external-optimizer-run-budget.ts:21, external-optimizer-runtime.ts:76-89), which resumes one optimizer process, not a campaign question.
Measured motive
From the 2026-08-30 continuity audit recorded in frontier.mjs:6-13: the branch primitive is real and was exercised 276 times, but 0 of 1,170 question runs ever used it. One round ended with "smallest counterexample now 11 <= n <= 14" and no successor question exists anywhere — an honest scoped partial terminated its own lineage with no next round. Stopping points died in the results file because nothing carried them into the next round's input.
Acceptance
Both files can be deleted when a test settles a campaign question without closing its objective, asserts exactly one successor is minted with an incremented generation counter and a resolvable link to its parent's state, asserts three successors that move nothing pause the campaign and a fourth is never dispatched, and asserts a banked claim whose reference does not resolve is refused.
What is missing
A campaign that runs out of budget dies instead of resuming, and nothing carries a campaign's stopping point into the next round's input. Two related capabilities:
1. Cross-window succession. When a campaign question settles without closing its objective, mint exactly ONE successor branched from the just-settled run, carrying a monotonic generation counter, so a sharded or multi-round campaign resumes across budget windows. With a hard stop-guard: N consecutive successors that move nothing — the run banked no result AND the objective did not advance — pause the campaign and surface it, so the N+1th is never burned. A run that produced no branchable state is deferred, never emitted as a row that would refuse every cycle forever.
2. A per-arm frontier record. One durable record per campaign arm that survives budget windows, process restarts, and machine crashes: the current objective, what is banked, what is ruled out, the generation counter, the unmoved streak, and the snapshot each successor is measured against. Movement on it is the round's grade, on an ordered scale: closed, advanced, ruled-out, unmoved. Two rules make it honest — the record is a SIBLING file, never a field inside the queue; and every banked or ruled-out claim must RESOLVE to a real artifact reference, so a campaign cannot self-grade its own movement.
Where it lives today
discovery-lab/tools/campaign-succession.mjs343 lines.discovery-lab/tools/frontier.mjs212 lines.Where it belongs
src/campaign/run-campaign.ts:225—export async function runCampaign(, which owns a campaign's lifecycle within one window and has no successor concept.src/campaign/parent-selection.ts:49—export function crowdedFrontierParent(, which selects a parent WITHIN a generation. Succession is the same selection across windows.src/campaign/search-ledger.ts—SearchCandidateLineage(:83),SearchPlannedOperation(:108), andSearchCandidateSlot(:113) already model lineage and planned work; the durable per-arm frontier and the generation counter are the missing records beside them.Grepped across
src/campaign/*.ts:successorandbarrenreturn nothing, and everyresumehit belongs to the external-optimizer subprocess path (external-optimizer-run-budget.ts:21,external-optimizer-runtime.ts:76-89), which resumes one optimizer process, not a campaign question.Measured motive
From the 2026-08-30 continuity audit recorded in
frontier.mjs:6-13: the branch primitive is real and was exercised 276 times, but 0 of 1,170 question runs ever used it. One round ended with "smallest counterexample now 11 <= n <= 14" and no successor question exists anywhere — an honest scoped partial terminated its own lineage with no next round. Stopping points died in the results file because nothing carried them into the next round's input.Acceptance
Both files can be deleted when a test settles a campaign question without closing its objective, asserts exactly one successor is minted with an incremented generation counter and a resolvable link to its parent's state, asserts three successors that move nothing pause the campaign and a fourth is never dispatched, and asserts a banked claim whose reference does not resolve is refused.