Skip to content

feat(liveness): honest SSE states — thinking must be backed by a live stream (L1, #638) - #640

Merged
aarontrowbridge merged 2 commits into
mainfrom
638-honest-liveness-the-sse-staleness-state-machine-thinking-must-be-backed-by-a-live-stream-l1
Aug 29, 2026
Merged

feat(liveness): honest SSE states — thinking must be backed by a live stream (L1, #638)#640
aarontrowbridge merged 2 commits into
mainfrom
638-honest-liveness-the-sse-staleness-state-machine-thinking-must-be-backed-by-a-live-stream-l1

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

Closes #638.

L1 of the harness-agnostic campaign — the fix for the recurring pain: the studio showing "thinking" while the harness is actually hung (worst across fleet connections).

What

  • src/sse_liveness.ts — a pure, injected state machine: connecting → live → stale → dead. Frames are the truth (ANY SSE block — events and the comment-only pings the old client discarded). No frames for the staleness threshold (30 s default) → STALE. The STALE branch probes the server: alive-but-quiet = half-open TCP → tear down + reconnect (never wait for TCP to notice); unreachable = DEAD. Transitions fire exactly once, with the evidence logged.
  • sse_client.ts — the tracker wired into the connect/reconnect loop: frames note liveness, connections/disconnections note state, the half-open signal destroys the socket and reconnects, every transition reaches the status bar and an onSseState hook. The "swallow errors" doctrine is narrowed to "don't crash the host" — the UI gets the truth.
  • status_bar.ts — honest states: Amicode (live, as today) · stream stalled — probing, reconnecting · server unreachable — work is not lost. Boot states untouched.
  • No protocol changes — works against the incumbent harness today; T4a's serve daemon will make heartbeat cadence part of the Harness Contract server-side.

Evidence

  • New tracker suite: 12 transition tests (fake timers, zero real sleeps) — stale detection, dead-probe, half-open reconnect cadence, frame recovery mid-probe, throwing probes never crash, dispose stops ticks.
  • Status-bar label tests extended (6 new assertions; the historical ready-state label preserved by default).
  • Extension vitest: 1714 passed; the only 3 failures are the known machine flakes that fail identically on pristine main on this dev box (python-venv + HOME-dependent terminal tests) and pass on CI.

Director-drafted in the harness-agnostic campaign (worktree off main @ the #622 ADR merge).

…stream is live (L1, #638)

The studio showed 'thinking' while the harness was hung: the SSE client
swallowed every error, health was probed only at boot, and the pings the
server already sends were discarded (sse_client's comment-only block
handler returned without recording anything).

The fix is an evidence-backed state machine: frames are the liveness
signal (events AND comment-only pings — the discarded-ping hole closed);
staleness (30s default, configurable) transitions LIVE→STALE; the STALE
branch probes the server to split dead from half-open — a live server
with a quiet stream tears down and reconnects (never wait for TCP to
notice), a dead one says so. Every transition fires onStateChange and
drives the status bar: 'Amicode' / 'stream stalled' / 'server
unreachable' — never 'thinking' without a live stream behind it.

The tracker is pure by injection (probe/clock/sinks) — sse_client is the
production caller; T4a's serve daemon tests the same semantics. No
protocol changes; works against the incumbent harness today.
@aarontrowbridge
aarontrowbridge marked this pull request as ready for review August 29, 2026 13:40
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 20285ae8-2fa5-4ff7-bc2b-a52baf829a77


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…mutation isn't visible to control-flow analysis (L1, #638)

CI's typecheck caught what local vitest couldn't: the stale-branch guard
compared a type TS had already narrowed to 'live'. The guard was dead
paranoia; the transition always lands. Also the local-gate lesson: run
typecheck, not just vitest.
@aarontrowbridge
aarontrowbridge merged commit ea169ec into main Aug 29, 2026
8 checks passed
@aarontrowbridge
aarontrowbridge deleted the 638-honest-liveness-the-sse-staleness-state-machine-thinking-must-be-backed-by-a-live-stream-l1 branch August 29, 2026 13:52
@aarontrowbridge
aarontrowbridge restored the 638-honest-liveness-the-sse-staleness-state-machine-thinking-must-be-backed-by-a-live-stream-l1 branch August 30, 2026 02:46
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.

Honest liveness: the SSE staleness state machine (thinking must be backed by a live stream) — L1

1 participant