WIP: Multiplayer#799
Draft
SawyerHood wants to merge 8 commits into
Draft
Conversation
… attribution columns Shared contracts and schema for multiplayer bb, landed serially so parallel workstreams build against fixed interfaces: - @bb/domain claimed-identity: x-bb-claimed-identity handshake header schema, handle normalization, and boundary encode/decode. Identity is claimed-only; admission gateways (connect gate / network) never assert identity. - @bb/domain change-kinds: typing client message plus thread-presence and presence-summary broadcasts (strict + lenient pairs). - @bb/db: collaborators table (handle-keyed) and nullable attribution columns events.actor_handle, threads.created_by_handle, queued_thread_messages.actor_handle, pending_interactions.resolved_by_handle. Plain text columns without FKs so the migration stays ADD COLUMN only. - @bb/connect-db: server_member table (gate admission list, owner-managed). - Server: accept the typing message as a no-op until presence lands; migrate drift manifest and rewind/replay tests updated for migration 0079. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…umbing WS1 (connect cloud): the gate admits invited members alongside the owner — non-owner sessions are checked against server_member for server-kind labels (desktop credentials stay owner-only), and admission fails closed unless a debounced member-admitted audit_log row lands, since that log is the system's only verified access record. Owner-session member management API on the worker: GET/POST /api/servers/:serverId/members and DELETE .../members/:userId (403 non-owner, 404 unknown handle, 409 duplicate, 400 owner-handle), with member-added/member-removed audit rows. WS2 (local server): every /api/v1 request and /ws upgrade resolves a claimed actor from x-bb-claimed-identity, falling back to a startup local-operator identity (OS username/hostname); collaborators are upserted through a new @bb/db data module with a 60s same-content debounce; sockets carry their actor via ws/socket-actors (registered at open, released on close) for the upcoming presence work. The server still never authorizes by identity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WS3 (attribution): the human request path records its actor everywhere —
events.actor_handle on sends (queued messages carry actor_handle and preserve
it through every drain path), threads.created_by_handle on human creates,
the acting handle on manual-stop interruption events, and
pending_interactions.resolved_by_handle on approval resolution. Actors come
only from the request-scoped identity, never from request bodies;
agent/thread/plugin-origin writes stay NULL. Turn commands gain an optional
speaker {handle, displayName}, populated only when the thread has two or more
distinct human authors (targeted countDistinct query), and the host daemon
prefixes provider input with "[from @handle] " — single-human threads produce
byte-identical provider input. HOST_DAEMON_PROTOCOL_VERSION 58 -> 59.
WS4 (presence): ephemeral presence derived from thread-detail subscriptions —
viewers deduped by handle with per-socket refcounts, typing with a 6s TTL via
the ws typing message, strict-schema thread-presence broadcasts to detail
subscribers and partial presence-summary patches to thread-list subscribers
(empty array removes an entry; no-op rebroadcasts suppressed), plus a
GET /api/v1/presence snapshot route. Nothing persisted.
Includes the regenerated @bb/plugin-sdk bundled types.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ws identity fallback The attribution column landed write-only in wave 2; this threads it through every read surface so the UI can render authorship: StoredEventRow -> EventMeta -> EventProjectionUserMessage -> TimelineUserConversationRow, plus the raw events endpoint's ThreadEventRow wrapper. Client-side schemas default actorHandle to null when parsing responses from pre-multiplayer servers. Also: /ws accepts the claimed identity via an `identity` query parameter carrying the same encoded payload, because browsers cannot set custom headers on WebSocket upgrades. Includes regenerated plugin-sdk bundled types and templates, and test-fixture updates for the now-required meta field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… management WS5 (app): claimed-identity store (localStorage, remote-context-only prompt + settings section; desktop stays the silent local operator), identity attached at the single fetch choke point and as ?identity= on the ws URL, presence store fed by thread-presence/presence-summary broadcasts and reseeded from GET /api/v1/presence on (re)connect, viewer avatars in the thread header, typing indicator + throttled typing emit at the composer, sidebar presence dots with click-to-follow, and author chips on user messages that appear only when a thread has 2+ distinct human authors. Optimistic user rows stamp the sender's own handle. WS6 (surfaces): tunnel-client strips inbound x-bb-via-tunnel and stamps it on every re-issued request/upgrade, so member management can be owner-console- only; connect member endpoints also accept the server's own tunnel credential as owner-equivalent; local GET/POST/DELETE /api/v1/members proxy (rejects tunnel-origin requests, surfaces enrollment/handle/duplicate errors); SDK members + presence areas and a claimedIdentity client option; bb members list/add/remove CLI; guide chapter, bb-cli skill, and docs updated; bb-app public SDK facade gains the new areas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
High findings: - Member management is now blocked at the connect gate for all forwarded visitor traffic (HTTP and ws-upgrade paths), so tunnels opened by pre-marker clients can no longer reach /api/v1/members; the local x-bb-via-tunnel check remains as defense in depth. - Membership mutations commit atomically with their audit rows (D1 batch, transaction fallback for the sqlite test double); a failed audit write leaves membership unchanged. - The speaker gate counts only attributed client/turn/requested events, so a manual stop by a second person no longer flips a single-author thread out of byte-identical provider input (covered by events_thread_type_sequence_idx, no new index). Medium findings: - Provider resolve, plugin respond, and cancel persist the first resolver's handle in the same conditional status transition; racing duplicates cannot overwrite it. - Typing TTLs are per socket, derived per handle, so one device stopping no longer clears a person's typing from their other device. - The app rebinds the live websocket when the claimed identity is saved, edited, or cleared (same socket, reconnect + resubscribe + reseed). - The presence store guards its reconnect snapshot with a generation counter so in-flight snapshots cannot clobber newer realtime updates or removals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… one beginSnapshot now issues a monotonically increasing snapshot id and applySnapshot drops any response that is no longer the most recently begun request, so overlapping (re)connect snapshots — e.g. during rapid reconnects or an identity rebind — can never overwrite the state a newer snapshot seeded. Per-thread realtime guards are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Backup PR for the multiplayer worktree before migrating the primary bb server to Bee.
This preserves the current implementation commits and the orchestration workflow files. It is intentionally opened as a draft and has not been rebased or prepared for merge.