Salvage the Work a Timeout Would Have Thrown Away
Kill a coding agent for stalling, not for being slow — and keep the work it already finished
0 milestones 4 sprints
41m 57s total 4m 49s per sprint
19.2M tokens in 123k tokens out
$18.50 nominal cost
This job changed what Gantry means when it stops an agent for spend. The old elapsed-time ceiling made a slow agent and a stuck agent look the same, then treated a coding-stage ceiling as proof that the sprint was too large even if the worktree already passed its tests.
The resulting design separates those cases. Streaming harnesses are watched for actual silence, non-streaming harnesses still have an absolute runaway bound, and a ceiling on the coding stage is judged by the worktree, the gate, and review before Gantry throws anything away.
How this walkthrough is structured
Feature
What did the run build and ship?
Gantry now treats agent silence, absolute runaway bounds, and test-passing timed-out execute work as separate runtime states instead of one terminal timeout.
Build
How did Gantry structure the work?
The run cut the timeout change into a progress detector, an execute-only salvage route, downstream accounting, and docs, with every sprint landing cleanly without repair or re-plan.
Adaptive Progress Guard
0 agents 18m wall time 59.3k tokens out $10.28 nominal cost
The agent runner now has a small decision helper that chooses between silence on a streaming harness and total elapsed time for harnesses without live progress. Config still carries an absolute ceiling, but it is documented in code as a runaway backstop, and the no-progress window is a separate value. Sprint files can override both the ceiling and the stall window. Current harness capabilities expose whether live usage streams are available, which is the flag the poll loop uses.
This first slice carried the signal change by itself. It kept the existing oversized outcome in place, so later code could still reason about the same failure class while the trigger underneath changed. The brief made the work compact enough for a fresh agent by asking for config, sprint front matter, and a pure reap decision around the existing poll loop. The gate stayed green, which fits the boundary: the sprint could prove the guard rules without yet deciding how timed-out work should be salvaged.
Execute-Stage Work Salvage
0 agents 5m 48s wall time 20.3k tokens out $2.51 nominal cost
An oversized outcome from the coding stage no longer forces an immediate oversized sprint result. In the current build module, execute-stage oversized and indeterminate outcomes return to the normal ground-truth path, while non-execute stages still stop conservatively. The regression tests include the incident shape: a coding agent exits through the timeout code after writing real work, the gate passes, and the sprint is recorded done rather than discarded. That route now lives under the split build module rather than the old single build file.
The hard behavior change was isolated after the oversized outcome already meant the right thing. Its brief did not ask a fresh agent to invent a new truth source; it pointed to the existing truncated-stream path, where execute work already fell through to confinement checks, the gate, bounded repair, and review. That made the boundary narrow: extend the same fall-through to execute-stage spend kills while leaving planner, fix, and review ceilings terminal. This sprint also landed cleanly, so the salvage rule reached the next work item as a proven routing change.
Timeout Detection Alignment
0 agents 3m 50s wall time 11.7k tokens out $1.79 nominal cost
Map units now let their gate decide whether a timeout-classified worker actually failed. A gate-green oversized map unit is recorded as done with no unit fault, so it never feeds the repeated-timeout monitor. The timeout classification still exists for work whose gate remains red after repair, preserving the systemic halt for real repeated runaway cases. The current source keeps an explicit comment on the difference between map's gate-based salvage and the milestone build pipeline's execute fall-through.
Once a ceiling could produce kept work, the accounting layer needed its own small pass. The brief scoped this as an audit of map-unit handling and the consecutive-timeout detector, not another rewrite of the salvage path. That made the fresh-agent problem mostly classification: a green salvaged unit must reset the timeout run, while a real repeated timeout must still halt. The run facts show no retry or re-plan here, so the difficulty stayed inside the classifier and map-driver tests rather than escaping into the surrounding run.
Timeout Mechanics Documentation
0 agents 3m 23s wall time 11k tokens out $1.61 nominal cost
The runtime docs now describe the spend guard as a no-progress guard on execute work, with an absolute backstop behind it and terminal handling kept for stages that cannot be judged by a tested worktree. The config docs list the stall setting and the absolute ceiling as separate settings, and the plan parser's module comment names the per-sprint overrides. Some original README text has since moved into the docs tree, but the described knobs and execute-stage salvage behavior are still documented at current HEAD.
The final slice was intentionally thin and depended on the earlier implementation being settled. Its brief limited the work to the public runtime and config prose plus the sprint-file module comment, so a fresh agent only had to align names and operator-facing behavior with code that already existed. The clean boundary mattered because docs could describe the final shape without anticipating another change. It also finished without a gate repair.