@xdxer/dingtalk-agent 0.1.4 → 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 (186) hide show
  1. package/CHANGELOG.md +232 -0
  2. package/README.en.md +115 -89
  3. package/README.md +111 -86
  4. package/dist/bin/dingtalk-agent.js +742 -152
  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 +4 -4
  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 +366 -0
  72. package/docs/INSTALLATION.md +8 -8
  73. package/docs/PLATFORM-GUARDRAILS.md +188 -0
  74. package/docs/PRIOR-ART.md +126 -0
  75. package/docs/SELF-TEST.md +182 -0
  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 +45 -0
  90. package/examples/agents/fde-coach/AGENTS.md +2 -25
  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 -25
  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 +18 -11
  112. package/skills/README.md +10 -8
  113. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/SKILL.md +49 -24
  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 +28 -3
  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 +35 -9
  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/dist/src/map.js +0 -157
  157. package/dist/src/map.js.map +0 -1
  158. package/docs/SECOND-AGENT-ACCEPTANCE.md +0 -62
  159. package/docs/architecture/agent-memory-topology.png +0 -0
  160. package/docs/architecture/agent-memory-topology.svg +0 -132
  161. package/docs/architecture/dingtalk-agent-blueprint.png +0 -0
  162. package/docs/architecture/durable-async-agent-runtime.png +0 -0
  163. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  164. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  165. package/docs/architecture/task-completion-gate.png +0 -0
  166. package/docs/assets/agent-delivery-lifecycle.svg +0 -103
  167. package/skills/core/dingtalk-basic-behavior/references/event-to-behavior.md +0 -24
  168. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +0 -28
  169. package/skills/platforms/deap/README.md +0 -3
  170. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +0 -40
  171. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +0 -49
  172. /package/examples/agents/fde-coach/{skills → agent/skills}/fde-coach/SKILL.md +0 -0
  173. /package/examples/agents/release-manager/{skills → agent/skills}/release-manager/SKILL.md +0 -0
  174. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/role-skill.template.md +0 -0
  175. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/storage-routing.md +0 -0
  176. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/evidence-contract.md +0 -0
  177. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/failure-to-case.md +0 -0
  178. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/local-connector-smoke.md +0 -0
  179. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/scenario-taxonomy.md +0 -0
  180. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/storage-modes.md +0 -0
  181. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/memory-candidate-proposal.json +0 -0
  182. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/task-checkpoint.json +0 -0
  183. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/action-contract.md +0 -0
  184. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/runtime-modes.md +0 -0
  185. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/task-lifecycle.md +0 -0
  186. /package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/references/promotion-observation-contract.md +0 -0
@@ -0,0 +1,366 @@
1
+ # dingtalk-agent 架构
2
+
3
+ 本文回答四个问题:**一个数字员工是什么**、**它由什么构成**、**每件事谁说了算**、**这个仓库分成哪几部分、各解决什么问题**。
4
+
5
+ 本文不写:安装与升级(见 [Installation](INSTALLATION.md))、评测方法与证据分层(见 [Self-test](SELF-TEST.md))、Agent 的行为协议(见 [Basic Behavior Skill](../skills/core/dta-basic-behavior/SKILL.md))、发布历史(见 [CHANGELOG](../CHANGELOG.md))、进行中的工作(见 [roadmap](roadmap/))。
6
+
7
+ ![dingtalk-agent 架构总览:五个部件、五个权威,本仓库只拥有一个](architecture/dingtalk-agent-architecture.svg)
8
+
9
+ 上图是全貌,编号对应 §1 的五个部件:实心编号是本仓库拥有的,空心编号由外部签发或提供。下面逐层展开。
10
+
11
+ ---
12
+
13
+ ## 1. 什么是一个数字员工
14
+
15
+ ![数字员工的五个部件与各自的权威](architecture/digital-employee-composition.svg)
16
+
17
+ 一个聊天机器人只需要把输入变成输出。一个数字员工要额外成立四件事:
18
+
19
+ - **稳定身份**:它是谁、受谁委托、以谁的名义在平台上留下痕迹,不随聊天内容变化;
20
+ - **明确作用域**:这次被授权做什么、对谁、到哪一步,不由正文自行扩张;
21
+ - **可核验的完成**:说"做完了"必须对应产物、Receipt 或独立回读,不能以回复正文自证;
22
+ - **可丢弃的执行体**:沙箱、进程、模型可以随时换掉,事情还能接着做。
23
+
24
+ **这四件事没有一件能由 Agent 自己提供——数字员工不等于 Agent。** 它是一个 Agent 装配上组织语境之后的结果:
25
+
26
+ ```text
27
+ 数字员工 = Agent 本体 ← 本仓库
28
+ + 组织身份与场域授权 ← 钉钉数字员工平台
29
+ + 感知通道(事件) ← 钉钉事件中心 / DWS
30
+ + 平台执行能力 ← DWS
31
+ + 运行位置 ← Managed Agent Platform / Agent Host
32
+ ```
33
+
34
+ 运行时上,本仓库只提供第一项;其余四项由外部提供,本仓库不实现也不替代,但必须逐一显式建模,否则边界会悄悄溜走(见 §3)。
35
+
36
+ > ⚠️ **这张等式回答的是「一个跑起来的数字员工由什么组成」,用途是界定依赖——它不是「本项目做什么」的答案。** 把两者混为一谈会严重低估本项目的范围。「本项目做什么」要换一个正交的视角看:**开发域**。
37
+
38
+ **开发域:把一个 Agent 变成钉钉数字员工,要走完六段——这六段本项目全管。**
39
+
40
+ | 段 | 本项目替开发者完成什么 |
41
+ |---|---|
42
+ | **① 本体与员工技能** | 一份可继承、可 hash、可验证的共享行为合同(响应资格、意图分级、授权模型、风险分级、证据阶梯、完成判定、记忆与遗忘),加本体与岗位骨架 |
43
+ | **② 身份获取与事件感知** | 把来路不明的原始事件归一成稳定合同,冻结回复目标与执行身份,按 Field 绑定权限与出口,补齐现场,并保证同一事件只产生一个 Run |
44
+ | **③ 托管平台部署** | 把手工搬运变成 plan → apply → 独立回读 → 加载烟测 → Receipt 的受控发布链,幂等、可回滚、可退役 |
45
+ | **④ 驱动它在钉钉里干活** | 四个动作原语 + Action Gate:副作用前冻结目标身份,副作用后强制平台回读,完成必须有物证 |
46
+ | **⑤ 评测设计** | L0–L4 证据分层方法学、四个 runner、多面证据硬门禁,以及「真实事故 → 可复跑场景」的沉淀路径 |
47
+ | **⑥ 观测与计量** | 目前**最薄的一段**:只有把线上人工观察安全灌回评测素材的受控通道;用量计量尚未实现(见 §8) |
48
+
49
+ 逐段的能力、边界与缺口见 [§8 开发生命周期](#8-开发生命周期从定义到观测)。一句话概括这两个视角的关系:**运行时的底座我们不造;但把 Agent 变成数字员工的这条生产线,从头到尾是我们的。**
50
+
51
+ 三类东西的可变性完全不同,必须分开对待:
52
+
53
+ | 类别 | 内容 | 本仓库的职责 |
54
+ |---|---|---|
55
+ | **外部签发** | 组织身份、场域授权、事件信封 | 冻结进 Session、全程审计,永不扩权 |
56
+ | **可替换** | 触发端、模型、沙箱、运行位置、岗位能力 | 只要求一份可验证的加载与执行合同 |
57
+ | **本仓库不变** | 定义、上下文、状态、闸门、效果证据 | 唯一拥有;全部设计取舍都服务于把它们从执行体里独立出来 |
58
+
59
+ 「外部签发」这一类最容易被漏掉:**身份既不可替换,也不由本仓库提供。**
60
+
61
+ ## 2. 一个 Agent 由什么构成(模型 A)
62
+
63
+ 三个模型互不重叠,各回答一个问题:**A 交付物由什么组成**、**B 每件事谁说了算**、**C 这个仓库自己分成哪几块**。「Skill 劝,CLI 拦,DWS 做」是贯穿三者的唯一职责口径(见 §4)。
64
+
65
+ | 部件 | 回答什么 | 落在哪 | 谁生成 / 谁校验 |
66
+ |---|---|---|---|
67
+ | **本体 Definition** | 我是谁、服务谁、岗位底线、做事范式、常犯错误 | `agent/AGENTS.md` | `agent enhance` 生成骨架;`agent audit` 校验语义占位符是否已填 |
68
+ | **公共行为** | 何时响应、如何追问、何时沉默、如何收口 | `agent/skills/dta-basic-behavior` | 内核内置;`agent audit --verify-load` 证明它真被加载 |
69
+ | **岗位能力** | 某个岗位的方法、SOP、禁区、验收标准 | `agent/skills/<role>/SKILL.md` | 开发者编写;`--require-skill` 校验存在与加载 |
70
+ | **存储路由** | 长期内容与私有控制状态各自去哪 | `agent.bindings.json`(可选) | `bootstrap` 归一成 `agent-definition@1`;缺省时按宿主 context > 环境变量 > Workspace manifest > 目录约定依次解析 |
71
+
72
+ 这四项不是设计出来的分类,而是从 `agent-definition@1` 直接读出来的字段(`src/agent-definition.ts`)。一个 Agent 的最小目录形态:
73
+
74
+ ```text
75
+ my-agent/
76
+ ├── AGENTS.md 仓库 Coding Agent 开发约束,不发布
77
+ ├── agent/ managed platform 的唯一同步边界
78
+ │ ├── AGENTS.md 本体:角色宪法 + Basic 继承锚点
79
+ │ └── skills/ Basic 与 Role Skills 的唯一发布源
80
+ ├── agent.bindings.json 存储路由与 DWS authority(可选,见下)
81
+ └── .dingtalk-agent/ 私有状态、证据与 Receipt(gitignored)
82
+ ```
83
+
84
+ Host 原生发现目录不是发布源。OpenCode 的 `.agents/skills/`、Claude Code 的 `.claude/skills/` 等只在 dta 创建的隔离工作区临时物化并回收,不能与 `agent/skills/` 一起提交。已有代码仓库可在 `dingtalk-agent.json` 显式声明其它 `agent.definition` 与 `agent.skillsRoot`,不因升级 CLI 被强制迁移。
85
+
86
+ "文件存在"不是继承证据。`agent audit --verify-load` 把真实加载结果绑定到 Definition/Skill hash、Host 与模型版本、隔离探针和原始 run/export;任何一项漂移,旧证据即失效。
87
+
88
+ ## 3. 每件事谁说了算(模型 B)
89
+
90
+ ![dingtalk-agent 在托管平台与钉钉之间的连接层位置](architecture/agent-platform-connection-layer.svg)
91
+
92
+ §1 的五个部件各有一个「谁说了算」。下表按权威归属重排,把本仓库拥有的那一项放在最后:其余四行本仓库只有约束——**写下来是为了让边界可检查,不是因为我们要做它们**:
93
+
94
+ | 这件事谁说了算 | 权威 | 本仓库的边界 |
95
+ |---|---|---|
96
+ | **组织身份、场域与权限** | 钉钉数字员工平台 | 不发证、不改写、不扩权;只把签发结果冻结进 Session 并全程审计 |
97
+ | **事件信封**(谁、在哪、说了什么) | 钉钉事件中心 / DWS | **不拥有触发器**(见下);只要求信封可信、可幂等 |
98
+ | **平台能力执行** | DWS | 不复制 DWS 命令面,只在需要冻结事务边界时包一层。`src/dws.ts` 是全仓库唯一 spawn `dws` 的地方;实战缺陷见 [DWS Field Notes](DWS-FIELD-NOTES.md) |
99
+ | **运行位置** | Managed Agent Platform / Agent Host | 不自己做 Host、不自建 Runtime;通过 registry + adapter 连接,只要求一份可验证的加载合同 |
100
+ | **本体、行为、状态与效果证据** | **本仓库 + Git** | 唯一拥有的一行 |
101
+
102
+ **运行位置既是可替换项,也是本项目的连接面。** 接入一个平台等于「**一个平台 Skill 包 + 注册表一条记录**」,方法学不进内核也不进 CLI(目录约定见 [skills/README](../skills/README.md))。当前 **Multica 已支持,DEAP 敬请期待**;「可扩展」指注册表与 adapter 合同可扩展,不表示尚未开放的平台已经可用——未开放平台的所有平台命令一律 fail-closed。各平台的最佳实践如何被观察和吸收,见 [Prior Art](PRIOR-ART.md)。
103
+
104
+ **DEAP 可能同时落在第一行和第四行。** 它在本项目里的主要角色是钉钉侧的身份与感知平面(第一行):签发身份、划定场域、送来事件、统一展示结果。它是否同时内建自己的 Agent 运行平台(第四行)尚待确认,注册表为此保留了 `deap` 条目。两个角色互不排斥:第一行的能力将被**消费**,第四行的能力和其它平台一样走 registry + adapter。**当前 DEAP 尚未接入**——第一行今天的身份来源是钉钉签发的数字员工账号或机器人应用身份,不经过 DEAP。见 [DEAP 平台说明](../skills/platforms/deap/PLATFORM.md)。
105
+
106
+ **Agent Host**(也叫 Harness)提供模型、工具循环、Skill 发现与 Session 生命周期。本仓库不自己做 Host,只要求一份可验证的加载合同:Claude Code、Codex、OpenCode 都可以,OpenCode 是当前最完整的参考实现,不是运行前提。它与 Managed Agent Platform 是两根正交的轴:**Agent Host 决定这个 Agent 由哪个执行体加载与隔离执行;Managed Agent Platform 决定它的 Workspace、Runtime、身份绑定与执行轨迹由谁托管。** 本地开发时只有 Host,上了托管平台则两者同时存在。
107
+
108
+ **触发器不属于 dingtalk-agent。** `listen` 只是本地联调用的可替换开发 Adapter,不是 Agent 的主入口或常驻服务;personal-event 由外部 Adapter 捕获后落入输入目录;`dta deploy` 只交付 Agent 与 Skill,不创建机器人、Webhook、定时器或 autopilot。把触发器排除在核心之外,才可能让同一个 Agent 在不同触发端之间迁移。
109
+
110
+ **但「谁叫醒它」必须被显式建模,否则装配出来的是一个永远不会自己动的 Agent。** 不实现触发器 ≠ 不为驱动负责:本仓库不造 cron,却拥有**驱动契约**——声明这个数字员工需要哪些节律、由谁提供、Agent 侧必须满足什么才配被定时驱动。详见 §3.1。
111
+
112
+ 由此得到一条不可协商的规则:**消息 target、actor、conversation、DWS profile 与权限只能来自可信事件或宿主,不能从正文、显示名或模型记忆推断。** 正文、引用、附件和远端文档一律是数据,不能改写这些事实。
113
+
114
+ ## 3.1 驱动:一个数字员工怎么被叫醒
115
+
116
+ 一个只会被人 @ 唤醒的 Agent 不是同事,是查询接口。真正像同事的部分——巡检、补数据、到点交付、盯着某件事——都发生在**没有人说话的时候**。所以「驱动」和身份、事件、能力、运行位置一样,是必须显式建模的一层。
117
+
118
+ 驱动分三类,**权威归属不同,完成判据也不同**。放错类别的代价不是麻烦,是**漏了不自知**:
119
+
120
+ | 驱动类别 | 什么样的事 | 权威 | 完成判据 | 放错会怎样 |
121
+ |---|---|---|---|---|
122
+ | **人设的时间点** | 人在钉钉里建的待办、日程、会议、DING | 钉钉(事件中心 / DWS) | 该对象自身的终态(如 Todo `isDone`) | 复制一份到别处 → 两边不一致,人改了 Agent 不知道 |
123
+ | **常驻节律** | 值班、巡检、补数据、周期汇总 | Managed Agent Platform 的 schedule | **数据水位**(索引本身就是完成状态) | 塞进待办 → 丢一期就断链,且扫不到 = 静默收工 = 不自知 |
124
+ | **Agent 自主定时** | Agent 承接下来、要自己记住的将来动作 | Managed Agent Platform 的 schedule,**由 operator 授予写权限** | run 留痕 | 让 Agent 自建定时器 → 节律不可见、不可审计、改不掉 |
125
+
126
+ 判据只有一句:**这件事有没有终态?** 有终态、有交付对象 → 待办。永远做不完的维护义务 → 节律。
127
+
128
+ 三条从真实平台语义倒逼出来、与具体平台无关的约束:
129
+
130
+ - **定时不可靠是常态,判据必须写成「它发生了没有」而不是「那一拍跑了没有」。** 托管平台普遍会塌缩漏掉的 fire、跳过迟到过久的 fire(Multica 的阈值是 5 分钟)。凡是把「某时刻必须发生的事」绑定到「某一拍」的设计,一次 runtime 抖动就永久丢一期,而且事后查不出来。
131
+ - **外发类节律的留痕在动作之后,所以它没有锁。** 两个节律落在同一分钟并发唤醒,就会把同一条消息发两遍给第三方。多节律拆分必须错开触发时刻。
132
+ - **Agent 不自建定时器、不自改节律。** 节律是可审计的部署产物;在线 Run 只能把新节律整理成候选交给 operator,不能自己配上再宣称配好了——这与 §1「在线 Run 不能热改身份、权限或已启用 Skill」是同一条边界的延伸。
133
+
134
+ **本仓库在这一层拥有什么**:不拥有 cron,拥有三件事——装配时**声明**需要哪些节律与是否允许 Agent 自主排程(`dta-agent-compose`);部署到具体平台时**校验**该平台是否真的提供这些能力、不提供就 fail closed(平台 Skill 包 + `agent-platform` 注册表);以及 Agent 侧被定时驱动时必须满足的**行为合同**(`dta-basic-behavior`)。**平台之间能力不同是常态**——同一个 Agent 的节律声明可以不变,能不能被满足由目标平台回答。`dta schedule show` 还会静态检两条与平台无关的不变量:**同刻并发**(按真实 occurrence 枚举判,判不准的当撞车挡住)和**缺完成判据**(声明了 cron 却没写数据派生 `completion` 的记成缺口)。
135
+
136
+ ## 4. 谁拦住什么:Skill 劝,CLI 拦,DWS 做
137
+
138
+ ![通用 Agent 行为内核拓扑](architecture/general-agent-kernel-topology.svg)
139
+
140
+ - **Skill 劝**:判断该不该做、为何做、做到哪一步。这是语义判断,会被上下文影响,因此不能承担安全边界。
141
+ - **CLI 拦**:固定身份、目标、预算、幂等、状态迁移与回读。不依赖模型自觉。
142
+ - **DWS 做**:执行具体钉钉产品能力。
143
+
144
+ 一个动作**只有**在需要下列任一项时才进入 `dingtalk-agent`,否则继续直接用 DWS:
145
+
146
+ 1. 冻结作用域或收件人;2. 权限与授权校验;3. 幂等,且失败后不能盲重试;4. 写后必须独立回读;5. 状态迁移有合法性约束;6. 跨产品事务组合。
147
+
148
+ 举例:`memory operational upsert` 之所以是 CLI 命令而不是一句 DWS 调用,正因为它同时命中 3、4、6——它按 `key + scopeId` 唯一定位一行,create/update 后必须按 recordId 独立回读,匹配多行或回读不一致就进入 reconcile 而不是重试。
149
+
150
+ ## 5. 三种运行模式与 Prepared Run 的四个对象
151
+
152
+ ![持久异步运行模型](architecture/durable-async-agent-runtime.svg)
153
+
154
+ | 模式 | 何时进入 | 关键边界 |
155
+ |---|---|---|
156
+ | **Direct Session** | 无 `CONTEXT.md`、无 Workspace | 全局 Skill 仍生效;不自动 init,不假造钉钉目标 |
157
+ | **Mounted Session** | 有 Workspace 或显式 storage | 通过 `bootstrap` 按需水合身份、记忆与知识 |
158
+ | **Prepared Run** | 上游提供可信事件 envelope | 冻结目标、身份、Field、Skill 与动作预算;副作用只走 typed Broker 或 `dta act` |
159
+
160
+ **Field** 是一个稳定的协作与权限边界:它声明这一摊事归谁、用哪个 DWS 身份出口、允许对哪些人和会话行动。一个 Workspace 可以有多个 Field;Session 创建时从中取走冻结副本,正文和在线 Run 都改不了它。默认模板见 `templates/fields/default/field.json`。
161
+
162
+ 三种模式的判定顺序与检测流程由 [Basic Behavior](../skills/core/dta-basic-behavior/SKILL.md) 拥有;`init` 与 `bootstrap`、`setup` 的分工见 [Installation](INSTALLATION.md)。
163
+
164
+ Prepared Run 只有四个公开对象:
165
+
166
+ | 对象 | 生命周期 | 物理形态 | 作用 |
167
+ |---|---|---|---|
168
+ | Workspace | 长期、可选 | 一个目录或远端语义挂载 | 身份、内容、Field 和 Skill 清单 |
169
+ | Session | 一件事 | `.dingtalk-agent/sessions/.../<sessionId>` | 工作记忆、Skill 绑定、跨消息延续 |
170
+ | Run | 一次信号 | `Session/runs/<runId>` | 冻结输入;每次可启动新沙箱 |
171
+ | Action | 一次效果 | intent + attempt + receipt | `ack` / `reply` / `ask` / `silence` |
172
+
173
+ 四个动作的语义、何时用哪一个,由 Basic Behavior 拥有,本文不复述。Wait、Event Journal、dispatch outbox 和 reply target 是宿主内部实现,不要求 Agent 学习。
174
+
175
+ **Task checkpoint 是 Session 的可选业务投影,不是第五个控制对象。** 只在跨 Run、等待依赖、已产生副作用或需要换手时创建;Prepared Run 写 `$DTA_SESSION/memory/task.json`,用 revision CAS 加 durable lease 防并发覆盖,原子写后必须回读。它不接管锁、事件去重或 Receipt。
176
+
177
+ 与异步进程模型的对应关系:
178
+
179
+ | 进程隐喻 | 实体 |
180
+ |---|---|
181
+ | Heap | Field/Workspace 的身份、知识、Skill |
182
+ | Stack | Session working memory 与事项状态 |
183
+ | 一次函数调用 | Run |
184
+ | syscall | Action |
185
+ | await continuation | 宿主内部 Wait |
186
+ | interrupt | 新事件、心跳、显式取消 |
187
+
188
+ `ask` 之后当前 Run 结束、沙箱释放;匹配事件产生新 Run 并回到原 Session。系统恢复的是显式 checkpoint 和外部成果,不序列化 JavaScript/LLM 隐藏栈。
189
+
190
+ 一个具体读法——FDE 教练实例:
191
+
192
+ | 对象 | 在 FDE 教练里是什么 |
193
+ |---|---|
194
+ | Workspace | 菲迪身份、评价原则、学员资料 |
195
+ | Role Skill | 生成评价、等待确认、调整、发布的方法 |
196
+ | Session | "给张三本轮评价并等确认"这一件事 |
197
+ | Run | 每条新信号唤醒的一次沙箱 |
198
+ | Action | 收到、回复、追问、沉默 |
199
+
200
+ FDE 的评价模板和发布流程不进入全局 Basic Behavior;否则任何钉钉员工都会被污染成教练。
201
+
202
+ ### 双半闸门
203
+
204
+ Response Gate 是**生成前**的安全半闸门:mention/DM 获得处理 origin 的资格,ambient group 固定 silent,heartbeat 只 inspect。Perception Enricher 是**贴心**半闸门——所谓"贴心"是指补齐 Agent 本该看见的现场(而不是放宽权限):宿主可提供可信 quote、recent messages 和 identity,内核按 conversation/actor/时间窗验证后生成 `EnrichedInvocation`;缺失、越界和截断必须显式记录。
205
+
206
+ 同一 eventId 的 perception input hash 是 durable 路由的一部分,重放时不能变化。Run 中的 `response-gate.json` 与 `enriched-invocation.json` 都进入 event-index 权威快照,Action Gate 产生副作用前复验。identity 的姓名、部门、职务只用于语境,权限仍取 Invocation/Definition 的可信 ID。
207
+
208
+ ## 6. 语义内容与控制状态必须分开
209
+
210
+ | 可放 Markdown / 钉钉文档 | 必须留在宿主 state store |
211
+ |---|---|
212
+ | 身份、长期记忆、知识、Skill 候选、业务 task checkpoint | EventIndex、Wait、锁、generation、幂等键、Action intent/receipt |
213
+
214
+ **Why:Markdown 没有可靠 CAS。** 请求超时也不能证明写失败,因此它不能承担并发控制。这是本仓库文档中该规则的唯一出处;违反它的表现形式包括把钉钉文档当锁、当幂等存储或当 Receipt。
215
+
216
+ 公开 Storage Provider:
217
+
218
+ ```text
219
+ local-dir:<path> 直接挂载已有目录,不复制
220
+ local-md:<path> Workspace manifest 的单文件挂载
221
+ dingtalk-doc:<node-or-url> DWS 拉取在线文档的只读快照
222
+ ```
223
+
224
+ 远端文档先用 `doc info` probe,只有 `ALIDOC/adoc` 才用 `doc read` 拉为隐藏只读快照。`bootstrap` 用 Storage canonical identity 派生内部 `scopeId`;`contextId` 只保留为 Prepared Run 的兼容字段。
225
+
226
+ ## 7. dingtalk-agent 分成哪几部分(模型 C)
227
+
228
+ 这是一个**划分**而不是叙事:`src/` 的每个文件各归一处,没有重叠也没有遗漏。行数为近似值,用于表达重心分布。
229
+
230
+ | 部分 | 解决什么问题 | `src/` 模块 | 主要 CLI | 关联 Skill | ≈行数 |
231
+ |---|---|---|---|---|---|
232
+ | **1 行为内核** | 把一个外部事件变成"能不能回应、回应给谁、这次允许做什么"的确定性判断,并保证同一事件不被处理两次 | `events` `invocation` `perception` `response-gate` `sessions` `waits` `actions` `fields` `config` `lease` `driver` `workspace` `skills` `types` | `prepare` `run` `dispatch` `act` `listen` | — | 4.0k |
233
+ | **2 装配与审计** | 让一个仓库、文件夹或钉钉文档变成可 hash、可继承的 Agent,并证明 Skill 真被加载而不只是文件存在 | `agent-definition` `agent-bindings` `bootstrap` `agent-audit` `agent-enhance` `instruction-path` | `bootstrap` `agent enhance` `agent audit` `info` | `dta-agent-compose` | 3.4k |
234
+ | **3 交付链** | 把本地通过的版本,在不改身份和权限的前提下受控放上托管平台,每一步都能独立回读 | `development-workspace` `opencode-*` `multica-*` `promotion` `agent-platform` | `agent-platform` `workspace *` `deploy` `promote` `observe` | multica 平台包 ×3 | 6.4k |
235
+ | **4 评测与证据** | 在花钱、外发和上线之前,用最低成本的层级证明它真会做事;失败沉淀成可复跑场景而不是一次口头修正 | `lab` `robot-evals` `opencode-evals` `remote-state-evals` `remote-semantic-state-*` `personal-event-evals` `storage-evals` `eval-evidence` | `lab *` `workspace eval` | `dta-agent-eval` | 6.2k |
236
+ | **5 状态与记忆** | 让 Run 崩了、沙箱没了、进程换了之后,事情还能接着做;同时不让 Markdown 承担它承担不了的并发控制 | `memory/*` | `task show/checkpoint` `memory operational` `memory candidate` | — | 2.6k |
237
+ | **6 机器与分发** | 一台新机器一条命令拿到 CLI、PATH、DWS 检查和 core Skill 套装,升级不产生第二份副本;并探测本机有哪些 Coding Agent Host 以及 Skill 对它们是否可见 | `setup` `doctor` `host-detect` `upgrade` `init` `skill-manager` `version` `package-root` | `setup` `doctor` `upgrade` `skill *` `init` | — | 1.4k |
238
+ | **平台适配** | 全仓库唯一 spawn `dws` 的地方 | `dws` | — | — | 0.5k |
239
+
240
+ 重心分布本身是个结论:交付链与评测各占约四分之一,合计超过一半。这个项目的难点从来不是"让模型说话",而是**证明它真的装好了、真的做对了、真的上线了**。
241
+
242
+ 对照 §3 的五个权威可以看出这六部分落在分工线的哪一侧:第 1、2、5 部分实现「本体、行为、状态与效果证据」那一行,是本仓库拥有的;**第 3 部分是通往「运行位置」那一行的连接面**——每接一个平台就多一个平台 Skill 包与一条注册表记录,行为内核不变;第 4 部分负责证明前三者在任意一个平台上都同样成立。第 6 部分服务开发者的机器本身,不在分工线上。
243
+
244
+ 两处接缝值得诚实标注,不糊弄过去:
245
+
246
+ - `init.ts` 按模块归第 6 部分,但 CLI `init` 是第 1 部分的可选前置——机器安装与 Workspace 初始化是两件事。
247
+ - 模型 A 的"公共行为"是**交付物**,不是本仓库的一个部分。它以 Skill 形式随包分发,由第 6 部分安装、第 2 部分校验加载、第 4 部分回归。这正是过去两张"四层表"打架的根因:一个在数交付物,一个在数代码分工。
248
+
249
+ 各部分的模块依赖由 TypeScript import 关系直接表达,不在此维护一张会漂移的手绘边图。
250
+
251
+ ## 8. 开发生命周期:从定义到观测
252
+
253
+ 这一节是「本项目做什么」的权威清单。**每一段都同时写明做什么与不做什么**——边界说不清,价值也就说不清。
254
+
255
+ ### ① 本体与员工技能
256
+
257
+ **做**:把「一个钉钉数字员工开口之前必须想清楚的事」沉淀成可版本化、可 hash、可机器验证继承的共享行为合同——响应资格、九类意图分级、外部动作的七字段授权、按五因素(可逆性/影响对象/数据归属/批量规模/权限范围)而非动作名的风险分级、证据阶梯与完成闸门、六类记忆与五种遗忘范围。另给本体四段骨架、岗位 Skill 五段骨架和两个已填好语义的完整样例。继承有三类机器证据:全树 hash 一致、Host 配置恰好一条强制加载、隔离副本里的随机 canary 精确回显。
258
+
259
+ **不做**:不提供统一的大 System Prompt,也没有 prompt 版本管理 / A-B / 变量注入这类设施;不写岗位方法、产品字段与 API 参数;不判断填进去的岗位内容对不对(那是 ⑤)。
260
+
261
+ ### ② 身份获取与事件感知
262
+
263
+ **做**:把形状各异的原始事件(`data` 是 JSON 字符串、`payload.body` 嵌套、命名风格混用)归一成稳定的事件合同;缺 conversation/message/sender 直接拒收而不是让 Agent 猜收件人;把回复目标与执行身份冻结成正文改不动的权威快照;按 Field 一次性绑定权限、行为包、DWS 身份与消息出口(一个 Field 只允许一个出口 owner,配错启动即失败);生成任何内容之前判定响应资格;用三个受约束的 Enricher(引用还原 / 同人连发合并 / 身份可读化)补齐现场,每项带来源、时间、截断与置信标记;按 eventId 抢 durable lease 保证同一事件只产生一个 Run,崩溃窗口先落 durable inbox 再物化,重放与漂移一律拒绝复用。
264
+
265
+ **不做**:不签发身份、不划定场域(钉钉侧的权限);**不拥有事件订阅与触发器**——Webhook、机器人回调、定时器、autopilot 都不属于本项目,`listen` 只是本地联调 Adapter。
266
+
267
+ ### ③ 托管平台部署
268
+
269
+ **做**:把手工搬运变成受控发布链——稳定 `planId` 冻结本体与整棵 Skill 树的 hash、原子动作清单与读写预算;apply 前重新回读身份/workspace/runtime 链,与冻结计划不一致就在任何写入之前失败;写后独立回读远端对象与 assignment,再发一个带随机 marker 的加载烟测,验证每个 Skill 真被 Host 原生加载;同源重放是零远端写的 noop;失败尽力回滚,超时进 reconciling 要求只读收敛而不是盲重试;`promote` 只接受与策略指定 suite/case/surface 精确匹配的证据 hash;`retire` 只归档那一个 Agent,保留 Skill、Issue 与产物。
270
+
271
+ **不做**:不创建任何事件入口(机器人、Webhook、定时器、autopilot);不创建远端 workspace/runtime,不做平台账号供给;不持有或代替用户登录平台凭据;不允许直接晋级到 prod。
272
+
273
+ ### ④ 驱动它在钉钉里干活
274
+
275
+ **做**:把外发收窄成四个互斥原语(`ack`/`reply`/`ask`/`silence`),模型造不出第五种副作用;ActionRequest 里不允许出现收件人、会话与身份,写错目标在结构上不可能;副作用**前**拦掉越权、超预算、目标漂移、状态非法等情况,副作用**后**强制平台回读把「命令返回成功」与「消息真的在钉钉里」分开记录;结果不确定时进入 reconcile 而**禁止盲重发**;跨 Run、跨沙箱靠宿主的 Wait 与 Session 续做,任务进度用 revision CAS 防覆盖;「完成」必须引用宿主签发、可重新核验的证据。
276
+
277
+ **不做**:不运行模型、不自带调度器、没有工作流引擎;进 Action Gate 的 typed 副作用**只有回复与表情两种**,其余钉钉动作继续直接走 DWS(判据是 §4 的六条),不受 Run 预算与 generation 约束。
278
+
279
+ > ⚠️ **一处「设计完成度 > 交付完成度」的断点**:完成证据的**核验**侧已完整实现并被合同锁定,但**签发**侧(`issueCompletionEvidence`)目前只有库 API,没有接到公开 CLI——`dta task` 只有 `show` 与 `checkpoint`。只用已发布 CLI 的开发者**无法把一件事推进到 `completed`**,需要宿主以库形式集成。
280
+
281
+ ### ⑤ 评测设计
282
+
283
+ **做**:给出「选最低够用的环境层级」的判断表与 L0–L4 分层;规定一次结论必须同时采集哪几个证据面,且回复正文永远不能自证完成;把硬门禁的判定顺序固定下来,防止安全失败被质量分平均掉;提供四个默认零副作用的 runner(真实外发需四道 gate 同时打开);给出「真实事故 → 可复跑场景」的沉淀路径与「这条该修进 CLI 还是修进 Skill」的判别原则;仓库自身的 62 个合同即范例,**每条都成对写明证明什么、不证明什么**。
284
+
285
+ **不做**:不做自然度与主观质量的自动判定,不允许用模型主观高分覆盖已实现的安全失败;不自动清理测试产物(写入授权不等于删除授权);不支持 prod 晋级。
286
+
287
+ ### ⑥ 观测与计量
288
+
289
+ **做**:`dta observe` 提供一条受控通道——把线上发现的一条**人工撰写**的脱敏观察,精确绑定到「线上跑的到底是哪一版」(必须与已 promoted Receipt 的 `observedHash` 逐字节相同),落成 gitignored 的 `proposed` 候选。它保证线上反馈**永远不会自动变成 Agent 的新行为**,且 CLI 会直接拒收手机号、邮箱、token 等敏感串。
290
+
291
+ **⚠️ 这是当前最薄的一段,必须说清楚**:`dta observe` **不采集任何线上数据**,它不是线上观测。执行轨迹的读取能力属于托管平台(随平台包分发一个薄 HTTP wrapper,换平台即失效)。**用量计量——交互量、任务量、线上 token、成本、按人/按群的使用分布——本项目一项都没有实现。** 最接近的是托管平台按 issue 聚合的 token 直通调用,以及本地评测执行的单次 token/花费(无聚合)。反馈采集也不是自动的,靠人手写 JSON;候选从 `proposed` 进入 Eval suite 的评审流程尚未实现。
292
+
293
+ **不做**:`observe` 产物不进 Git(团队间无法共享);不把线上数据写回 Prompt/Skill/suite;在线 Run 不得自动扩大身份、权限或启用 Skill。
294
+
295
+ > 计量这层 dta 不造,但**该怎么自建**有可抄的范式——运行记录账本(每 Run 一行)+ 费率折算 + 体检元节律 + L0–L4 达成度判据,见 [AGENT-IN-PRODUCTION.md](AGENT-IN-PRODUCTION.md)「观测这一层,dta 不替你造——但有可抄的范式」。
296
+
297
+ ---
298
+
299
+ Agent Project 与 Development Workspace 的基数关系:
300
+
301
+ ```text
302
+ 1 Agent Project ── 0..N Development Workspaces
303
+ 1 Workspace ── 1 Host Provider
304
+ 1 Workspace ── N Storage Bindings
305
+ 1 Workspace ── 0..N Sessions ── 0..N Runs
306
+ ```
307
+
308
+ `dingtalk-agent.json` 是进入 Git 的期望状态;`.dingtalk-agent/state/workspaces/<name>.json` 是 Provider 回读事实。Secret、Token、cookie 和凭据不得进入任何一层,环境字段只保留 `env:VAR` 来源。
309
+
310
+ **Host Provider 与 Storage Provider 正交**:OpenCode/Multica 决定"在哪里运行",`local-md`/`local-dir`/`dingtalk-doc` 决定"语义内容放在哪里"。因此缺少某个平台 CLI 只会让对应 Workspace 变 `partial`,不会污染其它 Workspace;state 中 Provider 与声明不一致、desired hash 漂移或非 ready 状态则一律 fail closed。
311
+
312
+ 所有远端写入都需要明确目标、当前 `planId` 和显式确认;所有计划默认零写入。设计推演见 [Provider-bound Development Workspace](roadmap/provider-bound-development-workspace.md)。
313
+
314
+ ## 9. Agent 如何演进:只产生候选,不热改
315
+
316
+ 在线 Run 可以提出候选,但**不能热修改身份、权限、已启用 Skill 或当前 Run 的策略**。这条规则在本仓库有两个同形状的实现,它们共享同一套治理结构:
317
+
318
+ | 通道 | 谁提出 | 落到哪 | 谁决定 |
319
+ |---|---|---|---|
320
+ | `memory candidate` | 在线 Run 从一次纠正中提取 | 绑定 scope/Run/Event/Definition hash 的候选 | 离线 reviewer,用 revision CAS approve/reject |
321
+ | `dta observe` | 已 promote 的部署反馈 | gitignored、`proposed`、不可直接发布的 eval candidate | 人工评审后才可能进入 Eval suite |
322
+
323
+ 两者都:只写候选、不改本体;都要求 provenance 与 scope;都用 revision CAS 或 expected hash 防止评审期间目标漂移;发布后都只影响**后续新 Session**,不改变当前 Run。
324
+
325
+ 本地/Git 发布使用 target expected hash、durable lease、原子替换和回读,CLI 不自动 commit/push。钉钉文档只追加唯一 marker 并全文回读——因为 Markdown 没有可靠 CAS(§6),其回执必须显式声明 `best-effort-read-check-append` 的并发语义。
326
+
327
+ W4 只在 W3 inspection 完整且未漂移时开放 `dta deploy`。plan 冻结 profile、Workspace、Runtime、Agent、Definition、完整 Skill tree hash 与 forward/rollback 最大写预算;apply 在写前重新执行 W3 scope 链回读,并先持久化 operation。Agent instructions 必须等于人类可读 Definition 原文,部署 hash 与 Skill 清单只进控制面;Basic 与 Role Skill 完整树、runtime/private mode 和唯一 assignment 都要写后独立回读。最后通过专用 Issue 直接取得每个 Skill 的 tool trace 与精确 JSON response,二者同时通过才签发本地 Receipt 并进入 `ready`:
328
+
329
+ ```text
330
+ trusted W3 inspection + local Definition/Skill tree
331
+ → stable dry-run planId (zero Provider calls)
332
+ → explicit planId + yes
333
+ → scope reinspection → operation persisted
334
+ → Skill/Agent/assignment reconcile → independent readback
335
+ → Basic → Role load smoke
336
+ → Receipt + workspace-state@1 ready
337
+ ```
338
+
339
+ ## 10. 当前明确不做
340
+
341
+ - 不把 `listen` 或任何触发器做成 Agent 主进程;
342
+ - 不自己做 Managed Agent Platform,也不签发组织身份或场域授权;
343
+ - 不把尚未开放的平台宣称为已支持、已部署或已 Live 验证;
344
+ - 不自动 init 任意代码仓库;
345
+ - 不把整个 DWS 复制成另一套 CLI;
346
+ - 不把钉钉文档当锁或事务数据库;
347
+ - 不序列化语言运行时栈;
348
+ - 不允许在线 Run 自动扩大身份、权限或启用 Skill;
349
+ - 不把本项目变成巨型 Prompt。
350
+
351
+ ## 11. 延伸阅读
352
+
353
+ | 想做什么 | 去哪 |
354
+ |---|---|
355
+ | **接手一个已经在跑的 Agent**(运行视角:一天怎么转、坏起来什么样、去哪看) | [Agent in Production](AGENT-IN-PRODUCTION.md) |
356
+ | 安装、升级与排障 | [Installation](INSTALLATION.md) |
357
+ | 评测方法、证据分层与晋级门禁 | [Self-test](SELF-TEST.md) |
358
+ | 创建或审计一个 Agent | [Compose Skill](../skills/core/dta-agent-compose/SKILL.md) |
359
+ | 测试或调试已交付的 Agent | [Eval Skill](../skills/core/dta-agent-eval/SKILL.md) |
360
+ | 公共行为协议本身 | [Basic Behavior Skill](../skills/core/dta-basic-behavior/SKILL.md) |
361
+ | DWS 与钉钉 API 的实战缺陷 | [DWS Field Notes](DWS-FIELD-NOTES.md) |
362
+ | 借鉴了哪些开源项目、各自取了什么 | [Prior Art](PRIOR-ART.md) |
363
+ | 真实事故该由平台哪一层兜(护栏清单) | [Platform Guardrails](PLATFORM-GUARDRAILS.md) |
364
+ | 尚未完成的工作 | [roadmap](roadmap/) |
365
+
366
+ 在本仓库工作的 Coding Agent 请先读 [AGENTS.md](../AGENTS.md),验证命令以那里为准。
@@ -69,7 +69,7 @@ npm 全局命令会被链接到 `{prefix}/bin`,但不同 Node 版本管理器
69
69
  npm install → dta setup
70
70
  → 安装当前版本到 ~/.local/bin
71
71
  → 检查并幂等补充 ~/.zshrc / ~/.bashrc PATH
72
- → 安装 canonical 内置 Skill(Basic Behavior + Compose)
72
+ → 安装 canonical 内置 Skill(Basic BehaviorCompose、Eval
73
73
  → 暴露给 Claude Code,验证 Codex/OpenCode 共享发现
74
74
  → 检查 DWS 版本和认证
75
75
  → 给出唯一下一条命令
@@ -124,7 +124,7 @@ dws auth login
124
124
 
125
125
  ```bash
126
126
  npx --yes --registry=https://registry.npmjs.org --package=skills@latest -- skills add \
127
- <package>/skills/core/dingtalk-basic-behavior \
127
+ <package>/skills/core/dta-basic-behavior \
128
128
  --global --yes --agent claude-code codex opencode
129
129
  ```
130
130
 
@@ -132,9 +132,9 @@ npx --yes --registry=https://registry.npmjs.org --package=skills@latest -- skill
132
132
 
133
133
  | 客户端 | 发现方式 | 路径 |
134
134
  |---|---|---|
135
- | Claude Code | 相对 symlink | `~/.claude/skills/dingtalk-basic-behavior` |
136
- | Codex | shared Agent Skills | `~/.agents/skills/dingtalk-basic-behavior` |
137
- | OpenCode | shared Agent Skills | `~/.agents/skills/dingtalk-basic-behavior` |
135
+ | Claude Code | 相对 symlink | `~/.claude/skills/dta-basic-behavior` |
136
+ | Codex | shared Agent Skills | `~/.agents/skills/dta-basic-behavior` |
137
+ | OpenCode | shared Agent Skills | `~/.agents/skills/dta-basic-behavior` |
138
138
 
139
139
  检查、重装当前 npm 包内版本和卸载:
140
140
 
@@ -155,11 +155,11 @@ OpenCode 官方同时支持 `.opencode/skills`、`.claude/skills` 和 `.agents/s
155
155
  ```bash
156
156
  # 有仓库权限
157
157
  npx skills add D1-2004/dingtalk-agent \
158
- --skill dingtalk-basic-behavior --global --yes \
158
+ --skill dta-basic-behavior --global --yes \
159
159
  --agent claude-code --agent codex --agent opencode
160
160
 
161
161
  # 本地 checkout
162
- npx skills add ./skills/core/dingtalk-basic-behavior \
162
+ npx skills add ./skills/core/dta-basic-behavior \
163
163
  --global --yes --agent claude-code --agent codex --agent opencode
164
164
  ```
165
165
 
@@ -194,7 +194,7 @@ dta prepare --event-file event.json --json
194
194
 
195
195
  ## 开发者 Golden Path
196
196
 
197
- 安装完成后,一个岗位 Agent 只需要三组输入:本地 `AGENTS.md`、本地 `skills/<role>/SKILL.md`,以及从 compose Skill 模板创建的 `agent.bindings.json`。本地模板把 memory/knowledge 指向 Markdown;远端模板只把这两个语义槽路由到专用钉钉文档,产物与控制状态仍留在 Agent 根目录。
197
+ 安装完成后,一个新岗位 Agent 只需要三组输入:`agent/AGENTS.md`、`agent/skills/<name>/` 单一发布源,以及从 compose Skill 模板创建的 `agent.bindings.json`。根 `AGENTS.md` 只约束仓库开发。Host exposure dta 在隔离工作区临时物化,不进入 Git;已有仓库可在 manifest 显式声明其它路径。
198
198
 
199
199
  ```bash
200
200
  # 在 Agent 根目录
@@ -0,0 +1,188 @@
1
+ # dta 平台护栏清单:哪些坑必须由工具层兜住
2
+
3
+ > 2026-07-24 一夜盯一个真实生产 Agent(FDE 教练)跑,踩出六个坑。本文回答一个问题:
4
+ > **每个坑该由谁兜——原语 / CLI 闸门 / Skill 纪律 / 文档?**
5
+ >
6
+ > 一条贯穿全文的判据:**凡是「dta 文档已经写过、业务方仍然逐个踩」的坑,就是该从文档下沉到 CLI 的信号。**
7
+ >
8
+ > ⚠️ **诚实说清本文的定位(经两轮 review 收窄)**:本文是**事故复盘 + 该由哪层兜的分析**,
9
+ > 不是"已封死"的宣告。本次 CR 真正落到**代码**的只有【节律静态检查(同刻并发按真实 occurrence 判、
10
+ > 完成判据存在性、计量标注)】;【AI 表格静默截断】和【完成判据分叉】这两个最核心的坑,
11
+ > 本次只做了**文档 + Skill 纪律 + 存在性检查**,**没有**做到类型层/注册表层的硬封印——那需要
12
+ > `completeness: proven\|unproven` 原语、`predicateRef` 注册表、no-op Receipt 合同,均已列为 follow-up issue。
13
+ > 换句话说:**别把本文当"每个 Agent 都自动免疫了",它是"我们知道坑在哪、部分下沉了、其余明确记账"。**
14
+ >
15
+ > 证据等级:**【实测】**本机只读复跑、**【读码】**对到 file:line、**【下界】**单读表格数可能偏小。
16
+
17
+ ---
18
+
19
+ ## 0. dta 今天的护栏落在哪三层
20
+
21
+ `README.md` / `AGENTS.md` 的口径是 **Skill 劝 · CLI 拦 · DWS 做**。【读码】实际分布:
22
+
23
+ | 层 | 位置 | 今天真拦住了什么 |
24
+ |---|---|---|
25
+ | Skill 劝 | `skills/core/dta-basic-behavior/SKILL.md` | 响应资格、意图、`nothing-to-save` 合法性、没 Receipt 不用完成措辞 |
26
+ | CLI 拦 | `src/dws.ts` 六条纪律、`records()` fail-closed、`src/actions.ts` 发消息后独立回读、`src/memory/operational.ts` 按 recordId 回读 + 命中多行拒绝 | 目标冻结、四原语、写后回读、幂等 |
27
+ | DWS 做 | `src/dws.ts`(全仓唯一 spawn `dws` 处) | — |
28
+ | **文档层**(既不劝也不拦) | `DWS-FIELD-NOTES.md`、`AGENT-IN-PRODUCTION.md` | **什么都拦不住** |
29
+
30
+ **最硬的一个判据**:`AGENT-IN-PRODUCTION.md` 早就写了"写后回读读的是同一个错误对象"、"同一个语义只留一个谓词"、"改 mode 就是在改计量口径"——**文档劝过了,业务方还是踩了**。这三条都该下沉。
31
+
32
+ ---
33
+
34
+ ## 1. 坑一 · AI 表格静默截断 → **必须是原语,不能只写进 Skill**
35
+
36
+ **【实测】** 同一 `--all --page-limit 0` 全表连读 6 次得 `400/300/1300/500/1800/700`,
37
+ pages `5/4/14/6/19/8`,**6 次全 `hasMore=false`、`partial` 键根本不存在**。单次最低 300 是并集下界的 17%。
38
+ 成功信封的全部键只有 `records/hasMore/pages`——**没有 `totalCount`,服务端不提供任何完整性凭据**。
39
+
40
+ **【读码】dta 今天的状态**:
41
+
42
+ - `src/dws.ts records()` 已 fail-closed 检查 `hasMore/partial`——**和 FDE 引擎 `query()` 同一道闸门、同一个漏洞**。平台谎报 `hasMore:false`,两道闸门同时被绕过。
43
+ - **更糟**:`src/dws.ts queryAiTableRecords()`(dta 自己的 Operational Memory 读路径)**不带 `--all`、不带 `--page-limit 0`,只 `--limit 100`**——比 FDE 引擎还弱一档。
44
+ - `DWS-FIELD-NOTES.md` 现有对策「`--all` 必配 `--page-limit 0`」**今晚实测证伪**:加了照样截断。
45
+
46
+ **为什么不能留给业务方**(不是偏好):
47
+ 1. 这是**介质属性**不是岗位知识。FDE 已严格按文档写对参数,仍被骗 → 这题在 Skill/文档层**无解**。
48
+ 2. 判据需要**跨调用状态**(多读、计数账本、水位),Skill 是无状态语义层。`AGENTS.md` 自己就写「幂等、回读、硬拒绝 → CLI/Gate,不得只写在 Prompt」。
49
+ 3. `dta-people-group-memory/references/storage-port.md` 自立原则「模型层不知道『截断』这个词」——既然模型层不该知道,就必须有人替它知道。
50
+
51
+ **该做什么**:
52
+
53
+ | 落层 | 改动 |
54
+ |---|---|
55
+ | **原语** `src/dws.ts` | `records()` 不再把 `hasMore=false` 当完整性证据。返回 `{records, completeness: 'proven'\|'unproven'}`,全量扫一律 `unproven`,调用方**编译期**绕不过去 |
56
+ | **原语** `src/dws.ts` | 把混为一谈的读拆成三个、在类型上分开可靠性:`getByRecordIds()`(≤100 定点,【实测】7/8 正确且失败 fail-loud)/`queryByKey(filters)`(服务端筛,**仍 unproven**)/`scanAll()`(**标记不可信**) |
57
+ | **原语** `src/memory/` | **count ledger**:写侧每次 `+1` 到 meta 表,读侧全量枚举时两数相比——**唯一**能把"读全了"变可证明的机制(服务端无 `totalCount` oracle)。诚实边界:只覆盖 dta 自己写的行,给"不少于";对单写者表等号成立 |
58
+ | **CLI 闸门** | 连读 K 次取 max **只提高发现截断的概率、不能证明完整**(【实测】并集到第 5 次才碰到 1800,仍是下界)。所以 K-读只作 `unproven→suspected-truncated` 降级信号,**不许当完整性证明**——写进代码注释,否则会被误当对策 |
59
+ | **文档** | 更正 `DWS-FIELD-NOTES.md`:`--all --page-limit 0` **不足以**防截断,附今晚数据 |
60
+ | **回归** | `evals/` 加 core 合同:fake dws stub 返回"页对齐前缀 + `hasMore:false`",断言 CLI **拒绝**当完整 |
61
+
62
+ **⚠️ 已推翻的一个说法**(复核纠正):曾以为"`--all` 的空返回有一种 fail-loud 安全形态"。**错**——
63
+ `--all` 路径上的空返回是 `{"hasMore":false,"pages":1,"records":null}`,`records` 键在、值为 `null`,
64
+ 两道闸门(`dws.ts` 的 `'records' in x` 和 `records || []`)都**静默**放过。`--all` 路径上**两种 0 都不安全**。
65
+
66
+ ---
67
+
68
+ ## 2. 坑二 · 写后回读读到同一个错对象 → **Action Gate 该管,今天管不到**
69
+
70
+ **背景事故**:FDE 的 `write-ai` 盲写 `rows[0]`、回读也取 `rows[0]` → 永远自洽 → 写错行永远发现不了。
71
+ 根因是「业务主键不唯一 + 定位靠读」,回读只是发现手段。
72
+
73
+ **【读码】dta 今天**:这条合同**已存在**——`src/memory/operational.ts` 按 recordId 独立回读、key 命中多行直接拒绝、
74
+ 创建后没拿到 recordId 就按 key 回查。`ARCHITECTURE.md` 还拿它当"为什么这必须是 CLI 命令"的范例。
75
+ **但覆盖面几乎为零**:只作用于 `dta memory operational upsert` 一条命令;进 Action Gate 的 typed 副作用
76
+ **只有回复与表情两种**,AI 表格写入根本不进 Gate。FDE 的 write-ai 是业务方自己写的,所以这条事故 dta 一点忙没帮上。
77
+
78
+ **该落哪**:
79
+ - **CLI 闸门(新增窄命令)**:按 `ARCHITECTURE.md` 的六条判据,业务表写入命中第 3(幂等且不能盲重试)+ 第 4(写后必须独立回读)→ **符合进 CLI 的标准**。但不做通用 CRUD(`ARCHITECTURE.md` 明禁复制 DWS 命令面)。折中:
80
+ `dta aitable upsert --key-field <f> --key <v> --required-nonempty <f,…>`,只做四件——按业务键定位 → 键唯一性断言 → 写 → 按 recordId 回读,其余回 DWS。
81
+ - **为什么不留给业务方**:这个错误 **100% 静默且自洽**(写 rows[0]、回读也取 rows[0] → 永远自证成功),数据上看不出来,只有 backlog 三十小时不降才反推得到。"结构性不可观测"的错误定义上就不该由每个业务方各自发现一次。
82
+
83
+ **⚠️ 一个未复现的推测**(复核纠正):曾推测 dta 自己的 `operational.ts` 也有同族"截断到 0 → 判不存在 → create 重复"的洞。
84
+ **在真实代码路径上未复现**:`operational.ts` 走 `--limit 100`(非 `--all`),【实测】连读 30 次里 2 次空返回都是
85
+ 带 `error` 的信封 → 进 `dws.ts` 的 `error.code` 判断 → **fail-loud(die)**,不是静默造重复。
86
+ 所以 dta 内核这条路是安全的——但**新增的 `dta aitable upsert` 若走 `--all` 定位就会引入这个洞**,设计时必须用 `getByRecordIds`/`queryByKey` 而非 `scanAll`。
87
+
88
+ ---
89
+
90
+ ## 3. 坑三 · 两个完成判据分叉 → **注册表 + 唯一入口,不是静态检查**
91
+
92
+ **背景事故**:FDE 的 `duty_runlog()` 完成判据只看答案原文、`_settled()` 还要问题原话,两谓词分叉 →
93
+ 心跳先问 done、done 就不跑补录 → 补救路径 30 小时没被触发、没有任何一层报警。
94
+
95
+ **【读码】现状**:`AGENT-IN-PRODUCTION.md` 已把结论写成「同一个语义只留一个谓词,两个调用方共用」;
96
+ `AGENTS.md` 有「每条不变量只选一个 owner」的表,但管的是**内容写在哪个文件**、不是**代码谓词的唯一性**。**没有机器检查。**
97
+
98
+ **能做**:
99
+ - **装配层**:`dta-agent-compose` 的节律声明里,每条 schedule 带 `doneWhen: predicate:<id>`。
100
+ - **CLI 闸门**:`dta schedule plan` 校验每个 predicate 在 Agent 侧可执行——`src/schedule-plan.ts` 已有
101
+ "平台不提供该能力就 supported:false 记缺口、绝不静默降级"的 fail-closed 骨架,**直接复用到 predicate**。
102
+ - **回归**:同一 duty 的两个调用点必须解析到同一 predicate id,不同就红。
103
+
104
+ **不能做(诚实标注)**:跨语言(FDE 引擎是 Python)**没法静态证明两个函数语义相同**。约束形式只能是「注册 + 唯一入口 + 谁绕过谁没 receipt」,不是分析。
105
+
106
+ ---
107
+
108
+ ## 4. 坑四 · 解析失败被折叠成"内容为空" → **解析失败必须留痕,拦在写入前**
109
+
110
+ **背景事故**:平台改中继模板标题 → FDE 的 `_RE_ASKED` 100% 不命中 → 抠不到问题原话 → **静默写空**。
111
+ 通用形状 = **解析失败与"本来就空"不可区分**,和 `DWS-FIELD-NOTES.md` 的「读错层级 → undefined → 当成空」同族。
112
+
113
+ **该落哪**:
114
+ - **原语/Skill 纪律**:凡"从外部信封解析出字段再写入"的路径,解析失败必须产出一个**可区分于空**的标记(如 `parse-miss`),
115
+ 而不是落一个空字符串。写入前若关键字段是 `parse-miss` → 记欠账、不写、可报警。
116
+ - **对应 `dta-people-group-memory` 的第 3 条不变式「读失败 ≠ 不存在」**——但那条现在只针对**读**,
117
+ 要扩到**解析**:解析失败 ≠ 字段为空。
118
+
119
+ ---
120
+
121
+ ## 5. 坑五 · ephemeral 不产 issue → 不可计量 → **观测缺口,ARCHITECTURE §8 自己承认**
122
+
123
+ **【读码】** 常驻节律多是 `ephemeral`(`run_only`),平台不为它建 issue → `/api/tasks/{id}/usage` 拿不到 →
124
+ 心跳的真实 Token 拿不到。`ARCHITECTURE.md §8` 自己说观测是"最薄的一段"。
125
+ FDE 侧实测:可见 IM 成本只是冰山一角,心跳那半平台不记账。
126
+
127
+ **该落哪**:
128
+ - **文档已对(`AGENT-IN-PRODUCTION.md` §6 写了盲区),但 dta 无计量能力**。这条不该硬造——
129
+ 但 dta 至少该在 `dta schedule plan` 输出里**标注每条节律的 `mode` 与可计量性**,让 operator 在排期时就知道哪块看不见,
130
+ 而不是等业务方各自发现。「改 `mode` 就是改计量口径」这句该从文档变成 `schedule plan` 的一条显式告警。
131
+
132
+ ---
133
+
134
+ ## 6. 坑六 · "无操作"不可观测 → **`nothing-to-save` 也要留痕**
135
+
136
+ **背景事故**:FDE 的单聊沉淀判 `nothing-to-save` 是合法结果,但**判了 nothing-to-save 和压根没跑,在外部完全不可区分**——
137
+ 沉淀这步没跑不留痕、跑了判空也不留痕。结果是"这个能力到底在不在工作"永远回答不了。
138
+
139
+ **该落哪**:
140
+ - **Skill 纪律(`dta-basic-behavior` + `dta-people-group-memory`)**:把「无操作也是一次可观测的操作」立成通用合同——
141
+ 判 `nothing-to-save` / `skip` / `no-op` 时**留一行结构化痕迹**(带原因),而不是静默返回。
142
+ - 这条和 `dta-basic-behavior` 的"没 Receipt 不用完成措辞"是一体两面:完成要有证据,**不完成也要有证据**。
143
+
144
+ ---
145
+
146
+ ## 7. 对 dta-people-group-memory 四条不变式的复核
147
+
148
+ 这个 Skill(v0.3.0)刚进默认套装,四条不变式在**静默截断**下逐条评估:
149
+
150
+ | 不变式 | 扛得住截断吗 | 说明 |
151
+ |---|---|---|
152
+ | ① 原始层只增不删,派生层可重建 | ✅ | 与截断无关 |
153
+ | ② 写后必回读,success 不算数 | ⚠️ **不够** | 回读若用 `scanAll` 会被截断骗;必须限定为**按 recordId 回读**(坑二)。「回读」要在契约里写死是哪种读 |
154
+ | ③ **读失败 ≠ 不存在** | 🔴 **最需要加强** | 现在只针对**报错的读**。而截断读**不报错**——它成功返回一个偏小的前缀。这条不变式的前提"读失败会被识别"在 `--all` 上**不成立**。必须补一句:**"成功但可能不完整"也算读失败**,全量枚举一律 `unproven`,绝不据此判"不存在"或新建重复 |
155
+ | ④ 先写事实、后推水位 | ✅ | 与截断无关,且正确 |
156
+
157
+ **核心修订**:第 ③ 条要从「读失败 ≠ 不存在」升级为「**读不完整 ≠ 不存在**,而全量枚举永远无法自证完整」。
158
+ 这正是坑一 G1 的原语要兜的——把"完整性未证明"变成一个类型层的显式状态,Skill 的第 ③ 条才有东西可依靠。
159
+
160
+ ---
161
+
162
+ ## 附:落地状态(2026-07-24 本次 CR,两轮 review 后收窄)
163
+
164
+ 分三档如实标:**代码闸门**(机器强制)、**文档/Skill**(劝、不强制)、**follow-up**(真封印,本次没做)。
165
+
166
+ **已落代码闸门(机器强制、CI 守)**
167
+ | 坑 | 落点 | 状态 |
168
+ |---|---|---|
169
+ | 坑三 判据缺失 | `schedule-plan.ts` 校验每条节律有 `completion`,缺失 `schedule show/plan` **exit 2**(json+人类都设,不 fail-open) | ✅ 代码 |
170
+ | 坑五 计量盲区 | `schedule-plan.ts` 每条节律标 `metered`(ephemeral 不记账显式提示) | ✅ 代码 |
171
+ | 撞车误报/漏报 | `firesCollide` 改**按真实 occurrence 判**(robfig dom/dow OR、名字字面量、闰年枚举);判不准的(跨时区/扩展语法)进 `unverifiedPairs`,**和确认撞车一样 exit 2 挡住**——`0 9 * * *`@Asia/Shanghai 与 `0 1 * * *`@UTC 是同一时刻,证不出不撞就不许部署 | ✅ 代码 + 回归 |
172
+
173
+ **已落文档/Skill 纪律(劝,不强制——这几条本次【没有】做成硬封印)**
174
+ | 坑 | 落点 | ⚠️ 局限 |
175
+ |---|---|---|
176
+ | 坑一 截断 | `DWS-FIELD-NOTES` 重写 + `dws.ts` 注释 + people-memory 不变式③「读不完整≠不存在」 | `records()` 仍会接受 `hasMore:false` 的部分前缀、把 `records:null` 折成 `[]`——**没有 completeness 类型封印**(见 follow-up) |
177
+ | 坑三 判据分叉 | `completion` 存在性检查 | **只证明"写了一句话"**,不保证运行时两个谓词引用同一个——原事故那种"各有一套判据"仍可能复发(见 follow-up) |
178
+ | 坑四 解析失败折叠成空 | `DWS-FIELD-NOTES`「解析失败≠空」+ `parse-miss` | 是文案,没有强制的 typed action |
179
+ | 坑六 无操作不可观测 | `dta-basic-behavior`:`nothing-to-save` 也要留痕 | 是文案,**没有** host 签发的 no-op Receipt 合同(见 follow-up) |
180
+ | 不变式② | people-memory:写后按 recordId 回读 | ✅ 纪律清晰 |
181
+
182
+ **明确 follow-up(真封印,本次没做,各开 issue)**
183
+ 1. `completeness: proven\|unproven` 读原语 + 页对齐前缀 fixture——把"未证明完整"变类型层显式状态。
184
+ 2. `predicateRef` 注册表 + 运行时引用校验——让"完成判据分叉"在编译期/运行期查得出来。
185
+ 3. host 签发的 no-op / nothing-to-save Receipt 合同——让"跑过判空"可与"没跑"区分。
186
+ 4. cron 同刻判定复用 provider(robfig)occurrence 预览,替掉本地模拟。
187
+
188
+ **明确没做(避免一味增加)**:不新增 `dta aitable upsert` CLI 命令面(`ARCHITECTURE.md` 明禁复制 DWS 命令面,且无现有调用方);`records:null` 不硬判死(dws 版本相关,硬判深耦合);计量不进 core。