Skip to content

🔍 Report what an abandoned xmd run wrote before its deadline - #509

Merged
taras merged 1 commit into
mainfrom
agent/issue-508-deadline-account
Aug 20, 2026
Merged

taras merged 1 commit into
mainfrom
agent/issue-508-deadline-account

Conversation

@taras

@taras taras commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Why

#508: WFC17 failed once inside a four-suite aggregate run and passed alone, and all the report could quote was the test title. The suite harness is why: runCli bounds every xmd subprocess with a 60s timebox, and when that deadline expires it throws xmd … timed out after 60000ms and discards everything the child wrote. Any load-dependent CLI flake that lands on this path is anonymous — there is nothing to say whether the child hung before its first line or after its last, and nothing about the contention that made the deadline expire.

Reproduction attempts on current main did not make WFC17 fail again: the exact aggregate command is green (ok | 325 passed (2637 steps), WFC17 at 4s), and the workflow suite beside two concurrently running package suites plus fork/exec churn (load average 20) is green too (WFC17 at 5s against a 60s box). The evidence for that is on the issue; this PR makes the next occurrence carry its own diagnosis instead of requiring another chase.

What changes

Before:

A runCli deadline threw xmd <args> timed out after <limit>ms — the child's output up to that moment was discarded with the halted exec.

After:

The same deadline throws a report carrying the host's load average and everything the child wrote on each channel before the run was abandoned. Completed runs are unchanged: join()/expect() return the same ProcessResult shape with the same capture semantics.

How it works

runCli → bounded() spawns the process itself and accumulates stdout/stderr outside the timebox → deadline expiry throws abandonedReport(args, limit, partial)

bounded now mirrors upstream @effectionx/process Exec.join() — spawn, subscribe to both channels, settle on join/expect — with the accumulators hoisted outside the timebox scope so a halted run still has an account. Chunks decode per-arrival exactly as upstream capture concatenates them.

How to verify it

  • packages/cli/tests/launch-timeout.test.ts runs a document that prints on both channels and then outlives the deadline; it proves the failure names the deadline and carries both markers, and fails if the timeout path discards output again. Verified under Deno (10s), Node (20s), and Bun (10s).
  • packages/cli/tests/workflow-cli.test.ts, cli-help.test.ts, process-retention.test.ts green under Deno — the join/expect result shape and capture are unchanged for completed runs.

Scope

Included

  • The harness deadline report in packages/test-support/launch.ts, and its regression test.

Intentionally unchanged

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

https://claude.ai/code/session_01MNztk1fikXUnD2FW4yS6Kr

@github-actions

github-actions Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

PR #509: 🔍 Report what an abandoned xmd run wrote before its deadline

2 files, +125 / -12

Scope

✅ PR scope looks good.

Structural

✅ No structural bloat detected.

Slop

✅ Slop indicators look low.

Static Analysis

Oxlint: 2 diagnostics across 1 file (1 rule)
Density: 0.016 violations/added-line

no-floating-promises (2): packages/test-support/launch.ts

Correctness

launch.ts, no-floating-promises, Signal clusters, Are multiple Oxlint violations in the same file indicative of unreviewed code or mechanical changes?

@taras
taras enabled auto-merge (squash) August 20, 2026 02:11
@taras
taras force-pushed the agent/issue-508-deadline-account branch from e796c1e to 9af5f7e Compare August 20, 2026 02:18
A runCli deadline used to discard the child's output, so a suite-level
timeout — the load-dependent flake shape the CLI suites see — left no
record of where the run hung. The failure now carries both channels as
received before the run was abandoned, and the host's load average,
which is the condition such deadlines expire under.

Claude-Session: https://claude.ai/code/session_01MNztk1fikXUnD2FW4yS6Kr
@taras
taras force-pushed the agent/issue-508-deadline-account branch from 9af5f7e to 0d6e3f7 Compare August 20, 2026 14:04
@taras
taras disabled auto-merge August 20, 2026 14:32
@taras
taras merged commit df5d92d into main Aug 20, 2026
30 of 32 checks passed
@taras
taras deleted the agent/issue-508-deadline-account branch August 20, 2026 14:56
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.

1 participant