@sema-agent/server 7.146.0 → 7.147.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 (398) hide show
  1. package/MIGRATION.md +384 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +170 -66
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +2 -2
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
  8. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  9. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  10. package/deploy/sema-up/chart/values.yaml +1 -1
  11. package/deploy/sema-up/cluster-up.sh +2 -1
  12. package/deploy/sema-up/lib/flagshape.sh +4 -0
  13. package/deploy/sema-up/lib/lanes.json +2 -5
  14. package/deploy/sema-up/sema-up.sh +12 -9
  15. package/deploy/sema-up/stack/compose.yaml +5 -4
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
  17. package/dist/approval-card.d.ts +4 -4
  18. package/dist/approval.d.ts +3 -3
  19. package/dist/audit.js +2 -2
  20. package/dist/bench/s1/live-deps.js +3 -1
  21. package/dist/boot/crash-last.js +2 -1
  22. package/dist/boot/device-lane.js +5 -5
  23. package/dist/boot/engine-lease.d.ts +12 -11
  24. package/dist/boot/execution-env.d.ts +2 -1
  25. package/dist/boot/execution-env.js +45 -33
  26. package/dist/boot/execution-lane.d.ts +37 -9
  27. package/dist/boot/execution-lane.js +74 -20
  28. package/dist/boot/exit-boundary.d.ts +1 -1
  29. package/dist/boot/exit-last.js +2 -1
  30. package/dist/boot/governance-seams.d.ts +2 -2
  31. package/dist/boot/leader.js +1 -1
  32. package/dist/boot/memory-boundary.d.ts +11 -11
  33. package/dist/boot/memory-boundary.js +3 -3
  34. package/dist/boot/memory-consolidation.d.ts +13 -24
  35. package/dist/boot/memory-consolidation.js +0 -13
  36. package/dist/boot/org-memory.js +3 -2
  37. package/dist/boot/parked-revive-gate.d.ts +1 -1
  38. package/dist/boot/parked-revive-gate.js +1 -1
  39. package/dist/boot/reapers.js +1 -1
  40. package/dist/boot/resolve-spec.js +91 -111
  41. package/dist/boot/retention-lane.d.ts +4 -42
  42. package/dist/boot/session-faces.d.ts +1 -0
  43. package/dist/boot/session-faces.js +8 -2
  44. package/dist/boot/stage-01-config.d.ts +1 -1
  45. package/dist/boot/stage-01-config.js +6 -2
  46. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  47. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  48. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  49. package/dist/boot/stage-04-stores.d.ts +1 -1
  50. package/dist/boot/stage-05-execution-env.d.ts +2 -2
  51. package/dist/boot/stage-05-execution-env.js +3 -3
  52. package/dist/boot/stage-06-runners.d.ts +3 -3
  53. package/dist/boot/stage-06-runners.js +1 -3
  54. package/dist/boot/stage-07-capability-layer.d.ts +3 -3
  55. package/dist/boot/stage-07-capability-layer.js +4 -9
  56. package/dist/boot/stage-08-reapers.d.ts +3 -3
  57. package/dist/boot/stage-09-leader.d.ts +4 -3
  58. package/dist/boot/stage-10-http-server.d.ts +4 -3
  59. package/dist/boot/stage-10-http-server.js +2 -1
  60. package/dist/boot/stores.d.ts +9 -0
  61. package/dist/boot/stores.js +18 -7
  62. package/dist/boot/web-admin.js +3 -3
  63. package/dist/capabilities/center-plugins.d.ts +2 -0
  64. package/dist/capabilities/center-plugins.js +6 -2
  65. package/dist/capabilities/composite-members.d.ts +1 -0
  66. package/dist/capabilities/composite-members.js +1 -0
  67. package/dist/capabilities/execution-lane.d.ts +7 -7
  68. package/dist/capabilities/execution-lane.js +2 -2
  69. package/dist/capabilities/hands-lane.d.ts +1 -1
  70. package/dist/capabilities/scenarios.d.ts +32 -18
  71. package/dist/capabilities/scenarios.js +13 -9
  72. package/dist/capabilities/settings-contract.d.ts +29 -0
  73. package/dist/capabilities/settings-contract.js +14 -0
  74. package/dist/capabilities/skills.d.ts +5 -5
  75. package/dist/capability-facts.d.ts +38 -0
  76. package/dist/capability-facts.js +34 -1
  77. package/dist/center-credential-renewer.js +3 -2
  78. package/dist/config-catalog.js +6 -5
  79. package/dist/config-invariants.d.ts +18 -3
  80. package/dist/config-invariants.js +36 -19
  81. package/dist/config-lkg.d.ts +1 -1
  82. package/dist/config-lkg.js +5 -6
  83. package/dist/config-provider.js +2 -0
  84. package/dist/config-types.d.ts +190 -186
  85. package/dist/config.d.ts +68 -5
  86. package/dist/config.js +80 -54
  87. package/dist/degenerate-instrument.js +1 -1
  88. package/dist/deploy-facts.js +3 -2
  89. package/dist/deployment-shape.d.ts +21 -12
  90. package/dist/deployment-shape.js +24 -6
  91. package/dist/env-facts.d.ts +7 -5
  92. package/dist/env-facts.js +10 -6
  93. package/dist/execution-config-root.d.ts +5 -5
  94. package/dist/execution-config-root.js +5 -5
  95. package/dist/execution-env-purpose.d.ts +14 -0
  96. package/dist/execution-env-purpose.js +29 -0
  97. package/dist/execution-lane-caps.d.ts +49 -86
  98. package/dist/execution-lane-caps.js +52 -62
  99. package/dist/execution-placement.d.ts +18 -2
  100. package/dist/execution-placement.js +19 -0
  101. package/dist/file-history-disclosure.d.ts +2 -2
  102. package/dist/fleet/drain-entry.d.ts +17 -10
  103. package/dist/fleet/drain-entry.js +1 -1
  104. package/dist/fleet/serving-lease.js +3 -4
  105. package/dist/history-anchor.d.ts +22 -0
  106. package/dist/history-anchor.js +14 -0
  107. package/dist/hooks/command-spawn.d.ts +1 -4
  108. package/dist/hooks/command-spawn.js +0 -11
  109. package/dist/hooks/hook-runner.d.ts +52 -8
  110. package/dist/hooks/hook-runner.js +160 -36
  111. package/dist/http/approval-sweeps.d.ts +2 -5
  112. package/dist/http/approval-sweeps.js +3 -2
  113. package/dist/http/checkpoint-ctx.d.ts +17 -0
  114. package/dist/http/checkpoint-ctx.js +6 -0
  115. package/dist/http/claim-latency.d.ts +10 -0
  116. package/dist/http/claim-latency.js +12 -0
  117. package/dist/http/dispatch.js +1 -1
  118. package/dist/http/durable-run-leg.js +2 -1
  119. package/dist/http/execution-context.d.ts +3 -1
  120. package/dist/http/execution-context.js +4 -0
  121. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  122. package/dist/http/memory-compliance-failure-reply.js +3 -0
  123. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  124. package/dist/http/memory-store-refusal-reply.js +3 -0
  125. package/dist/http/owner-access.d.ts +11 -0
  126. package/dist/http/owner-access.js +7 -4
  127. package/dist/http/principal-gate.d.ts +3 -14
  128. package/dist/http/principal-gate.js +0 -13
  129. package/dist/http/request-guards.d.ts +1 -1
  130. package/dist/http/resume-legs.d.ts +7 -10
  131. package/dist/http/resume-legs.js +79 -50
  132. package/dist/http/rewind-files-reply.d.ts +34 -0
  133. package/dist/http/rewind-files-reply.js +36 -0
  134. package/dist/http/route-ctx.d.ts +32 -16
  135. package/dist/http/route-table.js +2 -0
  136. package/dist/http/routes/approvals-assistant.js +5 -25
  137. package/dist/http/routes/capabilities.js +8 -2
  138. package/dist/http/routes/devices.js +1 -1
  139. package/dist/http/routes/memory-origin.d.ts +1 -1
  140. package/dist/http/routes/notify-wake.js +2 -1
  141. package/dist/http/routes/projects.d.ts +70 -0
  142. package/dist/http/routes/projects.js +86 -0
  143. package/dist/http/routes/rules.js +30 -2
  144. package/dist/http/routes/runs.js +8 -8
  145. package/dist/http/routes/session-sync.js +27 -10
  146. package/dist/http/routes/sessions.d.ts +7 -1
  147. package/dist/http/routes/sessions.js +104 -2
  148. package/dist/http/routes/tasks.js +9 -3
  149. package/dist/http/server.d.ts +24 -10
  150. package/dist/http/server.js +17 -6
  151. package/dist/http/stored-body-replay.d.ts +5 -3
  152. package/dist/http/stored-body-replay.js +10 -1
  153. package/dist/http/wire-types.d.ts +19 -10
  154. package/dist/index.d.ts +2 -2
  155. package/dist/index.js +1 -1
  156. package/dist/instruction-source-notice.d.ts +1 -1
  157. package/dist/memory-embedder-reembed.d.ts +38 -0
  158. package/dist/memory-embedder-reembed.js +20 -0
  159. package/dist/memory-incident-sink.d.ts +0 -28
  160. package/dist/memory-incident-sink.js +5 -0
  161. package/dist/memory-scope.d.ts +2 -2
  162. package/dist/memory-scope.js +1 -1
  163. package/dist/memory-store-refusal.d.ts +17 -4
  164. package/dist/memory-store-refusal.js +1 -1
  165. package/dist/memory-sync-client.d.ts +2 -0
  166. package/dist/memory-sync-client.js +13 -11
  167. package/dist/memory-sync.js +1 -1
  168. package/dist/model-compat.d.ts +35 -21
  169. package/dist/model-compat.js +49 -21
  170. package/dist/model-entry-refusal.d.ts +11 -1
  171. package/dist/model-entry-refusal.js +7 -0
  172. package/dist/namespaced-rule-name.d.ts +18 -1
  173. package/dist/namespaced-rule-name.js +12 -0
  174. package/dist/observability/fail-open.d.ts +17 -9
  175. package/dist/observability/fail-open.js +17 -9
  176. package/dist/observability/metrics.d.ts +2 -0
  177. package/dist/observability/metrics.js +2 -0
  178. package/dist/observability/secret-env-scrub.d.ts +30 -4
  179. package/dist/observability/secret-env-scrub.js +15 -3
  180. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  181. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  182. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  183. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  184. package/dist/org-memory-admission.d.ts +5 -2
  185. package/dist/org-memory-admission.js +25 -10
  186. package/dist/parked-decide.d.ts +33 -26
  187. package/dist/parked-decide.js +36 -44
  188. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  189. package/dist/plugins/approval-ask-store-file.js +37 -4
  190. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  191. package/dist/plugins/approval-ask-store-memory.js +11 -2
  192. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  193. package/dist/plugins/approval-ask-store-sql.js +3 -1
  194. package/dist/plugins/blob-backend.d.ts +38 -195
  195. package/dist/plugins/blob-backend.js +33 -229
  196. package/dist/plugins/caching-session-store.d.ts +9 -4
  197. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  198. package/dist/plugins/checkpoint-index-columns.js +3 -2
  199. package/dist/plugins/checkpoint-store-face.d.ts +1 -1
  200. package/dist/plugins/device-store-sql.d.ts +2 -2
  201. package/dist/plugins/device-store-sql.js +5 -10
  202. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  203. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  204. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  205. package/dist/plugins/execution-placement-sql.js +94 -54
  206. package/dist/plugins/file-run-store.d.ts +26 -12
  207. package/dist/plugins/file-run-store.js +63 -63
  208. package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
  209. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  210. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  211. package/dist/plugins/inbox-payload-column.js +13 -0
  212. package/dist/plugins/local-checkpoint-store.d.ts +5 -0
  213. package/dist/plugins/local-checkpoint-store.js +11 -7
  214. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  215. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  216. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  217. package/dist/plugins/local-engine-high-water.js +59 -0
  218. package/dist/plugins/local-session-store.d.ts +91 -25
  219. package/dist/plugins/local-session-store.js +124 -45
  220. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  221. package/dist/plugins/local-task-attachment-store.js +10 -11
  222. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  223. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  224. package/dist/plugins/memory-embedder.d.ts +1 -1
  225. package/dist/plugins/memory-embedder.js +2 -2
  226. package/dist/plugins/memory-engine-pg.d.ts +4 -3
  227. package/dist/plugins/memory-engine-pg.js +4 -4
  228. package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
  229. package/dist/plugins/memory-engine-sql-apply.js +1 -1
  230. package/dist/plugins/memory-engine-tidb.d.ts +8 -5
  231. package/dist/plugins/memory-engine-tidb.js +7 -8
  232. package/dist/plugins/one-time-migrations.d.ts +145 -35
  233. package/dist/plugins/one-time-migrations.js +272 -120
  234. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  235. package/dist/plugins/owner-only-file-mode.js +141 -0
  236. package/dist/plugins/permission-rule-store-file.d.ts +8 -8
  237. package/dist/plugins/permission-rule-store-file.js +14 -2
  238. package/dist/plugins/pg-pool.d.ts +2 -1
  239. package/dist/plugins/pg-pool.js +11 -4
  240. package/dist/plugins/release-version.d.ts +20 -0
  241. package/dist/plugins/release-version.js +28 -0
  242. package/dist/plugins/remote-env-adb.d.ts +20 -4
  243. package/dist/plugins/remote-env-adb.js +39 -11
  244. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  245. package/dist/plugins/remote-env-e2b.js +6 -4
  246. package/dist/plugins/remote-env-host.d.ts +9 -1
  247. package/dist/plugins/remote-env-host.js +6 -5
  248. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  249. package/dist/plugins/remote-env-k8s.js +15 -4
  250. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  251. package/dist/plugins/remote-env-local-docker.js +3 -3
  252. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  253. package/dist/plugins/remote-env-ssh.js +26 -24
  254. package/dist/plugins/remote-shell.d.ts +59 -30
  255. package/dist/plugins/remote-shell.js +175 -62
  256. package/dist/plugins/retention-declaration.d.ts +37 -0
  257. package/dist/plugins/retention-declaration.js +9 -0
  258. package/dist/plugins/retention-deployment.d.ts +126 -0
  259. package/dist/plugins/retention-deployment.js +88 -0
  260. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  261. package/dist/plugins/retention-lane-store-sql.js +103 -1
  262. package/dist/plugins/retention-sql.d.ts +29 -0
  263. package/dist/plugins/retention-sql.js +8 -0
  264. package/dist/plugins/schema-consistency.d.ts +0 -6
  265. package/dist/plugins/schema-consistency.js +1 -2
  266. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  267. package/dist/plugins/schema-ensure-legs.js +11 -1
  268. package/dist/plugins/session-ext-table.d.ts +74 -0
  269. package/dist/plugins/session-ext-table.js +121 -0
  270. package/dist/plugins/session-fork.d.ts +1 -1
  271. package/dist/plugins/session-row-sql.d.ts +8 -7
  272. package/dist/plugins/session-row-sql.js +15 -7
  273. package/dist/plugins/session-store-sql.d.ts +131 -0
  274. package/dist/plugins/session-store-sql.js +298 -0
  275. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  276. package/dist/plugins/session-workspace-cell.js +2 -2
  277. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  278. package/dist/plugins/shared-memory-store-sql.js +13 -13
  279. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  280. package/dist/plugins/sql-driver.d.ts +23 -7
  281. package/dist/plugins/sql-driver.js +41 -8
  282. package/dist/plugins/sql-errors.d.ts +5 -2
  283. package/dist/plugins/sql-errors.js +4 -0
  284. package/dist/plugins/store-backend.d.ts +35 -8
  285. package/dist/plugins/store-backend.js +184 -62
  286. package/dist/plugins/store-contracts.d.ts +9 -2
  287. package/dist/plugins/store-contracts.js +1 -0
  288. package/dist/plugins/task-attachment-store.d.ts +6 -8
  289. package/dist/plugins/task-attachment-store.js +15 -10
  290. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  291. package/dist/plugins/text-column-capacity.d.ts +21 -0
  292. package/dist/plugins/text-column-capacity.js +5 -0
  293. package/dist/plugins/tidb-pool.d.ts +3 -2
  294. package/dist/plugins/tidb-pool.js +19 -31
  295. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  296. package/dist/read-face-posture.d.ts +6 -6
  297. package/dist/read-face-posture.js +2 -2
  298. package/dist/request-value-closure.d.ts +5 -5
  299. package/dist/request-value-closure.js +1 -1
  300. package/dist/rules-consent.d.ts +41 -13
  301. package/dist/rules-consent.js +101 -53
  302. package/dist/run-local.js +17 -13
  303. package/dist/runs.d.ts +48 -30
  304. package/dist/runs.js +26 -16
  305. package/dist/runtime-caps-resolver.d.ts +15 -8
  306. package/dist/runtime-caps-resolver.js +14 -10
  307. package/dist/sealed-key-layout.d.ts +2 -3
  308. package/dist/sealed-key-layout.js +0 -1
  309. package/dist/sealed-key.js +7 -5
  310. package/dist/security.d.ts +5 -3
  311. package/dist/sema-config-dir.js +2 -2
  312. package/dist/server-secret-env.d.ts +2 -0
  313. package/dist/service-version.d.ts +2 -1
  314. package/dist/service-version.js +2 -2
  315. package/dist/session-error-wire.d.ts +1 -1
  316. package/dist/session-incarnation.d.ts +8 -5
  317. package/dist/session-resident-background.d.ts +85 -32
  318. package/dist/session-resident-background.js +75 -7
  319. package/dist/session-row.d.ts +1 -1
  320. package/dist/session-sync-kernel.d.ts +1 -1
  321. package/dist/session-workspace.d.ts +11 -2
  322. package/dist/session-workspace.js +5 -0
  323. package/dist/sighup-idle.d.ts +1 -1
  324. package/dist/store-posture.d.ts +2 -1
  325. package/dist/stored-request-hooks-m20.d.ts +3 -2
  326. package/dist/stored-request-hooks-m20.js +19 -14
  327. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  328. package/dist/stores-sql/blob-index-sql.js +154 -0
  329. package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
  330. package/dist/stores-sql/checkpoint-store-sql.js +11 -27
  331. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  332. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  333. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
  334. package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
  335. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  336. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  337. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  338. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  339. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  340. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  341. package/dist/stores-sql/session-write-hooks.js +2 -0
  342. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  343. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  344. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
  345. package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
  346. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  347. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  348. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  349. package/dist/stores-sql/windowed-session-storage.js +61 -0
  350. package/dist/task-a2a.d.ts +7 -1
  351. package/dist/task-a2a.js +15 -14
  352. package/dist/task-cwd.d.ts +11 -3
  353. package/dist/task-cwd.js +17 -1
  354. package/dist/task-mcp.d.ts +10 -2
  355. package/dist/task-mcp.js +13 -16
  356. package/dist/task-settings.d.ts +9 -4
  357. package/dist/task-settings.js +17 -6
  358. package/dist/tool-approval.d.ts +21 -8
  359. package/dist/tool-approval.js +10 -6
  360. package/dist/trace/core-keyset-guard.d.ts +9 -3
  361. package/dist/trace/engine-notice-wire.d.ts +1 -1
  362. package/dist/trace/engine-notice-wire.js +2 -0
  363. package/dist/trace/exit-seat.d.ts +23 -1
  364. package/dist/trace/exit-seat.js +3 -0
  365. package/dist/trace/project.d.ts +33 -16
  366. package/dist/trace/project.js +12 -9
  367. package/dist/trace/redact.d.ts +1 -1
  368. package/dist/trace/redact.js +61 -73
  369. package/dist/trace/self-minted-wire.d.ts +263 -10
  370. package/dist/trace/self-minted-wire.js +90 -2
  371. package/dist/trace/sema-provenance.d.ts +45 -41
  372. package/dist/trace/sema-provenance.js +81 -10
  373. package/dist/trace/task-notification-facets.d.ts +70 -2
  374. package/dist/trace/task-notification-facets.js +71 -1
  375. package/dist/trace/wire-projection-faces.d.ts +38 -2
  376. package/dist/trace/wire-projection-faces.js +26 -1
  377. package/dist/unread-request-members.d.ts +66 -0
  378. package/dist/unread-request-members.js +41 -0
  379. package/dist/user-input-ledger.d.ts +2 -2
  380. package/dist/web-admin-client/apply-effective.js +22 -26
  381. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  382. package/dist/web-admin-client/candidate-gate.js +53 -5
  383. package/dist/web-admin-client/center-request.d.ts +4 -1
  384. package/dist/web-admin-client/center-request.js +2 -1
  385. package/dist/web-admin-client/effective-keys.js +0 -1
  386. package/dist/web-admin-client/facade.d.ts +1 -1
  387. package/dist/web-admin-client/http-client.d.ts +1 -0
  388. package/dist/web-admin-client/http-client.js +17 -9
  389. package/dist/web-admin-client/restart-signal.js +5 -2
  390. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  391. package/dist/web-admin-client/skills-mcp.js +26 -21
  392. package/dist/web-admin-client/types.d.ts +34 -49
  393. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  394. package/package.json +13 -12
  395. package/scripts/drain-check-local.mjs +2 -28
  396. package/scripts/drain-check.mysql.sql +2 -18
  397. package/scripts/drain-check.pg.sql +2 -18
  398. package/wire-changes/server@7.147.0.json +813 -0
@@ -1,4 +1,3 @@
1
- import { type SemaProvenanceInput } from "../trace/sema-provenance.js";
2
1
  import { type SystemInjectionPriority, type TaskNotificationPayload } from "@sema-agent/core";
3
2
  import type { LedgerEventType } from "../trace/ledger-events.js";
4
3
  /** One pending completion, scoped to the session that must be told about it. `summary` is ALREADY
@@ -17,11 +16,12 @@ export interface WorkflowCompletionInboxEntry {
17
16
  * originating leg was IDLE (core's in-process injection had no harness to steer — the durable half
18
17
  * is the deployment's job). `runId` then holds the core task_id (disjoint id spaces). */
19
18
  kind?: "workflow_complete" | "task_notification";
20
- /** The per-kind extras as a JSON text — bounded + redacted AT ENQUEUE (the store carries only egress-safe bytes).
19
+ /** The per-kind extras as a JSON text — bounded + redacted AT ENQUEUE (the store carries only egress-safe bytes) and judged against
20
+ * the entry byte budget by {@link encodeInboxBody}, the only minter of {@link InboxPayload}.
21
21
  * `task_notification`: {task_type, toolUseId?, result?, output_file?, …}. `workflow_complete`: at most `{"completionId": …, "diagnostics": …}`
22
- * (see {@link buildWorkflowCompleteInboxEntry}; each key absent when the engine minted none). The SQL stores' existing `payload`
23
- * column carries it verbatim for both kinds — no DDL. */
24
- payload?: string;
22
+ * (see {@link buildWorkflowCompleteInboxEntry}; each key absent when the engine minted none). Over budget, either kind carries its minimal
23
+ * form instead (stream-key fields + `_sema_provenance` when it fits + `payloadTruncated`). The SQL stores' existing `payload` column carries it verbatim for both kinds — no DDL. */
24
+ payload?: InboxPayload;
25
25
  }
26
26
  /** Session-keyed queue of finished-workflow completions awaiting a push to the originating session.
27
27
  * Two-phase delivery (1.80, closes the 1.77-review "drained-but-append-failed" at-most-once window): `pending`
@@ -199,6 +199,21 @@ export declare class FileWorkflowCompletionInbox extends InMemoryWorkflowComplet
199
199
  /** Close the ledger fd (shutdown). */
200
200
  close(): void;
201
201
  }
202
+ /** 品牌键:模块私有的 `unique symbol` —— 别处写不出一个 {@link InboxPayload} 字面量。 */
203
+ declare const INBOX_PAYLOAD: unique symbol;
204
+ /** 判过条目字节预算的 `payload` 文本(JSON)。`string` 的子型:读者零改;条目的 `payload` 位只收 {@link encodeInboxBody} 铸的值 ⇒ 绕过预算座是 tsc 红。
205
+ * 读侧(SQL 店把列读回来、File 店重放账本)单跳收窄:那些字节只可能是本座写下的(或预算立座之前的存量行,drain 照读)。 */
206
+ export type InboxPayload = string & {
207
+ readonly [INBOX_PAYLOAD]: true;
208
+ };
209
+ /** 被裁条目在 payload(与 drain 出的补投帧)上的点名:`droppedKeys` = 全形里被丢的成员名(全形键序;末尾的 `summary` = 摘要原句被扣下、帧上的 `summary`
210
+ * 是 {@link INBOX_SUMMARY_WITHHELD}),`bytes` = 全形的 UTF-8 字节数。 */
211
+ export interface PayloadTruncated {
212
+ droppedKeys: string[];
213
+ bytes: number;
214
+ }
215
+ /** 摘要原句因失去归因被扣下时,帧上 `summary` 换成的**本服务铸**的一句(受信、不含任何对端字节)。 */
216
+ export declare const INBOX_SUMMARY_WITHHELD = "[payload over budget: summary withheld; see payloadTruncated]";
202
217
  /**
203
218
  * 一次 workflow 完成 → 入箱条目(`workflow_complete` 家族;启动期投递闭包的**唯一**构造点)。`summary` 在 core 的 notifier seam 上已脱敏 + 限长,这里原样入箱;
204
219
  * `completionId`(引擎铸,`WorkflowCompletionPayload` 上在场 iff 引擎给了)逐字落进 `payload` 列 —— 同一次完成的补投帧与 live 帧同一个相关 id,本服务零自铸。
@@ -286,7 +301,12 @@ export type EngineNotificationParkInput = ParkedNotificationFields & {
286
301
  from: string;
287
302
  body: string;
288
303
  };
289
- _sema_provenance?: SemaProvenanceInput;
304
+ _sema_provenance?: unknown;
305
+ /** [ref]:会话箱车道的三只载体 —— 判据与 live 腿同一只(`trace/task-notification-facets.ts`,入参按 `unknown` 收)。park 腿**真的会**收到它们:
306
+ * 会话箱 drain 的注入先经本服务的 `onTaskNotification` 观察者,sync 腿的停驻判据含「客户端已断开」(run 未收束的窗里一次轮界 drain 就走到这里)。 */
307
+ crossSessionMessage?: unknown;
308
+ crossSessionNotice?: unknown;
309
+ inboxNotice?: unknown;
290
310
  /** [ref](core 7.30.0 [ref] S1 / [ref] / [ref]):委派终态帧三枚 facet + 重供两键 —— 判据与 live 腿同一只
291
311
  * (`trace/task-notification-facets.ts`,入参按 `unknown` 收、判过形才成 typed)。 */
292
312
  spawnName?: string;
@@ -1,12 +1,15 @@
1
- import { mkdirSync, openSync, writeSync, fsyncSync, closeSync, renameSync } from "node:fs";
1
+ import { openSync, writeSync, fsyncSync, closeSync } from "node:fs";
2
+ import { OWNER_ONLY_FILE_MODE, atomicWriteFileSync } from "../plugins/owner-only-file-mode.js";
2
3
  import { join } from "node:path";
3
4
  import { redactSecrets } from "../trace/redact.js";
4
5
  import { seatText } from "../trace/exit-seat.js";
5
6
  import { replayJsonlSkipping } from "../observability/corrupt-read-seat.js";
7
+ import { recordFailOpen } from "../observability/fail-open.js";
8
+ import { INBOX_PAYLOAD_MAX_BYTES } from "../plugins/inbox-payload-column.js";
6
9
  import { injectionTierOrAbsent } from "../trace/injection-tier.js";
7
- import { semaProvenanceOrAbsent } from "../trace/sema-provenance.js";
8
- import { resupplyFields, terminalFrameFacetFields } from "../trace/task-notification-facets.js";
9
- import { taskNotificationDedupKey } from "@sema-agent/core";
10
+ import { semaProvenanceFields } from "../trace/sema-provenance.js";
11
+ import { resupplyFields, sessionBoxCarrierFields, terminalFrameFacetFields } from "../trace/task-notification-facets.js";
12
+ import { ensureDir, taskNotificationDedupKey } from "@sema-agent/core";
10
13
  export const MAX_PENDING_PER_SESSION = 100;
11
14
  export const COMPACT_EVERY = 512;
12
15
  export const PURGE_FENCE_MS = 10 * 60 * 1000;
@@ -155,7 +158,7 @@ export class FileWorkflowCompletionInbox extends InMemoryWorkflowCompletionInbox
155
158
  super(onWarn);
156
159
  this.fsyncEnabled = fsyncEnabled;
157
160
  this.dir = join(root, "workflow-completion-inbox");
158
- mkdirSync(this.dir, { recursive: true, mode: 0o700 });
161
+ ensureDir(this.dir);
159
162
  this.ledgerPath = join(this.dir, "inbox.jsonl");
160
163
  this.replay();
161
164
  this.compact();
@@ -187,7 +190,7 @@ export class FileWorkflowCompletionInbox extends InMemoryWorkflowCompletionInbox
187
190
  }
188
191
  commit(rec) {
189
192
  if (this.fd === undefined)
190
- this.fd = openSync(this.ledgerPath, "a", 0o600);
193
+ this.fd = openSync(this.ledgerPath, "a", OWNER_ONLY_FILE_MODE);
191
194
  writeSync(this.fd, `${JSON.stringify(rec)}\n`);
192
195
  if (this.fsyncEnabled)
193
196
  fsyncSync(this.fd);
@@ -202,35 +205,11 @@ export class FileWorkflowCompletionInbox extends InMemoryWorkflowCompletionInbox
202
205
  closeSync(this.fd);
203
206
  this.fd = undefined;
204
207
  }
205
- const tmp = `${this.ledgerPath}.tmp.${process.pid}`;
206
208
  const lines = [];
207
209
  for (const q of this.bySession.values())
208
210
  for (const entry of q.values())
209
211
  lines.push(JSON.stringify({ op: "enqueue", entry }));
210
- const tfd = openSync(tmp, "w", 0o600);
211
- try {
212
- if (lines.length)
213
- writeSync(tfd, `${lines.join("\n")}\n`);
214
- if (this.fsyncEnabled)
215
- fsyncSync(tfd);
216
- }
217
- finally {
218
- closeSync(tfd);
219
- }
220
- renameSync(tmp, this.ledgerPath);
221
- if (this.fsyncEnabled) {
222
- try {
223
- const dfd = openSync(this.dir, "r");
224
- try {
225
- fsyncSync(dfd);
226
- }
227
- finally {
228
- closeSync(dfd);
229
- }
230
- }
231
- catch {
232
- }
233
- }
212
+ atomicWriteFileSync(this.ledgerPath, lines.length ? `${lines.join("\n")}\n` : "", { durability: "best-effort" });
234
213
  this.appendsSinceCompact = 0;
235
214
  }
236
215
  async enqueue(entry) {
@@ -274,18 +253,60 @@ function readEntryExtras(payload) {
274
253
  }
275
254
  return typeof extras === "object" && extras !== null && !Array.isArray(extras) ? extras : {};
276
255
  }
277
- function encodeWorkflowCompleteExtras(extras) {
256
+ const STREAM_KEY_FIELDS = { task_type: true, task_id: true, status: true, seq: true, attempt: true };
257
+ const ATTRIBUTION_MEMBERS = ["_sema_provenance", "agentMessage", "crossSessionMessage"];
258
+ export const INBOX_SUMMARY_WITHHELD = "[payload over budget: summary withheld; see payloadTruncated]";
259
+ function encodeInboxBody(summary, body, at) {
260
+ const full = JSON.stringify(body);
261
+ const bytes = Buffer.byteLength(full, "utf8");
262
+ const out = bytes <= INBOX_PAYLOAD_MAX_BYTES ? { summary, payload: full } : trimToBudget(summary, body, bytes, at);
263
+ return { summary: out.summary, payload: out.payload };
264
+ }
265
+ function trimToBudget(summary, body, bytes, at) {
266
+ const present = Object.entries(body).filter(([, v]) => v !== undefined);
267
+ const attributed = present.some(([k]) => ATTRIBUTION_MEMBERS.includes(k));
268
+ const minimal = (keepProvenance) => {
269
+ const kept = {};
270
+ const droppedKeys = [];
271
+ for (const [k, v] of present) {
272
+ if (Object.hasOwn(STREAM_KEY_FIELDS, k) || (keepProvenance && k === "_sema_provenance"))
273
+ kept[k] = v;
274
+ else
275
+ droppedKeys.push(k);
276
+ }
277
+ const withhold = attributed && !Object.hasOwn(kept, "_sema_provenance");
278
+ if (withhold)
279
+ droppedKeys.push("summary");
280
+ const payloadTruncated = { droppedKeys, bytes };
281
+ return { summary: withhold ? INBOX_SUMMARY_WITHHELD : summary, payload: JSON.stringify({ ...kept, payloadTruncated }), droppedKeys };
282
+ };
283
+ const withProvenance = minimal(true);
284
+ const out = Buffer.byteLength(withProvenance.payload, "utf8") <= INBOX_PAYLOAD_MAX_BYTES ? withProvenance : minimal(false);
285
+ recordFailOpen("server.workflow-completion-inbox.payload-over-budget", `sessionId=${at.sessionId} key=${at.key} bytes=${String(bytes)} budget=${String(INBOX_PAYLOAD_MAX_BYTES)} dropped=${out.droppedKeys.join(",")}`);
286
+ return out;
287
+ }
288
+ function readPayloadTruncated(v) {
289
+ if (typeof v !== "object" || v === null)
290
+ return undefined;
291
+ const { droppedKeys, bytes } = v;
292
+ return Array.isArray(droppedKeys) && droppedKeys.every((k) => typeof k === "string") && Number.isSafeInteger(bytes) && bytes >= 0
293
+ ? { droppedKeys: droppedKeys, bytes: bytes }
294
+ : undefined;
295
+ }
296
+ function encodeWorkflowCompleteExtras(summary, extras, at) {
278
297
  const body = {
279
298
  ...(extras.completionId ? { completionId: extras.completionId } : {}),
280
299
  ...(extras.diagnostics ? { diagnostics: extras.diagnostics } : {}),
281
300
  };
282
- return Object.keys(body).length > 0 ? { payload: JSON.stringify(body) } : {};
301
+ return Object.keys(body).length > 0 ? encodeInboxBody(summary, body, at) : { summary };
283
302
  }
284
303
  function workflowCompleteFrameExtras(payload) {
285
- const { completionId, diagnostics } = readEntryExtras(payload);
304
+ const { completionId, diagnostics, payloadTruncated } = readEntryExtras(payload);
305
+ const truncated = readPayloadTruncated(payloadTruncated);
286
306
  return {
287
307
  ...(typeof completionId === "string" && completionId !== "" ? { completionId } : {}),
288
308
  ...(typeof diagnostics === "string" && diagnostics !== "" ? { diagnostics } : {}),
309
+ ...(truncated !== undefined ? { payloadTruncated: truncated } : {}),
289
310
  };
290
311
  }
291
312
  export function buildWorkflowCompleteInboxEntry(route, p, enqueuedAt) {
@@ -294,9 +315,8 @@ export function buildWorkflowCompleteInboxEntry(route, p, enqueuedAt) {
294
315
  owner: route.owner,
295
316
  runId: p.runId,
296
317
  status: p.status,
297
- summary: p.summary,
298
318
  enqueuedAt,
299
- ...encodeWorkflowCompleteExtras({ completionId: p.completionId, diagnostics: p.diagnostics ? seatText("inbox-diagnostics-text", p.diagnostics) : undefined }),
319
+ ...encodeWorkflowCompleteExtras(p.summary, { completionId: p.completionId, diagnostics: p.diagnostics ? seatText("inbox-diagnostics-text", p.diagnostics) : undefined }, { sessionId: route.sessionId, key: p.runId }),
300
320
  };
301
321
  }
302
322
  export async function emitPendingWorkflowCompletions(inbox, sessionId, callerPrincipal, emit, diag) {
@@ -384,24 +404,22 @@ export function taskNotificationInboxEntry(sessionId, owner, n, enqueuedAt, pare
384
404
  ...(n.result ? { result: cap(redactSecrets(n.result), 4000) } : {}),
385
405
  ...(n.output_file ? { output_file: cap(redactSecrets(n.output_file), 1024) } : {}),
386
406
  ...(n.agentMessage !== undefined ? { agentMessage: { from: n.agentMessage.from, body: cap(redactSecrets(n.agentMessage.body), 4000) } } : {}),
387
- ...(() => {
388
- if (n._sema_provenance === undefined)
389
- return {};
390
- const p = semaProvenanceOrAbsent(n._sema_provenance);
391
- return p !== undefined ? { _sema_provenance: p } : {};
392
- })(),
407
+ ...semaProvenanceFields(n, "inbox-frame-text"),
393
408
  ...terminalFrameFacetFields(n),
394
409
  ...resupplyFields(n),
410
+ ...sessionBoxCarrierFields(n, "inbox-frame-text"),
395
411
  };
412
+ const runId = taskNotificationFoldKey(n);
413
+ const out = encodeInboxBody(cap(redactSecrets(n.summary ?? ""), 4000), { ...extras, task_id: n.task_id }, { sessionId, key: runId });
396
414
  return {
397
415
  sessionId,
398
416
  owner,
399
- runId: taskNotificationFoldKey(n),
417
+ runId,
400
418
  status: n.status === "completed" ? "completed" : "failed",
401
- summary: cap(redactSecrets(n.summary ?? ""), 4000),
419
+ summary: out.summary,
402
420
  enqueuedAt,
403
421
  kind: "task_notification",
404
- payload: JSON.stringify({ ...extras, task_id: n.task_id }),
422
+ payload: out.payload,
405
423
  };
406
424
  }
407
425
  export async function resolveCompletionRoute(p, getRun, requirePrincipal) {
@@ -16,12 +16,13 @@
16
16
  * (请求来源的 scope 没有调用方 ⇒ 引擎在自己的门上先拒,不问本解析器)—— 本模块按这一判别式分支,不另判一次缺席;
17
17
  * 引擎型不可达的那一组合(无调用方 ∧ 请求来源 scope)若仍到了这里 ⇒ 抛,不放行。
18
18
  */
19
- import type { MemoryScopeAdmission } from "@sema-agent/core";
19
+ import { type MemoryScopeAdmission } from "@sema-agent/core";
20
+ import type { Logger } from "./observability/logger.js";
20
21
  /**
21
22
  * 单机腿:装载 `MEMORY_ORG_DIRECTORY_JSON`(`Record<principal, Record<orgScope, {write?}>>`)。启动期调用,
22
23
  * **fail-loud**——任何非法直接 throw 且消息点名坏在哪个键(响亮拒是正确方向:一张半坏的授权表比拒绝
23
24
  * 启动更危险)。principal 键复用 {@link assertPrincipalShape}(拒不是名字的串 / 保留哨兵 / 超长租户名,与所有其它
24
- * principal 入口同一道闸;拒句按键在 JSON 文本里的出现序点名,不回显不是名字的键 —— 对象的枚举序会把整数形的键排到最前,不能拿它编号);scope 键必须是 `org:` 前缀、值必须是仅含可选 `write: boolean` 的 plain object。
25
+ * principal 入口同一道闸;拒句按键在 JSON 文本里的出现序点名,不回显不是名字的键 —— 对象的枚举序会把整数形的键排到最前,不能拿它编号);scope 键必须过 core 的 org scope 键判官(`isOrgScopeKey`:`org:` 加一段 v2 编码的名;判官只有 core 这一只,本仓不另存文法)、值必须是仅含可选 `write: boolean` 的 plain object。
25
26
  */
26
27
  export declare function parseOrgDirectoryStatic(json: string): Map<string, Record<string, {
27
28
  write?: boolean;
@@ -62,6 +63,8 @@ export interface OrgMemoryDirectoryOptions {
62
63
  unavailableBackoffMs: number;
63
64
  /** 时间注入(测试用);默认 `Date.now`。 */
64
65
  now?: () => number;
66
+ /** 远程腿一代目录被按坏形拒时的留声口(只用 `warn`;缺席 = 不留声)。 */
67
+ logger?: Pick<Logger, "warn">;
65
68
  }
66
69
  type OrgDirectoryUnavailableReason = "fetch_failed" | "section_absent" | "malformed" | "stale_generation";
67
70
  /**
@@ -1,7 +1,15 @@
1
+ import { isOrgScopeKey } from "@sema-agent/core";
1
2
  import { PrincipalOrgMemoryWire } from "@sema-agent/settings-schema";
3
+ import { echoCallerText } from "./caller-text-echo.js";
2
4
  import { assertPrincipalShape } from "./security.js";
5
+ function observe(hook) {
6
+ try {
7
+ hook();
8
+ }
9
+ catch {
10
+ }
11
+ }
3
12
  const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
4
- const ORG_SCOPE_RE = /^org:\S+$/;
5
13
  function topLevelKeysInTextOrder(json) {
6
14
  const keys = [];
7
15
  let depth = 0;
@@ -58,8 +66,8 @@ export function parseOrgDirectoryStatic(json) {
58
66
  }
59
67
  const scopes = {};
60
68
  for (const [scope, entryRaw] of Object.entries(scopesRaw)) {
61
- if (!ORG_SCOPE_RE.test(scope)) {
62
- throw new Error(`MEMORY_ORG_DIRECTORY_JSON[${JSON.stringify(principal)}] has an invalid org scope key ${JSON.stringify(scope)} (must match /^org:\\S+$/)`);
69
+ if (!isOrgScopeKey(scope)) {
70
+ throw new Error(`MEMORY_ORG_DIRECTORY_JSON[${JSON.stringify(principal)}] has an invalid org scope key ${JSON.stringify(scope)} (core's org scope key rule refuses it — spell the org with core's formatOrgScope: "org:" plus the name's percent-encoded segment)`);
63
71
  }
64
72
  if (!isPlainObject(entryRaw)) {
65
73
  throw new Error(`MEMORY_ORG_DIRECTORY_JSON[${JSON.stringify(principal)}][${JSON.stringify(scope)}] must be an object`);
@@ -78,6 +86,8 @@ export function parseOrgDirectoryStatic(json) {
78
86
  }
79
87
  return table;
80
88
  }
89
+ const REFUSED_GENERATION_KEYS_NAMED = 5;
90
+ const REFUSED_GENERATION_KEY_ECHO_CHARS = 80;
81
91
  export function createOrgMemoryDirectory(opts) {
82
92
  if ((opts.fetchSection !== undefined) === (opts.staticTable !== undefined)) {
83
93
  throw new Error("createOrgMemoryDirectory requires exactly one of fetchSection or staticTable (both given or both missing)");
@@ -117,6 +127,17 @@ export function createOrgMemoryDirectory(opts) {
117
127
  if (!parsed.success) {
118
128
  return markUnavailable(state, "malformed");
119
129
  }
130
+ const badKeys = Object.keys(parsed.data.scopes).filter((key) => !isOrgScopeKey(key));
131
+ if (badKeys.length > 0) {
132
+ const refused = markUnavailable(state, "malformed");
133
+ observe(() => opts.logger?.warn("org_directory_generation_refused", {
134
+ gen: parsed.data.gen,
135
+ badKeyCount: badKeys.length,
136
+ badKeys: badKeys.slice(0, REFUSED_GENERATION_KEYS_NAMED).map((key) => echoCallerText(key, { maxChars: REFUSED_GENERATION_KEY_ECHO_CHARS })),
137
+ kept: "this generation is not adopted (the whole generation, not just the keys core refuses); the lookup answers unavailable(malformed) and is retried after the backoff window",
138
+ }));
139
+ return refused;
140
+ }
120
141
  if (state.highWaterGen !== undefined && parsed.data.gen < state.highWaterGen) {
121
142
  return markUnavailable(state, "stale_generation");
122
143
  }
@@ -157,13 +178,7 @@ export class OrgMemoryAdmissionRetryError extends Error {
157
178
  }
158
179
  }
159
180
  export function createMemoryScopeAdmission(directory, opts) {
160
- const emit = (outcome, details) => {
161
- try {
162
- opts.onOutcome?.(outcome, details);
163
- }
164
- catch {
165
- }
166
- };
181
+ const emit = (outcome, details) => observe(() => opts.onOutcome?.(outcome, details));
167
182
  return async (input) => {
168
183
  const { requested, requestedWriteScope } = input;
169
184
  const attributed = (details) => input.principal === undefined ? details : { principal: input.principal, ...details };
@@ -63,20 +63,16 @@ export type ParkOrigin = {
63
63
  park: WorkflowRunParkKey;
64
64
  }
65
65
  /**
66
- * **这条决定证不了属于哪一条记录**(core 7.44.0 [ref] 的「没有持有者」两臂;判决属主 = 索引模块的 `routeWorkflowPark`)。
67
- * `cause`:`unreadable` = 某一条点名这个子会话的记录 `parks[]` 读不出(条目形坏 / 这一位在场却不是列表;缺席 = 没有条目,不在此列)—— 它可能正是持有者;
68
- * `older_engine` = 点名它的条目没有持有者位(写于不带 `parkedBy` / `generation` 的引擎,升级那一刻还停驻着的存量记录)。
69
- * 两种都**响亮拒**(409 `decide.workflow_parks_unreadable`,码一个、句子按成因两句),一步都不驱动;出路按成因:`older_engine` = 去续跑 `runId` 那条 run
70
- * (新引擎准入后走到这张停驻会写下自己的持有者行,之后在这里决就正常);`unreadable` = 修好那条记录(它的指针不随任何后继记录消失,续跑解不开)。
71
- * 不回落读 `agents[]`(那是被退役的第二种读法)。
72
- * `readableHolderRunId`(只在 `unreadable` 上可能在场):其余可读记录里持有这张卡的最高代次恰一条 —— 读不出的那条引擎往往恰拒续跑,健康的持有者
66
+ * **这条决定证不了属于哪一条记录**(core 7.44.0 [ref] 的「没有持有者」一臂;判决属主 = 索引模块的 `routeWorkflowPark`):某一条点名这个子会话的记录
67
+ * `parks[]` 读不出(条目形坏 / 这一位在场却不是列表;缺席 = 没有条目,不在此列)—— 它可能正是持有者。**响亮拒**(409 `decide.workflow_parks_unreadable`),
68
+ * 一步都不驱动;出路 = 修好那条记录(`runId`;它的指针不随任何后继记录消失,续跑解不开)。不回落读 `agents[]`(那是被退役的第二种读法)。
69
+ * `readableHolderRunId`:其余可读记录里持有这张卡的最高代次恰一条 —— 读不出的那条引擎往往恰拒续跑,健康的持有者
73
70
  * 就在旁边,拒体多给这一条线索(判决不变,仍是整卡拒;不是解除阻断的出路)。
74
71
  */
75
72
  | {
76
73
  kind: "workflow_parks_unreadable";
77
74
  runId: string;
78
75
  run: WorkflowRun;
79
- cause: "unreadable" | "older_engine";
80
76
  readableHolderRunId?: string;
81
77
  }
82
78
  /**
@@ -216,6 +212,24 @@ export interface ParkedDecideDeps {
216
212
  };
217
213
  warn?: (event: string, fields: Record<string, unknown>) => void;
218
214
  }
215
+ /**
216
+ * 「本会话放行」落在**记不住的车道**上怎么答(闭集;两扇门之间唯一允许的差 —— 其余两口同读同答,铸点只有续跑腿一只):
217
+ * · `refuse` —— `/decide` 体上的 `remember:"session"`:那是一个硬意图键,认领之前 400 点名车道(`decide.workflow_remember_unsupported` /
218
+ * `decide.parked_remember_unsupported`),去掉它再决即可,零副作用;
219
+ * · `decide_once` —— 应答口命中停驻行的 `allow_session`:那是卡上的一个选项,主内容是「放行」。照常放行这一次、不落豁免、回执
220
+ * `rememberApplied:false` —— 与活卡上「记不住的卡点 allow_session」同一答法;不把一次已经成立的批准改成 400(窗到期那一拍的按键今天是成的)。
221
+ * 记不住的车道 = workflow 车道(它的 200 证不出引擎已提交这次决定)、无会话锚的 bg 停驻行(豁免无处可锚)。
222
+ */
223
+ export type RememberLaneCannotRecord = "refuse" | "decide_once";
224
+ /**
225
+ * 停驻车道上的「本会话放行」请求。`anchor` 由车道在认领赢下之后、驱动之前调,只**记下**锚(行的 root/host 会话 id —— 部署侧三个豁免探针
226
+ * (policy 层 / fs-write 门 / workflow 门)的闭包统一捕获 host 会话键,落子代会话则键永不相交;[ref] 候裁② 的 server 侧修,经两轮行为探针实证);
227
+ * 豁免**落店**只在续跑腿拿到「这次决定被证明已结清」之后(`resumeCheckpoint` 的唯一铸点),车道从不写店。
228
+ */
229
+ export interface ParkedRemember {
230
+ readonly anchor: (rootSessionId: string) => Promise<void>;
231
+ readonly laneCannotRecord: RememberLaneCannotRecord;
232
+ }
219
233
  export interface ParkedDecideRequest {
220
234
  token: string;
221
235
  scope: string;
@@ -235,13 +249,9 @@ export interface ParkedDecideRequest {
235
249
  /** D-1 决断绑定:决断方点名它看到的那一对(必在 —— 续跑腿的判官 `decidedActionOf` 判过才交下来)与决定体的其余两位;
236
250
  * server 绝不重算、绝不从停驻行补,core resume 侧做 fail-closed 等值校验 —— 与 legacy 腿同姿势。 */
237
251
  binding: Omit<DecideBinding, "checkpointToken" | "boundCallId" | "boundInputHash"> & DecidedAction;
238
- /** body 带了 `remember:"session"` 时路由传入的 grant 执行器([ref] 候裁② 的 server 侧修,经两轮
239
- * 行为探针实证):豁免必须锚在**行的 root/host 会话 id**——部署侧三个豁免探针(policy 层/fs-write
240
- * 门/workflow 门)的闭包统一捕获 host 会话键且签名不携身份(1.393 seam 亲读:`sourceSessionId` 只在
241
- * onAsk 层的 AskRequest,durable 车道无 onAsk),grant 落子代会话则键永不相交(G-F4 原案);落
242
- * root 会话则宿主键闭包立即命中,复活子代的后续同工具 ask 被短路(探针 v2 实证),语义与同步车道/
243
- * 宿主任务的「本会话不再询问」一致(= host 会话树全域)。行无 root 锚(病态形)⇒ claim 前诚实 400。 */
244
- grantRemember?: (rootSessionId: string) => Promise<void>;
252
+ /** 这次决定带着「本会话放行」请求(`/decide` 的 `remember:"session"` / 应答口命中停驻行的 `allow_session`,两口同一只请求;
253
+ * 铸点 = 续跑腿 `resumeCheckpoint`)时,续跑腿交下来的**锚点记录器** + 记不住时怎么答({@link ParkedRemember})。 */
254
+ remember?: ParkedRemember;
245
255
  /** [ref](core 5.7.0,F6 翻案):AskUserQuestion 的 approve 携操作员答案——原样透传进
246
256
  * `ResumeOutcome.answer`(形状校验在路由层 isQuestionAnswer;header 逐字匹配等语义校验在 core,
247
257
  * server 不预判)。core 拒绝形:同步腿 409 invalid_outcome field:"answer",parked 腿经 drive 失败
@@ -250,9 +260,6 @@ export interface ParkedDecideRequest {
250
260
  /** 决定体带的续跑请求重述键(`mcpServers` / `a2aPeers`;路由已过提交腿同一只判官)。两条车道各自决定拿它怎么办:workflow 车道盖在宿主会话的续跑输入上、
251
261
  * 并进决定的同一性({@link parkDecisionFingerprint});bg 赎回腿不从存量提交体重建任务规格,盖不上 ⇒ claim 前诚实 400(`decide.parked_restatement_unsupported`)。 */
252
262
  restatement?: ResumeRestatement;
253
- /** claim CAS 赢了(≈ legacy 腿的 markResuming 赢)之后、execute 之前触发——remember 豁免 grant
254
- * 的挂点(调用方自吞错,绝不抛落赎回)。claim 败/判别 miss 恒不触发。 */
255
- onDecideCommitted?: () => Promise<void>;
256
263
  }
257
264
  /**
258
265
  * 后台子代赎回腿({@link decideParkedAgent})收的请求 = 两条车道共用的那一份 + 选中这张卡的**门身份片段**。workflow 车道是投递、不收它
@@ -331,7 +338,10 @@ export type WorkflowParkedDecidePlan = {
331
338
  ok: true;
332
339
  hostSessionId: string;
333
340
  runId: string;
334
- message: string;
341
+ message: {
342
+ text: string;
343
+ trusted: true;
344
+ };
335
345
  outcome: WorkflowParkOutcome;
336
346
  } | {
337
347
  ok: false;
@@ -339,19 +349,16 @@ export type WorkflowParkedDecidePlan = {
339
349
  };
340
350
  /**
341
351
  * **证不了这条决定属于哪一条记录**的响亮拒(与上面那族拒臂同一种返回形)—— 判决属主 = 索引模块的 `routeWorkflowPark`
342
- * (「没有持有者」两臂)。码一个(409 `decide.workflow_parks_unreadable`),句子按成因两句,体键 `runId` = 去续跑的那一条;`unreadable` 臂另带顶层
352
+ * (「没有持有者」一臂:某一条点名这张卡的记录读不出)。码一个(409 `decide.workflow_parks_unreadable`),体键 `runId` = 读不出的那一条;另带顶层
343
353
  * `readableHolderRunId`(与 `runId` / `runIds` 同为顶层键)—— **在场才带,缺席整键不在**(没有 / 并列的可读持有者不编一个):读不出的那条引擎往往恰拒续跑,
344
354
  * 健康的持有者在旁时指给人看工作可以从哪条记录续上。**只是线索,不是解除阻断的出路**:判决仍是整卡拒(规则 ①),读不出的那条的指针不随任何后继记录消失 ——
345
355
  * 续跑可读持有者之后这张卡照旧答本码,直到读不出的那条被修好(拒句如实说了这一点)。
346
356
  *
347
357
  * 为什么是拒而不是「尽力而为地投递一次」:「这条记录的 run 站在这张停驻上」只有一种读法(`parkedBy === record.id`),读不出来 ⇒
348
358
  * 这条决定结构上送不出去,答 200「已交给宿主的下一跑」就是一张兑付不了的回执:卡还 pending、人以为决完了。⇒ 拒,把真话说出来;
349
- * 卡仍 pending,什么都没有被伪造。不回落读 `agents[]`(那正是被退役的第二种读法)。
350
- * · `older_engine`:点名这张卡的条目写于不带持有者位的引擎(升级那一刻还停驻着的存量记录)。续跑这条 run ⇒ 新引擎准入、走到这张
351
- * 停驻时写下自己的持有者行 ⇒ 之后在这里决就正常;
352
- * · `unreadable`:某一条点名这张卡的记录读不出(条目形坏 / 这一份在场却不是列表;记录上**没有**这一份 = 没有条目,不到这里 —— 规则见
353
- * `readRunParks`)。续跑**不是**出路:读不出的那条记录的指针不随任何后继记录消失,续跑之后规则 ① 照旧整卡拒(条目形坏的记录引擎本来也拒续跑);
354
- * 出路 = 运维修好那条记录(`runId`),之后在这里决就正常。
359
+ * 卡仍 pending,什么都没有被伪造。不回落读 `agents[]`(那正是被退役的第二种读法)。读不出 = 条目形坏 / 这一份在场却不是列表(记录上**没有**这一份 = 没有条目,
360
+ * 不到这里 —— 规则见 `readRunParks`)。续跑**不是**出路:读不出的那条记录的指针不随任何后继记录消失,续跑之后规则 ① 照旧整卡拒(条目形坏的记录引擎本来也拒续跑);
361
+ * 出路 = 运维修好那条记录(`runId`),之后在这里决就正常。
355
362
  *
356
363
  * 🔴 **[ref](词域门)**:句子不提 `checkpointToken`(契约 D-1 逐字:server-INTERNAL、合规 SDK 绝不发送)与内部机件名;判据与冻结钉见
357
364
  * `test/api-error-text-lexicon.test.ts` / `test/api-error-text-freeze.test.ts`。
@@ -43,7 +43,7 @@ export async function findParkOrigin(sources, cp) {
43
43
  case "forked":
44
44
  return { kind: "workflow_park_forked", runIds: route.runIds };
45
45
  case "unproven":
46
- return { kind: "workflow_parks_unreadable", runId: route.runId, run: route.run, cause: route.cause, ...(route.readableHolderRunId !== undefined ? { readableHolderRunId: route.readableHolderRunId } : {}) };
46
+ return { kind: "workflow_parks_unreadable", runId: route.runId, run: route.run, ...(route.readableHolderRunId !== undefined ? { readableHolderRunId: route.readableHolderRunId } : {}) };
47
47
  case "none":
48
48
  return undefined;
49
49
  default: {
@@ -110,6 +110,18 @@ export async function findParkedAgentForCheckpoint(agentStore, cp) {
110
110
  function grantRootOf(row) {
111
111
  return row.rootSessionId ?? row.parentSessionId;
112
112
  }
113
+ function refusesWhereUnrecordable(remember) {
114
+ switch (remember.laneCannotRecord) {
115
+ case "refuse":
116
+ return true;
117
+ case "decide_once":
118
+ return false;
119
+ default: {
120
+ const unhandled = remember.laneCannotRecord;
121
+ throw new Error(`unhandled remember lane answer: ${String(unhandled)}`);
122
+ }
123
+ }
124
+ }
113
125
  function mintReviveArgs(row, knownAgentTypes) {
114
126
  return {
115
127
  prompt: row.description ?? "resume parked agent",
@@ -134,35 +146,17 @@ export function buildParkedResumeOutcome(req) {
134
146
  };
135
147
  }
136
148
  export function denyWorkflowParksUnreadable(origin) {
137
- switch (origin.cause) {
138
- case "older_engine":
139
- return {
140
- status: 409,
141
- body: refusalBody({
142
- errorCode: "decide.workflow_parks_unreadable",
143
- message: "this decision cannot be matched to the pending step it belongs to: the run's record was written by an earlier engine version, which did not record which run is waiting on each pending step — and that record is the only proof that the approval you are deciding belongs to this run. The decision is therefore NOT delivered, rather than answered with a receipt nothing can redeem: the approval card stays pending and nothing is forged. Resume the run itself instead — `Workflow({resumeFromRunId})` with the runId below — and once the resumed run is waiting on this step again it records itself as the one waiting, after which deciding here works normally. Only if the engine also refuses that resume is the run truly unrecoverable",
144
- facts: {
145
- runId: origin.runId,
146
- },
147
- }),
148
- };
149
- case "unreadable":
150
- return {
151
- status: 409,
152
- body: refusalBody({
153
- errorCode: "decide.workflow_parks_unreadable",
154
- message: "this decision cannot be matched to the pending step it belongs to: this run's record cannot be read (the list of pending steps the run owns is damaged: one of its entries is malformed, or it is not a list at all) — and that list is the only proof that the approval you are deciding belongs to this run. The decision is therefore NOT delivered, rather than answered with a receipt nothing can redeem: the approval card stays pending and nothing is forged. Resuming does not clear this: the damaged record keeps naming this step whatever runs after it, so the decision stays undeliverable until whoever operates this deployment repairs that record (the runId below); after that, deciding here works normally. When the response also carries readableHolderRunId, that run's record is readable and is the latest one waiting on this step — it is where the work can be carried on, but the damaged record above still keeps this decision from being delivered until that record is fixed",
155
- facts: {
156
- runId: origin.runId,
157
- ...(origin.readableHolderRunId !== undefined ? { readableHolderRunId: origin.readableHolderRunId } : {}),
158
- },
159
- }),
160
- };
161
- default: {
162
- const unhandled = origin.cause;
163
- throw new Error(`unhandled workflow parks-unreadable cause: ${String(unhandled)}`);
164
- }
165
- }
149
+ return {
150
+ status: 409,
151
+ body: refusalBody({
152
+ errorCode: "decide.workflow_parks_unreadable",
153
+ message: "this decision cannot be matched to the pending step it belongs to: this run's record cannot be read (the list of pending steps the run owns is damaged: one of its entries is malformed, or it is not a list at all) — and that list is the only proof that the approval you are deciding belongs to this run. The decision is therefore NOT delivered, rather than answered with a receipt nothing can redeem: the approval card stays pending and nothing is forged. Resuming does not clear this: the damaged record keeps naming this step whatever runs after it, so the decision stays undeliverable until whoever operates this deployment repairs that record (the runId below); after that, deciding here works normally. When the response also carries readableHolderRunId, that run's record is readable and is the latest one waiting on this step — it is where the work can be carried on, but the damaged record above still keeps this decision from being delivered until that record is fixed",
154
+ facts: {
155
+ runId: origin.runId,
156
+ ...(origin.readableHolderRunId !== undefined ? { readableHolderRunId: origin.readableHolderRunId } : {}),
157
+ },
158
+ }),
159
+ };
166
160
  }
167
161
  export function denyWorkflowParkForked(origin) {
168
162
  return {
@@ -177,7 +171,7 @@ export function denyWorkflowParkForked(origin) {
177
171
  };
178
172
  }
179
173
  export function planWorkflowParkedDecide(origin, req) {
180
- if (req.grantRemember !== undefined) {
174
+ if (req.remember !== undefined && refusesWhereUnrecordable(req.remember)) {
181
175
  return {
182
176
  ok: false,
183
177
  deny: {
@@ -214,10 +208,13 @@ export function planWorkflowParkedDecide(origin, req) {
214
208
  hostSessionId,
215
209
  runId: origin.runId,
216
210
  outcome: buildParkedResumeOutcome(req),
217
- message: `The human approval that workflow run "${origin.runId}" parked on (agent callKey "${origin.park.callKey}") has been ${verdict}. ` +
218
- `Resume that run now: re-invoke Workflow with the SAME script source you launched it from (script / name / scriptPath) ` +
219
- `AND resumeFromRunId: "${origin.runId}" — the decision is already held by the deployment and will be applied to the parked ` +
220
- `agent; completed steps replay from the journal. Do not re-issue the original call.`,
211
+ message: {
212
+ text: `The human approval that workflow run "${origin.runId}" parked on (agent callKey "${origin.park.callKey}") has been ${verdict}. ` +
213
+ `Resume that run now: re-invoke Workflow with the SAME script source you launched it from (script / name / scriptPath) ` +
214
+ `AND resumeFromRunId: "${origin.runId}" — the decision is already held by the deployment and will be applied to the parked ` +
215
+ `agent; completed steps replay from the journal. Do not re-issue the original call.`,
216
+ trusted: true,
217
+ },
221
218
  };
222
219
  }
223
220
  function sessionGone(taskId) {
@@ -256,8 +253,8 @@ async function voidUnrevivableCard(deps, req, match) {
256
253
  }
257
254
  export async function decideParkedAgent(deps, req, match) {
258
255
  const row = match.row;
259
- const rememberRoot = req.grantRemember !== undefined ? grantRootOf(row) : undefined;
260
- if (req.grantRemember !== undefined && rememberRoot === undefined) {
256
+ const rememberRoot = req.remember !== undefined ? grantRootOf(row) : undefined;
257
+ if (req.remember !== undefined && rememberRoot === undefined && refusesWhereUnrecordable(req.remember)) {
261
258
  return { status: 400, body: refusalBody({ errorCode: "decide.parked_remember_unsupported", message: "remember cannot be applied: this parked agent row carries no root/parent session anchor for the exemption", facts: { taskId: match.handle } }) };
262
259
  }
263
260
  if (req.restatement !== undefined) {
@@ -325,14 +322,9 @@ export async function decideParkedAgent(deps, req, match) {
325
322
  await rollback("revive_surface_threw");
326
323
  throw e;
327
324
  }
328
- try {
329
- await req.onDecideCommitted?.();
330
- }
331
- catch {
332
- }
333
- if (req.grantRemember !== undefined && rememberRoot !== undefined) {
325
+ if (req.remember !== undefined && rememberRoot !== undefined) {
334
326
  try {
335
- await req.grantRemember(rememberRoot);
327
+ await req.remember.anchor(rememberRoot);
336
328
  }
337
329
  catch {
338
330
  }
@@ -1,4 +1,5 @@
1
1
  import { type ExecutionLane } from "../execution-lane-caps.js";
2
+ import { type LocalAskLaneBackfillRefusal } from "./one-time-migrations.js";
2
3
  import type { AskState } from "../approval-ask-machine.js";
3
4
  import type { SettleCause } from "../approval-deny-reasons.js";
4
5
  import type { AskCallCoordinate, AskRow, AskTerminalClaimIntent, AskTerminalClaimOpts, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, DecideResult, EnsureAskResult, ExpireResult, NewAskRow } from "./approval-ask-store-sql.js";
@@ -235,9 +236,16 @@ export declare class FileApprovalAskStore implements ApprovalAskStore {
235
236
  /**
236
237
  * 执行放置切换 ④b 的 local 腿(一次性迁移登记表 M32;`LocalBackend.runOneTimeMigrations` 在任何读者之前调):升级前写下的问(日志 `ensureAsk` 记录行 /
237
238
  * 压实快照行没有 `executionLane`)记成本部署车道表的唯一项,然后**一次压实**把整本账重写成带车道的快照(压实 = 既有整本原子重写)。
238
- * 没有缺车道的行 ⇒ 零写。车道表不是一元而还有缺车道的行 ⇒ 抛与 SQL 同一只拒(`backfill_ambiguous`,由调用方铸),一个字节没写。
239
+ * 只填**缺席**:记下了而不是车道词的问 ⇒ 抛 `unknown_lane`(由调用方铸,点名问与词)—— 拿此刻的车道盖掉它就是替问改了出处。没有缺车道的行 ⇒ 零写。
240
+ * 车道表不是一元而还有缺车道的行 ⇒ 抛与 SQL 同一只拒(`backfill_ambiguous`,由调用方铸)。两种拒都一个字节没写。
239
241
  */
240
- backfillExecutionLanes(lanes: readonly ExecutionLane[], refuse: (pending: number) => never): number;
242
+ backfillExecutionLanes(lanes: readonly ExecutionLane[], refuse: (refusal: LocalAskLaneBackfillRefusal) => never): number;
243
+ /**
244
+ * 一次性迁移 M40 的 local 问账腿(`LocalBackend.runOneTimeMigrations` 调,排在 M32 的问回填 {@link backfillExecutionLanes} 之前 —— 否则旧词先撞那里的词表外拒):
245
+ * 出处车道记成退役词的问改记新名,然后**一次压实**重写整本账。没有 ⇒ 零写。返回改了的问数。词的属主 = `execution-lane-rename-m40.ts`。
246
+ * 压实写不进 ⇒ {@link ExecutionLaneRenameWriteRefusedError}(拒启;内存里已改的行随进程退出作废,盘上账本原样,下次起服重跑)。
247
+ */
248
+ renameRetiredExecutionLaneWordM40(): number;
241
249
  /** 释放追加 fd(`LocalBackend.close` → 优雅重启重开)。不包 try/catch 的理由同
242
250
  * {@link FileApprovalNonceStore.dispose}:core 的 `AppendLog.close()` 自己就是全函数。 */
243
251
  dispose(): void;