feat(runner): persist and resume partial sample outcomes across aborted runs - #52
feat(runner): persist and resume partial sample outcomes across aborted runs#52jamespsterling wants to merge 2 commits into
Conversation
…ed runs Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Original prompt from James
|
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
- report absolute progress counts when resuming from skipped sample-epochs - persist and validate the run scope (epochs/range) with partial outcomes, discarding persisted outcomes from a mismatched scope - remove the partial store only after final result persistence succeeds - log partial-store read failures instead of silently starting fresh - link the persisted schemas to the source types via ZodShape and cover optional fields (trajectory, responseItems, requestBody, metadata, serverToolUse, reasoningTokens) in round-trip tests Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Closing in favor of #48 (per-sample write-through persistence), based on an empirical head-to-head of both resume strategies on the same deterministic workload: Findings
Worth porting into #48 (its write failures are currently silently swallowed):
|
TL;DR
Adds an optional
PartialOutcomeStoreServiceso an aborted run (e.g. Cloud Run SIGTERM) flushes completed sample outcomes durably, and the retry skips those sample/epochs and aggregates the combined result.What changed?
src/results/partial-outcome-store.ts(new):PartialOutcomeStoreServicecontract (read/write/remove) plus Zod schemas (SampleOutcomeSchema,PartialOutcomesSchema) to validate persisted JSON at runtime. Exported as./partial-outcome-store.src/harness/run.ts:RunConfiggainsskipSampleEpochs?: ReadonlySet<string>andonOutcome?: (outcome: SampleOutcome) => void.sampleEpochKey(sampleId, epoch)andaggregateOutcomes(outcomes)(loop-based fold into the existingFoldAccumulator/finalizeRun).onOutcomebefore progress reporting.src/runner/run-by-id.ts:partialOutcomeStore?on the run input. Flow:read()prior outcomes (best-effort) and build the skip set.skipSampleEpochs+ collect new outcomes viaonOutcome.abortSignal.abortedand new outcomes exist):write()prior + new outcomes, then rethrow/return the abort as before.RunResultandremove()the partial object.Why?
Cloud Run gives ~10s between SIGTERM and SIGKILL. Without a durable flush, every completed-but-unpersisted sample in an in-flight chunk is lost and re-run on retry. With this, the retry only reruns missing sample/epochs. Cancellation semantics are unchanged — an aborted run still surfaces as aborted; the flush is a side effect.
How to test
bun test src/harness/run.test.ts src/results/partial-outcome-store.test.ts— covers skip-set filtering,onOutcomeinvocation, aggregation, and schema accept/reject.read()returns prior outcomes; observe skipped sample/epochs in the run and a final result aggregating both sets, followed byremove().Benchmark impact
No score changes for uninterrupted runs (store is optional and unused by default). Resumed runs aggregate persisted + new outcomes identically to a single full run over the same sample/epochs.
Reviewer focus
run-by-id.ts(only when abort signal fired and new outcomes exist; write errors are logged, never masked into a different failure).sampleEpochKeyidentity — stable across attempts so skip sets are safe.Checklist
Link to Devin session: https://openrouter.devinenterprise.com/sessions/4899435489c14bba8242921472c31807
Requested by: @jamespsterling