@sema-agent/server 7.43.0 → 7.44.0

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 (345) hide show
  1. package/USAGE.md +18 -0
  2. package/dist/adoption/plan.js +31 -192
  3. package/dist/adoption/quiesce.js +3 -86
  4. package/dist/adoption/runner.js +3 -140
  5. package/dist/adoption/sql.js +0 -74
  6. package/dist/adoption/wire.js +0 -80
  7. package/dist/approval-ask-machine.js +0 -75
  8. package/dist/approval-card.js +0 -323
  9. package/dist/approval-deny-reasons.js +0 -42
  10. package/dist/approval-hmac.js +0 -35
  11. package/dist/approval-reconciler.js +8 -166
  12. package/dist/approval.js +4 -67
  13. package/dist/audit.js +1 -44
  14. package/dist/auth-bridge.js +4 -47
  15. package/dist/auth-keys.js +0 -23
  16. package/dist/bake-runner/main.js +4 -65
  17. package/dist/bake-runner/protocol.js +3 -58
  18. package/dist/bake-runner/runner.js +5 -91
  19. package/dist/bench/l8/artifact.js +2 -61
  20. package/dist/bench/l8/escape.js +0 -25
  21. package/dist/bench/l8/index.js +0 -14
  22. package/dist/bench/l8/probes.js +0 -60
  23. package/dist/bench/l8/run-probes.js +2 -45
  24. package/dist/bench/s1/arms.js +14 -189
  25. package/dist/bench/s1/live-deps.js +11 -253
  26. package/dist/bench/s1/oracle.js +1 -36
  27. package/dist/bench/s1/repair-oracle-adapter.js +0 -30
  28. package/dist/bench/s1/reviewer.js +0 -34
  29. package/dist/bench/s1/row.js +0 -62
  30. package/dist/bench/s1/run-firm.js +4 -70
  31. package/dist/bench/s1/runner-ctx.js +0 -40
  32. package/dist/bench/s1/tasks.js +0 -115
  33. package/dist/boot/adoption.js +0 -20
  34. package/dist/boot/budget-tracing.js +3 -55
  35. package/dist/boot/config-center.js +43 -551
  36. package/dist/boot/coordinators.js +1 -69
  37. package/dist/boot/crash-last.js +0 -18
  38. package/dist/boot/deferred-sandbox-path-env.js +3 -119
  39. package/dist/boot/execution-env.js +5 -171
  40. package/dist/boot/governance-seams.js +0 -92
  41. package/dist/boot/leader.js +0 -69
  42. package/dist/boot/limit-sync.js +0 -2
  43. package/dist/boot/memory-boundary.js +3 -91
  44. package/dist/boot/org-memory.js +1 -25
  45. package/dist/boot/parked-revive-gate.js +0 -150
  46. package/dist/boot/permission-rules-audit.js +1 -56
  47. package/dist/boot/reapers.js +15 -273
  48. package/dist/boot/resolve-spec.js +9 -768
  49. package/dist/boot/retention-lane.js +4 -87
  50. package/dist/boot/runner-deps.js +3 -297
  51. package/dist/boot/runtime-caps.js +0 -40
  52. package/dist/boot/session-faces.js +2 -133
  53. package/dist/boot/shutdown.js +9 -83
  54. package/dist/boot/side-query-lane.js +2 -137
  55. package/dist/boot/stores.js +15 -215
  56. package/dist/boot/task-list-lane.js +0 -18
  57. package/dist/boot/webfetch-summarize-lane.js +0 -47
  58. package/dist/boot/workflow-orchestration.js +3 -99
  59. package/dist/boot-reclaim.js +0 -20
  60. package/dist/bounded-session-map.js +0 -19
  61. package/dist/brain.js +2 -139
  62. package/dist/budget.js +9 -244
  63. package/dist/capabilities/builtin-tools.js +0 -3
  64. package/dist/capabilities/center-plugins.js +6 -51
  65. package/dist/capabilities/center-prompts.js +6 -71
  66. package/dist/capabilities/code-review-council.js +7 -40
  67. package/dist/capabilities/collab-workflows.js +1 -44
  68. package/dist/capabilities/hands-lane.js +0 -65
  69. package/dist/capabilities/memory-notice.js +0 -70
  70. package/dist/capabilities/prompt.js +0 -14
  71. package/dist/capabilities/prompts/code-review.js +0 -14
  72. package/dist/capabilities/prompts/identity.js +0 -6
  73. package/dist/capabilities/prompts/team.js +0 -4
  74. package/dist/capabilities/repo-tools.js +0 -34
  75. package/dist/capabilities/sandbox-file-send.js +3 -92
  76. package/dist/capabilities/scenarios.d.ts +0 -1
  77. package/dist/capabilities/scenarios.js +18 -279
  78. package/dist/capabilities/select-environment-tool.js +0 -32
  79. package/dist/capabilities/send-user-file-tool.js +2 -66
  80. package/dist/capabilities/skills.d.ts +1 -2
  81. package/dist/capabilities/skills.js +3 -21
  82. package/dist/capabilities/team.d.ts +3 -11
  83. package/dist/capabilities/team.js +3 -51
  84. package/dist/capabilities/tool-defer.js +0 -3
  85. package/dist/config-center/apply-effective.js +15 -330
  86. package/dist/config-center/apply-ledger.js +5 -38
  87. package/dist/config-center/facade.js +0 -41
  88. package/dist/config-center/hot-keys-registry.js +0 -20
  89. package/dist/config-center/http-client.js +2 -125
  90. package/dist/config-center/mcp-revocation.js +2 -34
  91. package/dist/config-center/read-face.js +0 -59
  92. package/dist/config-center/restart-signal.js +1 -85
  93. package/dist/config-center/skills-mcp.d.ts +1 -1
  94. package/dist/config-center/skills-mcp.js +9 -76
  95. package/dist/config-center/stage-limits.js +8 -35
  96. package/dist/config-invariants.js +0 -16
  97. package/dist/config-lkg.js +0 -42
  98. package/dist/config-provider.js +3 -186
  99. package/dist/config-types.js +0 -5
  100. package/dist/config.js +107 -1145
  101. package/dist/degenerate-instrument.js +3 -67
  102. package/dist/deployment-governance.js +0 -124
  103. package/dist/digest-form.js +0 -12
  104. package/dist/elicitation.js +3 -86
  105. package/dist/env-facts.js +7 -75
  106. package/dist/fleet/fleet-bus.js +34 -507
  107. package/dist/fleet/fleet-reconciler.js +9 -149
  108. package/dist/fleet/fleet-terminal-window.js +10 -178
  109. package/dist/fleet/subagent-tail-bus.js +3 -72
  110. package/dist/fleet-client.js +10 -70
  111. package/dist/fleet-lease.js +5 -79
  112. package/dist/git-api-kind.js +0 -3
  113. package/dist/governance-ask-marks.js +2 -78
  114. package/dist/hooks/branch-transcript.js +0 -74
  115. package/dist/hooks/cc-agent-hook-prompt.js +0 -29
  116. package/dist/hooks/cc-stop-prompt.js +1 -46
  117. package/dist/hooks/hook-llm.js +1 -53
  118. package/dist/hooks/hook-runner.js +20 -414
  119. package/dist/http/active-run-conflict.js +4 -129
  120. package/dist/http/cursor-fingerprint.d.ts +5 -0
  121. package/dist/http/cursor-fingerprint.js +5 -0
  122. package/dist/http/idempotency.js +0 -37
  123. package/dist/http/principal-gate.js +3 -40
  124. package/dist/http/route-ctx.js +0 -9
  125. package/dist/http/routes/a2a-serve.js +7 -319
  126. package/dist/http/routes/admin-config-refresh.js +0 -4
  127. package/dist/http/routes/admin-drain.js +0 -10
  128. package/dist/http/routes/adoption.js +1 -29
  129. package/dist/http/routes/agents-roster.js +1 -47
  130. package/dist/http/routes/approvals-assistant.js +32 -395
  131. package/dist/http/routes/attachments.js +4 -22
  132. package/dist/http/routes/capabilities.js +3 -420
  133. package/dist/http/routes/diagnostics.js +1 -81
  134. package/dist/http/routes/fleet.js +9 -185
  135. package/dist/http/routes/images.js +14 -239
  136. package/dist/http/routes/leader.js +0 -13
  137. package/dist/http/routes/memory-bundle.js +1 -61
  138. package/dist/http/routes/memory-policy.js +9 -99
  139. package/dist/http/routes/notify-wake.js +3 -37
  140. package/dist/http/routes/observability.js +2 -19
  141. package/dist/http/routes/retention-ops.js +2 -34
  142. package/dist/http/routes/rules.js +1 -93
  143. package/dist/http/routes/runs.js +64 -873
  144. package/dist/http/routes/session-sync.js +19 -258
  145. package/dist/http/routes/sessions-list.js +17 -43
  146. package/dist/http/routes/sessions.js +34 -226
  147. package/dist/http/routes/shared-memory.js +5 -36
  148. package/dist/http/routes/side-query.js +1 -87
  149. package/dist/http/routes/tasks.js +52 -722
  150. package/dist/http/routes/trace-usage.js +32 -195
  151. package/dist/http/routes/workflows.js +19 -195
  152. package/dist/http/run-meta.js +0 -6
  153. package/dist/http/send.js +0 -32
  154. package/dist/http/server.js +92 -1597
  155. package/dist/http/sse-lifecycle.js +2 -13
  156. package/dist/http/sse-log.js +3 -48
  157. package/dist/http/tar.js +5 -21
  158. package/dist/http/verify-rounds.js +0 -5
  159. package/dist/http/wire-gate.js +0 -9
  160. package/dist/http/workspace-content.js +0 -10
  161. package/dist/images/bake-validate.js +1 -70
  162. package/dist/images/manifest.js +1 -6
  163. package/dist/index.js +0 -21
  164. package/dist/key-resolver.js +2 -17
  165. package/dist/leader/diffout.js +1 -20
  166. package/dist/leader/diffup.js +0 -47
  167. package/dist/leader/endpoint.js +2 -57
  168. package/dist/leader/fanout.js +3 -45
  169. package/dist/leader/grader-env-factory.js +3 -72
  170. package/dist/leader/leader.js +5 -156
  171. package/dist/leader/merge.js +8 -115
  172. package/dist/leader/planner.js +3 -54
  173. package/dist/leader/repair-oracle.js +1 -60
  174. package/dist/leader/repair-wire.js +2 -79
  175. package/dist/leader/wire.js +8 -307
  176. package/dist/lsp/e2b-bridge.js +4 -64
  177. package/dist/lsp/e2b-manager.js +6 -94
  178. package/dist/lsp/lsp-frames.js +0 -12
  179. package/dist/lsp/manager.js +4 -96
  180. package/dist/lsp/ws-transport.js +5 -55
  181. package/dist/lsp-evict.js +1 -15
  182. package/dist/main.js +57 -765
  183. package/dist/memory-bundle-engine.js +0 -55
  184. package/dist/memory-export.js +0 -4
  185. package/dist/memory-posture.js +1 -15
  186. package/dist/memory-scope.js +11 -148
  187. package/dist/memory-sync-client.js +2 -44
  188. package/dist/memory-sync.js +1 -80
  189. package/dist/model-select.js +3 -80
  190. package/dist/observability/cost-quota.js +1 -17
  191. package/dist/observability/cost-taxonomy.js +0 -34
  192. package/dist/observability/fail-open.js +7 -86
  193. package/dist/observability/logger.js +0 -6
  194. package/dist/observability/metrics.js +0 -94
  195. package/dist/observability/otel-exporter.js +3 -13
  196. package/dist/observability/principal-context.js +0 -9
  197. package/dist/observability/prompt-manifest.js +1 -37
  198. package/dist/observability/rate-limit.js +0 -4
  199. package/dist/observability/secret-env-scrub.js +2 -56
  200. package/dist/observability/tool-trace.js +1 -70
  201. package/dist/orchestration/hardened-vm-runner.js +4 -118
  202. package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
  203. package/dist/orchestration/hardened-vm-worker.js +0 -27
  204. package/dist/orchestration/subagent-steer.js +1 -45
  205. package/dist/orchestration/workflow-agent-steer.js +1 -80
  206. package/dist/orchestration/workflow-completion-inbox.js +32 -285
  207. package/dist/orchestration/workflow-notify-journal.js +16 -259
  208. package/dist/org-memory-admission.js +3 -47
  209. package/dist/parent-watch.js +2 -48
  210. package/dist/parked-decide.js +1 -109
  211. package/dist/per-task-image.js +0 -57
  212. package/dist/plan-cache-probe.js +3 -27
  213. package/dist/plugins/adoption-log-sql.js +2 -119
  214. package/dist/plugins/approval-ask-store-memory.js +3 -38
  215. package/dist/plugins/approval-ask-store-sql.js +6 -188
  216. package/dist/plugins/approval-exemption-store.js +2 -28
  217. package/dist/plugins/background-agent-store-sql.js +4 -105
  218. package/dist/plugins/background-shell-support.js +14 -122
  219. package/dist/plugins/blob-backend.js +6 -169
  220. package/dist/plugins/breaker-state-sql.js +8 -46
  221. package/dist/plugins/caching-session-store.js +4 -106
  222. package/dist/plugins/checkpoint-store-sql.js +18 -505
  223. package/dist/plugins/e2b-orphan-reclaim.js +0 -45
  224. package/dist/plugins/file-outcome-sink.js +0 -9
  225. package/dist/plugins/file-resume-anchor-store.js +4 -43
  226. package/dist/plugins/file-run-store.js +26 -364
  227. package/dist/plugins/file-snapshot-store-sql.js +10 -181
  228. package/dist/plugins/fork-routing-session-store.js +8 -111
  229. package/dist/plugins/host-platform.js +2 -91
  230. package/dist/plugins/image-bake-store-sql.js +7 -250
  231. package/dist/plugins/image-index-sql.js +4 -123
  232. package/dist/plugins/k8s-bg-scripts.js +4 -88
  233. package/dist/plugins/k8s-exec-protocol.js +0 -41
  234. package/dist/plugins/leader-run-store-sql.js +0 -101
  235. package/dist/plugins/local-checkpoint-store.js +8 -128
  236. package/dist/plugins/local-session-store.js +34 -296
  237. package/dist/plugins/local-task-attachment-store.js +2 -16
  238. package/dist/plugins/mailbox-store-sql.js +8 -65
  239. package/dist/plugins/memory-embedder-fingerprint.js +5 -166
  240. package/dist/plugins/memory-embedder.js +4 -70
  241. package/dist/plugins/memory-engine-pg.js +6 -170
  242. package/dist/plugins/memory-engine-tidb.js +7 -155
  243. package/dist/plugins/memory-engine-vector-util.js +0 -10
  244. package/dist/plugins/memory-key-guards.js +0 -34
  245. package/dist/plugins/memory-origin-law.js +0 -187
  246. package/dist/plugins/memory-resume-anchor-store.js +0 -17
  247. package/dist/plugins/memory-run-store.js +12 -89
  248. package/dist/plugins/memory-session-policy-store.js +0 -17
  249. package/dist/plugins/memory-sync-store-pg.js +4 -49
  250. package/dist/plugins/memory-sync-store-tidb.js +3 -35
  251. package/dist/plugins/outcome-ledger-sql.js +3 -97
  252. package/dist/plugins/permission-rule-store-file.js +5 -133
  253. package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
  254. package/dist/plugins/permission-rule-store-sql.js +50 -307
  255. package/dist/plugins/pg-cost-quota.js +0 -7
  256. package/dist/plugins/pg-pool.js +0 -92
  257. package/dist/plugins/pg-rate-limiter.js +2 -13
  258. package/dist/plugins/pg-safe-json.js +4 -40
  259. package/dist/plugins/pg-session-storage.js +25 -189
  260. package/dist/plugins/posix-shell-fs.js +1 -31
  261. package/dist/plugins/remote-env-adb.js +12 -101
  262. package/dist/plugins/remote-env-e2b.js +40 -371
  263. package/dist/plugins/remote-env-file-error.js +0 -37
  264. package/dist/plugins/remote-env-host.js +63 -483
  265. package/dist/plugins/remote-env-k8s.js +32 -326
  266. package/dist/plugins/remote-env-local-docker.js +24 -157
  267. package/dist/plugins/remote-env-ssh.js +20 -128
  268. package/dist/plugins/remote-scratchpad.js +2 -32
  269. package/dist/plugins/remote-shell.js +1 -32
  270. package/dist/plugins/resume-anchor-store-sql.js +0 -11
  271. package/dist/plugins/retention-lane-store-sql.js +0 -108
  272. package/dist/plugins/retention-store-sql.js +4 -383
  273. package/dist/plugins/roster-store-sql.js +0 -55
  274. package/dist/plugins/run-store-sql.js +14 -251
  275. package/dist/plugins/s3-presign.js +2 -49
  276. package/dist/plugins/scheduler-support.js +3 -80
  277. package/dist/plugins/send-file-ledger.js +4 -53
  278. package/dist/plugins/send-user-file.js +4 -94
  279. package/dist/plugins/session-placement.js +1 -89
  280. package/dist/plugins/session-policy-store-sql.js +3 -81
  281. package/dist/plugins/session-store.js +0 -57
  282. package/dist/plugins/shared-memory-store-sql.js +4 -167
  283. package/dist/plugins/sql-driver.js +0 -17
  284. package/dist/plugins/sql-errors.js +0 -7
  285. package/dist/plugins/sql-escape.js +0 -8
  286. package/dist/plugins/sql-row-helpers.js +0 -25
  287. package/dist/plugins/store-backend.js +42 -222
  288. package/dist/plugins/store-contracts.js +2 -46
  289. package/dist/plugins/task-attachment-store.js +3 -49
  290. package/dist/plugins/task-list-store-sql.js +0 -79
  291. package/dist/plugins/tidb-cost-quota.js +1 -4
  292. package/dist/plugins/tidb-pool.js +1 -207
  293. package/dist/plugins/tidb-rate-limiter.js +3 -9
  294. package/dist/plugins/tidb-session-storage.js +4 -70
  295. package/dist/plugins/tidb-session-store.js +19 -341
  296. package/dist/plugins/tool-result-store-sql.js +4 -179
  297. package/dist/plugins/usage-window-store-sql.js +0 -8
  298. package/dist/plugins/web-search.js +10 -132
  299. package/dist/plugins/workflow-journal-store-sql.js +2 -58
  300. package/dist/plugins/workflow-run-store-sql.js +6 -91
  301. package/dist/plugins/worktree-isolation.js +6 -126
  302. package/dist/plugins/write-behind-counter.js +16 -75
  303. package/dist/principal-jwt.js +5 -60
  304. package/dist/project-memory.js +15 -146
  305. package/dist/prompts-domain-validate.js +1 -51
  306. package/dist/question.js +2 -111
  307. package/dist/resource-suspend.js +0 -18
  308. package/dist/router/route-orchestration.js +0 -77
  309. package/dist/rules-consent.d.ts +44 -5
  310. package/dist/rules-consent.js +75 -215
  311. package/dist/run-local.js +14 -381
  312. package/dist/runs.js +29 -617
  313. package/dist/runtime-caps-resolver.js +6 -132
  314. package/dist/runtime-governance.js +1 -232
  315. package/dist/sandbox-pkg-source.js +0 -37
  316. package/dist/sealed-key.js +3 -68
  317. package/dist/security.js +6 -291
  318. package/dist/session-leaf-bus.js +0 -32
  319. package/dist/session-sync-content.js +1 -69
  320. package/dist/session-sync-kernel.js +3 -60
  321. package/dist/session-sync.js +3 -66
  322. package/dist/session-titler.js +7 -41
  323. package/dist/session-watch.js +9 -73
  324. package/dist/shared-memory-scope-authorizer.js +0 -18
  325. package/dist/sighup-idle.js +1 -12
  326. package/dist/spec-fields.js +4 -143
  327. package/dist/store-live-probe.js +3 -49
  328. package/dist/task-a2a.js +1 -126
  329. package/dist/task-cwd.js +1 -103
  330. package/dist/task-mcp.js +1 -89
  331. package/dist/task-settings.js +10 -300
  332. package/dist/task-workflow.js +8 -75
  333. package/dist/tool-approval.d.ts +28 -1
  334. package/dist/tool-approval.js +70 -1430
  335. package/dist/trace/artifacts.js +5 -20
  336. package/dist/trace/engine-notice-wire.js +6 -138
  337. package/dist/trace/ledger-sink.js +7 -96
  338. package/dist/trace/project.js +4 -448
  339. package/dist/trace/redact.js +9 -77
  340. package/dist/turn-activity.js +1 -27
  341. package/dist/usage-analytics.js +4 -34
  342. package/dist/wall-clock-jump-guard.js +1 -68
  343. package/package.json +3 -3
  344. package/dist/capabilities/scenario-alias.d.ts +0 -27
  345. package/dist/capabilities/scenario-alias.js +0 -61
@@ -1,122 +1,48 @@
1
- /** 第 `i` 个占位符(1-based)。TiDB `?` / PG `$i` —— 这是本文件唯一的方言分岔点。 */
2
1
  export function ph(dialect, i) {
3
2
  return dialect === "tidb" ? "?" : `$${i}`;
4
3
  }
5
- /**
6
- * 目的地冲突探针(phase 0,**任何 UPDATE 之前**)。
7
- *
8
- * 判据 = 「to 侧已有的行,与 from 侧的行,是否共享同一个**逻辑键**」。逻辑键 =
9
- * `leg.residualKey`(该表最紧的唯一键**去掉身份轴**之后剩下的列):
10
- * · `undefined` ⇒ 没有唯一键含这根轴 ⇒ 结构性无冲突,本函数不该被调用(调用方按 `undefined` 短路);
11
- * · `[]` ⇒ 唯一键**就是**这根轴(PK(scope))⇒ 两侧各有任意一行即冲突,退化成笛卡尔计数;
12
- * · 非空 ⇒ 逐列相等的自连接计数。
13
- *
14
- * 参数序:`[toValue, fromValue]`。
15
- */
16
4
  export function buildConflictProbeSql(dialect, leg) {
17
5
  const on = (leg.residualKey ?? []).map((c) => ` AND a.${c} = b.${c}`).join("");
18
6
  return (`SELECT COUNT(*) AS n FROM ${leg.table} a, ${leg.table} b` +
19
7
  ` WHERE a.${leg.matchColumn} = ${ph(dialect, 1)} AND b.${leg.matchColumn} = ${ph(dialect, 2)}${on}`);
20
8
  }
21
- /**
22
- * 桶迁/行迁的等值 UPDATE。`columns` 里的每一列都被设成**同一个**新值(字节孪生 `*_key` 与可读列一起走),
23
- * 谓词打在 `matchColumn` 上。参数序:`[...新值 × columns.length, 旧值]`。
24
- *
25
- * 幂等性来自谓词本身:重跑时旧值已经不在库里 ⇒ 零行匹配 ⇒ 零行变化。
26
- */
27
9
  export function buildRebindSql(dialect, leg) {
28
10
  const sets = leg.columns.map((c, i) => `${c} = ${ph(dialect, i + 1)}`).join(", ");
29
11
  return `UPDATE ${leg.table} SET ${sets} WHERE ${leg.matchColumn} = ${ph(dialect, leg.columns.length + 1)}`;
30
12
  }
31
- /**
32
- * memory 族的 scope 值扫描:把「属于这个 principal 的 scope 键」从库里**读出来**,而不是用 LIKE 去猜。
33
- *
34
- * 🔴 为什么不是 `LIKE '<前缀>%'`:scope 的 tenant 段是**百分号编码**的(`user%3Aweb-demo`),而 `%` 在
35
- * LIKE 里是通配符 —— 不逐字符转义就会误命中别的租户的盘(**跨租户误迁**,不是性能问题)。`LEFT(col, n) = ?`
36
- * 是纯等值比较,没有元字符面,两方言同形。
37
- *
38
- * 参数序:`[userScope, projHead.length, projHead, userProjHead.length, userProjHead]`。
39
- */
40
13
  export function buildMemoryScopeScanSql(dialect, table) {
41
14
  return (`SELECT DISTINCT scope FROM ${table}` +
42
15
  ` WHERE scope = ${ph(dialect, 1)}` +
43
16
  ` OR LEFT(scope, ${ph(dialect, 2)}) = ${ph(dialect, 3)}` +
44
17
  ` OR LEFT(scope, ${ph(dialect, 4)}) = ${ph(dialect, 5)}`);
45
18
  }
46
- /**
47
- * 残留计数:某条腿上**仍挂在旧身份名下**的行数。参数序:`[fromValue]`。
48
- *
49
- * 用途见 wire.ts 的 `current.residualSourceRows`:收编不给普通写者上栅栏(183 I1 = 运维前提「引擎先停」),
50
- * 所以「终态之后旧身份下又长出行」是一个真实可能的形 —— 这条查询把它变成可见读数,而不是靠祈祷。
51
- */
52
19
  export function buildResidualCountSql(dialect, table, matchColumns) {
53
- // 🔴 **一张表一条 COUNT**,谓词是该表全部身份轴的**并**(codex R3-F4):逐腿各数一次会把一条
54
- // 两根轴都还带旧身份的行数成 2(background_agent 甚至能数成 3),而字段名承诺的是「行数」。
55
20
  const where = matchColumns.map((c, i) => `${c} = ${ph(dialect, i + 1)}`).join(" OR ");
56
21
  return `SELECT COUNT(*) AS n FROM ${table} WHERE ${where}`;
57
22
  }
58
- /**
59
- * `blob-rewrite` 腿的扫描:按**旧**身份值把行连同 JSON 载荷读出来。
60
- * 匹配面 = `matchColumn` 与 `blob.alsoMatch` 的**并**(同表两根轴都可能带旧值)。
61
- * 参数序:`[fromValue × (1 + alsoMatch.length)]`。
62
- */
63
23
  export function buildBlobScanSql(dialect, leg) {
64
24
  const blob = leg.blob;
65
25
  if (blob === undefined)
66
26
  throw new Error(`buildBlobScanSql: leg ${leg.leg} has no blob spec`);
67
27
  const cols = [...blob.pk, blob.revColumn, blob.column].join(", ");
68
- // 🔴 匹配面同时收**旧值与新值**两个桶(codex R2-F1 的可见性半):投影列已经迁了、载荷还停在旧身份的
69
- // 那种「劈开」行(列腿与载荷腿之间插进来的写、或上一轮扫描漏掉的行),只按旧值找是**永远找不到**的
70
- // ——而那正是最危险的一类残留:黑盒上看起来已迁移。载荷里真带旧身份才会被改写,所以多扫一个桶零副作用。
71
28
  const cells = [leg.matchColumn, ...(blob.alsoMatch ?? [])];
72
29
  const match = [...cells.map((c, i) => `${c} = ${ph(dialect, i + 1)}`), ...cells.map((c, i) => `${c} = ${ph(dialect, cells.length + i + 1)}`)].join(" OR ");
73
30
  return `SELECT ${cols} FROM ${leg.table} WHERE ${match}`;
74
31
  }
75
- /**
76
- * `blob-rewrite` 腿的逐行回写。参数序:`[新载荷文本, ...pk 值]`。
77
- *
78
- * 幂等性:重跑时载荷里的身份字段已是新值 ⇒ 调用方算出的新载荷与库里逐字节相同 ⇒ 语义无操作
79
- * (行数可能仍报 1,故回执的行数按「**内容真变了**才计」在调用侧收窄)。
80
- */
81
32
  export function buildBlobWriteSql(dialect, leg) {
82
33
  const blob = leg.blob;
83
34
  if (blob === undefined)
84
35
  throw new Error(`buildBlobWriteSql: leg ${leg.leg} has no blob spec`);
85
36
  const where = blob.pk.map((c, i) => `${c} = ${ph(dialect, i + 2)}`).join(" AND ");
86
- // 🔴 `AND rev = ?` = 乐观并发守卫(codex R2-F1):这三张表的正常写路径都用 rev 做 CAS,收编不许绕过。
87
- // 读到的 rev 与写时不符 ⇒ `affected === 0` ⇒ 调用方响亮抛、整事务回滚,而不是把别人刚写的载荷盖掉。
88
- // 🔴 `SET rev = rev + 1` 同样是承重的(codex R3-F1):只**读**不**推**这把守卫,一个在收编写入**之前**
89
- // 就读到 rev=N 的正常写者,在收编提交之后仍然能以 rev=N 的 CAS 写成功,把刚迁好的载荷原样盖回旧身份
90
- // —— 收编那时已经报 adopted。推进 rev 才让那些「站在过去」的写者按 OCC 的本意输掉并重试。
91
37
  return `UPDATE ${leg.table} SET ${blob.column} = ${ph(dialect, 1)}, ${blob.revColumn} = ${blob.revColumn} + 1 WHERE ${where} AND ${blob.revColumn} = ${ph(dialect, blob.pk.length + 2)}`;
92
38
  }
93
- /**
94
- * 规则桶的**整桶改键**(A-010.16)。参数序:`[newOwnerKey, toPrincipal, oldOwnerKey]`。
95
- *
96
- * `owner_key = sha256("principal:" + principal)` —— 身份在**键的 hash 原像**里,与 session_policy
97
- * 同族。差别在于这把键**不含逐行变量**(session_policy 的原像里还有 session_id),所以不必逐行扫出来
98
- * 重算:一对 (旧键, 新键) 算一次,一条等值 UPDATE 走完全表。
99
- *
100
- * `principal` 列跟着同改:它是 owner_key 的**明文原像列**(店按前者寻址、`GET /v1/rules` 的回执与运维
101
- * 的 `WHERE principal = …` 排查按后者读)。只改一列,库里就有两份互相矛盾的身份说法。
102
- *
103
- * 幂等性来自谓词:重跑时旧桶键已经不在库里 ⇒ 零行匹配 ⇒ 零行变化。
104
- * `owner_kind = 'local-owner'` 的那只桶天然不受影响 —— 它的 owner_key 是 `sha256("local-owner")`,
105
- * 与任何 principal 派生的键都不相等,所以**匹配不到**(不需要额外的 owner_kind 谓词来护住它)。
106
- */
107
39
  export function buildRuleOwnerRekeySql(dialect, leg) {
108
40
  return (`UPDATE ${leg.table} SET owner_key = ${ph(dialect, 1)}, principal = ${ph(dialect, 2)}` +
109
41
  ` WHERE owner_key = ${ph(dialect, 3)}`);
110
42
  }
111
- /** session_policy 重键腿的扫描:拿到 from 侧每一行的 `(policy_key, session_id)`。参数序:`[fromPrincipal]`。 */
112
43
  export function buildSessionPolicyScanSql(dialect) {
113
44
  return `SELECT policy_key, session_id FROM session_policy WHERE principal = ${ph(dialect, 1)}`;
114
45
  }
115
- /**
116
- * session_policy 的逐行重键改写。`policy_key = sha256(JSON.stringify([sessionId, principal ?? null]))`,
117
- * 身份在**主键的 hash 原像**里 ⇒ 等值 UPDATE 够不着,必须读出来重算再改写。
118
- * 参数序:`[newPolicyKey, toPrincipal, oldPolicyKey]`。
119
- */
120
46
  export function buildSessionPolicyRewriteSql(dialect) {
121
47
  return (`UPDATE session_policy SET policy_key = ${ph(dialect, 1)}, principal = ${ph(dialect, 2)}` +
122
48
  ` WHERE policy_key = ${ph(dialect, 3)}`);
@@ -1,62 +1,24 @@
1
- /**
2
- * design/183 §6 —— 收编回执的**唯一包络**(form b:纯身份重绑,数据已在 SQL、承运腿为零)。
3
- *
4
- * 🔴 为什么 schema 在这里而不是散在路由里(clay 最高宪法「边界必 schema 禁裸 as-cast」):这份包络是
5
- * **跨仓 wire 契约** —— 下游(cli / web-admin / 围栏 E2E)要按字段名逐字钉围栏。请求体在入口 zod 解析,
6
- * 响应体从这里的类型铸出,于是「路由改了字段名而围栏不知道」是编译红而不是运行期静默漂移。
7
- *
8
- * ── 与 183 §6 的**逐条差异**(如实登记,不假装同形)────────────────────────────────────────────────
9
- * ① `AdoptionReport.credentials` **缺席**。183 的那一格服务的是 form a「云铸新身份 ⇒ 凭据领取位」;
10
- * form b 的 `toPrincipal` 是**运维在请求体里点名的既存身份**,本车不铸任何凭据 ⇒ 给一个 `ref` 就是
11
- * 凭空发明一个兑取不到的 claim(而 183 §4.3 恰恰要求该 ref 是 durable 可重复兑取的)。缺席是诚实,
12
- * 假字段是谎。form a 承运车落地时由那台车补这一格。
13
- * ② `AdoptionReceipt.current.quarantined` **恒 0**。隔离位是承运腿(对端拒收行)的概念,form b 零承运
14
- * ⇒ 结构位在场、读数恒 0。保留字段是为了 form a 上车时包络不变形(下游围栏不用改)。
15
- * ③ `notMigratedByDesign` 是 **v2 小票新增**的机读位(183 只在散文里说「按设计不迁」)。成员标识符
16
- * ({@link NotMigratedFace})与字段名一样是**冻结的机读词表**,下游按它写正向断言(§10.5:把「按
17
- * 设计不迁」与「漏了没迁」在黑盒上分开)。加成员=加行为面,减成员=下游围栏红。
18
- *
19
- * `immutableReport` 逐字节恒同 = 幂等判据(183 §8):它在 phase 6 一次性落库,此后任何重跑原样回放,
20
- * **绝不重算**。`current` 反过来每次现算(配置账未见证项、隔离计数),两半各钉各的(§10.6)。
21
- */
22
1
  import { z } from "zod";
23
- /** 收编来源(form b 只有具名 principal 一形;`local-owner` 是 form a 的形,本车不产出也不接受)。 */
24
2
  export const AdoptionSourceSchema = z.object({ kind: z.literal("principal"), principal: z.string().min(1) }).strict();
25
- /** per-store 腿的动作词(183 §6 闭集;form b 只会产出前两个 + `none`)。 */
26
3
  export const AdoptionLegActionSchema = z.enum(["bucket-rebind", "row-rewrite", "carried", "none", "reset"]);
27
4
  export const AdoptionLegSchema = z
28
5
  .object({
29
- /** 腿的稳定标识 = `<表名>#<身份轴列>`(下游按它对账;表名/列名都是本仓 schema 的真名)。 */
30
6
  store: z.string().min(1),
31
7
  action: AdoptionLegActionSchema,
32
- /** 本次真改了几行。**重跑恒 0**,而 `immutableReport` 里冻的是**首次**的读数(史实)。 */
33
8
  rows: z.number().int().nonnegative().optional(),
34
9
  quarantined: z.number().int().nonnegative().optional(),
35
10
  })
36
11
  .strict();
37
- /**
38
- * 受影响部署配置清单(183 §6 表)。`migrated` 对 server 半场**恒 false**——这些配置全在别的部署单元
39
- * (BFF / cli / env / core 声明位),收编动作**够不到**它们,而 183 §3.3 的明令是「改不到的配置,不假装
40
- * 改了」。清单在场 + `migrated:false` + 配置账不清 = 下游围栏「配置不迁如实红」的凭据(§10.4)。
41
- */
42
12
  export const AdoptionConfigEntrySchema = z
43
13
  .object({
44
14
  deployment: z.string().min(1),
45
15
  key: z.string().min(1),
46
16
  requiredValue: z.string(),
47
17
  migrated: z.boolean(),
48
- /** 运维表态位(只作记录,**不清账**——183 r3 按 codex r2-F6:手写布尔可以把账清成假绿)。 */
49
18
  ack: z.boolean(),
50
- /** 消费端运行时真读回 requiredValue 的 typed 回执时刻。**null = 未见证 = 未清账**。 */
51
19
  witnessedAtMs: z.number().int().nonnegative().nullable(),
52
20
  })
53
21
  .strict();
54
- /**
55
- * **机读词表**:server 侧按设计不迁的面,逐项挂 183 的裁决号。
56
- *
57
- * 🔴 这是**冻结的闭集**(下游按成员名写正向断言)。改名/删员 = wire 破坏;新增 = 新行为面,要先过三问。
58
- * 判据形见 183 §10.5:「按设计不迁」与「漏了没迁」在黑盒上必须可分,所以它是**正向声明**而不是沉默。
59
- */
60
22
  export const NOT_MIGRATED_FACES = [
61
23
  "usage-window",
62
24
  "cost-quota",
@@ -64,26 +26,19 @@ export const NOT_MIGRATED_FACES = [
64
26
  "approval-exemption-grantor",
65
27
  "approval-ask-decision-actor",
66
28
  "image-bake-requested-by",
67
- // A-010.22(台账 P1)—— 规则店族此前对回执**零表态**:`permission_rule` 那只**活桶**现在真迁了
68
- // (`permission_rule#owner_key` 腿),但同族另外两张表按 D2/D1 刻意不迁,而「刻意不迁」与「漏了没迁」
69
- // 在黑盒上必须可分(§10.5)。少了这两员,运维读到的回执是:`notMigratedByDesign` 里没有规则店的影子、
70
- // `residualSourceRows` 又把它们数成 0 —— 一份「什么都没落下」的**假声明**。
71
29
  "permission-rule-approval-history",
72
30
  "permission-rule-import-ticket",
73
31
  ];
74
32
  export const AdoptionNotMigratedSchema = z
75
33
  .object({
76
34
  face: z.enum(NOT_MIGRATED_FACES),
77
- /** 183 §12 的裁决号(`D1` = 配额窗清零重计;`D2` = 史实字段不改写)。 */
78
35
  ruling: z.enum(["D1", "D2"]),
79
36
  reason: z.string().min(1),
80
37
  })
81
38
  .strict();
82
- /** 终态快照(**不可变史实**,phase 6 一次落库,逐字节恒同 —— 183 I4 + §8 幂等判据)。 */
83
39
  export const AdoptionReportSchema = z
84
40
  .object({
85
41
  adoptionId: z.string().min(1),
86
- /** 本车只做 form b;`form` 显式在场是为了 form a 上车后回执可分辨(下游不必按缺席位推断)。 */
87
42
  form: z.literal("b"),
88
43
  from: AdoptionSourceSchema,
89
44
  toPrincipal: z.string().min(1),
@@ -93,48 +48,19 @@ export const AdoptionReportSchema = z
93
48
  notMigratedByDesign: z.array(AdoptionNotMigratedSchema),
94
49
  })
95
50
  .strict();
96
- /**
97
- * 唯一回执包络。**首次成功与一切幂等重跑同形**(183 §6 r7);别处不得另造第二种回执。
98
- *
99
- * `status`:`adopted` = 终态在;`stalled` = 在飞(锁被别的副本持着 / 崩溃后尚未续完)。
100
- * **`rejected` 不在这个闭集里**:被拒的收编从来不产出回执,POST 与 GET 一律以 typed 409 应答
101
- * (`adoption.destination_conflict` / `adoption.source_already_bound`),否则「拒」与「成」共用一个 200
102
- * 包络,消费端要靠读字段猜——那正是 183 §7.3「拒绝可判别」要消灭的形。
103
- */
104
51
  export const AdoptionReceiptSchema = z
105
52
  .object({
106
53
  status: z.enum(["adopted", "stalled"]),
107
54
  immutableReport: AdoptionReportSchema,
108
55
  current: z
109
56
  .object({
110
- /** 配置账里 `witnessedAtMs === null` 的项(`<deployment>:<key>`)。空 = 账已清。 */
111
57
  outstandingConfigs: z.array(z.string()),
112
- /** form b 恒 0(零承运 ⇒ 无拒收行);字段在场见本文件顶注差异②。 */
113
58
  quarantined: z.number().int().nonnegative(),
114
- /**
115
- * **仍挂在旧身份名下的行数**(每次现算,跨全部迁移腿求和)。
116
- *
117
- * 🔴 为什么这一格是承重的(codex 对抗复审 R1-F1,采纳其可检测半):收编**不**给普通写者上栅栏
118
- * ——183 I1 的口径是「引擎必须先停」,那是**运维前提**,不是机器保证。于是一个还在按旧身份注入的
119
- * 调用方(配置未随迁 ⇒ `outstandingConfigs` 非空)会在终态之后继续往旧身份下写行,而终态 + 幂等
120
- * 短路会让回执一直说「adopted」。
121
- *
122
- * 这一格把那件事**变成可见的读数**:`>0` = 这个部署仍在往旧身份写,配置随迁没做完。
123
- * 每次 **POST**(写动词)会顺带把这些迟到行扫进新身份并重报此数;**GET** 只读不扫。
124
- * `immutableReport` 是史实、不受影响 —— 史实与现势各住各的字段(183 §6)。
125
- */
126
59
  residualSourceRows: z.number().int().nonnegative(),
127
60
  })
128
61
  .strict(),
129
62
  })
130
63
  .strict();
131
- /**
132
- * 库里那三个 JSON 文本列(`legs` / `configs` / `reject_detail`)读回内域时的 schema。
133
- *
134
- * 🔴 为什么不是「解析完直接裸铸形」(clay 最高宪法 §2 + `boundary-cast-gate`):DB 行与 HTTP body 同属
135
- * **进程外数据**。裸 `as` 是「库里的字节直接冒充内域类型」—— 一次手改库/一次旧版本残留行,坏形就会带着
136
- * 一个说谎的类型annotation 流进回执,而回执是下游围栏的判据源。
137
- */
138
64
  export const AdoptionLegsSchema = z.array(AdoptionLegSchema);
139
65
  export const AdoptionConfigsSchema = z.array(AdoptionConfigEntrySchema);
140
66
  export const AdoptionRejectDetailSchema = z
@@ -143,13 +69,7 @@ export const AdoptionRejectDetailSchema = z
143
69
  conflicts: z.array(z.object({ leg: z.string(), table: z.string(), overlapping: z.number().int().nonnegative() }).strict()),
144
70
  })
145
71
  .strict();
146
- /**
147
- * 拒绝码的**闭集**(与附录 A 的 `adoption.*` 族逐字同名)。住在 wire 契约里而不是实现里,因为落库的
148
- * `adoption_log.reject_code` 与 wire 上的 `errorCode` 必须是**同一个词表** —— 两处各写一份字符串字面量,
149
- * 就是「库里记了一个 wire 上不存在的码」这类漂移的入口。路由的 switch 对它穷举:加成员即编译红。
150
- */
151
72
  export const ADOPTION_REJECT_CODES = ["adoption.destination_conflict", "adoption.destination_unrepresentable"];
152
- /** `POST /v1/adoption` 的请求体。`.strict()` = 写面纪律:多余键是调用方错误,当场 400(不静默吞)。 */
153
73
  export const AdoptionRequestSchema = z
154
74
  .object({
155
75
  fromPrincipal: z.string().min(1).max(190),
@@ -1,42 +1,6 @@
1
- /**
2
- * 流内审批协议(design/172 v3.1 §3.0)持久层状态机 —— #151 车1。纯函数,零 IO:态词表 + 合法转移表 +
3
- * 判定函数 + 确定性 id 派生。所有落库/网络/时钟一律不在本文件——store 层(approval-ask-store-*.ts)消费
4
- * 这里的 `canAskTransition`/`canBatchTransition` 做 SQL 前置合法性判定,`deriveAskId`/`deriveBatchId`
5
- * 做身份键计算。
6
- *
7
- * ── 态词表(闭集)────────────────────────────────────────────────────────────────────────────────
8
- * ask 级 6 态:STREAM_PENDING(流内待决)| DECIDED(已回决)| PARKING(窗到期中选、正在转投递面)|
9
- * PARKED(已绑定投递坐标,等待走 gate)| DENIED(已拒)| VOID(非中选兄弟收敛/撤卡终态)。
10
- * 批级 4 态:OPEN(接受回决)| ROUTING_UNBOUND(已转投递面,尚未绑定具体 ask)|
11
- * ROUTING_BOUND(bind-once 后已绑定)| ABORTED(整批撤卡)。
12
- *
13
- * ── 合法转移表(design/172 §3.0 图,逐字照抄,全枚举——本文件是唯一真源)────────────────────────
14
- * ask: STREAM_PENDING → DECIDED | PARKING | VOID
15
- * PARKING → PARKED | DENIED | VOID(VOID = 非中选兄弟收敛)
16
- * 其余(4 个终态) → ∅ —— 唯一例外是 §3.0/§4 的 provisional 版本化补偿:那条路径专走
17
- * store 的 `resolveProvisional`(WHERE …AND provisional=1…),故意**不**经过这张表——
18
- * 补偿允许终态→终态,而这张表把终态定义为「无出边」,两者不矛盾(不同的门,不同的谓词)。
19
- * 批: OPEN → ROUTING_UNBOUND | ABORTED
20
- * ROUTING_UNBOUND → ROUTING_BOUND | ABORTED
21
- * 其余(2 个终态) → ∅
22
- *
23
- * 🔴 施工纪律:表驱动,禁 if 链——`canAskTransition`/`canBatchTransition` 只做一次数组查找,新增/
24
- * 删除一条转移只需要改上面两张 `Record<State, readonly State[]>` 字面量,不需要碰判定函数本体。
25
- */
26
1
  import { createHash } from "node:crypto";
27
- /** ask 侧终态集合(无出边的 4 态)——store 层 CAS 谓词与 reap/对账扫描复用这份闭集,不许各自重列。 */
28
2
  export const ASK_TERMINAL = new Set(["DECIDED", "PARKED", "DENIED", "VOID"]);
29
- /** 批侧终态集合(无出边的 2 态)。 */
30
3
  export const BATCH_TERMINAL = new Set(["ROUTING_BOUND", "ABORTED"]);
31
- /**
32
- * #229:回决理由(`AskRow.decisionNote` → `decision_note` 列)的字符上限,**两条回决腿共用一个常量**。
33
- *
34
- * 🔴 为什么住在这个模块:两个消费者分别是 durable 腿的 zod 体(`http/routes/runs.ts` 的
35
- * `AskDecisionBodySchema`)与 live 腿的手写 parser(`tool-approval.ts` 的 `parseToolApprovalResponse`),
36
- * 两处都在 ask 状态机的**同一张行**上写同一列。上限各写一份字面量 = 同一列上两个口径,而分歧只会在
37
- * 「一条腿收下、另一条腿 400」的那天才被发现。本模块是两腿唯一的共同上游(askId/batchId 铸造与转移表
38
- * 都在这里),放这里不引新依赖边。
39
- */
40
4
  export const MAX_DECISION_NOTE_CHARS = 2048;
41
5
  const ASK_TRANSITIONS = {
42
6
  STREAM_PENDING: ["DECIDED", "PARKING", "VOID"],
@@ -52,59 +16,20 @@ const BATCH_TRANSITIONS = {
52
16
  ROUTING_BOUND: [],
53
17
  ABORTED: [],
54
18
  };
55
- /** ask 转移合法性(表驱动,含拒绝同值自环——STREAM_PENDING→STREAM_PENDING 不在表里,故 false)。 */
56
19
  export function canAskTransition(from, to) {
57
20
  return ASK_TRANSITIONS[from].includes(to);
58
21
  }
59
- /** 批转移合法性,同形。 */
60
22
  export function canBatchTransition(from, to) {
61
23
  return BATCH_TRANSITIONS[from].includes(to);
62
24
  }
63
- // ─────────────────────────────────────────────────────────────────────────────────────────────────
64
- // 确定性 id 派生(design/172 §3.1 / 本车设计定稿 §5)
65
- // ─────────────────────────────────────────────────────────────────────────────────────────────────
66
- /**
67
- * 分隔符用 NUL(U+0000)而非任何可打印字符:各 id 部件(sourceTaskId/toolCallId/…)是外部系统给的
68
- * 不透明字符串,不能假设它们不含冒号/空格/其他候选分隔符——黑板有 sessionId 用单字符分隔拼接被
69
- * 注入撞键的既往 finding(同族修法),NUL 是唯一一个这些部件字段实际上不会自然出现的字节,
70
- * 所以拼接后不同的 (parts) 元组不可能被撞成同一条 pre-hash 字符串。
71
- */
72
25
  const ID_SEPARATOR = "\u0000";
73
- /** parts 用 NUL 拼接 + sha256 定长——哈希输出恒 64 hex 字符,`.slice(0, 64)` 是防御性写法而非实际截断
74
- * (VARCHAR(255) 列宽远超过 64,这里的「截 64」纯粹是把长度收拢到一个恒定值,不依赖 sha256 实现细节)。 */
75
26
  function deterministicId(prefix, parts) {
76
27
  const joined = [prefix, ...parts.map((p) => p ?? "")].join(ID_SEPARATOR);
77
28
  return createHash("sha256").update(joined, "utf8").digest("hex").slice(0, 64);
78
29
  }
79
- /**
80
- * 🔴 身份元组的两条轴(车3 设计稿 §3.2′,2026-08-06 换轴,原轴 `(sourceTaskId, toolCallId, leg:number)`
81
- * 被推翻)—— 这段注释是「为什么是这五个部件」的唯一书面记录:
82
- *
83
- * ── `runId`(新增轴,封死跨 run 复用)────────────────────────────────────────────────────────────────
84
- * core 给 `AskRequest.sourceTaskId` 填的是 **sessionId**(`prepare-task.js:2595` 的 `askSourceIdentity`),
85
- * 不是 wire run id。而原轴给每条新 run 的首腿都重置 `leg=0` ⇒ 同一会话的**下一次全新提交**若撞上同一
86
- * `toolCallId`(design/172 定稿 §3.1 记录了部分网关按**请求编号**而非全局编号铸它)会整组重现,
87
- * `ensureAsk` 的幂等 upsert 于是命中上一 run 已 `DECIDED(approve)` 的旧行并把它回放成 `true` ——
88
- * 静默复用一次早已过去的人类同意。这不是低概率碰撞,是可确定复现的路径(§10 钉 C-1)。
89
- * `runId` = 本 run 的 wire id(durable 腿 = 真 run uuid;adhoc 腿 = 该腿一次性 uuid):每次全新提交必是
90
- * 新值,同一腿内恒定(重试/failover/闭包再入不变)⇒ 幂等仍成立。
91
- *
92
- * ── `legKey`(取代数值 `leg`,一腿一凭据)─────────────────────────────────────────────────────────────
93
- * = `sha256(resume checkpoint token)` 的 hex,**首腿 = 空串**。一次 park→resume 的 token 就是这条腿的
94
- * 天然身份:同 token 重投 = 同一腿(幂等,正确);新 park ⇒ 新 token ⇒ 新腿 ⇒ 新 askId。
95
- * 取摘要而非原始 token 是因为 token 是能力凭据(本仓有 `stripCheckpointToken` 专门把它从可重放账本里
96
- * 剥掉),而 `askId` 是 wire 可见值 ⇒ **只存/只喂摘要**。用它当轴顺带消掉了原裁需要的 `task_run` 加列
97
- * 与 `markResuming` 返回加宽(后者有第二个调用点 `http/routes/runs.ts:463`,加宽会误杀已成功 resume 的
98
- * running run)。残留边界:同一 run 内**不经 checkpoint token** 的重入形若未来出现会得到同一 legKey ——
99
- * 今天不存在这种腿(run 内每次重入都必须经 checkpoint resolve),故不设兜底。
100
- */
101
- /** ask_id = sha256('ask' ⊕ sourceTaskId ⊕ runId ⊕ toolCallId ⊕ legKey ⊕ parentToolCallId).slice(0,64)。
102
- * 确定性:同参数元组(含重试/failover/闭包再入)永远派生同一个 id——这是 ensureAsk 幂等 upsert 成立的前提。 */
103
30
  export function deriveAskId(sourceTaskId, runId, toolCallId, legKey, parentToolCallId) {
104
31
  return deterministicId("ask", [sourceTaskId, runId, toolCallId, legKey, parentToolCallId]);
105
32
  }
106
- /** batch_id = sha256('batch' ⊕ sourceTaskId ⊕ runId ⊕ legKey).slice(0,64)。同一 (sourceTaskId, runId,
107
- * legKey) 恒派生同一批——批 = 同一决策点的兄弟 ask 集合,故不掺 toolCallId。 */
108
33
  export function deriveBatchId(sourceTaskId, runId, legKey) {
109
34
  return deterministicId("batch", [sourceTaskId, runId, legKey]);
110
35
  }