feat(miner-hands): two-tier stalled-output fast-fail timeout for the CLI-subprocess driver (#5167) - #5251
Conversation
…CLI-subprocess driver (JSONbored#5167) Ports the firstOutputTimer/resolveClaudeFirstOutputTimeoutMs pattern from src/selfhost/ai.ts (built after a naive single-timeout design caused a real production outage, JSONbored#4994/JSONbored#5053) into the CLI-subprocess CodingAgentDriver. CliSubprocessDriverOptions gains an optional firstOutputTimeoutMs: when set and the injected spawn reports timedOut+stalledNoOutput, the driver returns a distinct "<command>_stalled_no_output" error instead of the generic timeout error, so a hung CLI with zero stdout is separately countable from a genuine full-timeout where output was at least flowing. Omitting the option leaves behavior unchanged (opt-in, backward compatible). This driver never reads or writes attempt/governor state either way -- it only reports which timeout fired.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5251 +/- ##
=======================================
Coverage 94.34% 94.34%
=======================================
Files 473 473
Lines 39982 39985 +3
Branches 14576 14578 +2
=======================================
+ Hits 37722 37725 +3
Misses 1585 1585
Partials 675 675
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-12 11:49:42 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 5 non-blocking
Review context
Contributor next steps
Signal definitions
[BETA] Chat with GittensoryAsk Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Summary
packages/gittensory-engine/src/miner/cli-subprocess-driver.ts'screateCliSubprocessCodingAgentDrivercurrently wires only a single flattimeoutMswith no first-output liveness signal. Ports the provenfirstOutputTimer/resolveClaudeFirstOutputTimeoutMspattern fromsrc/selfhost/ai.ts-- built specifically because a naive single-timeout design caused a real production outage against the identical claude/codex binaries (fix(review): claude-code subscription-CLI hangs/times out repeatedly (4,030 Sentry events, ongoing) #4994/fix(selfhost): claude-code fast-fail timeout false-positives on --output-format json (buffered, non-streaming) #5053).CliSubprocessDriverOptionsgains an optionalfirstOutputTimeoutMs.CliSubprocessSpawnFn's opts/return shape grows to match (firstOutputTimeoutMsin,stalledNoOutputout), mirroringsrc/selfhost/ai.ts'sSpawnFnexactly.timedOut && stalledNoOutput, the driver returns a distinct${command}_stalled_no_outputerror (never reusing${command}_timeout_...) -- so a hung CLI with zero stdout is separately countable in logs from a genuine full timeout where output was at least flowing.firstOutputTimeoutMsis omitted, it is not even forwarded tospawn's opts, so behavior is byte-for-byte unchanged from before this option existed.Test plan
npx vitest run test/unit/cli-subprocess-driver.test.ts-- 11/11 passing, including the newdescribe("two-tier stalled-output fast-fail timeout (#4994/#5053)", ...)block: zero-stdout stall (killed early, distinct error), live-output-before-deadline (not misclassified as a stall), output-arrived-but-never-exited (existing full-timeout behavior preserved unchanged -- the regression guard), omitted-option backward compatibility, and an invariant asserting the result never carries any field beyond theCodingAgentDriverResultcontract (no attempt/governor state leak).npx vitest run test/contract/coding-agent-driver-parity.test.ts-- 18/18 passing (unaffected).npx vitest run test/unit/coding-agent-miner.test.ts-- 57/57 passing (unaffected; this driver's consumers didn't need changes).npm --workspace @jsonbored/gittensory-engine run build-- clean.npm run typecheck-- clean.COVERAGE_NO_THRESHOLDS=1 npx vitest run test/unit/cli-subprocess-driver.test.ts --coverage --coverage.include="packages/gittensory-engine/src/miner/cli-subprocess-driver.ts"-- 100% statements/branches/functions/lines.npm run docs:drift-check-- clean.npm run test:coveragelocally (shared/resource-contended machine); relying on CI's Codecov patch-coverage gate plus the isolated-coverage check above.Fixes #5167.