Skip to content

A run that dies mid-fan-out loses every answer it already collected #58

Description

@CryptoJones

A roundtable run that is interrupted anywhere during the fan-out discards all completed lane answers, including paid http lanes that have already billed for tokens. The user-visible symptom is a run that "randomly dies" with zero output and no transcript.

Cause

main() collected the fan-out with results = list(pool.map(...)), which blocks until the last lane returns, and only then wrote the transcript:

with cf.ThreadPoolExecutor(max_workers=max(len(lanes), 1)) as pool:
    results = list(pool.map(lambda l: ask(...), lanes))
...
if not a.no_transcript:
    path.write_text(json.dumps({"brief": prompt, "results": results, ...}))

Every answer is therefore held in memory for the whole run. A SIGKILL, a closed terminal, a harness/task timeout, or a Ctrl-C at any point before the last lane returns throws away everything already collected. Nothing hits disk.

This is invisible in normal use — a run that completes looks fine — and it is worst exactly when it costs the most: a long brief with many lanes, where the slowest lane decides whether the other eleven survive.

Repro

  1. roundtable --lanes JARVIS,HAL9000,Wintermute "..."
  2. kill -9 the process once at least one lane has answered
  3. Before the fix: no transcript is written at all; stdout is empty. The completed answers are gone.

Observed tonight on a 7-lane, 92 KB brief: the run was stopped mid-flight and left a 0-byte output and no transcript, after dispatching every lane.

Fix

Claim the transcript path before the fan-out and persist after every lane completes, via as_completed with results written into the slot each lane was dispatched from, so ordering is preserved and a partial transcript reads exactly like a complete one (null for lanes still out). Writes are atomic (write-to-.tmp, then replace), so a kill during the write leaves the previous good transcript rather than a truncated one. Partial transcripts carry "partial": true and a note.

Verified: kill -9 mid-run now leaves a transcript containing the two lanes that had answered, with the third slot null. Full suite green (119 passed, 29 subtests).

🤖 Generated with Claude Code

https://claude.ai/code/session_01VmauK5UCYGRYyXoQ36FQ3S

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions