@senguoyun/dsh-arkme 0.1.82 → 0.1.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/docs/ai-points-implementation.md +43 -0
  2. package/docs/interwoven-compact-summary-regression-2026-09-28.md +35 -0
  3. package/docs/interwoven-original-read-receipt-regression-2026-09-28.md +50 -0
  4. package/docs/personal-detail-consistency-regression-2026-09-28.md +40 -0
  5. package/docs/recognized-speaker-directory-backend-handoff-2026-09-28.md +157 -0
  6. package/docs/recognized-speaker-entry-and-visits.md +47 -0
  7. package/docs/recognized-speaker-presence-delivery.md +51 -0
  8. package/docs/recognized-speaker-sorting.md +30 -0
  9. package/docs/send-to-self-roles-cross-client-api-handoff-2026-09-27.md +9 -0
  10. package/lib/client.js +3358 -1946
  11. package/lib/client.js.map +1 -1
  12. package/lib/harness-model-client.js +168 -38
  13. package/lib/harness-native-selection-client.js +92 -1
  14. package/lib/harness-sidebar-client.js +31 -0
  15. package/lib/index.js +347 -132
  16. package/lib/persistent-extension.js +1 -1
  17. package/lib/{persistent-runtime-DV9Hme-U.js → persistent-runtime-CuKplHIv.js} +607 -303
  18. package/lib/sdk.js +31 -0
  19. package/lib/types/ai-points.d.ts +61 -0
  20. package/lib/types/ai-points.d.ts.map +1 -0
  21. package/lib/types/arkme-service.d.ts +11 -1
  22. package/lib/types/arkme-service.d.ts.map +1 -1
  23. package/lib/types/billing-gateway.d.ts.map +1 -1
  24. package/lib/types/client/ArkmeAccountUsage.d.ts +1 -3
  25. package/lib/types/client/ArkmeAccountUsage.d.ts.map +1 -1
  26. package/lib/types/client/ArkmeArkoSurface.d.ts.map +1 -1
  27. package/lib/types/client/ArkmeBillingSettings.d.ts +3 -2
  28. package/lib/types/client/ArkmeBillingSettings.d.ts.map +1 -1
  29. package/lib/types/client/ArkmeDataManagementSettings.d.ts.map +1 -1
  30. package/lib/types/client/ArkmeDocumentComposerInput.d.ts.map +1 -1
  31. package/lib/types/client/ArkmeEmojiPicker.d.ts.map +1 -1
  32. package/lib/types/client/ArkmeInterwovenReadReceipt.d.ts +12 -0
  33. package/lib/types/client/ArkmeInterwovenReadReceipt.d.ts.map +1 -0
  34. package/lib/types/client/ArkmeModelPricing.d.ts +9 -0
  35. package/lib/types/client/ArkmeModelPricing.d.ts.map +1 -0
  36. package/lib/types/client/ArkmeModelSelect.d.ts.map +1 -1
  37. package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
  38. package/lib/types/client/ArkmePointsConsumption.d.ts +5 -0
  39. package/lib/types/client/ArkmePointsConsumption.d.ts.map +1 -0
  40. package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts +6 -2
  41. package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts.map +1 -1
  42. package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
  43. package/lib/types/client/ArkmeRelatedQuickNotes.d.ts.map +1 -1
  44. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  45. package/lib/types/client/ArkoModelMenu.d.ts.map +1 -1
  46. package/lib/types/client/api.d.ts +1 -1
  47. package/lib/types/client/api.d.ts.map +1 -1
  48. package/lib/types/client/interwoven-moments.d.ts.map +1 -1
  49. package/lib/types/client/interwoven-read-receipt-store.d.ts +32 -0
  50. package/lib/types/client/interwoven-read-receipt-store.d.ts.map +1 -0
  51. package/lib/types/client/locales/actions-en.d.ts.map +1 -1
  52. package/lib/types/client/locales/dynamic-en.d.ts.map +1 -1
  53. package/lib/types/client/locales/en.d.ts.map +1 -1
  54. package/lib/types/client/reaction-preview-store.d.ts +1 -0
  55. package/lib/types/client/reaction-preview-store.d.ts.map +1 -1
  56. package/lib/types/client/recognized-speaker-directory.d.ts +36 -0
  57. package/lib/types/client/recognized-speaker-directory.d.ts.map +1 -0
  58. package/lib/types/client/recognized-speaker-order.d.ts +28 -0
  59. package/lib/types/client/recognized-speaker-order.d.ts.map +1 -0
  60. package/lib/types/client/recognized-speaker-tracker.d.ts +33 -0
  61. package/lib/types/client/recognized-speaker-tracker.d.ts.map +1 -0
  62. package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts +12 -0
  63. package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts.map +1 -0
  64. package/lib/types/client/recordings/SpeakerSelfGuide.d.ts +8 -0
  65. package/lib/types/client/recordings/SpeakerSelfGuide.d.ts.map +1 -0
  66. package/lib/types/client/recordings/recording-speaker-options-store.d.ts.map +1 -1
  67. package/lib/types/client/self-role-presentation.d.ts +6 -1
  68. package/lib/types/client/self-role-presentation.d.ts.map +1 -1
  69. package/lib/types/client/use-personal-extension-parents.d.ts +4 -0
  70. package/lib/types/client/use-personal-extension-parents.d.ts.map +1 -0
  71. package/lib/types/host-api.d.ts.map +1 -1
  72. package/lib/types/index.d.ts.map +1 -1
  73. package/lib/types/managed-ai/adapter.d.ts +2 -1
  74. package/lib/types/managed-ai/adapter.d.ts.map +1 -1
  75. package/lib/types/managed-ai/operation.d.ts +17 -0
  76. package/lib/types/managed-ai/operation.d.ts.map +1 -0
  77. package/lib/types/managed-ai/transport.d.ts +1 -0
  78. package/lib/types/managed-ai/transport.d.ts.map +1 -1
  79. package/lib/types/record-extension-tree.d.ts +2 -0
  80. package/lib/types/record-extension-tree.d.ts.map +1 -1
  81. package/lib/types/sdk/index.d.ts +14 -0
  82. package/lib/types/sdk/index.d.ts.map +1 -1
  83. package/lib/types/services/ai-points-service.d.ts +13 -0
  84. package/lib/types/services/ai-points-service.d.ts.map +1 -0
  85. package/lib/types/services/arko-service.d.ts.map +1 -1
  86. package/lib/types/services/chat-service.d.ts +9 -1
  87. package/lib/types/services/chat-service.d.ts.map +1 -1
  88. package/lib/types/services/interwoven-service.d.ts +3 -1
  89. package/lib/types/services/interwoven-service.d.ts.map +1 -1
  90. package/lib/types/services/recording-service.d.ts +2 -5
  91. package/lib/types/services/recording-service.d.ts.map +1 -1
  92. package/lib/types/services/unmarked-speaker-service.d.ts.map +1 -1
  93. package/lib/types/tools/business/account/ai-points.d.ts +4 -0
  94. package/lib/types/tools/business/account/ai-points.d.ts.map +1 -0
  95. package/lib/types/tools/business/account/index.d.ts.map +1 -1
  96. package/lib/types/tools/business/recordings/index.d.ts +1 -1
  97. package/lib/types/tools/business/recordings/index.d.ts.map +1 -1
  98. package/lib/types/tools/business/recordings/speaker-presence.d.ts +2 -0
  99. package/lib/types/tools/business/recordings/speaker-presence.d.ts.map +1 -0
  100. package/lib/types/tools/ports/profile.d.ts +3 -0
  101. package/lib/types/tools/ports/profile.d.ts.map +1 -1
  102. package/lib/types/tools/ports/recordings.d.ts +4 -0
  103. package/lib/types/tools/ports/recordings.d.ts.map +1 -1
  104. package/lib/types/types.d.ts +33 -8
  105. package/lib/types/types.d.ts.map +1 -1
  106. package/package.json +5 -5
  107. package/lib/types/recording-speaker-presence.d.ts +0 -28
  108. package/lib/types/recording-speaker-presence.d.ts.map +0 -1
@@ -0,0 +1,43 @@
1
+ # AI 积分接入
2
+
3
+ 基线:用户指定 origin/dev(114ad18),任务 worktree;不修改 DSH、根 README 或版本号。
4
+
5
+ 本次积分 API 只读取账户及已结算消费。会员发放与模型收费分别由 Backend 和 Intelligent 持有;插件不估算余额,不从 Token 遥测推导扣费。
6
+
7
+ | 能力面 | 实现入口 | 验证状态 |
8
+ | --- | --- | --- |
9
+ | UI | 用量与额度 → AI 积分、扣费明细;充值保留人民币支付价格 | 已完成,相关单测及官方 DSH 正式 tgz 链路通过 |
10
+ | Tools | 当前登录账号 AI 积分及消费查询,只读,不发放、不充值 | 已完成,相关单测及官方 DSH 正式 tgz 链路通过 |
11
+ | SDK | aiPoints 能力探测、类型化账户与分页明细,支持 AbortSignal | 已完成,相关单测及官方 DSH 正式 tgz 链路通过 |
12
+ | Host owner | AiPointsService:统一账号作用域、契约校验和错误语义 | 已完成,相关单测及官方 DSH 正式 tgz 链路通过 |
13
+
14
+ 不扣积分的后台业务不进入此页面。Token 只出现在已扣费请求的展开明细。存储、语音等独立额度沿用原 owner 与计量单位。
15
+
16
+ 验收使用官方 `dsh-v0.1.5-rc.2` / `fb2c4b9e`,源代码未修改;独立 profile 通过官方 CLI 安装 tgz。因官方 peer 范围 `>=0.1.5` 不匹配已发布 rc 包,测试 profile 按目标官方版本固定其同套依赖,未改插件版本/依赖或用户常驻环境。8 场景覆盖正常、异常、恢复;真实 UI、公共 SDK、注册 Tools 读取同一账本。余额不足文案统一为积分;同账号请求并发冲突提示等待,不自动重试扣费。
17
+
18
+ 更完整的测试矩阵与基线限制见 meta 的 `docs/analysis/2026-09-22-ai-points-verification.md`。
19
+
20
+ ## 2026-09-23 三端体验收口
21
+
22
+ 用户侧统一称“Arkme 3.0”,充值页说明与 APP 共用积分。现有充值流程不变;APP/旧 Flutter PC 只提供查询、消费与官网下载指引,不扩展支付渠道。
23
+
24
+ | 能力面 | 本轮增量与验证 |
25
+ | --- | --- |
26
+ | UI | 模型菜单增加独立折叠计费说明,查看不改变选择;消费按可信 Agent operation_uid 聚合,展开仍显示调用级准确费用;无标识的 Arkme 请求保持独立 |
27
+ | Tools | 原 arkme_ai_points / arkme_ai_points_consumption 保留共享 owner;正式包的注册 Tools 在真实会话作用域读取同一账本,未新增计费或写入工具 |
28
+ | SDK | 公共 aiPointsConsumption 保留 operationUid;完整业务组可超过20个调用,仍最多20组;包外 SDK consumer 已经官方运行时验证,错误账号作用域仍拒绝 |
29
+ | Host owner | AiPointsService 统一契约校验/账号边界;报价来自 Intelligent point_pricing,不按Token遥测、模型昵称或UI倍率重算价格 |
30
+
31
+ 747个测试文件、8828项测试通过(11文件/15项按原配置跳过),类型检查与构建通过。新增分组、报价及“查看不选中”回归。正式 `.tgz` 通过官方 CLI 安装至全新隔离 profile,官方 DSH `dsh-v0.1.5-rc.2` 源码未改,已通过含 UI/Tools/SDK/真实HTTP/真实MySQL 的跨仓链路;真实供应商和支付仍使用隔离边界,未作线上验收。
32
+
33
+ 完整本轮记录位于 meta:`docs/analysis/2026-09-23-ai-points-ux-delivery.md`。没有改插件版本、根 README 或发行配置。
34
+
35
+ ## 2026-09-24 消费月份交互修复
36
+
37
+ 对照 `origin/dev`(8b6be0d)及 `origin/master`(052ac40)的 `ArkmeTokenUsageBreakdown`,基线使用原生 `select`;积分页的 `input type="month"` 会把年月文字点击解释成分段编辑。现恢复基线下拉选择及同一套样式,文字和箭头区域均可展开。默认列出最近 24 个月,“更早月份”每次扩展 12 个月,不改变当前账期、不发查询,也不限制历史记录范围。月份按上海时区确定,切换后继续由原有请求 owner 取消旧请求、隔离旧月份结果。
38
+
39
+ | 能力面 | 本轮范围与证据 |
40
+ | --- | --- |
41
+ | UI | 月份选择交互;42 项相关测试、类型检查和构建通过。隔离浏览器组件页面验证文字/箭头点击、键盘切换、取消及扩展历史;未替换用户常驻 DSH |
42
+ | Tools / SDK | N/A:仅替换 UI 控件,未新增业务能力或修改公共接口 |
43
+ | Host owner | AiPointsService 及账本查询契约不变 |
@@ -0,0 +1,35 @@
1
+ # 私聊群互动:正文优先的轻量摘要行
2
+
3
+ ## 已确认的交互
4
+
5
+ - 保持居中的透明单行提示,不改成普通消息左右头像气泡,不新增预览卡片。
6
+ - 最新确认方案使用 20px 发送人头像代替「我/对方」,不再显示完整昵称;头像与正文垂直居中,不增加行高。
7
+ - 顺序调整为:发送人小头像 → 正文摘要 → 弱化的群名 → 原群消息已读状态 → 详情箭头。
8
+ - 复用现有发送人头像字段及共享图片缓存;缺图、加载中或图片加载失败时显示昵称首字,避免空白灰头像。头像来源变化或图片地址更新后可重新显示新头像。
9
+ - 群名最多占行内 24% 且不超过 9em;正文超出时省略,群名也可省略。
10
+ - 悬浮或键盘聚焦立即显示完整发送人、群名及已有摘要。提示不会为了补正文再联网。
11
+ - 阅读角标使用独立的阅读者说明,不与整行说明重叠;未知状态仍不显示标记。
12
+ - 点击或 Enter 打开原快记详情;不改变互动身份、时间顺序、原群已读语义及权限。
13
+
14
+ ## 实现范围
15
+
16
+ 仅修改 `ArkmeInterwovenMentionCard` 摘要呈现及对应中英文文字,详情仍保留原发送人头像和姓名。不新增后端接口。补充覆盖双方头像、缺图、损坏图片、切换发送人、悬浮、键盘、详情点击、长群名、省略和提示清理的测试。
17
+
18
+ 上一轮全量回归唯一失败是公开服务方法清单漏登记两个已实现的方法。本轮补齐明确的 `interwovenReadReceipts`、`sourceMessageExtensionParent`,保留严格全量相等检查,不删除或放宽断言。
19
+
20
+ ## 验证
21
+
22
+ - 4 个相关测试文件、59 项通过。
23
+ - 头像版最终全量:806 个文件通过、11 个文件跳过;9506 项通过、15 项跳过、0 项失败。
24
+ - 类型检查、构建与 `git diff --check` 通过。
25
+ - 3100 独立 Web 预览保留登录并使用头像版;现有私聊 18 条群互动中,双方头像全部正常加载,尺寸为 20×20px。
26
+ - 默认 1153px 及 900 / 680 / 420px 验证,无横向溢出,摘要按钮仍为 28px 高,头像和文字垂直居中。
27
+ - 900px 时长摘要可用宽约 313px,群名 99px;680px 时摘要约 248px;420px 极窄时群名约 40px、正文约 47px,省略更多,但不与状态重叠,可通过完整提示或详情查看。
28
+ - 实际键盘聚焦可显示完整群名、发送人和摘要;Tab 到已读角标后切换为阅读状态说明;Escape 可关闭提示,Enter 可打开原消息详情。
29
+ - 本轮只读导航,不创建测试消息、不移动或删除消息、不直接上报群已读;未修改已安装 Arkme 客户端。
30
+
31
+ ## 交付边界
32
+
33
+ 开发验收时未推送、未创建 PR。随后按用户要求准备合并:先完整备份本地增量及提交历史,再将 PR #702 之后的两个增量提交重放到最新 `origin/dev`(`ffb33cc7`),没有产生冲突。重放前后增量补丁的 SHA-256 完全一致,保留 dev 的 v0.1.82 版本信息和数据管理入口更新,不重复带入已合入的上一批功能。
34
+
35
+ 相关快记云端召回波动、跨端角色同步及双账号实时已读端到端验收仍沿用此前文档的边界,本次没有扩大为后端实现。
@@ -0,0 +1,50 @@
1
+ # 私聊中群互动行:原群消息已读状态
2
+
3
+ ## 需求与展示
4
+
5
+ - 范围是私聊内容区穿插的群互动单行,不是第二栏联系人卡片。
6
+ - 在摘要末尾、跳转箭头前显示状态,不新增卡片、不增加行高。
7
+ - 未读为小蓝点;已读复用私聊消息及 @ 标识的圆圈对勾。
8
+ - 鼠标悬浮或键盘聚焦立即显示说明,区分“对方已阅读群内原消息”和“你已阅读群内原消息”。仅有明确逐条阅读时间时显示时间。
9
+ - 状态未知保持空白,不能当作未读。原行点击打开详情的行为保持不变。
10
+
11
+ ## 数据语义与接口
12
+
13
+ 新增插件宿主只读操作 `source.interwoven-read-receipts`,参数为 `sourceRef` 和最多 20 个宿主签名的 `momentRefs`。
14
+
15
+ | 场景 | 状态依据 |
16
+ | --- | --- |
17
+ | 我在群里 @ 当前私聊联系人 | 原群消息 `/api/v1/chats/read-receipts/detail` 中该联系人唯一的成员回执,不使用全群已读数量 |
18
+ | 对方在群里 @ 我 | 原群 `/api/v1/chats/detail` 中自己的有效 `current_cursor` / `unread_snapshot`,与原消息 `seq` 比较 |
19
+ | 原消息不可定位、已撤销、失去权限、对应成员缺失或响应异常 | 未知,不显示蓝点或对勾 |
20
+
21
+ 不会根据私聊行是否可见来确认已读,不调用群已读上报接口,不修改未读数量。
22
+ 浏览器只传签名引用;账号、私聊对象、群、消息、发送者、阅读者均在宿主校验。退出/切换账号丢弃旧请求结果。
23
+
24
+ ## 旧服务副本兼容
25
+
26
+ 实际联调发现:World 交织列表的近期记录使用 `chat_legacy_receive_...` 副本 UID,不能直接交给 Chat 的原消息定位接口。直接调用 `/api/v1/chat/timeline/around` 会返回业务码 2001,导致近期互动全部未知。
27
+
28
+ - 复用 `/api/v1/chats/interwoven/occurrences/query` 获得当前私聊双方互动的 canonical 群、消息、关系、owner 和 seq。
29
+ - 按 Subject 源码 `buildLegacyReceiveRecordEdgeUID` 的既有规则核对副本身份:`chat_legacy_receive_` + `sha256(groupUid + ':' + relationUid)` 的前 32 个十六进制字符。
30
+ - 必须同时匹配私聊、群、消息 owner、发送者及方向;重复身份对应不同原消息则拒绝。不是按正文、时间或名称猜测。
31
+ - 兼容查询每次最多 3 页、每页 50 条,携带结果版本;版本变化/覆盖不完整则不接收映射。精确映射在签名引用有效期内复用。
32
+ - 普通旧 UID 则通过 exact group + owner + record 的 `timeline/around` 校验并取得 seq。
33
+ - 超出兼容窗口或仍无法准确对应的记录保持未知;不宣称所有历史互动均有回执。后续后端若直接返回 canonical locator,可移除这一兼容映射。
34
+
35
+ ## 请求控制
36
+
37
+ - 只查询可视行(含 80px 预取范围),100ms 合并,每批最多 20 行,宿主上游最多 3 个并发。
38
+ - 存在未读时每 15 秒检查;全未知时每 60 秒重试;网络错误退避至最多 60 秒。
39
+ - 全部已读后停止轮询;实时失效事件、重新聚焦或重新进入可视区域时刷新。
40
+ - 隐藏页面、切换会话/账号会取消请求并清理状态。没有已读状态的无浏览器测试环境安全跳过监听。
41
+
42
+ ## 验证结果
43
+
44
+ - 10 个相关测试文件共 **713 项通过**,覆盖宿主权限边界、原群 cursor、指定成员回执、旧副本映射、版本变化、分页上限、取消/轮询、账号隔离、行末位置、提示及原点击行为。
45
+ - `pnpm typecheck`、`pnpm build`、`git diff --check` 通过。
46
+ - 3100 独立 Web 预览真实会话:抽查最近 10 条互动,9 条获得明确已读状态,1 条未知并保持空白。出站回执带对方阅读时间,入站 cursor 不伪造逐条阅读时间。
47
+ - 浏览器实际看到摘要行末圆圈对勾,箭头位置保留;聚焦后立即出现正确阅读者提示,Escape 可关闭。当前窄/常规宽度未产生额外行高。
48
+ - 没有为测试发送新消息或上报群已读。仅重新部署独立的 3100 预览,未更改安装的桌面客户端。
49
+ - 控制台仍有运行时重启后的旧控制流断开记录及 TRTC 预加载 AbortError;本次未修改通话模块,不将这些记录描述为已修复。
50
+ - 尚未做双账号实时收发的端到端人工验收,也未推送或合并分支。
@@ -0,0 +1,40 @@
1
+ # 发给自己:跨主题延展与详情一致性回归
2
+
3
+ ## 问题与根因
4
+
5
+ 场景:未分类快记 A 被延展为 B,之后仅将 B 放入主题。
6
+
7
+ - 聚合个人列表带有 A 的引用,但主题分页中的同一 B 可能完全没有 `parent_record_uid`。
8
+ - `records/detail` 和批量读取的基本记录也没有该关系;不能用“主题列表没给引用”判断“消息没有来源”。
9
+ - 现有 `/api/v1/records/extensions/tree` 能返回 B 的顶层 `parent_record_uid`,以及 A 的记录,即使 `tree` 以 B 为中心、`edges` 和 B 的子回复都是空数组。
10
+ - 原详情只消费列表附带的引用,因而不同入口显示不一致。
11
+ - 相关快记原有读取已按记录身份查询,不按主题过滤;加载期间原来完全隐藏,易被误认为缺少内容。
12
+
13
+ ## 本次处理
14
+
15
+ 1. 复用既有云端延展树;独立解析当前消息的直接来源,不误用整棵树的根或兄弟节点。
16
+ 2. 新增插件内部只读操作 `source.message-extension.parent`。仍需有效来源和签名消息操作引用,不接受任意记录 UID 读取。
17
+ 3. 个人消息列表仅为可见区域及附近缺失引用的记录补读,最多并行 2 个;同一来源版本已完成的记录不重复读取,切换账号或来源取消旧请求。
18
+ 4. 完整详情从消息自己的延展关系补齐来源;主题外的来源可经“全部”定位打开,并支持返回原子消息。
19
+ 5. 详情始终显示消息所属主题;时间线气泡仍保持不重复展示当前主题的简约规则。
20
+ 6. 相关快记以轻量文字提示正在加载;成功刷新期间保留当前内容;错误可重试,真实空结果仍不占空间。
21
+ 7. 原有私聊、群聊引用定位方式不变;私密、不可访问或已删除的来源不泄露正文。
22
+
23
+ ## 验证
24
+
25
+ - 类型检查、构建、差异空白检查通过。
26
+ - 13 个相关测试文件,共 858 项通过,包含消息发送/目录、详情、角色头像、服务授权和插件操作分发。
27
+ - 后续补充的跨主题气泡点击及取消信号分发测试通过。
28
+ - 3100 独立预览更新,浏览器实际验证:
29
+ - “未分类 A → 延展 B → B 移入主题”:B 的主题气泡恢复引用;主题内外详情都显示 A、正文、所属主题;点击 A 打开详情,A 的回复列表含 B,可返回 B。
30
+ - 另一条已有内容的消息在全部与主题内均显示 1 条相关快记、2 条延展,包含正确的本我头像及本地角色表现。
31
+ - 无回复时不显示空的延展区域。
32
+ - 验证仅使用已有消息读取和页面导航,未发送、移动或删除真实消息;未修改已安装桌面客户端,未推送代码。
33
+
34
+ ## 云端待排查:相关快记结果波动
35
+
36
+ 本次联调同一用户、同一记录、同一组参数的 `/api/v1/records/related/query`,先返回 20 条,随后返回 0 条,再次打开后又返回 20 条。直接请求云端也捕获到 HTTP 200、业务 code 0、`items: []`(另有 `recall_mode` 字段),不只是前端渲染现象。
37
+
38
+ 固定参数形状:`record_uid`、`record_owner_user_id`、`context_type: "record"`、`limit: 20`;不传主题条件。前端没有把空结果替换成历史结果,也没有合成相关内容。
39
+
40
+ 请后端排查同一记录的召回策略、索引就绪状态及空结果稳定性。如果空表示“索引/召回暂未就绪”而非“确实没有关联”,建议提供明确状态或可重试标记,使各端能区分暂不可用与真正为空。本次不能保证云端在不同时刻返回完全相同的相关条目。
@@ -0,0 +1,157 @@
1
+ # 已识别说话人:统一目录、总数、新增提醒与跨端同步——后端交接
2
+
3
+ 日期:2026-09-28
4
+
5
+ 范围:录音板块的「已识别说话人」。不涉及聊天已读、消息通知或 AI Token 用量。
6
+
7
+ **结论:已标记说话人的出现天数、最近发声时间已接入,不需要重新开发一套统计。当前主要缺统一目录查询和目录级查看进度。建议优先提供统一摘要、统一分页列表、查看确认三个能力;接口路径和字段名均为建议,可扩展现有接口实现。**
8
+
9
+ 核对依据:当前插件实现、3100 预览的本轮实际结果,以及本地 `jotmo-audio` 源码。源码存在不代表所有线上环境已部署;下文单独列出需要确认的项目。旧版 `recognized-speaker-presence-api-handoff-2026-09-27.md` 中「只缺统计/尚未部署」属于当时记录,不能继续当作本轮需求状态。
10
+
11
+ ## 1. 要达到的用户体验
12
+
13
+ - 录音页入口直接显示「已识别说话人 N」。多个原始识别身份标记成同一人后只计一人;同名不同人不能合并。
14
+ - 自上次打开目录后有真正新增时,第二行显示「新识别 M 个」。打开目录并成功展示后清除;同账号其他设备随后也应同步清除。
15
+ - 「经常出现」:出现天数降序,同天数按最近发声时间降序。
16
+ - 「最近出现」:最近发声时间降序,同时间按出现天数降序。
17
+ - 已确认是本人的身份在全部/已标记列表置顶;搜索仍尊重搜索条件,未标记筛选不强行插入本人。
18
+ - 首屏即可得到正确全局排序,不需要前端把几千人全部读完后再排序。后续返回立即展示缓存,只检查更新。
19
+
20
+ 这里的总数是**当前目录合并口径下的可展示身份数**:没有可靠绑定关系的匿名候选仍分别计数,不能承诺已经识别出真实世界全部不重复的人。
21
+
22
+ ## 2. 已有能力与需要确认的项目
23
+
24
+ | 能力 | 当前证据与状态 | 本轮处理 |
25
+ | --- | --- | --- |
26
+ | 已标记身份及绑定账号 | 插件使用 `POST /api/v1/audio/get-speaker-ls`,按绑定账号或独立 Speaker 归组 | 复用,不另造身份系统 |
27
+ | 已标记人的出现天数、最近发声时间 | 插件使用 `POST /api/v1/audio/speaker-presence/list`;本轮预览已显示全历史统计;本地聚合已处理同一绑定用户的多 Speaker 日期并集 | 已有,不重复提为新缺口 |
28
+ | 未标记候选及统计 | `POST /api/v1/audio/unmarked-speakers/list` 已有分页、日期统计、候选标识及投影状态 | 扩展排序/搜索/统一目录能力 |
29
+ | 未标记轻量总数 | 本地后端已注册 `POST /api/v1/audio/unmarked-speakers/count`,含 `total_count/state/published_version/updated_at/retry_after_ms` | 请确认部署和灰度;插件当前尚未专门接入这个 count 路由,这部分是前端可补接,不是要求从零开发 |
30
+ | 已标记者关联的原始识别身份详情 | 插件已对接 `/speaker-presence/detail`,支持 `speaker_id/expected_version`;本次核对的本地后端路由未找到该 detail 注册 | 请后端确认实际分支、部署环境及契约,不直接认定线上不存在,也不默认已验收 |
31
+ | 本人判断、声纹状态及录入 | 当前可从绑定账号判定本人,已有 `/voiceprint/my` 及录入流程 | 置顶和引导本身不需要新接口;统一分页时需把本人信息随目录返回 |
32
+
33
+ 已有候选 ID 跨请求稳定,也已有部分聚类成员信息。**真正缺少的是整个目录跨设备可用的统一身份,以及标记、合并、拆分、重聚类时对「是否新增、是否已查看」的继承规则**,不是完全没有候选 ID。
34
+
35
+ ## 3. 当前前端临时方案及体验边界
36
+
37
+ 1. 总数暂由「已标记人去重数+未标记候选数」拼接。它们不保证来自同一个后端快照,标记与重建交错时可能短暂不一致。
38
+ 2. 新增提醒保存在当前浏览器源、当前账号下。首次完整读取静默建立基准;换设备不能同步查看状态。
39
+ 3. 前端无法准确识别「旧候选消失+新身份出现」究竟是合并还是新发现,因此保守抑制这次新增;同时发生合并和真正新增时可能漏报。
40
+ 4. 全局排序、搜索目前依赖读取全部元数据;最多 40 页/2,000 个未标记候选是**插件当前的保护上限,不是后端产品上限**。超过上限只展示部分结果,不能保证全局排序与搜索完整。
41
+ 5. 已实现入口/列表共享缓存、分页复用和限流退避。本轮真实账号完整读到 1,990 个目录身份,再次进入能直接显示;但首次补齐仍慢,不能靠缓存解决首次正确排序。
42
+ 6. 现有后端已有 `scan_truncated`、整理中数量等信息;插件适配层也应完整透传,不能将已有字段未接入误列为后端缺失。
43
+
44
+ ## 4. P0:本轮优先补齐的能力
45
+
46
+ ### A. 统一轻量摘要
47
+
48
+ 建议能力名:`speaker-directory/summary`。
49
+
50
+ 一次读取返回账号级、同快照的:
51
+
52
+ | 字段示意 | 含义 |
53
+ | --- | --- |
54
+ | `total_count`、`marked_count`、`unmarked_count` | 当前可展示目录去重数;三个字段必须同快照且口径一致 |
55
+ | `unseen_count` | 自目录查看基准之后的新增身份数,按当前合并结果计数,不是「总数之差」 |
56
+ | `snapshot_version`、`updated_at` | 与列表绑定的快照版本及更新时间 |
57
+ | `state`、`coverage` | `fresh/stale/building/failed`;数据是否完整,不能把截断结果称为全量 |
58
+ | `change_cursor` | 这个快照覆盖到的变化边界,供查看确认和后续增量使用 |
59
+ | `retry_after_ms` | 整理中、失败或限流时的重试建议 |
60
+
61
+ 要求:入口统计不遍历名单、不逐人查询、不在每次读取时同步扫描全部录音。无可用快照时返回明确的未知值/状态,不能用 `0` 冒充空目录。存在旧快照时可返回旧数值并明确标记为过期。
62
+
63
+ 可复用现有未标记 count 与已标记 presence 投影,但需要后端给出两者一致的合并结果;单纯把两个不同时点的接口相加不能替代统一摘要。
64
+
65
+ ### B. 已标记+未标记的统一分页、全局排序和搜索
66
+
67
+ 建议能力名:`speaker-directory/list`。
68
+
69
+ 请求支持:`filter=all|marked|unmarked`、`sort=frequent|recent`、`query`、`limit`、`cursor`,以及与摘要一致的 `snapshot_version` 或等效机制。
70
+
71
+ 每行至少包含:稳定的账号内 `person_key`、类型、展示名称/编号、头像引用、`is_self`、`day_count`、`last_seen_at`、详情定位引用。稳定身份 ID 不是授权凭据;任何详情/标记请求仍需验证当前登录账号。
72
+
73
+ 关键规则:
74
+
75
+ - 先按实际身份合并,再排序分页。全部列表必须混排,而不是「已标记排完再排未标记」。
76
+ - frequent:`day_count DESC, last_seen_at DESC, person_key ASC`;recent:`last_seen_at DESC, day_count DESC, person_key ASC`。本人按前述筛选规则优先,仍只出现一次。
77
+ - 当前未标记固定排序在同天数时先比较发声总时长,不符合本次「同天数看最近时间」规则;不能只给现有排序改一个名字。
78
+ - `last_seen_at` 统一指最后一个有效发声片段的时间,不能混成文件结束、身份修改或入库时间;天数继承已确认的录音自然日去重口径。
79
+ - 游标绑定登录账号、快照、筛选、搜索、排序;换排序不复用旧游标。快照失效时明确返回失效状态,不静默拼接新旧结果。
80
+ - 超过 2,000/10,000 身份也可持续分页;只加载第一屏就能得到该筛选下正确的第一屏排序。搜索应覆盖完整目录,而非前端已加载部分。
81
+ - 只有声纹授权、通讯录联系人、从未在录音出现的空身份,不应自动算作已识别的人;保留旧空身份如有产品需要,请返回明确类别并单列口径。证据不足/处理中是否进总数也必须与可展示列表一致,不能计数却无法查看。
82
+
83
+ ### C. 目录级「新增」及跨端查看确认
84
+
85
+ 建议能力名:`speaker-directory/seen`。确认请求携带**已成功展示快照的** `through_cursor`,不使用客户端时间。
86
+
87
+ - 「已查看」表示用户已打开该目录,不代表逐人读过每一张卡片,更不是录音消息已读。
88
+ - 为匹配「点进去提示就去掉」,第一屏成功展示后,可确认该目录快照覆盖到的新增事件;后续分页无需全部滚到底。不能拿一个新摘要的游标去确认仍在显示的旧快照。
89
+ - 同账号各端共享,确认幂等、只向前推进;旧设备较晚提交旧游标不能覆盖新游标。
90
+ - 用户打开快照 C 后,新身份 D 才到达:确认 C 不能清除 D。加载失败、离线、账号切换后的迟到响应都不能推进查看边界。
91
+ - 发布此能力时设定账号级首次基准,不把已有几年历史全部报成新增;后续换设备或重装不重新初始化。
92
+
93
+ 新增必须依据服务端首次发现/进入目录的事件序号,而不是录音发生的 `first_seen_at`:今天上传旧录音发现新对象,应按今天发现处理。已知人再次讲话、改名、重新转写、引用过期不算新增。
94
+
95
+ ### D. 身份继承:为上述统计提供正确依据
96
+
97
+ 可内部维护事件和映射,不强制将全部关系暴露给前端。需明确:
98
+
99
+ - 未标记 A、B 标记成同一人 P:目录只剩 P,计 1;标记动作本身不新增一人。
100
+ - A、B 都未查看时合成 P,待查看数按 1;已查看身份的纯合并不能重新提醒。
101
+ - 已查看身份拆分或技术重聚类,继承其已知/查看状态;不能因换 ID 把历史全变成新增。若确实发现之前未覆盖的新对象,由后端明确产生发现事件。
102
+ - 合并与真正新增 X 同时发生,仍正确提示 X;不能因为总数没增加就漏报。
103
+ - 同昵称但无绑定关系不能合并;同一绑定用户的多个 Speaker 或多个候选归属同一正式人,按确认关系合并。
104
+ - 删除、恢复、取消标记、重新绑定、撤销合并需有明确继承规则。已看过对象的恢复默认不当新发现;有效名单和统计随录音删除/恢复更新。
105
+
106
+ ## 5. P1:更及时的更新与更稳的服务保障
107
+
108
+ 1. **变化检查/增量读取**:摘要支持条件版本检查,或提供 `changes(since_cursor)` 返回新增/更新/移除以及新版本。版本未变无需下发完整名单。若使用推送,只推账号级「目录变了」通知即可,不需推音频或 ASR 原文。
109
+ 2. **可解释的退避**:请在 429 返回明确错误码、`Retry-After` 或 `retry_after_ms`。区分限额耗尽、旧路径计算锁占用、基础设施异常;前端能保留内容并按服务端建议重试。
110
+ 3. **确认轻量投影已覆盖目标环境**:本地源码存在新投影读取和旧同步读取两条路径,限频不同。请确认灰度、部署版本及 count/list 的一致性;不要单纯取消限流。前端发生过 429,尚未取得服务端日志,不能断定线上一定走哪条路径。
111
+ 4. **原始身份详情核验**:确认 `/speaker-presence/detail` 对应分支及部署,返回与列表一致的版本、全历史关联编号、统计、分页或明确覆盖范围;不要为已有接口重复开发另一条同义接口。
112
+
113
+ 本人置顶、无本人时显示引导、按钮布局和空态都可由前端完成。后端只需可靠的账号绑定及声纹状态;可选在摘要中返回 `self_person_key/self_state` 减少额外请求,不是首期必需的新模块。
114
+
115
+ ## 6. 迁移和客户端配合
116
+
117
+ - 当前插件的 `personKey/identityKey/candidateRef` 有本机密钥封装,不能直接作为各端通用 ID。后端提供账号内稳定身份,插件 Host 负责适配;前端不上传本机 HMAC 并假定后端能还原。
118
+ - 本机新增记录不是权威历史。最小迁移方案是后端统一一次性静默基准,之后各端共用后端游标;不要每台新设备把全量旧人重新报新。
119
+ - 如果必须保留上线前每台设备尚未查看的提醒,需要另定可验证映射和幂等迁移流程,不能悄悄以客户端列表覆盖后端查看状态。
120
+ - 后端统一查询落地后,插件移除「为全局排序扫描全部名单」的降级路径,改用服务端分页;保留同账号缓存、请求合并、失效保护和退避。
121
+ - 同步透传已有版本、截断、状态与退避字段,并接入已部署的轻量 count;这是客户端对接工作,不全部算成后端新增需求。
122
+
123
+ ## 7. 联调验收清单
124
+
125
+ | 场景 | 预期 |
126
+ | --- | --- |
127
+ | 3 个候选标记为同一人 | 总数相应合并为 1;摘要和列表一致 |
128
+ | 多轨道同一天有讲话 | 人级出现 1 天,最近时间取最后有效片段 |
129
+ | 同天数但发声时长不同 | frequent 仍按最近时间作为第二排序条件 |
130
+ | 本人不在普通排序第一页 | 全部/已标记第一页仍置顶本人,后续页不重复 |
131
+ | 超过 2,000/10,000 身份 | 首屏全局排序正确,跨页无漏项/重复,搜索可命中后部数据 |
132
+ | 同一个人又说了几天、改名 | 天数/时间更新,不增加新增人数 |
133
+ | 合并两个未查看候选 | 新增人数由 2 变 1,不额外产生第三个新人 |
134
+ | 已查看人重聚类+真正新增同时发生 | 旧人不重报,新人不漏报 |
135
+ | 今天导入上月录音发现新对象 | 按发现事件计新增,不因录音日期旧而漏报 |
136
+ | A 端打开目录,B 端检查 | 两端查看状态一致,无需重新加载全部身份 |
137
+ | A 确认旧快照时又来了新人 | 新人提示保留;重复确认安全,旧确认不回退状态 |
138
+ | 初始化/换设备/重装 | 历史不全部报新,不重置其他端已查看状态 |
139
+ | 构建中、截断、429、服务故障 | 不把未知显示为 0;保留旧快照并明确状态,按建议重试 |
140
+ | 伪造其他账号身份或游标 | 拒绝访问;缓存、计数、详情和查看状态均账号隔离 |
141
+
142
+ 以上均可使用合成身份/录音夹具验收,不应为测试擅自修改真实用户的说话人归属或声纹。
143
+
144
+ ## 8. 请后端回复的交付信息
145
+
146
+ 1. 哪些能力可直接扩展现有接口,哪些需要新接口;最终请求/响应示例和字段口径。
147
+ 2. P0(三个读取/确认能力及其身份继承规则)的排期,以及 P1 的拆分计划。
148
+ 3. 已部署环境、版本或分支、灰度范围;特别是 count 和 presence/detail 的当前状态。
149
+ 4. 身份合并/拆分/首次基准规则、快照和游标失效方式、限流退避约定。
150
+ 5. 可用的合成测试账号与验收结果,避免将「本地有代码」等同「插件已能在线调用」。
151
+
152
+ ### 核对入口(仓库相对路径)
153
+
154
+ - 插件:`src/client/recognized-speaker-directory.ts`、`recognized-speaker-tracker.ts`、`recognized-speaker-order.ts`、`ArkmeRecognizedSpeakersSurface.tsx`。
155
+ - 插件适配:`src/services/unmarked-speaker-service.ts`、`src/services/recording-service.ts`。
156
+ - Audio:`gin/api/router.go`、`gin/api/audio_unmarked_speaker.go`、`gin/api/audio_speaker_presence.go`。
157
+ - Audio 数据口径:`internal/audio/unmarked_speaker_candidates.go`、`internal/audio/speaker_presence_stats.go`、`internal/audio/repository.go`。
@@ -0,0 +1,47 @@
1
+ # 已识别说话人:入口统计、本机新增提醒与本人引导
2
+
3
+ ## 本轮交互
4
+
5
+ - 录音页入口显示合并后人数:已标记按稳定 personKey 去重,加未标记候选总数。同名不同身份不合并,同一个人关联多个说话人只算一个。
6
+ - 有尚未查看的新增时,入口第二行显示「新识别 N 个」;无新增不占用第二行。加载失败不伪装为零。
7
+ - 本人按账号归属 isCurrentUser 判断,在「全部/已标记」中始终排第一;其余按用户选择排序。搜索仍筛选本人,「未标记」不混入已标记本人。
8
+ - 未找到本人时,读取现有 voiceprint.status,区分未录入、处理中、已录入但尚未匹配。状态请求失败不声称没有声纹。
9
+ - 复用「从录音中标记我」和「录入我的声纹/管理声纹」。前者返回录音页,明确引导先试听、点击说话人名称并选择自己;不会把创建同名角色当作账号身份绑定。后者进入现有声纹流程,不自动打开麦克风或提交录音。
10
+
11
+ ## 本机新增口径与边界
12
+
13
+ - 按环境和账号在当前 Web 源保存已知身份、上次完整名单、待查看身份;首次完整读取静默建立基准,不把全部历史报为新增。
14
+ - 未标记新增使用 Host 签发的稳定只读 identityKey,不使用 30 分钟到期的 candidateRef。identityKey 通过本机持久密钥、环境、账号、上游候选 ID 生成;不是权限凭据,不被标记等写接口接受,不存姓名、录音正文或声纹音频。
15
+ - 只有完整且 fresh 的名单才能产生新增统计;部分加载、上限截断、游标异常或网络失败时不提供精确新增数。总数可先使用服务端轻量汇总,不必等所有元数据加载完。
16
+ - 正常进入并成功呈现列表后清除已知待查看提示;后续完整名单成功呈现后更新已查看基准。失败或账号切换后的迟到响应不确认未知数据。
17
+ - 同一身份继续讲话、改名、临时引用轮换不产生新增。曾见过的身份消失后再出现也不重复提醒。
18
+ - 现有接口缺少合并和重聚类的身份继承关系。一次快照里同时有旧身份消失、新身份出现时,本机版保守不报这些新身份,避免把合并误当新识别。因此同时发生合并和真正新增时可能漏报,不承诺严格事件级统计。
19
+ - 仅本机、当前浏览器源保存查看进度;退出/切换账号清理内存列表,持久查看进度仍按账号隔离。禁用本地存储时降级到本次运行记忆。
20
+ - 录音页活跃且页面可见时每分钟检查本机缓存;已标记名单缓存一分钟,完整候选名单缓存五分钟,到期后后台更新。入口和列表共用同账号快照及进行中的读取,不因切换入口重读;显式刷新或标记变更使缓存失效。仍沿用单次 40 页/2,000 个候选上限;跨端登录不会同步已查看进度。
21
+
22
+ ## 后端后续建议(字段是建议,不是已上线接口)
23
+
24
+ 建议增加按当前登录账号授权的统一轻量目录摘要和查看游标:
25
+
26
+ 1. 摘要:deduplicated_total、unseen_count、snapshot_version、state、latest_change_cursor。总数与新增必须在同一身份合并规则和快照中计算。
27
+ 2. 稳定 person/identity key,以及 merged_into、split_from 或等效身份继承信息;新增事件采用首次识别入库序号,不使用录音发生时间或可重算的 first_seen_at。
28
+ 3. 查看确认:按已成功展示的 change_cursor 幂等确认,不以服务端收到请求的当前时间清除未来新增;离线、失败不推进游标。
29
+ 4. 明确跨端已读是否共享。建议同账号共享,但与录音消息已读分离;合并已看过的身份不产生新提醒,多个尚未查看身份合成一人时仅计一人。
30
+ 5. 列表返回与摘要一致的快照版本,并支持服务端 frequent/recent 排序;失败或构建中的摘要不得返回误导性的 0。
31
+
32
+ ## 验证
33
+
34
+ 覆盖总数合并去重、同名不合并、首次基准、累计新增、点开清除、稳定身份、跨账号隔离、重启与存储禁用、部分结果/失败、合并保守降级、本人置顶和三种声纹状态。只使用合成数据验证标记相关逻辑,不在真实账号执行标记或声纹录入。
35
+
36
+ ### 2026-09-28 本地验证结果
37
+
38
+ - 类型检查、构建通过;相关 23 个测试文件共 304 项通过。最终入口排版调整后,另复跑其中 3 个文件的 36 项,全部通过。
39
+ - 3100 独立预览已更新,产物与工作区构建结果一致;桌面客户端未改动,既有登录保持。
40
+ - 浏览器确认入口总数单行呈现、返回录音页后总数保留;切换两种排序时已标记本人均在首位。真实账号未制造新候选,新增提示及无本人引导使用合成数据验证。
41
+ - 初版浏览器打开列表时未标记接口返回 HTTP 429,页面保留已标记结果,并明确提示列表不完整。该次不能据此声称真实账号全量排序/新增统计均已验证。
42
+ - 读取路径核对:入口和列表分别执行候选分页扫描,进入列表会从第一页重读;每次最多 40 页。Host 页缓存仅 10 秒,第一页请求带 refresh。后端本地源码有投影读取每分钟 120 次、旧读取每分钟 20 次的限流;尚未确认线上命中的分支及阈值。重复扫描最可能放大了请求量,但不能断言是此次 429 的唯一原因。
43
+ - 用户确认后的收尾已实现:入口和列表共享读缓存;切换页面给予 250ms 请求交接窗口,无消费者时中止网络读取。成功分页保留五分钟,失败重试复用已读页;过期或后端报告游标失效时重建,不混用快照。
44
+ - 网络分页间隔至少 750ms。HTTP 429 等待至少 60 秒重试,连续失败指数退避,最多五分钟;其他读取失败从 15 秒开始退避。手动刷新不绕过退避。旧完整名单在后台刷新期间保留,新完整快照完成后整体替换;失败不清空列表,不把旧缓存当作本次新读取成功。
45
+ - 缓存只驻留当前页面运行内存,不写入录音或服务端资料。退出/切换账号清空快照并中止请求;晚到响应不得重新写入。标记操作后使相关读取失效。限流恢复不重试任何标记/写操作。
46
+ - 收尾新增 12 项自动测试,相关 24 个文件共 **316 项通过**,类型检查、构建和差异检查通过。覆盖入口与列表往返复用、进行中请求交接、失败分页续读、刷新不绕过退避、过期快照替换、账号清理、游标失效与自动恢复。
47
+ - 收尾浏览器验证:3100 真实账号完整呈现 **1,990 人**,完整加载后的状态提示和错误均为空;「最近出现」下本人仍优先于最近时间更新的其他候选。返回录音再进入名单后立即展示首批 100 行,无重新加载/不完整提示;总数仍为 1,990。测试后恢复「经常出现」排序。首次大名单扫描仍有等待,不能宣称解决了后端全局分页排序能力;新增提醒及限流自动恢复另由合成数据测试验证,未在真实账号制造新人或故意触发限流。
@@ -0,0 +1,51 @@
1
+ # 已识别说话人全历史统计
2
+
3
+ 本次延续用户指定的 dev 基线与任务 worktree。UI 布局、标记、搜索、筛选和导航保留;临时七天扫描替换为 Audio 全历史 owner。统计表示 system ASR 中已确认人物的出现,不能与声纹调用账本或授权目录混用。
4
+
5
+ | 能力面 | 接入方式 | 完成证据 |
6
+ | --- | --- | --- |
7
+ | UI | 既有已识别说话人列表与人物原始声音详情 | 原始布局实机验收;列表/详情统一全历史,版本变化刷新、非 fresh 数字隐藏、账号切换、卸载取消测试通过 |
8
+ | Tools | arkme_speaker_presence,只读列表/详情,不透明 Speaker 引用 | 正式 catalog/schema/grant 注册;官方未修改 DSH 0.1.5-rc.2 的真实 agent session 发现并调用成功 |
9
+ | SDK | recordingSpeakerCandidates/Presence/Members,speakerPresence capability,AbortSignal | 隔离安装 tgz 的仓外 Consumer,strict/NodeNext 编译执行;不支持 capability 与取消场景通过 |
10
+ | Host owner | RecordingService | UI/Tool/SDK 共用权限、账号绑定引用、字段校验与后端;服务测试和真实本地 Audio 联调通过 |
11
+
12
+ 无新增配置项、版本号修改或旧服务七天回退。不改变既有 OpenAPI 转写读取的 owner;新 Tool 只暴露本目录统计,不提供第二套转写/日历读取接口。
13
+
14
+ ## 验证
15
+
16
+ - Node 24.19.0;typecheck、build 通过。
17
+ - 全量:最终 dev `bcf37019` 合并后,811 个文件通过、11 个跳过;9,547 条测试通过、15 条跳过。
18
+ - `tests/consumers/speaker-presence-consumer.mts` 仅导入公开 SDK。Consumer 在仓外、含空格目录,以 strict/exactOptionalPropertyTypes/NodeNext 编译并执行。
19
+ - `tests/e2e/speaker-presence.e2e.mjs` 经正式 CLI 安装的 tgz,使用官方 DSH 的公开 boot fallback 和原测试 Scaffold。统计转发真实本地 Audio/Mongo,鉴权及其他无关上游为隔离桩;列表和详情都返回 2 天、原始声音 12;正式取消接口使统计减为 1 天,再经原候选 UI 确认标记恢复 2 天;正式 Audio 软删除后隐藏统计,恢复后重新显示 2 天。
20
+ - E2E 需要 `ARKME_DSH_CHECKOUT`、`ARKME_PACKED_PROFILE`、仅允许 127.0.0.1 的 `ARKME_AUDIO_E2E_ORIGIN`、测试 TLS key/cert 与固定种子账号。它不在默认单元测试中访问真实服务。
21
+ - DSH 源码、用户 Profile、常驻 DSH、插件版本、根 README 未修改。tgz 的旧 peer 自动安装在当前 registry 不完整,隔离安装关闭自动补齐 peer,并通过官方 `healProfilesModuleFallback` 接入运行时已有依赖;没有手写运行时软链或产品 fallback。
22
+
23
+ ## 运行边界
24
+
25
+ 后端先更新全部源写入进程及清理 cron,再发布本批插件。后端未就绪会显式失败,不返回近七天数据冒充全历史。统计版本校验为读取观察到的完整版本,不承诺数据库事务快照。
26
+
27
+ Audio 热读仍为 O(Child + 摘要桶),本地五次采样约 8,760 分片 130–206ms、52,560 分片 0.99–1.36s、525,600 分片 11.31–19.89s。不是 P95;高密度性能是发布前需按实际负载确认的边界,未宣称所有账号秒级。固定后端读取预算 25 秒,无新增配置开关。
28
+
29
+ 本次开发与修复已提交到任务开发分支并推送;未合并、创建 PR 或部署。正式发布前仍需实际环境容量验收。
30
+
31
+ ## 合并前复审(2026-09-28)
32
+
33
+ - 已同步 dev 的 AI points 改动(独立 SDK import/export 均保留),以及后续 `bcf37019` 的快记/群互动修复;后者自动合并无冲突,重新完成全量验证。
34
+ - 修复手动刷新未中止旧统计轮询的竞争,以及旧分页请求结束后误释放新请求的忙碌状态;原 UI 和交互入口不变。
35
+ - 真实写链路发现 Audio 取消例外字段 `qu` 未读取、候选确认只改轨道却未重新标记取消片段;两项在 Audio owner 修复,前端不伪造统计来补偿写入错误。
36
+ - E2E 种子由 Audio `tools/fixtures/speaker_presence_e2e.js` 提供,只可用于任务隔离 Mongo 测试库。页面测试需匹配本批 Audio 版本。
37
+ - 验收范围为 macOS Chrome、官方未修改 DSH 0.1.5-rc.2、正式安装的不可变 tgz;不据此声称 Windows/Linux 或生产环境已经验收。
38
+
39
+ 最新合并前容量复测:525,600 个 Child 串行 5 次读取为 10.27–10.92 秒;与本机其他测试并发时一次读取触发 25 秒截止。两者均非生产 P95。高密度及目标机器并发性能门禁仍未关闭,当前不能无条件建议上线合并。完整场景矩阵和五项审查修复记录在同任务 Meta 的合并前复审文档。
40
+
41
+
42
+ ## 原页面业务口径复核
43
+
44
+ 最近出现时间保持原交接和原临时统计的有效片段结束时间最大值;日期仍按录音本地开始日去重。Audio 摘要算法 3 修正了开发算法 2 曾使用开始时间的问题。原未标记卡片本就优先读取 latest_day_end_at,本轮不改其计算、排序或交互。插件产品代码没有额外修改,仅 E2E 增加列表/详情和取消、重标前后的精确结束时间断言。
45
+
46
+ 原不可变包连接修正后的真实本地后端,SDK、Tool 和 Chrome 页面完整链路通过(14.19 秒);相关 UI/服务测试 5 文件 / 131 条通过。高密度性能限制仍按上节保留。
47
+
48
+
49
+ ## 最终审核补充
50
+
51
+ 任务分支已合入 dev `8c48a6b8`(v0.1.83 来自上游),类型检查、完整测试 9,550 条、构建和打包通过。新不可变包在官方 DSH 原运行时连接本地 Audio 的 SDK、Tool 与页面写读链通过(18.17 秒),仓外 SDK Consumer 编译执行通过。本轮没有额外前端产品改动。Audio 修复单候选确认后的历史天数被最近六个展示日期截断的回归,并修正多候选日期并集;原 UI 操作入口与流程保持一致。高密度账号性能阻断仍未关闭。
@@ -0,0 +1,30 @@
1
+ # 已识别说话人排序
2
+
3
+ ## 交互
4
+
5
+ - 搜索框右侧提供「经常出现」「最近出现」;默认经常出现。
6
+ - 经常出现:出现天数降序,同天数按最近时间降序。
7
+ - 最近出现:最近时间降序,同时间按出现天数降序。
8
+ - 完全相同的统计按名称自然序和稳定引用排序;未知或失效统计不冒充 0 天。
9
+ - 全部、已标记、未标记共用规则,全部不再把已标记固定排在前面。后续本人置顶:账号确认归属的本人在全部/已标记筛选内优先,其余仍遵循排序;搜索和未标记筛选不额外插入本人。
10
+ - 选择按账号保存在当前 Web 源的 localStorage,不承诺跨端同步;筛选、搜索不重置选择。
11
+
12
+ ## 数据和分页
13
+
14
+ 已标记使用正式全历史 presence 统计。未标记目录额外透传已有的 appearanceDays、latestAtMillis 数值,禁止解析展示文案来排序。
15
+
16
+ 现有 Audio 未标记接口固定按 day_count、total_speech_duration_ms、last_seen_at 排序,无 sort 参数。插件串行读取列表元数据,不读取音频或逐人详情;补齐后才具有完整排序覆盖。读取中、失败、投影未就绪和游标版本变化均明确标识不完整;旧版本游标重启一次,取消或账号切换后忽略晚到结果。
17
+
18
+ 单次自动遍历最多 40 页、2,000 个未标记候选,与 Host 当前候选引用容量对齐。到达边界而仍有更多数据时保留「列表尚未完整」提示,不宣称全量排名。显示每批 100 行只是渲染限制,搜索和排序仍覆盖所有已加载记录。
19
+
20
+ 2026-09-28 补充共享读缓存:录音页入口与名单页共用分页和完整快照;失败保留已读取页面,限流退避后续读,不因反复进入页面从头发起全部请求。完整名单保留五分钟后后台更新,标记后失效重读。详见 `recognized-speaker-entry-and-visits.md`。
21
+
22
+ ## 后端后续能力
23
+
24
+ 大于上述边界或希望避免扫描全部元数据时,需要 Audio 列表正式提供服务端排序:frequent = day_count DESC、latest_day_end_at DESC、candidate_id ASC;recent = latest_day_end_at DESC、day_count DESC、candidate_id ASC。游标应绑定账号、投影版本、筛选及排序规则;切换排序不得复用旧游标。若提供统一的已标记/未标记轻量索引,可直接支持混合全局分页。当前插件没有发送未经支持的 sort 参数,也没有修改 Audio 服务。
25
+
26
+ ## 验证范围
27
+
28
+ 排序比较、本机记忆、全量元数据遍历、跨页最新人物、混合分类、搜索、分批渲染、游标失效、刷新竞争、取消、失败和读取上限均有自动测试。8 个相关测试文件共 154 项通过,类型检查、构建和差异检查通过。
29
+
30
+ 2026-09-28 在固定 3100 独立 Web 预览验证:两种排序均切换实际名单;已标记和未标记按统计混合排列;筛选、搜索可配合排序;刷新并重新进入后保留「最近出现」选择。测试后恢复「全部+经常出现」并清空搜索。当前账号分批加载结束后,加载及不完整提示均消失;大名单的加载等待仍依赖现有固定顺序分页接口,不能据此承诺首屏即获得完整最近排名。仅进行只读列表检查,未修改录音或说话人标记。
@@ -102,6 +102,14 @@ DELETE /me/self-roles/{roleId} -> { revision }
102
102
 
103
103
  本机角色资料的备份/迁移要与消息正文区分:现有正文在云端,本机角色展示元数据若卸载或清空对应本机数据可能丢失。跨端接口落地前不要将“登录同账号”宣传成能恢复角色资料。
104
104
 
105
+ ### 5.1 角色尚未同步时的头像兼容规则(2026-09-28)
106
+
107
+ - 当前端有该消息的本机角色快照:继续显示该角色头像(未设图片时使用角色文字头像),保留左侧角色排布。
108
+ - 普通「我」,或另一台设备尚未获得该消息的角色信息:优先使用**当前账号头像**,保留右侧排布。即使消息携带旧头像资产、失效图片地址或其他设备的本机头像引用,也不能让这些引用优先于可用的当前账号头像。
109
+ - 上述规则统一覆盖「发给自己」、个人主题内的消息列表、消息详情及本人延展回复;不替换其他作者或私聊群聊的头像。不增加“当前资料”等提示文案。
110
+ - 这是显示层回退,不是角色同步。不得把回退得到的账号头像写成角色历史快照,不得清除本机角色绑定。未来云端角色快照回填成功后,其他端再按真实角色信息展示。
111
+ - 当前账号资料尚未加载时可暂用记录已有头像;资料到达后自动切到账号头像。账号本身没有设置头像或网络无法读取头像时,仍使用既有默认显示,不能伪造头像。
112
+
105
113
  ## 6. 联调验收
106
114
 
107
115
  1. A 端建角色并设头像,B 端在线时及时出现;B 端断网后重连也能补齐,账号 C 绝不可读。
@@ -112,6 +120,7 @@ DELETE /me/self-roles/{roleId} -> { revision }
112
120
  6. 列表、详情、搜索、分页、刷新和重新登录的展示一致;角色消息仍由真实账号拥有,不生成自发未读/通知。
113
121
  7. 本机旧数据迁移后的消息条数不变,逐条核对快照及头像;冲突有可审计结果。
114
122
  8. 迁移前已删除的角色、直接在详情页发送的延展、多个独立本机目录分别导入后,其他端均按各条消息发送时的角色显示;断网重试和重复导入不改写快照。
123
+ 9. 同步接口上线前:A 的本我消息显示当前账号头像,A 的角色消息保留角色头像;B 无对应角色信息时统一显示当前账号头像。列表、详情、延展回复一致;回退前后本机角色绑定及历史快照保持不变。
115
124
 
116
125
  ## 7. 请后端同事优先确认
117
126