Skip to content

Fix host-connected broadcast racing observable host status - #539

Merged
SawyerHood merged 4 commits into
mainfrom
bb/host-offline-issue-thr_v7jjaqbtaw
Jul 8, 2026
Merged

SawyerHood merged 4 commits into
mainfrom
bb/host-offline-issue-thr_v7jjaqbtaw

Conversation

@SawyerHood

Copy link
Copy Markdown
Collaborator

Problem

After #538, desktop cold starts still showed a stale "Host is offline" composer. An instrumented build proved why: the client-side watermark fix worked exactly as designed, but lost a server-side race.

The server broadcast host-connected when the daemon session opened (the HTTP call in createSession), but GET /hosts reports "connected" only once the daemon's WebSocket registers in the hub (getDaemonSessionIdForHost) — ~60–100ms later. Timeline from a real cold start:

t event
+0.62s daemon session opens → server broadcasts host-connected
+0.62s renderer receives it, invalidates, refetches /hosts
+0.67s server answers /hosts with "disconnected" (daemon WS not attached yet)
+0.68s daemon WS attaches — status now reads "connected" — no broadcast fires

The renderer caches "disconnected" as fresh post-watermark data and nothing ever invalidates it again. No client-side mitigation can win this: the event races the observable state it advertises.

Fix

Emit host-connected from NotificationHub.registerDaemon — the moment the advertised state is actually observable — and drop the session-open broadcast. A daemon session without an attached socket reads "disconnected" everywhere, so staying silent there is correct; hostEventWaiters and re-registration after transient WS drops resolve at the same, now-consistent point.

Tests

  • New hub test: registerDaemon broadcasts host-connected to host-list subscribers.
  • turbo run typecheck test --filter=@bb/app --filter=@bb/server --filter=@bb/db --force — 320 db + 955 server + 1299 app tests pass.
  • turbo run test --filter=@bb/integration-tests --force — 54 pass (incl. daemon crash/restart flows).
  • Verified end-to-end on a packaged desktop build: instrumented timeline shows broadcast now fires at WS attach with /hosts returning "connected" 1ms later, and the composer comes up healthy on cold start.

Notes

The two DIAGNOSTIC commits in this branch add and then fully revert the instrumentation used to capture the timeline; they are net-zero in the squash.

🤖 Generated with Claude Code

SawyerHood and others added 4 commits July 8, 2026 09:00
…erver)

Renderer logs ws lifecycle, watermark invalidation, and host/provider query
cache events, shipped to POST /api/v1/diag/renderer; server logs client WS
registration/subscribes, host/system broadcasts with matched-socket counts,
and GET /hosts responses. Everything lands ordered in server.N.log.

Not for merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The host-connected event fired at daemon session open (HTTP), but GET
/hosts reads "connected" only once the daemon's WebSocket registers in
the hub ~60ms later. A client that refetched on the broadcast (exactly
what the #538 watermark fix does) captured "disconnected" as fresh
post-watermark data, and nothing ever invalidated it again — the stale
"Host is offline" composer on desktop cold start.

Emit the broadcast from NotificationHub.registerDaemon instead, where
the state it advertises is actually observable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@SawyerHood
SawyerHood merged commit dbf981d into main Jul 8, 2026
6 checks passed
@SawyerHood
SawyerHood deleted the bb/host-offline-issue-thr_v7jjaqbtaw branch July 8, 2026 16:29
Samuka007 added a commit to Samuka007/bb that referenced this pull request Oct 8, 2026
…ey 行(ApiKeyCredentialRow 同款 write-only 模式,brave 行泛化共享)+ engines.exa presence wire 形状
Samuka007 added a commit to Samuka007/bb that referenced this pull request Oct 8, 2026
…ilableEngines 词表后的链序断言 + 双 keyed 行 findAllBy 占位符
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