fix(engine,web): F2 pong reports sent position + watchdog two-strike (WI-126) - #670
Closed
thedancingdeveloper wants to merge 1 commit into
Closed
thedancingdeveloper wants to merge 1 commit into
thedancingdeveloper wants to merge 1 commit into
Conversation
The liveness probe could force a spurious reconnect on a bursty session. The inbound task answered a ping with scrollback_position() (total_written) and handed the pong to the outbound task on a separate channel; select! could send that pong before the broadcast chunks it referenced, so the client briefly saw serverPos > localPos, printed [disconnected], and reattached. Engine (ws.rs): the ping id is forwarded to the outbound task, which answers with sent_pos — the offset actually written to this socket — after flushing anything already queued (new flush_available helper). The pong is therefore ordered after those chunks on the wire and its pos can never exceed what the client has received. ENGINE.md documents the pong pos semantics. Web (terminalWatchdog.ts): a single behind pong is a suspect, not a verdict — it arms a prompt confirm probe rather than recycling. Only a second behind pong within WATCHDOG_TIMEOUT_MS, with no output in between, is treated as a real stall; any output clears the suspicion. (terminalWatchdog.test.ts already existed, contrary to the plan note; extended with the two-strike cases.) Tests: - engine pong_never_reports_the_server_ahead_of_this_socket: under load, ping mid-stream and assert pong.pos <= snapshot_end + live bytes received on the socket. - web: five two-strike watchdog cases (suspect, confirm-recycle, output clears, caught-up clears, stale-suspect drop). Verification: cargo test -p vogt-engine-server --test integration 105 passed; fmt + clippy clean; web typecheck clean; pnpm vitest 913 passed; scripts/check_docs.py clean. WI-126. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UtEFLJAhLiq4NfZCN2vuBb
This was referenced Sep 9, 2026
Contributor
Author
|
Cleanup: superseded by the single promotion PR #676. All of this work is already integrated into |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fourth PR of the terminal-attach-budget initiative (WI-121). Stacked on #669 (F3) so the diff is F2-only; all land on
feat/terminal-attach-budget.The bug (WI-126)
A bursty session could trip a spurious reconnect. The inbound task answered a
pingwithscrollback_position()(total_written) and handed thepongto the outbound task on a separate channel;select!could send that pong before the broadcast chunks it referenced, so the client briefly sawserverPos > localPos, printed[disconnected], and reattached — replaying scrollback for no reason.The fix
Engine (
ws.rs) — the ping id is forwarded to the outbound task, which answers withsent_pos(the offset actually written to this socket) after flushing anything already queued (flush_available). The pong is ordered after those chunks on the wire, so itsposcan never exceed what the client has received.docs/ENGINE.mddocuments thepong.possemantics.Web (
terminalWatchdog.ts) — a single behind pong is a suspect, not a verdict: it arms a prompt confirm probe instead of recycling. Only a second behind pong withinWATCHDOG_TIMEOUT_MS, with no output in between, is a real stall; any output clears the suspicion.Tests
pong_never_reports_the_server_ahead_of_this_socket: ping mid-stream under load, assertpong.pos ≤ snapshot_end + live bytes received on the socket.Verification
cargo test -p vogt-engine-server --test integration— 105 passed;fmt/clippyclean.pnpm typecheckclean;pnpm vitest— 913 passed;scripts/check_docs.pyclean.The plan's stated acceptance ("no
[disconnected]during H3's steady-state phase") lands with the H3 live spec (WI-124).🤖 Generated with Claude Code
https://claude.ai/code/session_01UtEFLJAhLiq4NfZCN2vuBb