feat(presence): member_joined / member_left + 预留 host/capabilities/budgetHint (PR8)#195
Open
raysonmeng wants to merge 1 commit into
Open
feat(presence): member_joined / member_left + 预留 host/capabilities/budgetHint (PR8)#195raysonmeng wants to merge 1 commit into
raysonmeng wants to merge 1 commit into
Conversation
…dgetHint (PR8)
v3 §11.1 单团队 MVP 的 PR8。broker 在房间成员到场/离场时合成 presence 事件
(§11.1 bullet 9),让成员实时看到谁在房间里。
PR8 of the v3 §11.1 single-team MVP. The broker synthesizes presence events as
members arrive/leave a room, so members see who is live.
- src/presence.ts: buildPresenceEnvelope — broadcast, online_only (EPHEMERAL,
never persisted for offline replay), payload {displayName, host, capabilities,
budgetHint}. budgetHint is reserved for the B-class; the A-class MVP ignores it.
- src/broker.ts: addTopicMember/removeTopicMember now return the membership
transition. member_joined on the 0→1 transition (a 2nd connection for the same
identity does NOT re-announce); member_left on →0 (last connection leaving),
emitted from BOTH unsubscribe AND close() so a crash-disconnect still leaves.
from.agentId is the broker-authenticated identity (unspoofable). hello may
carry a reserved presence blob, validated by sanitizePresence (drops malformed
input — non-string fields, nested objects, __proto__).
- src/broker-client.ts: optional presence meta in the hello frame.
member_joined is emitted BEFORE draining the joiner's own backlog so a future
truly-async Store can't reorder it after a close()-emitted member_left.
Tests: presence (3) + sanitize-presence boundary (4, incl. __proto__ + malformed)
+ broker-presence integration (3: existing-subscriber sees join with reserved
meta + self-skip, member_left on disconnect, multi-connection refcount = join
once / leave only on last). broker-routing WsClient filters presence churn (those
tests assert routing of published envelopes, not presence).
Cross-review: 4 rounds (foreground), fixed 1 latent ordering (join-after-drain)
+ 1 HIGH test gap (sanitizePresence had zero adversarial-input coverage);
converged on 2 consecutive clean rounds. bun run check green: 1786 pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
概要 / Summary
v3 §11.1 单团队 MVP 的 PR8(stacked,base =
feat/v3-pr7-completion/ #194)。broker 在房间成员到场/离场时合成 presence 事件(§11.1 bullet 9),让成员实时看到谁在房间里。The broker synthesizes presence events as members arrive/leave a room (§11.1 bullet 9), so members see who is live.
改动 / Changes
src/presence.ts—buildPresenceEnvelope:广播(无to)、online_only(临时,绝不为离线补投落库)、payload{displayName, host, capabilities, budgetHint}。budgetHint是 B 类预留,A 类 MVP 忽略。src/broker.ts—addTopicMember/removeTopicMember现返回成员转换:0→1 发member_joined(同身份第二条连接不重复广播);→0(最后一条连接离开)发member_left,从unsubscribe和close()两路径发出 —— 崩溃断连也会离场。from.agentId是 broker 鉴权身份(不可伪造)。hello 可带预留 presence,经sanitizePresence校验(丢弃非字符串/嵌套对象/__proto__等畸形输入)。src/broker-client.ts— hello 帧可选携带 presence 元数据。member_joined在 drain joiner 自身 backlog 之前发出,未来真异步 Store 也不会把它排到close()的member_left之后(幽灵顺序)。测试 / Tests
presence(3)+sanitize-presence边界(4,含__proto__+ 畸形输入)+broker-presence集成(3:既有订阅者见到带预留 meta 的 join + 自跳过、断连 member_left、多连接引用计数 = join 一次 / 末次才 leave)。broker-routing的 WsClient 过滤 presence churn(那些用例断言已发布信封的路由,非 presence)。bun run check全绿:1786 pass / 0 fail,bundle 同步,版本对齐。Cross-review
4 轮(前台并行),修 1 latent ordering(join-after-drain)+ 1 HIGH 测试缺口(
sanitizePresence信任边界零对抗性输入覆盖);连续两轮 0 真实 issue 收敛。铁律自检 / Invariants
online_only绝不落库;from.agentId不可伪造;hello presence 经 sanitize。BrokerClientOptions.presence可选不破坏既有调用;无新增运行时依赖。feat/v3-pr7-completion(feat(completion): task_completed 事件 + 发布节流 + Stop hook 发布 (PR7) #194)。🤖 Generated with Claude Code