fix(web): web-v4 键家族收敛为唯一工厂,并修好一族「打不中任何缓存」的失效(#2261 残项,ADR-029) - #2317
Merged
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
DeliciousBuding
enabled auto-merge (squash)
September 4, 2026 08:07
残项裁决的触发条件已满足,不是为统一而统一:普查发现 Web 有 6 类失效/刷新 指向根本不存在生产者的键,用户可见后果实测存在。 真实缺陷(本次修掉的): 1. contactQueries 的 6 处联系人失效全部打在 hubQueryKeys.contacts.list 上, 而 Web 的联系人列表实际缓存在 webQueryKeys.contacts.list(hubReady)。该查询 只有 staleTime、没有 refetchInterval ⇒ 接受/拒绝好友请求、删除、拉黑、取消 拉黑、改备注之后,联系人列表一直显示旧状态,直到窗口重新聚焦。 2. createGroupSession 失效打在 hubQueryKeys.threads.list(Web 无生产者)⇒ 新建 群聊最多要等一个 10s 轮询才出现在会话列表里。 3. useWebAuth 登录后的「refetch threads」打在 hubQueryKeys.threads.root ⇒ 整个 登录后刷新是静默 no-op。 4. webHubRealtime 的 CONTACT_EVENTS 打在一个少了 hub- 段的手写键上 ⇒ 别的标签页 接受好友请求,本页联系人列表不刷新。 5. useWebWorkbenchModel 的审批失效写着裸 ['agent-teams'](连命名空间都没有)⇒ 从来不命中;改为 hubQueryKeys.agentTeams.root(真命中 usageBoard)。 6. webPlatformMessageHelpers 的注释断言「['hub','threads'] 就是 Web 的会话列表键」 ——事实错误,正是 1/2/3 的认知根源,已改写为真实键。 消融(0 生产者,逐条普查 app/web + app/workbench + app/shared,workbench 完全不用 react-query 键,无任何隐藏生产者): - DEVICE_EVENTS 里 Web 命名空间的 execution-targets 孪生键:真缓存只在 hubQueryKeys.executionTargets.list(context) ⇒ 删死的那条,保留能命中的 root。 - NOTIFICATION_EVENTS 整个分支:Web 根本没有通知查询 ⇒ 两条失效都命中 0 个缓存 条目,分支与事件集合一并删除;新增测试钉住「通知帧不得动任何 Web 缓存」。 - TEAM_EVENTS 里 5 条 run 级键(两个命名空间的 runs/runDetail):Web 只有 usageBoard ⇒ 收敛为 1 条 family root,连带删掉只为拼死键而存在的 teamId/teamRunId 解析。 机制: - app/shared/src/stores/queryKeys.ts 新增 webQueryKeys,成为 web-v4 命名空间的 唯一字面量产出点;app/web/src 非测试代码里的键数组字面量从 58 处降到 0 (grep "\['web-v4'" = 0;残留 3 处 web-v4 字符串分别是 dispatch source 标签、 client_msg_id 前缀、命名空间名的散文提及,都不是查询键)。 - 键值逐字不变,只搬产出点 ⇒ 既有断言键值的测试无需改动。 - 新增 QueryKeyPointer:可空指针原样穿过工厂,不归一化成 ''——否则会给 webHubMessagesFamily.sessionIdOf 造出一个字符串会话 id,被重连补发当成真会话。 证据(不是只看调用,而是看缓存真的变陈旧): - 新增 app/web/src/platform/webQueryCacheTargets.test.ts(8 例):按真实生产者键 播种 QueryClient,跑真实失效代码路径,断言 getQueryState(...).isInvalidated。 - 变异测试 7 发,6 发翻红(M1 联系人失效回退 / M2 会话失效回退 / M3 realtime 联系人回退 / M4 device 回退 / M5 team 回退 / M7 useWebAuth 回退)。 M6(把已删的通知分支放回去)如实登记为不翻红:它证明的是该分支本来就惰性, 不是证明删除必要——测试钉的是「通知帧不动任何 Web 缓存」,删前删后都成立。 - 删掉 webHubRealtime.test.ts 里那条把 bug 钉死的 spy 断言 (toHaveBeenCalledWith(['web-v4','execution-targets'])):它断言的是「调用发生了」, 而那个键没有任何生产者,所以套件一直绿着,失效一直空转。 - useWebAuth.test.tsx 同步改为断言真键 + 反向断言不再使用死键。 Co-authored-by: Cursor <cursor@vectorcontrol.tech> 裁决落盘:docs/decisions.md 新增 ADR-035(本 PR 的五条结论:唯一产出点 / 可空指针不得归一化 / 失效必须有生产者 / 无生产者一律删不留孪生键 / 断言看缓存效果不看调用),#2261 残项由 DEFERRED 转为 landed。
DeliciousBuding
force-pushed
the
fix/web-v4-query-key-convergence
branch
from
September 4, 2026 08:17
767cf2d to
97ec472
Compare
This was referenced Sep 4, 2026
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.
为什么现在做(不是为统一而统一)
#2261 残项的 DEFERRED 触发条件是「下次真要动 web-v4 键形状时同 PR 收敛」。本 PR 之所以成立,不是因为键写法不统一,而是因为普查发现了一族打不中任何缓存的失效,其中数条有明确用户可见后果 —— 与 #2252 / #2310 同一个失效模式,只是换到 Web。
修掉的真实缺陷(6 条)
contactQueries的 6 处失效打在hubQueryKeys.contacts.list,而 Web 的联系人列表实际缓存在webQueryKeys.contacts.list(hubReady)。该查询只有staleTime、没有refetchInterval⇒ 接受/拒绝好友请求、删除、拉黑、取消拉黑、改备注之后,列表一直显示旧状态,直到窗口重新聚焦。createGroupSession失效打在hubQueryKeys.threads.list(Web 无生产者)⇒ 最多等一个 10s 轮询。useWebAuth的refetchQueries(hubQueryKeys.threads.root)在 Web 匹配不到任何缓存条目。webHubRealtime的 CONTACT_EVENTS 打在一个少了hub-段的手写键上 ⇒ 另一标签页接受好友请求,本页不动。useWebWorkbenchModel审批失效写着['agent-teams']⇒ 从来不命中;改为hubQueryKeys.agentTeams.root(真命中usageBoard)。这里选择retarget 而非删除:审批决定确实会改变 usage board 聚合的 runs,原作者的意图是对的,只是键写错了。webPlatformMessageHelpers的注释断言「['hub','threads']就是 Web 的会话列表键」——事实错误,正是 1/2/3 的共同根源,已改写为真实键。消融(每条都有 0 生产者证据)
普查范围:
app/web+app/workbench+app/shared全量queryKey:生产点;workbench 完全不使用 react-query 键(0 处hubQueryKeys/web-v4),所以不存在隐藏生产者。hubQueryKeys.executionTargets.list(context))⇒ 删死的那条,保留能命中的 family root。usageBoard)⇒ 收敛为 1 条 family root,连带删掉只为拼死键而存在的teamId/teamRunId解析。机制
app/shared/src/stores/queryKeys.ts新增webQueryKeys,成为web-v4命名空间唯一的字面量产出点。app/web/src非测试代码里的键数组字面量 58 → 0(grep "\['web-v4'"= 0;残留 3 处web-v4字符串分别是 dispatch source 标签、client_msg_id前缀、命名空间名的散文提及,都不是查询键)。QueryKeyPointer:可空指针原样穿过工厂,不归一化成''。归一化会给webHubMessagesFamily.sessionIdOf造出一个字符串会话 id,被重连补发当成真会话去 sync —— 那是把一个死键 bug 换成一个更糟的活 bug。证据
app/web/src/platform/webQueryCacheTargets.test.ts(8 例):按真实生产者键播种QueryClient,跑真实失效代码路径,断言getQueryState(...).isInvalidated。断言的是缓存真的变陈旧,不是「调用发生了」。useWebAuth回退 —— 各自精确翻红对应的那一条测试。webHubRealtime.test.ts原本toHaveBeenCalledWith({ queryKey: ['web-v4','execution-targets'] })—— 键没有任何生产者,但套件一直绿着,失效一直空转。已由 effect-based 测试取代。validatejob 全 62 条命令 PASS=62 FAIL=0。Refs #2261