Skip to content

fix(opencode): bound the opt-in Responses first-byte stall window by the stream readiness timeout - #14940

Merged
diegosouzapw merged 3 commits into
diegosouzapw:release/v3.8.51from
maxmad64bis:fix/responses-stall-harden
Sep 28, 2026
Merged

diegosouzapw merged 3 commits into
diegosouzapw:release/v3.8.51from
maxmad64bis:fix/responses-stall-harden

Conversation

@maxmad64bis

@maxmad64bis maxmad64bis commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ base-red inherited: #14963

Summary

A streamed Responses reply that stays silent past the configured first-byte window held the request until the stream readiness timeout (80-180 s) even with the opt-in stall guard: the window was not bounded by the readiness timeout. The window is now capped by the readiness timeout (default 80 s), keeping one rotation then failing fast on the stall arm. With the flag off, behavior is unchanged: the window is 0 and the readiness timeout stays the only bound.

Related Issues

Validation

  • Change type: routing
  • Focused tests and category gates from the golden path — new suite (25 cases) green, one of them pins the cap and fails without the change; watchdog, flag and timeout suites (83 cases) green
  • npm run lint — ESLint on the touched files is clean
  • Reconciled with the current active release base; focused checks rerun afterward
  • Production-code changes include a new or updated automated test in this PR — tests/unit/opencode-responses-stall-harden.test.ts (new)

Tests Added Or Updated

  • tests/unit/opencode-responses-stall-harden.test.ts (new, 25 cases): window matrix (flag off, non-Responses, 0, over-cap clamp, invalid), guard identity/reject, setup wiring, executor flag-off identity and flag-on rotation.
  • One existing first-byte-stall case fails on the release base as well (it compares ephemeral ports literally); it is not touched here.

Coverage Notes

  • open-sse/executors/opencodeResponsesStall.ts (window computation and cap): the window matrix of the new suite.
  • open-sse/executors/opencode.ts (call site): the executor cases of the same suite (flag-off identity, flag-on rotation).

Reviewer Notes

Maintainer rework (merge-batch 2026-09-28)

  • Readiness disabled no longer disables the guard. STREAM_READINESS_TIMEOUT_MS=0 means "no readiness bound", so a non-positive bound is now treated as no ceiling: resolveResponsesStallWindowMs returns the configured window instead of 0, and setupStallGuard no longer reports (or logs) a cap in that case. Before, the guard switched off exactly when it was the only first-byte bound left. The test that pinned the old behavior is inverted, plus one setupStallGuard case (both fail on the previous head, pass now).
  • Cap at the bound, not strictly below — documented. The guard consumes the first byte before the executor returns, and chatCore's readiness check only starts on the response the executor hands back (replaying that byte at once), so the two waits never race; firing at exactly the bound costs the same wall time the readiness check would, but buys the rotation.
  • Scope wording. Changelog now states this only affects RESPONSES_FIRST_BYTE_TIMEOUT_MS configured above STREAM_READINESS_TIMEOUT_MS with the opt-in flag on; windows at or below the bound, readiness disabled, and the flag off are unchanged.
  • Reconciled with the current release/v3.8.51 tip (real merge). Focused: opencode-responses-stall-harden 26/26; stall/watchdog/executor suites green except opencode-responses-first-byte-stall "flag off … untouched", which fails identically with the tip's sources (inherited). typecheck:core, check:open-sse-typecheck, check-file-size green.

@maxmad64bis
maxmad64bis force-pushed the fix/responses-stall-harden branch from 4b7bbe0 to 6c8df9e Compare September 27, 2026 12:54
@maxmad64bis
maxmad64bis marked this pull request as ready for review September 27, 2026 16:29
@maxmad64bis
maxmad64bis force-pushed the fix/responses-stall-harden branch from 6c8df9e to d349b42 Compare September 28, 2026 17:56
A non-positive readiness bound (STREAM_READINESS_TIMEOUT_MS=0) means no
readiness ceiling, so the guard keeps the configured first-byte window
instead of switching off. The cap only applies when the configured window
exceeds a positive readiness bound; document why equal to the bound is
enough (the guard consumes the first byte before chatCore's readiness
check starts, so the two waits never race).
@diegosouzapw
diegosouzapw merged commit 5f267fa into diegosouzapw:release/v3.8.51 Sep 28, 2026
10 of 16 checks passed
@maxmad64bis
maxmad64bis deleted the fix/responses-stall-harden branch September 30, 2026 00:22
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.

2 participants