@xdxer/dingtalk-agent 0.1.5-beta.1 → 0.1.5-beta.10

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 (175) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/README.en.md +99 -66
  3. package/README.md +99 -66
  4. package/dist/bin/dingtalk-agent.js +735 -149
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +3 -2
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +202 -85
  9. package/dist/src/agent-audit.js.map +1 -1
  10. package/dist/src/agent-definition.js +7 -3
  11. package/dist/src/agent-definition.js.map +1 -1
  12. package/dist/src/agent-enhance.js +51 -32
  13. package/dist/src/agent-enhance.js.map +1 -1
  14. package/dist/src/agent-platform.js +3 -3
  15. package/dist/src/agent-platform.js.map +1 -1
  16. package/dist/src/bootstrap.js +6 -2
  17. package/dist/src/bootstrap.js.map +1 -1
  18. package/dist/src/development-workspace.js +210 -34
  19. package/dist/src/development-workspace.js.map +1 -1
  20. package/dist/src/doctor.js +65 -9
  21. package/dist/src/doctor.js.map +1 -1
  22. package/dist/src/dws.js +67 -3
  23. package/dist/src/dws.js.map +1 -1
  24. package/dist/src/init.js +2 -1
  25. package/dist/src/init.js.map +1 -1
  26. package/dist/src/memory/noop-receipt.js +306 -0
  27. package/dist/src/memory/noop-receipt.js.map +1 -0
  28. package/dist/src/memory/operational.js +27 -3
  29. package/dist/src/memory/operational.js.map +1 -1
  30. package/dist/src/memory/remote-state.js +2 -1
  31. package/dist/src/memory/remote-state.js.map +1 -1
  32. package/dist/src/multica-deploy.js +692 -125
  33. package/dist/src/multica-deploy.js.map +1 -1
  34. package/dist/src/multica-provider.js +303 -25
  35. package/dist/src/multica-provider.js.map +1 -1
  36. package/dist/src/multica-runtime-vocabulary.js +110 -0
  37. package/dist/src/multica-runtime-vocabulary.js.map +1 -0
  38. package/dist/src/opencode-evals.js +6 -6
  39. package/dist/src/opencode-evals.js.map +1 -1
  40. package/dist/src/opencode-provider.js +21 -7
  41. package/dist/src/opencode-provider.js.map +1 -1
  42. package/dist/src/opencode-workspace.js +3 -3
  43. package/dist/src/opencode-workspace.js.map +1 -1
  44. package/dist/src/personal-event-evals.js +4 -2
  45. package/dist/src/personal-event-evals.js.map +1 -1
  46. package/dist/src/promotion.js +2 -1
  47. package/dist/src/promotion.js.map +1 -1
  48. package/dist/src/remote-semantic-state-live-evals.js +14 -8
  49. package/dist/src/remote-semantic-state-live-evals.js.map +1 -1
  50. package/dist/src/remote-state-evals.js +2 -2
  51. package/dist/src/remote-state-evals.js.map +1 -1
  52. package/dist/src/robot-evals.js +3 -3
  53. package/dist/src/robot-evals.js.map +1 -1
  54. package/dist/src/schedule-plan.js +380 -0
  55. package/dist/src/schedule-plan.js.map +1 -0
  56. package/dist/src/sessions.js +1 -1
  57. package/dist/src/sessions.js.map +1 -1
  58. package/dist/src/skill-manager.js +145 -13
  59. package/dist/src/skill-manager.js.map +1 -1
  60. package/dist/src/skills.js +2 -0
  61. package/dist/src/skills.js.map +1 -1
  62. package/dist/src/tui.js +369 -0
  63. package/dist/src/tui.js.map +1 -0
  64. package/dist/src/upgrade.js +113 -33
  65. package/dist/src/upgrade.js.map +1 -1
  66. package/dist/src/waits.js +2 -1
  67. package/dist/src/waits.js.map +1 -1
  68. package/dist/src/workspace.js +12 -7
  69. package/dist/src/workspace.js.map +1 -1
  70. package/docs/AGENT-IN-PRODUCTION.md +255 -0
  71. package/docs/ARCHITECTURE.md +165 -31
  72. package/docs/INSTALLATION.md +7 -7
  73. package/docs/PLATFORM-GUARDRAILS.md +188 -0
  74. package/docs/PRIOR-ART.md +4 -0
  75. package/docs/SELF-TEST.md +4 -4
  76. package/docs/architecture/agent-platform-connection-layer.svg +120 -0
  77. package/docs/architecture/digital-employee-composition.svg +92 -0
  78. package/docs/architecture/dingtalk-agent-architecture.svg +125 -0
  79. package/docs/assets/digital-employee-at-work.svg +77 -0
  80. package/docs/schemas/multica-deployment-plan.schema.json +3 -1
  81. package/docs/schemas/multica-deployment-receipt.schema.json +17 -3
  82. package/docs/schemas/multica-deployment-status.schema.json +6 -2
  83. package/docs/schemas/multica-workspace-inspection.schema.json +16 -0
  84. package/docs/schemas/multica-workspace-run-plan.schema.json +31 -0
  85. package/docs/schemas/multica-workspace-run.schema.json +161 -0
  86. package/docs/schemas/multica-workspace-status.schema.json +2 -0
  87. package/docs/schemas/project.schema.json +54 -3
  88. package/docs/schemas/workspace-scaffold.schema.json +38 -0
  89. package/examples/agents/README.md +10 -8
  90. package/examples/agents/fde-coach/AGENTS.md +2 -34
  91. package/examples/agents/fde-coach/agent/AGENTS.md +35 -0
  92. package/examples/agents/fde-coach/agent.bindings.json +10 -0
  93. package/examples/agents/release-manager/AGENTS.md +2 -34
  94. package/examples/agents/release-manager/agent/AGENTS.md +35 -0
  95. package/examples/agents/release-manager/agent.bindings.json +10 -0
  96. package/lab/agent-eval/catalog.json +5 -5
  97. package/lab/agent-eval/classic-failures.json +4 -4
  98. package/lab/agent-eval/completion-gate-regression.json +9 -9
  99. package/lab/agent-eval/personal-event-live.example.json +3 -3
  100. package/lab/agent-eval/remote-semantic-state-live.example.json +1 -1
  101. package/lab/agent-eval/workspace/opencode.json +2 -2
  102. package/lab/project-workspace/fake-multica-provider.mjs +171 -17
  103. package/lab/project-workspace/multica-deploy.fixture.json +2 -2
  104. package/lab/project-workspace/multica-readonly.fixture.json +4 -16
  105. package/lab/project-workspace/opencode-provider-suite.json +3 -3
  106. package/lab/project-workspace/project.fixture.json +2 -6
  107. package/lab/robot-eval/suite.json +1 -1
  108. package/lab/robot-eval/workspace/AGENTS.md +1 -1
  109. package/lab/robot-eval/workspace/opencode.json +2 -2
  110. package/lab/schemas/personal-event-eval.schema.json +1 -1
  111. package/package.json +12 -9
  112. package/skills/README.md +10 -8
  113. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/SKILL.md +48 -23
  114. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/AGENTS.template.md +1 -1
  115. package/skills/core/dta-agent-compose/assets/REPOSITORY.template.md +10 -0
  116. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/agent.bindings.dingtalk-doc.template.json +2 -2
  117. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/agent.bindings.local.template.json +2 -2
  118. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/hosts/opencode/opencode.template.json +3 -2
  119. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/evals/evals.json +4 -4
  120. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/agent-definition-contract.md +7 -7
  121. package/skills/core/dta-agent-compose/references/drive-and-schedules.md +166 -0
  122. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/host-loading-contract.md +11 -13
  123. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/hosts/claude-code.md +13 -12
  124. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/hosts/opencode.md +14 -13
  125. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/SKILL.md +2 -2
  126. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/assets/eval-catalog.template.json +1 -1
  127. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/evals/evals.json +1 -1
  128. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/eval-topology.md +3 -3
  129. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/interactive-debug-channels.md +10 -4
  130. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/SKILL.md +21 -5
  131. package/skills/core/dta-basic-behavior/references/event-to-behavior.md +38 -0
  132. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/memory-and-evolution.md +3 -1
  133. package/skills/core/dta-basic-behavior/references/perception-and-gates.md +87 -0
  134. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/risk-authority-and-privacy.md +12 -0
  135. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/truth-and-recovery.md +4 -2
  136. package/skills/core/dta-people-group-memory/COMPLETENESS.md +36 -0
  137. package/skills/core/dta-people-group-memory/SKILL.md +69 -0
  138. package/skills/core/dta-people-group-memory/references/adapters.md +273 -0
  139. package/skills/core/dta-people-group-memory/references/assembly-guidance.md +40 -0
  140. package/skills/core/dta-people-group-memory/references/binding.md +110 -0
  141. package/skills/core/dta-people-group-memory/references/cold-start.md +70 -0
  142. package/skills/core/dta-people-group-memory/references/config-binding.md +89 -0
  143. package/skills/core/dta-people-group-memory/references/consent-and-visibility.md +83 -0
  144. package/skills/core/dta-people-group-memory/references/consolidation.md +162 -0
  145. package/skills/core/dta-people-group-memory/references/event-ingest.md +103 -0
  146. package/skills/core/dta-people-group-memory/references/guided-setup.md +70 -0
  147. package/skills/core/dta-people-group-memory/references/model.md +148 -0
  148. package/skills/core/dta-people-group-memory/references/storage-port.md +107 -0
  149. package/skills/platforms/deap/PLATFORM.md +30 -1
  150. package/skills/platforms/multica-dingtalk/PLATFORM.md +34 -8
  151. package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/SKILL.md +10 -8
  152. package/skills/platforms/multica-dingtalk/dta-deploy-multica/references/multica-deployment-contract.md +67 -0
  153. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/SKILL.md +81 -11
  154. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/scripts/bootstrap.sh +2 -2
  155. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/scripts/multica_ext.py +264 -16
  156. package/docs/assets/agent-delivery-lifecycle.svg +0 -103
  157. package/skills/core/dingtalk-basic-behavior/references/event-to-behavior.md +0 -24
  158. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +0 -28
  159. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +0 -40
  160. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +0 -49
  161. /package/examples/agents/fde-coach/{skills → agent/skills}/fde-coach/SKILL.md +0 -0
  162. /package/examples/agents/release-manager/{skills → agent/skills}/release-manager/SKILL.md +0 -0
  163. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/role-skill.template.md +0 -0
  164. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/storage-routing.md +0 -0
  165. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/evidence-contract.md +0 -0
  166. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/failure-to-case.md +0 -0
  167. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/local-connector-smoke.md +0 -0
  168. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/scenario-taxonomy.md +0 -0
  169. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/storage-modes.md +0 -0
  170. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/memory-candidate-proposal.json +0 -0
  171. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/task-checkpoint.json +0 -0
  172. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/action-contract.md +0 -0
  173. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/runtime-modes.md +0 -0
  174. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/task-lifecycle.md +0 -0
  175. /package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/references/promotion-observation-contract.md +0 -0
@@ -0,0 +1,83 @@
1
+ # 用户侧的感知与选择 —— 别让人在不知情的情况下被建档
2
+
3
+ 开发者在装配时选了这个能力,**不等于**被记录的同事同意了。这一层解决:**真实使用中,人怎么知道 Agent 在记、怎么看到记了什么、怎么让它别记。**
4
+
5
+ 没有这一层,这个能力就是"背着人建档案"。
6
+
7
+ ## 一、首次启用:三条铁律
8
+
9
+ 1. **不在上线时问。** 上线就弹一句"我要开始记住大家了吗",用户既没有上下文也没有判断依据,只会随手同意或随手拒绝。
10
+ 2. **先默默只读探测,直到真的有东西要记。** 在此之前不建任何目录、不写任何页、不提任何事。
11
+ 3. **提议只作正事收口后的尾句,不占用"问一个问题"的额度,用户不回答即不启用。** 这个能力永远不该阻塞用户当前真正要办的事。
12
+
13
+ ## 二、提议怎么说:三件套
14
+
15
+ 提议必须同时给出这三样,缺一样用户就没法判断:
16
+
17
+ 1. **这次具体要记的那一条**(原文或贴近原文的一句),不是抽象描述
18
+ 2. **人话说清落点与可见范围**:存在哪个文档、谁能看到
19
+ 3. **反悔成本**:怎么让它别记、已经记的怎么删
20
+
21
+ 参考措辞:
22
+
23
+ > 顺带一句——你刚说的「周会前同步方案,周四之前」这类约定,我可以记进一份长期档案,下次你提起这事我就能接上。档案存在你的「XX 知识库」里,只有你和我能看到,你随时可以让我删掉或者整个关掉。要开吗?不用回也行,不回我就不记。
24
+
25
+ 🔴 **不许用的措辞**:不要说"为了更好地服务你"、不要说"这会让我更懂你"——这是把一个隐私决策包装成好处。就说要记什么、存哪、谁能看、怎么撤。
26
+
27
+ ## 三、未启用态:禁用一切"我记住了"
28
+
29
+ 落点未配置 / 用户没启用 / 判定为 `read-only` 时:
30
+
31
+ - ❌ 不许说"我记住了""我记下了""下次我会记得"
32
+ - ✅ 可以说"我这次记着,但没有长期档案"
33
+
34
+ 这条很重要:用户听到"我记住了"就会停止重复交代。如果实际上没落盘,下次 Agent 完全不记得,**用户会认为 Agent 在骗人**——而且他会到那时候才发现。
35
+
36
+ ## 四、首次落盘之后:念一遍 + 给口子
37
+
38
+ 第一次真的写进档案后,**回读并把写进去的内容原样念给用户**,再给一个可点的文档链接:
39
+
40
+ > 记好了,写进去的是这两条:
41
+ > · 周会前同步方案(约定,截止 2026-07-24)
42
+ > · 回复偏好:结论先行、带日期口径
43
+ > 档案在这里 <链接>,你可以直接打开看、改,或者让我删。
44
+
45
+ **只念第一次。**之后每次沉淀都念会变成噪音,用户会开始忽略它——那就等于又回到了不知情。
46
+
47
+ ## 五、"你记了我什么" —— 必须能答,且只答属于他的
48
+
49
+ 任何人问起,都要能立刻答上来。规则:
50
+
51
+ - 回答**他本人**:他自己那份档案里的内容不受限,包括 A1。**给可点链接,让他自己看原文**,不要只给你的转述。
52
+ - 回答**第三方**:只给 A3 中性事实。引用条目的〔源〕圈子不含提问者 → **拒答**,直说"这我不方便讲",不要编一个模糊版本。
53
+ - 无论对谁:**不展示任何介质地址、内部 ID 或维护过程**(用户可见链接的锚点是 `(subjectKey, section, evidenceId)` 三元,不含物理位置)。
54
+ - 区分**事实 / 归纳 / 建议**。档案里的结论是 Agent 的归纳,不是他本人或别人的原话——`(编译推演)` 的条目要说明是自己推的。
55
+
56
+ ## 六、"别记了" —— 分层处理,不要一句话糊过去
57
+
58
+ 用户说"别记这个""忘掉""以后别记我了"时,先把它拆开:
59
+
60
+ | 用户可能是什么意思 | 立刻能做的 | 不能立刻声称的 |
61
+ |---|---|---|
62
+ | 这条别用 | 本 Run/Session 停止使用 | ——(这条当场就能兑现) |
63
+ | 以后都别用这条 | 写 tombstone(范围+要求人+日期,**绝不复述被删内容**),每次 ingest 前先读并跳过 | "已经彻底删了" |
64
+ | 整个别记我 | 该对象转 `paused`,停止一切写入 | "所有地方都删干净了" |
65
+ | 把已有的删掉 | 提出删除动作、执行后回读 | 没有回读证据前不说"已删除" |
66
+
67
+ 🔴 **原始层只增不删是底线**,遗忘请求也不能破坏它——改为写 tombstone,不静默篡改历史。
68
+ 🔴 **平台历史、文档版本、别人已经看到的内容不是你的语义记忆**,不得承诺"所有地方都已删除"。
69
+
70
+ ## 七、随时可关
71
+
72
+ 用户说"把这个功能关了"时:
73
+
74
+ 1. 该对象或全局转 `paused`,**立刻停止一切写入**,本 Session 生效。
75
+ 2. 已落盘内容**不自动删除**——那是用户的文档,删不删由用户决定。明确告诉他档案还在哪、他可以自己删或让你删。
76
+ 3. 需要彻底移除能力(从 `agent.skills` 摘掉)时告诉用户这要走一次受控发布,不是一句话的事;发布前最后一次运行在落点顶部写一行「本档案由 &lt;Agent 名&gt; 维护至 &lt;日期&gt;,此后不再更新」。
77
+
78
+ ## 八、可机械验收
79
+
80
+ 1. 未启用态的全程 trace **零写调用**,且回复文本不得出现"我记住了 / 记下了 / 下次会记得"。
81
+ 2. 同一对象第二轮**不再出现**启用提议文本(提议账本命中)。
82
+ 3. 首次落盘后的那条回复里**必须**包含回读到的条目原文与一个文档链接。
83
+ 4. 对第三方提问,引用条目〔源〕圈子不含提问者时必须拒答。
@@ -0,0 +1,162 @@
1
+ # 消化-编译流水线 —— raw 只增前提下的近期/长期压缩
2
+
3
+ 跑一年会怎样:raw 只增,一年后一个密切同事的 `interaction` 上千行、一个活跃群的 `conventions` 过百条。而 `doc read` 在 ~341 行 / 31.9KB **静默截断**(`success:true`、无 truncated 字段)。**不做消化,编译层从某月起就在读被切尾的 raw 重建结论,画像静默失真、没有任何报错。**
4
+
5
+ 本篇在 raw 与 derived 之间插一层 **digest(月度消化缓存)**,把编译成本从 `O(全历史)` 压到 `O(当月增量 + 有界 digest)`。三条承诺:**raw 永不删、封存的月永不被再读、回答"这人是谁/什么状态"永远只读固定几页。**
6
+
7
+ ---
8
+
9
+ ## 0. 地基:完整性靠计数,不靠介质自报(load-bearing)
10
+
11
+ 🔴 **整套机制的正确性都押在这一条上,先立它,其余才成立。**
12
+
13
+ 问题:消化要"把一整月 raw 读回来压成 digest",但生产介质的 `doc read` 被截断时**不报错**。若信 `success:true`,就会把被切尾的半个月封存成 digest,尾部事实永久丢失——而且每实体每月都发生一次。`read.completeness` 这个能力位在生产适配器上因此是 no-op。
14
+
15
+ 修法:**写侧记数,读侧对账。**
16
+
17
+ - 每次 `appendFacts(subject, section, facts)` 成功后,在 meta 里累加 `count:(subject, section, partition)` += 已确认写入的条数。
18
+ - 封月或全量读时,`readFacts` 返回的条数必须 **等于** meta 里记录的条数,才判 `complete=true`。
19
+ - 不等 → `complete=false` → 记欠账、水位不动、**倒逼适配器把该分区切到读墙以下再重试**(见 §8)。
20
+
21
+ 计数本身存在 meta 键空间(每分区一行、按主键哈希桶分片、自身有界),它不经过那堵会截断的读墙。这就是 `read.completeness=verified-partial` 的**具体实现**,不是新增能力位。
22
+
23
+ ---
24
+
25
+ ## 1. 分层保留(热 / 温 / 冷)
26
+
27
+ | 层 | section | 大小上限 | 重编频率 | 编译读谁 |
28
+ |---|---|---|---|---|
29
+ | **热(近期)** | 当月 raw 分区 + 全部 live derived 视图(identity/working-on/collaboration/public-facts;群 charter/conventions/roster) | 当月 raw ≤300 行/分区;每视图 <17KB(<70% 的 24KB 墙) | 有新料的夜间增量重编 | 当月 raw delta + digest |
30
+ | **温(月度消化)** | 每个 raw 家族一个 digest 视图:`interaction-digest` / `activity-digest` / `chronicle-digest` | 每月 block ≤8 行;整视图逼近 70% 墙就年折叠 | 封月时一次,之后只读 | 该月 raw(一次,count 对账) |
31
+ | **冷(稳定特质)** | identity/collaboration 的稳定特质、年度 epoch 折叠块、conventions/public-facts 的 curated 投影 | 各 <17KB | 月度,或视图逼近 70% 墙时折叠 | digest + 当月 raw |
32
+
33
+ 热层 raw **按月物理滚页**,当月分区天然有界。超活跃 `activity` 单月仍 >341 行时,适配器降到按周分区(内部策略)——但**是否真滚页由 count 对账兜底**:没滚到墙下,封月就判 `complete=false`,不会静默切尾。
34
+
35
+ ---
36
+
37
+ ## 2. 消化 = 封月,可撤销,不是删除
38
+
39
+ **封月(seal)**:某月完全过去、且 ingest 水位 ≥ 月末 + grace 后,对该月 raw 消化一次:
40
+
41
+ 1. `readFacts(range=该月)` 读回 → **count 对账**(§0)。不 `complete=true` 就停:记欠账、水位不动。
42
+ 2. 按 salience(§6)产出该月 digest block:≤8 行,每行携 `[occurredAt 区间, firstEvidenceId, lastEvidenceId]`。
43
+ 3. `putView` 追加进 `*-digest` → `confirm` → 才推进 digest 水位到月末。
44
+
45
+ **digest 是缓存,raw 是 ground truth**:digest 的每一行都能凭内嵌 evidenceId drill-down 回 raw 原件;digest 损坏可从不可变的封存月 raw 重新封。这满足端口不变式「View 里不得存在唯一信息」。封月后该月 raw 进入"归档、可 drill-down、不进工作集",编译层从此只读 digest。**这就是 raw 只增的泄压阀——raw 无限长,编译读取面恒定。**
46
+
47
+ 🔴 **封月必须可撤销(迟到 raw)**:文档/待办通道可能迟到,一条 `occurredAt` 落进已封月。ingest 写入 `occurredAt < digest 水位` 的 raw 时,**把对应月标脏、允许对已封月追加"补充 block"并触发 re-seal**(reseal 产新版 digest 并 supersede 旧版,不改原件)。封月不是一次性焊死,否则迟到数据永久不被编译。
48
+
49
+ ---
50
+
51
+ ## 3. 有界工作集(O(1),与运行时长无关)
52
+
53
+ 回答"这人是谁 / 什么状态",只读这几页,**页数与系统跑了几年无关**:
54
+
55
+ **Person(5 + 1 可选)**:identity · working-on · collaboration · public-facts · interaction-digest · (可选)当月 interaction raw
56
+ **Conversation(4 + 1 可选)**:charter · conventions(curated) · chronicle-digest · roster · (可选)当月 chronicle raw
57
+
58
+ 每页都是单个有界 View 或单个当月分区,**都 <341 行**,单次读装得下。全历史 drill-down 是按 evidenceId 定位单月 raw 的**按需旁路**,不进工作集。
59
+
60
+ ---
61
+
62
+ ## 4. 编译水位与 digest 水位(增量,不全量)
63
+
64
+ 复用 `(subject, channel)` meta 键空间,加两个 channel(只是键命名,非能力位):
65
+
66
+ - `watermark:(subject, compile)` = live 视图已折进的最后 occurredAt
67
+ - `watermark:(subject, digest)` = 已封存的最后一个月
68
+
69
+ 规则:
70
+ - **只重编有新料的**:`ingest 水位 > compile 水位` 才重编,且只读 `(compile 水位, now]` 的当月 raw delta + 现有 digest,**不读封存月 raw**。
71
+ - **只消化刚封月的**:一个月只封一次。
72
+ - 🔴 **seal 必须触发 compile**:某实体封月后可能再无新 im 事件(变安静),若 compile 只靠 `ingest>compile` 触发,该实体永远不吸收封存月里升进的稳定事实。**seal 完成即 enqueue 一次该 subject 的 compile**,不依赖 ingest 水位。
73
+ - 🔴 **范围算术不重叠**:compile 对 `[.., digest 水位]` 只读 digest block、对 `(digest 水位, now]` 读 raw。compile 水位落后于 digest 水位时,必须先吸收对应 digest block,不得同区间既读 raw 又读 digest(否则双主、重复计入)。
74
+ - 因果沿用不变式:**先写视图/digest、后推水位**;任一步失败水位不动、下轮 evidenceId 幂等重放。
75
+
76
+ 于是 70 实体的夜间维护恒为「当日增量 + 至多一个刚封的月」,**全量重读越墙 raw 这个致死操作从主路径消失**。
77
+
78
+ 🔴 **错峰封月**:按每实体自身的安静窗封月,不按全局日历月初——否则 70 实体在月初同一窗口各做一次全月至墙读,惊群。
79
+
80
+ ---
81
+
82
+ ## 5. decay(working-on 老化)
83
+
84
+ `working-on` 是时效性 derived。每条记 `lastSeen`(最近支撑证据的 occurredAt);`now - lastSeen > W`(如 21 天未刷新)则**从视图退场**:
85
+
86
+ - **证据留在 raw**:对应原件一条不删,drill-down 仍可查。
87
+ - **结论退出工作集**:working-on 是 derived、可重建,退场不需 supersede、不写 tombstone——只是本轮编译不再纳入。
88
+ - 退场前若已固化为稳定职责(见 §6 确定性阈值),**升迁**到 collaboration 而非蒸发。
89
+
90
+ 结果:working-on 永远只装"当前真在推",不对第三方播报已交付/放弃的僵尸条目。
91
+
92
+ ---
93
+
94
+ ## 6. salience:确定性升迁 + LLM 只管 gist
95
+
96
+ 🔴 这里是对抗检验抓到的关键裂缝:§2 承诺"digest 损坏可从 raw 重封得同一结果",但如果"什么升进 identity"靠 LLM 打分,重封不可复现,承诺破产。
97
+
98
+ **切开两件事**:
99
+
100
+ - **升进稳定层(identity/collaboration/public-facts)用确定性阈值**,在 raw 里可确定性重算:频次 ≥N、`provenance==agreed`、audience 标记(A3/A2 才可进 public-facts)、或明确"改变了以后对这个人的预期"。这些不依赖 LLM 判断。
101
+ - **月度 digest 的 gist 措辞允许 LLM**——但它是"封月一次性打分并**冻结**",之后只读不重判。gist 的错不影响稳定层(稳定层走确定性阈值),只影响那一行摘要的可读性。
102
+
103
+ 🔴 **稳定层单调粘滞**:进了 identity/collaboration 的条目,**只能被 raw 里显式 supersede 才退场**,不能因为某晚 LLM 没再选中就消失(否则稳定性倒挂 flicker)。热层每晚只增量吸收新升迁,不重新裁决旧升迁。
104
+
105
+ 三分类(封月时):升进稳定层 / 进 digest(月度摘要行)/ 只留 raw 归档(寒暄、一次性、机器抄录明细、被 supersede 的旧值——凭 evidenceId 可查,不占编译面)。**近期高细节、久远折叠成一行。**
106
+
107
+ ---
108
+
109
+ ## 7. 修 `derived·只增` 矛盾:derived 永远可 curate
110
+
111
+ 🔴 **这是 model.md 的一个建模错误**:`conventions` / `public-facts` 标了 `derived·只增`。`derived` 的定义是"可整体重建","只增"却禁止 curate——于是它可重建却无泄压阀,一年后过百条越过 341 行、fail-open。
112
+
113
+ **改正:只有 raw 是只增。derived 永远可 curate。** conventions/public-facts 的"只增"是**语义保证**(一条仍生效的约定不会静默消失),不是字节布局承诺。因为 ground truth 在 raw(chronicle/interaction),curate 可复现即合法:
114
+
115
+ - **去重**:同一约定重复达成 → 合并一行,保留首次拍板日 + reaffirm 次数。
116
+ - **合并**:窄规则并入广规则,narrower 的 evidenceId 挂进合并行锚点。
117
+ - **退 superseded**:被明确推翻的约定移出 active 视图(supersede 链在 raw chronicle 里),视图尾留 drill-down 计数("另有 N 条已废止,可查")。
118
+ - **红线**:绝不丢一条仍生效的约定;每次收缩必须有 raw 里可追溯的 supersede/retire 依据;curate 后回读校验。
119
+
120
+ curate 读的是 digest + 当月 raw(非全量),所以 public-facts/conventions 恢复了"可负担且可靠地重建"——正是原病理里最先塌缩的东西。
121
+
122
+ ---
123
+
124
+ ## 8. 并发与幂等(无 CAS 的现实)
125
+
126
+ 🔴 生产介质无 CAS,`putView` 追加(§2)与年折叠/curate 的整视图重写(§7)并发会互相 clobber。设计不能押在"每 subject 只有一个串行夜间维护"这个从未声明的假设上:
127
+
128
+ - **单写者租约**:meta 里放一个 per-subject lease;维护前取租约,取不到就跳过本轮(不阻塞)。
129
+ - **建页幂等**:首次为 `*-digest` 建页,走"按稳定 id check-exists → adopt-existing",**绝不 name-based 盲建**——否则 create 与推水位之间崩溃、重试再建同名页 → `(1)` 孪生 → readView 命中错误那份。
130
+ - **整视图重写强制 `--content-file` + 回读断言字节数**:curate/fold 逼近 17KB 的视图整体重写,若正文偏 ASCII 会越 1 万字符单写墙;把部分写暴露成显式失败。
131
+
132
+ ---
133
+
134
+ ## 9. 端口层面:不新增能力位
135
+
136
+ 现有 10 操作 + 8 位够用:
137
+
138
+ - **digest 视图** = derived section → 复用 `putView`/`readView`。
139
+ - **raw 按月/按周滚页** = 适配器内部分区,归 `read.completeness` + `limits.*`,模型层只调 `readFacts(range=月)`。
140
+ - **compile/digest 水位、count 计数** = `metaGet/metaPut` 的新键,channel/key 是命名空间不是能力位。
141
+ - **count-based 完整性** = `read.completeness=verified-partial` 的具体实现(§0),不是新位。
142
+
143
+ 准入规则检验:8 位已满,本流水线不产生"需同时改变 ≥2 适配器行为"的新语义——`local-md`(`read.completeness=exact`、∞ 容量、有原子 rename)上封月/digest 退化为纯优化、正确性不依赖它;`dingtalk-doc` 上才真正吃到有界工作集的收益。**不新增位。** 新增的全是模型层约定(digest section、水位 channel、count 键、salience/decay/curate 规则),落在既有端口形状内。
144
+
145
+ ---
146
+
147
+ ## 10. 不变式对账 + 做不到什么
148
+
149
+ | 不变式 | 对账 |
150
+ |---|---|
151
+ | raw 只增 | 封月不删 raw,digest 是旁路缓存,drill-down 永远回得去 ✓ |
152
+ | 写后回读 | 封月/curate/重编均 confirm(含 count 对账)后才推水位 ✓ |
153
+ | 读失败≠不存在 | count 对账把静默截断变成显式 `complete=false` → 记欠账,绝不写成空 digest ✓(**前提是 §0 落地,否则本条被击穿**)|
154
+ | 先写后推水位 | compile/digest 水位严格后于视图落盘 ✓ |
155
+
156
+ **做不到什么(诚实清单)**:
157
+
158
+ - **count 对账依赖写侧计数不丢**。若某次 append 的 count 累加自己失败或被并发 clobber,对账会假阴(永远判不完整、卡住该月)。计数键必须和它保护的 section 同一个租约下原子推进。
159
+ - **digest 的 gist 措辞是 LLM 软界**,`≤8 行`不是介质硬保证。年折叠触发必须按"测量视图字节逼近 70% 墙"而非"满 12 个 block",并在折叠前后做 block 计数断言。
160
+ - **稳定层的"确定性阈值"需要真的可确定性重算**——频次/provenance/audience 都在 raw 里,但"改变了以后对这个人的预期"这条仍是判断。把它降级为"辅助信号",硬升迁只认前三个可算的。
161
+ - **迟到 raw 的 re-seal 有成本**:一个总迟到的通道会让某月反复 re-seal。应对:re-seal 有冷却窗(如同月 24h 内合并多次迟到再统一 reseal)。
162
+ - **本机制尚无实现,也未在 `local-md --chaos` 上验证**。count 对账、单写者租约、错峰封月这些都只是契约;chaos 档必须注入"静默截断 + 计数对不上 + 并发双写"才能证明它真的接住。
@@ -0,0 +1,103 @@
1
+ # 事件 ingest —— 各类事件怎么变成 Fact
2
+
3
+ 输入是**事件**,输出是 `model.md` 定义的 Fact。本篇不碰存储,只碰"这个事件说明了什么、值不值得留、归给谁"。
4
+
5
+ ## 一、两种驱动方式,同一套映射
6
+
7
+ | 驱动 | 何时 | 用途 |
8
+ |---|---|---|
9
+ | **推送(event-driven)** | 可信 IM 事件到达(单聊消息、群 @、群消息) | 常态。事件里已带 actor / conversation / 稳定消息标识,**不需要轮询** |
10
+ | **拉取(poll)** | 会话收口时、明确指令时、批量追平时 | 补推送拿不到的渠道(待办、文档),以及补账 |
11
+
12
+ 两者**产出同样的 Fact、用同样的 `evidenceId`**,所以推送与拉取重叠时天然幂等,不会双写。
13
+
14
+ ## 二、事件类型 → Fact 映射表
15
+
16
+ ### IM 消息事件
17
+
18
+ | 事件 | 归给谁 | section | 判据 |
19
+ |---|---|---|---|
20
+ | 单聊消息 | 对方 Person | `interaction` (raw) | 蒸馏后写,不逐条抄 |
21
+ | 群消息(成形议题) | Conversation | `chronicle` (raw) | ≥3 人参与或 ≥5 条往返才算成形 |
22
+ | 群里公开达成的口径 | Conversation | `conventions` | 必须是**公开达成**,不是某个人的主张 |
23
+ | 引用/回复边 | 双方 Person | `activity` | 互动强度信号,两端都用稳定人标识 |
24
+ | 群改名/群主变更/规模跨档/装新自动化 | Conversation | `chronicle` | 群生命事件 |
25
+ | 成员加入/退出 | Conversation | `roster` | 派生层,可整体重拉 |
26
+
27
+ ### 待办事件
28
+
29
+ | 事件 | 归给谁 | section |
30
+ |---|---|---|
31
+ | 认领/被指派/参与一个待办 | Person | `activity` (raw),三元 = 待办主键 + 角色 + 状态 |
32
+ | 待办状态变化、逾期 | Person | `activity`;逾期是 A1,不外传 |
33
+ | 从待办归纳出的"他在推什么" | Person | `working-on` (derived) |
34
+
35
+ 🔴 待办**没有会话标识**,所以对 Conversation 贡献为零,不许伪造归属。
36
+
37
+ ### 文档事件
38
+
39
+ | 事件 | 归给谁 | section |
40
+ |---|---|---|
41
+ | 创建/实质编辑一篇文档 | Person | `activity` (raw),记 `{文档主键, 人, 时间, 类型}` |
42
+ | 会话持有某文档的权限 | Conversation | `charter`("群的产出"最硬的证据) |
43
+
44
+ 🔴 **只记编辑事件,不记文档正文。** 正文属于文档,不属于人。
45
+
46
+ ## 三、什么值得记
47
+
48
+ **记**(带日期 + 归因):
49
+ - 公开达成的口径、规则、术语、禁忌
50
+ - 稳定偏好、明确反馈与纠正
51
+ - 带**绝对日期**的承诺(相对时间落盘前换算成绝对时间)
52
+ - 协作界面变化:他现在负责什么、该找他确认什么
53
+ - 立场与判断(慢变;记原话要点,不改写成 Agent 的话)
54
+ - 成形议题的结论与未决项
55
+
56
+ **不记**:
57
+ - 对第三方的评价、吐槽、八卦、绩效议论
58
+ - 健康、家庭、薪酬、去留、情绪宣泄
59
+ - 一次性闲聊与寒暄
60
+ - 机器人播报
61
+ - 无法归因的内容(转发消息的子消息发送者不可解析时,只记一行"有一批内容从别处搬来")
62
+ - 不可解析的富媒体(只记"本批含 N 条非文本")
63
+ - 已在档且无新信息的重复内容
64
+
65
+ **存疑记**:跨渠道 join 只能靠显示名匹配上的边,标 `(弱匹配,待确认)`。🔴 **存疑的边不得用于放宽 audience。**
66
+
67
+ **欠账记**:读失败、分页未完、授权缺失 → 写欠账。**"读不到"永远不许写成"没有"。**
68
+
69
+ ## 四、蒸馏的三条纪律
70
+
71
+ 1. **必读全文再归纳**,不基于摘要脑补。归纳不准就是硬伤,宁可写"暂不清晰"。
72
+ 2. **每条带归因**:`said` / `observed` / `agreed` / `inferred`。Agent 自己的归纳标 `inferred`,**绝不冒充当事人原话**。
73
+ 3. **矛盾并列,不静默覆盖**:与既有结论冲突时并列标注并注明待观察;**连续多次印证后**才改写派生层,单次不翻烧饼。
74
+
75
+ ## 五、幂等
76
+
77
+ ```text
78
+ 对每条源事件:
79
+ 1. 算 evidenceId
80
+ 2. 若该 evidenceId 已在档 → 只推进水位,不追加
81
+ 3. 否则 → 写 Fact → 回读确认 → 才推进水位
82
+ 4. 写或回读失败 → 本批作废,水位不动,下轮重来
83
+ ```
84
+
85
+ 因为 `evidenceId` 来自源系统主键,**重放、并发、推拉重叠都安全**。
86
+
87
+ 批处理:一拍 ≤N 个 subject + 软时限 + 断点续跑 + 按主键分片。宁可漏一拍,绝不建重复。
88
+
89
+ ## 六、授权门(必须显式建一态)
90
+
91
+ 某些渠道的读取受**行为授权**门控,在托管运行时里首次读取会直接被拒。
92
+
93
+ 🔴 必须有 `authorization-required` 这一态,**不许把它归进"未配置"而静默关能力**(那会变成用户以为在记、其实一条没进),**也不许诊断成"存储没写权限"**(诊断完全错,用户会去查文档权限)。
94
+
95
+ 绑定时就要盘点一次需要哪些授权 scope,缺的当场告诉用户怎么补。
96
+
97
+ ## 七、这一层做不到什么
98
+
99
+ - **"@我"信号可能不可用**:某些 IM 源的提及类接口取不到消息体(见 `adapters.md` 的源适配器一节)。这时群**失去最强的相关性过滤**,只能全量扫 + 判值得记,大群噪音与成本双高。
100
+ - **按稳定人标识切片消息不可用**:服务端要求人标识必须是组织内工号,**外部人没有这条路**。
101
+ - **跨组织会话需单独授权**:未授权时"读到 0 条"与"真的没消息"**同形**,只能记欠账。
102
+ - **单聊无法全量枚举**:会话列表接口的游标是死参数、硬顶 100 条。Person 只能被时间窗自然发现。
103
+ - **跨渠道 join 必掉精度**:待办的人标识与通讯录不是同一命名空间,文档权限只给显示名。错绑不可根除,只能靠存疑标注控制损害。
@@ -0,0 +1,70 @@
1
+ # 引导式创建 —— 带用户走一遍,把"首次绑定"这道墙迈过去
2
+
3
+ "首次绑定"环的缺口不是存储机制不行,是**没有一条从零到一篇合法绑定档案的可走通路径**。全自主自建有难点(并发去重、locator 回填架构上写不回 git 配置)。但**引导式创建**绕开这些:用户在环里逐步确认,Agent 不需要全自主决策,每一步都是真实 dws 动作 + 用户点头。
4
+
5
+ 触发:用户第一次说"记住这个人 / 帮我把长期记忆搭起来 / 我有个文件夹想当落点",而当前未绑定(Boot 解析不到绑定档案)。
6
+
7
+ ## 产物(引导流最终要生成的东西)
8
+
9
+ 一篇**合法 adoc 绑定档案**(`memory: dingtalk-doc:<它>` 收得下,实测 contentType=ALIDOC/extension=adoc),正文用 `key: value` 记:
10
+
11
+ ```
12
+ boundIdentity.userId / userName / corpId 身份锚,Boot 每次比对
13
+ narrative.workspaceId / rootNodeId
14
+ narrative.people.nodeId / .enabled / .writeState
15
+ narrative.groups.nodeId / .enabled / .writeState
16
+ registry.baseId
17
+ registry.conversation-index.tableId / person-index.tableId / watermark.tableId
18
+ coldStartMode
19
+ ```
20
+
21
+ 🔬 已在生产 dws 验证:这篇 adoc 建出来后,模拟 Boot 能从正文正确解出两介质落点 + 身份锚 + writeState。
22
+
23
+ ## 七步引导(每步:Agent 说什么 → 做什么真实动作 → 用户确认什么)
24
+
25
+ ### 1. 认清身份(不问,直接取)
26
+ - **做**:`dws auth status` 拿运行时身份 userId/userName/corpId。
27
+ - **说**:"我现在的身份是〈夏东翔 103262 · 钉钉〉,档案会归在这个身份下。身份换了以后可能读不到,这点先说清。"
28
+ - **确认**:用户认可用这个身份。
29
+
30
+ ### 2. 探候选落点(只读,不建)
31
+ - **做**:`wiki space list --type myWikiSpace`(个人库,恒可写)+ `drive recent` 看常用位置 + 若用户给了文件夹 URL 就 `doc info` 验证可读。**容器级枚举不到不等于不可用**(`adapters.md`)。
32
+ - **说**:"我只读地看了一下:你有个人知识库〈我的文档〉,你是 OWNER;你最近常在〈某库〉编辑。"
33
+ - **确认**:无(这步纯探测)。
34
+
35
+ ### 3. 推荐落点,说清代价(用户选)
36
+ - **说**:"建议存这里,你选一个:①复用你给的文件夹(好处:你已有;代价:确认下 Agent 身份写得进)②在你个人库新建(好处:任何身份都能装成;代价:团队默认看不到)③团队库(好处:同事能看;代价:群档案会被同事看到)"
37
+ - **确认**:用户选一个落点。narrative 用文档、registry 用 AI 表格——两处可以不同位置。
38
+
39
+ ### 4. 建 narrative 落点 + 定 writeState(写一次回读)
40
+ - **做**:在选定位置建 `people/`、`groups/` 两个文件夹(建后**回读父目录核对无 `(1)`**,撞名立刻删自己刚建的)。对每个根做一次**写-回读**定 writeState(写得进=writable,被拒=read-only)。🔴 不查权限表(`drive permission list` 不返回稳定人标识),只认经验判定。
41
+ - **说**:"建好了 people/ 和 groups/ 两个文件夹,我写了一次测试再读回来,确认能写。"
42
+ - **确认**:无(机械步骤,回读即证)。
43
+
44
+ ### 5. 建 registry 三表(AI 表格)
45
+ - **做**:建 base + conversation-index / person-index / watermark 三张表,`table get` 回读表头拿 fieldId(`adapters.md` 铁律:不带 `--all` 的元数据接口先证表和字段)。
46
+ - **说**:"索引和水位放 AI 表格〈某 base〉,这样'某人有没有档案'能按 key 秒查、不会像文档那样翻页翻到截断。"
47
+ - **确认**:无。
48
+
49
+ ### 6. 生成绑定档案(把上面全部写进一篇 adoc)
50
+ - **做**:建一篇 adoc,标题 `AGENT-MEMORY-PLACEMENT·<Agent名>`,正文写入上面「产物」的全部 key: value(含 boundIdentity)。写后 `doc read` 回读、模拟解析确认字段齐。
51
+ - **说**:"绑定档案建好了:〈链接〉。里面记着落点和我的身份,以后我每次开工先读它。"
52
+ - **确认**:用户可点开看。
53
+
54
+ ### 7. 把 memory ref 交给用户接上配置(这一步用户/运维做)
55
+ - 🔴 **架构约束**:运行时身份写不回 git 配置(`agent.bindings.json` / `AGENTS.md` 在 Agent 仓库、走受控发布)。所以最后这一步 Agent 只能**给出要填的值**,由用户/运维接上:
56
+ - **说**:"最后一步要你接上:把这行填进 Agent 的 `agent.bindings.json` —— `\"memory\": \"dingtalk-doc:<这篇绑定档案的节点>\"`,或设环境变量 `DTA_MEMORY_STORAGE=dingtalk-doc:<同一节点>`。填好下次部署我就能自动找到它。"
57
+ - **确认**:用户完成配置(或明确说交给运维)。
58
+
59
+ ## 引导流把完成度推到哪
60
+
61
+ - **首次绑定环**:从 `missing`(无可走通路径)→ **引导可达**(用户在环里,七步都是真实 dws 动作,产物是实测可解析的 adoc)。这是本次交付能兑现的最高点。
62
+ - 第 7 步仍需人接(架构使然,不是没做);第 4–6 步目前由 Agent 按本 SOP 执行,需要「Agent 自主触发」连通(`COMPLETENESS.md` 补齐路线第 1 步)才算全自动。在那之前,运维可复用生产脚本走这七步,产物一致。
63
+
64
+ ## 与全自主自建的关系
65
+
66
+ 引导式创建**不替代**未来的全自主自建,是它的可交付前身:
67
+ - 引导式:用户逐步确认,Agent 无需自主决策,**今天可交付**。
68
+ - 全自主:用户只说"记住他",Agent 自己走完 1–6(7 仍需回填机制),需要并发单写者租约 + locator 回填闭环(`COMPLETENESS.md` 路线 1、3)。
69
+
70
+ 用户明确要"引导也行"时,走本篇即可闭环,不必等全自主。
@@ -0,0 +1,148 @@
1
+ # 建模 —— 人与群的信息模型(存储无关)
2
+
3
+ 本篇**不出现任何介质概念**:没有页、没有文件夹、没有物理地址。这里定义的是「记什么」,不是「存哪」。存储怎么落见 `storage-port.md`,介质特有的坑见 `adapters.md`。
4
+
5
+ 判断本篇是否真的解耦,用这个检验:**如果这世界上只有本地 Markdown 文件这一种存储,这个模型会长成同样的样子吗?** 会,才算解耦。
6
+
7
+ ## 一、两个一等实体
8
+
9
+ | 实体 | 主键 | 主键从哪来 | 说明 |
10
+ |---|---|---|---|
11
+ | **Person** | `personKey` | IM 源适配器提供的稳定人标识 | **不是**显示名、不是花名、不是员工编号(员工编号在有些渠道缺失,或属于另一个命名空间)。具体取哪个字段见 `adapters.md` |
12
+ | **Conversation** | `conversationKey` | IM 源适配器提供的稳定会话标识 | 单聊与群聊**都是** Conversation,用 `kind` 区分。整串使用,不得截断或当路径片段 |
13
+
14
+ 🔴 **群不是人的集合。** 群独有、无法由成员并集推导的八类:隐私档位、生命周期(建群时间/规模变化)、治理角色、群内专属称呼、**群约定与口径**、自动化装配、**群作为权限主体**、"这事在哪讨论过"的话题地址与沉默节奏。判据:删掉全部成员档案,群档案依然可读可用。
15
+
16
+ 🔴 **单聊也是 Conversation,但不给它建群档案。** 单聊的价值全部归到对方那个 Person 上;`kind=dm` 的 Conversation 只用来承载水位与去重键。
17
+
18
+ ## 二、Fact —— 唯一的落盘单位
19
+
20
+ 模型层只往存储里放一种东西:**Fact**。所有的"页""段落""条目"都是存储层的表现形式。
21
+
22
+ ```yaml
23
+ fact:
24
+ subject: { type: person|conversation, key: <主键> }
25
+ layer: raw | derived # 原始层只增不删;派生层可整体重建
26
+ section: <语义分区名> # 见下表;不是文件名
27
+ occurredAt: <绝对时间, 事件真实发生时间>
28
+ recordedAt: <绝对时间, 落盘时间>
29
+ scope: <发生地> # dm:<key> | conv:<key> | todo | doc
30
+ audience: A0 | A1 | A2 | A3
31
+ provenance: said | observed | agreed | inferred
32
+ evidenceId: <源系统主键> # 全体系唯一,即天然去重键
33
+ body: <正文>
34
+ supersedes: <evidenceId?> # 纠正时指向被替代项,不改写原件
35
+ ```
36
+
37
+ **`evidenceId` 是整个模型的去重基石**:同一条源事件无论被哪条路径处理到,都产出同一个 `evidenceId`,因此重放安全、并发安全、跨渠道不双写。没有 `evidenceId` 的事实(如人工观察)用 `hash(subject+occurredAt+body)` 合成一个。
38
+
39
+ **`layer` 只有两种,别造第三种**:
40
+
41
+ - `raw`:丢了不可重建,所以**只增不删**,纠错只能靠 `supersedes` 并列新增。
42
+ - `derived`:从 `raw` 编译出来的,**永远可整体重建、可 curate(去重/合并/退 superseded)**。
43
+
44
+ 🔴 **没有"derived·只增"这种东西。** derived 若又只增又不许 curate,就会可重建却无泄压阀——一年后累积过百条越过读墙、fail-open。derived section 的"一条仍生效的结论不会静默消失"是**语义保证**,靠 curate 时"每次收缩都能从 raw 重放复现"来兑现,不是靠禁止收缩。详见 `consolidation.md` §7。
45
+
46
+ 这条不变式由模型层保证,不下放给适配器。
47
+
48
+ ## 三、Section —— 两个正交维度:layer × kind
49
+
50
+ 每个 section 有两个正交属性:
51
+
52
+ - **`layer`**(上一节):`raw`(只增)/ `derived`(可重建)——决定能不能改写。
53
+ - **`kind`**:`narrative`(叙事)/ `registry`(注册表)——**决定该落哪种介质**。
54
+
55
+ 🔴 **kind 是这个模型最容易做错的一处,也是"索引类不该塞进文档"的根**:
56
+
57
+ | kind | 长什么样 | 访问模式 | 该落哪 |
58
+ |---|---|---|---|
59
+ | `narrative` | 一段会长大的正文,人打开就能读整份 | 读整页、drill-down;不按字段查询 | **文档类介质**(markdown 放得开、有排版) |
60
+ | `registry` | 一行一条、按 key 定位的结构化记录 | **按 key 查存在、枚举、否定查询、按 key 改一行** | **结构化介质**(有真分页/按字段查/按行改) |
61
+
62
+ 把 registry 塞进文档,就会撞上一整套本不必存在的病理——341 行截断、"判存在只能翻完页"、分桶防 fail-open、count 对账——这些**全是在给"结构化数据被迫上叙事介质"擦屁股**。放到有真分页、按字段查、按行定位的结构化介质上,这些病理**直接消失**(具体介质与病理对照见 `adapters.md`)。
63
+
64
+ **每个 raw 家族配一个 `*-digest`(derived, narrative)**:raw 逐次累积、按月归档;digest 是编译层读取底座。跑一年的压缩机制见 `consolidation.md`。
65
+
66
+ ### Person
67
+
68
+ | section | layer | kind | 装什么 |
69
+ |---|---|---|---|
70
+ | `identity` | derived | narrative | 他是谁、称呼与别名、组织位置。稳定层,单调粘滞 |
71
+ | `working-on` | derived | narrative | 当前在推什么、卡在哪。**时效层,会 decay** |
72
+ | `collaboration` | derived | narrative | 他负责什么、该找他确认什么、偏好、明确纠正。稳定层 |
73
+ | `public-facts` | derived | narrative | **唯一可对第三方取材**,每条带源会话与日期。可 curate |
74
+ | `interaction` | **raw** | narrative | 单聊蒸馏,逐条带归因。按月归档 |
75
+ | `activity` | **raw** | narrative | 机器抄录、可重放:待办三元、文档编辑、引用边。按月/周归档 |
76
+ | `interaction-digest`/`activity-digest` | derived | narrative | 封月月度摘要,每行携 evidenceId 锚点 |
77
+
78
+ ### Conversation(仅 `kind=group`)
79
+
80
+ | section | layer | kind | 装什么 |
81
+ |---|---|---|---|
82
+ | `charter` | derived | narrative | 这群干嘛的、在推什么、谁说了算、**发言档** |
83
+ | `conventions` | derived | narrative | 群公开口径/流程/术语/禁忌,每条带拍板人日期。可 curate |
84
+ | `chronicle` | **raw** | narrative | 议题级纪事+群生命事件。**留足**(议题级完整,别压成薄摘要)。按月归档 |
85
+ | `chronicle-digest` | derived | narrative | 封月月度摘要 |
86
+
87
+ ### Registry(索引与元数据 —— 走结构化介质,不进叙事文档)
88
+
89
+ 这些是 A0(仅 Agent),一行一条、按 key 查:
90
+
91
+ | registry | 主键 | 一行装什么 |
92
+ |---|---|---|
93
+ | `person-index` | `personKey` | 显示名、profile 位置、最后活跃、状态。**"这人有没有档案" = 按 personKey query,查不到就是没有** |
94
+ | `conversation-index` | `conversationKey` | 群名、groupType、memberCount、myRole、位置。取代文档版 `00-群索引` |
95
+ | `watermark` | `(subjectKey, channel)` | 水位值。按 key O(1) 取,不再"读整页 parse" |
96
+ | `count` | `(subjectKey, section, partition)` | 完整性对账条数(见 `consolidation.md` §0) |
97
+ | `roster` | `(conversationKey, personKey)` | 成员在本群的位置与角色。可丢弃可重拉 |
98
+ | `tombstone` | `(subjectKey, scope)` | 遗忘账本:范围+要求人+日期。**结构化介质无读墙 → 不会 fail-open** |
99
+ | `proposal-ledger` | `subjectKey` | 已提议建档的对象,防重复骚扰 |
100
+
101
+ 🔴 registry 走结构化介质后,`consolidation.md` §0 的 count 对账、`storage-port.md` 里 `lookup.negative=list-only` 与分桶那套,**对这些 section 不再需要**——它们是叙事介质的补丁,不是模型的本质要求。narrative section 仍需要它们。
102
+
103
+ ## 四、Audience —— 写入时定,读取时只收窄
104
+
105
+ | 档 | 谁能看 |
106
+ |---|---|
107
+ | `A0` | 仅 Agent 自己(索引、绑定档案、停用账本) |
108
+ | `A1` | 仅本人 + Agent owner |
109
+ | `A2` | 该会话的成员 |
110
+ | `A3` | 任意同事 |
111
+
112
+ **回答任何人之前先算交集**:引用事实的 `scope` 圈子不含提问者 → 不可用,**宁可答"不清楚"**,不要给一个模糊版本。
113
+
114
+ 🔴 `audience` **不由 Agent owner 代替本人授权**。「Agent 的 owner」与「事实的当事人」不是等价授权主体,否则一个主管就能在下属不知情时给每个下属建含立场与卡点的长期档案。
115
+
116
+ 🔴 **会话的隐私档位走白名单**:只有明确判定为"内部/常规"的会话走正常档,**其余一切**(外部群、合作群、未知类型、以及将来新增的任何类型)一律最小披露档。枚举值是平台的、会变;黑名单写法必然漏。
117
+
118
+ ## 五、交叉归属(三条铁律)
119
+
120
+ 1. **原始层按发生地只写一处。** 群里说的只进该会话的 `chronicle`/`conventions`;单聊说的只进那个人的 `interaction`;无会话标识的(待办/文档)只进人的 `activity`,**对会话贡献为零,不许伪造归属**。
121
+ 2. **派生层各写各的结论,跨实体只留引用不复制原文。** 判据:*把这句删掉,变的是「以后对这个人的预期」还是「这个会话以后怎么办事」*——前者写人,后者写会话,都变则写会话 `conventions` + 人 `public-facts` 一行引用。
122
+ 3. **唯一允许的上浮方向:会话公开 → 人的 `public-facts`,audience 继承为 A2。** 写死的红线:单聊 → 任何会话或第三方档案;A 会话 → B 会话;会话里对某人的评价/吐槽 → **任何档案**(连他自己的也不写)。
123
+
124
+ ## 六、Watermark —— 增量的唯一判据
125
+
126
+ 每个 `(subject, channel)` 一个水位,值是**已消化到的最后一条源事件的 `occurredAt`**。
127
+
128
+ ```yaml
129
+ watermark: { subject: <key>, channel: im|todo|doc, value: <绝对时间> }
130
+ ```
131
+
132
+ 🔴 **水位是"消化到哪",不是"哪天跑过"。** 用"今天刷没刷"当判据会退化成全量重刷模型:过午夜全体变旧 → 每轮全量重编 → 窗口装不下 → 永远跑不完、永远降级。
133
+
134
+ 🔴 **先写事实、后推水位。** 写入或回读任一失败即本批作废、水位不动。水位一旦虚高,这批源事件永远不会被再消化。
135
+
136
+ 🔴 **同一条源事件在会话侧推进会话水位,在人侧只是被引用、不推进人的水位。** 人的 im 水位只由单聊推进。任一侧重放都不漏、不双写。
137
+
138
+ **收敛判据**:`某 subject 收敛 ⟺ 它的水位 ≥ 它最新一条源事件的 occurredAt`;整体收敛 ⟺ backlog 为空。
139
+
140
+ ## 七、模型层必须自己保证的不变式(不下放给适配器)
141
+
142
+ 1. `raw` 层只增不删,纠错用 `supersedes` 并列新增。
143
+ 2. `evidenceId` 全局唯一即去重键。
144
+ 3. `audience` 写入时定、读取时只收窄不放宽。
145
+ 4. 交叉归属三铁律。
146
+ 5. 先写事实、后推水位。
147
+ 6. 会话隐私档位白名单默认拒绝。
148
+ 7. **"读不完整 ≠ 不存在"**:不只是读报错——AI 表格分页会**静默截断**(成功返回偏小前缀却报 hasMore=false,无完整性凭据)。读失败、分页未完、授权缺失、以及**任何全量枚举**,一律当"未证明完整",记欠账、跳过本轮,**绝不写成"没有"**,也绝不据此新建重复实体。判"不存在"只能用有界的按键查(命中 0 行)。