Skip to content

test(server): cover PTY heartbeat reaping and document the synchronous replay→subscribe invariant #150

Description

@0xabstracted

Context

The hosted web-terminal stack (#140 foundation, #136 byte-offset resume) has two server-side
correctness mechanisms that currently rest on implicit guarantees rather than tests.

Problem

1. Heartbeat reaping is untested. PtyWebSocketServer runs a protocol-level ping/pong
heartbeat (HEARTBEAT_INTERVAL_MS = 30_000, isAlive flip, client.terminate() on a missed
pong) so a browser tab that vanished without a close frame (laptop sleep, dropped wifi) is
reaped instead of lingering as a phantom subscriber. There is no test that a socket which stops
answering pings is marked isAlive=false on the next tick and terminated on the tick after.

2. The replay→subscribe invariant is undocumented and untested. On attach,
PtyWebSocketServer does, in order: getReplay(sessionId, offset) (snapshots the buffer +
computes attached{base,gap,next}) → sends size → sends attached → sends the replay binary
frame → addSubscriber(sessionId, ws) (joins the live stream). Correctness (no dropped or
duplicated bytes across the replay/live seam) depends entirely on no PTY data event being
delivered to a new subscriber between the getReplay snapshot and addSubscriber
— i.e. on
Node's single-threaded synchronous execution of that block. This ordering invariant is load-bearing
but only implied by a code comment; nothing pins it.

Acceptance criteria

  • A PtyWebSocketServer test proves a socket that stops responding to pings is flipped to
    isAlive=false on the first heartbeat tick and terminate()d on the next (fake timers).
  • A test proves the heartbeat interval is unref'd and cleared on stopHeartbeat() / server
    shutdown (no leaked timer, process can exit).
  • A test asserts the attach ordering: for a live PTY that emits a data chunk immediately
    after getReplay, the reconnecting client receives that chunk exactly once (via live stream,
    not replay) with no gap and no duplication — the replay next offset abuts the first live byte.
  • The synchronous replay→subscribe requirement is documented as an explicit invariant at the
    attach site (why the two calls must not be separated by an await or async boundary).

Refs

Foundation #140, offset-resume #136. Files: maestro-server/src/infrastructure/websocket/PtyWebSocketServer.ts,
maestro-server/src/application/services/PtyHostService.ts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions