Skip to content

feat(statistics): reconstruct a sequential e-process after a restart - #671

Merged
drewstone merged 1 commit into
mainfrom
feat/sequential-gate-resume
Aug 21, 2026
Merged

feat(statistics): reconstruct a sequential e-process after a restart#671
drewstone merged 1 commit into
mainfrom
feat/sequential-gate-resume

Conversation

@drewstone

Copy link
Copy Markdown
Contributor

Why

#411 criterion 2 asks for proof that sequential state reconstructs after a process restart. It did not: EProcessState reported wealth and n but not the running sums the next bet is computed from, and eProcess had no way to take a snapshot back, so a campaign that died mid-stream had to restart the test from n=0 — which is a fresh type-I budget on data that was already spent.

What

  • EProcessState gains sumX and varSum, the two running sums the plug-in bet reads (λ_i is a function of x_1..x_{i-1} only, so the sums are exactly what a restart needs).
  • eProcess({ resume }) rebuilds a process from a snapshot. The snapshot never supplies the parameters: alpha, maxBet, and nullMean resolve from the options as for a fresh process, and a snapshot recorded under different ones is refused with a ValidationError — continuing a stream under new parameters after seeing the data reopens optional stopping.
  • sequentialPairedGate({ resume }) rebuilds the observe-stream from the newly exported SequentialStreamState (the e-process state plus the gate decision). decide(ctx) is untouched: it always runs its own fresh stream.
  • Refusals are loud and name the field: running sums outside [0, n], a latch without its decidedAtN, an undecided snapshot already above the threshold, a gate decision this configuration could not have reached at that n (promote below minN, continue at maxN, undecided-at-maxN at the wrong n).
  • sequentialDecide needs no snapshot — it is replayed from the generation history it is handed, and consumes each generation exactly once.

Proof

pnpm typecheck                        tsc --noEmit, clean
pnpm lint                             biome, 722 files, no fixes
pnpm exec vitest run src/statistics src/campaign/gates
                                      18 files, 330 tests passed
pnpm build                            tsdown + OpenAPI emit, clean
pnpm typecheck:examples               clean
pnpm typecheck:scripts                clean
pnpm verify:package                   publint + attw + packed exports + evidence check, clean

The restart proof is src/statistics/sequential-eprocess.test.ts and the new block in src/campaign/gates/sequential.test.ts: a stream is interrupted at n = 0, 1, 4, 5, 7, 20, 30, 59, 119 and at the decision crossing, persisted through JSON.parse(JSON.stringify(state())), rebuilt, and driven to the end — the wealth sequence, the observation sequence, the decision, and the final state are identical to the uninterrupted run, including a double restart and a manifest-bound stream.

Full pnpm test locally: 5,330 passed, 12 files fail — the same 12 that fail on unmodified origin/main in this checkout (python-venv, subprocess, and git-worktree tests: benchmark-command*, gepa-*, skillopt-*, external-optimizer-process, worktree, product-benchmark/export). Verified by running that exact set on a clean origin/main worktree: same 12 files, 58 failures. None touch statistics or the campaign gates. CI has the python toolchain and is the authority.

Simplification: none — this is an irreducible addition. The two running sums already existed as closure state; the change publishes them on the snapshot instead of adding a parallel checkpoint path, so resume reuses the existing state() shape rather than introducing a second one.
Net: +596 / -16 lines, 12 files, 0 paths removed.
Tests: +2 files, 40 assertions covering restart identity and snapshot refusal (each prevents a resumed gate silently restarting its type-I budget or continuing under swapped parameters), -5 shape-only assertions dropped from the first draft (the type proves them).
Not done here: sequentialDecide gets no resume — it reconstructs from history by design; a durable snapshot store for campaigns is a separate change.

Refs #411 (criterion 2: restart reconstruction). Criteria 3 and 4 land in follow-up PRs.

@drewstone
drewstone force-pushed the feat/sequential-gate-resume branch from b93584b to b390bd6 Compare August 21, 2026 01:33

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — b390bd66

This PR was opened by the trusted drewstone account.

This approval is provisional and was applied by the local stand-in because the pr-reviewer webhook host is unreachable (2026-08-21). CI on this head is fully green. The full PR reviewer audit re-runs via the resweep when the service returns and will publish findings if it detects issues.

@drewstone
drewstone merged commit c9093f5 into main Aug 21, 2026
2 checks passed
@drewstone
drewstone deleted the feat/sequential-gate-resume branch August 21, 2026 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants