@sema-agent/server 7.132.0 → 7.134.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 (473) hide show
  1. package/MIGRATION.md +353 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +301 -64
  5. package/deploy/sema-up/README.md +35 -1
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
  9. package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
  10. package/deploy/sema-up/chart/templates/server-v4pro.yaml +19 -2
  11. package/deploy/sema-up/chart/templates/server.yaml +19 -2
  12. package/deploy/sema-up/chart/values-full-single.yaml +5 -1
  13. package/deploy/sema-up/chart/values.yaml +34 -0
  14. package/deploy/sema-up/stack/compose.yaml +3 -0
  15. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  16. package/dist/adoption/plan.d.ts +3 -2
  17. package/dist/adoption/plan.js +7 -5
  18. package/dist/adoption/runner.js +3 -10
  19. package/dist/adoption/sql.d.ts +3 -2
  20. package/dist/adoption/sql.js +3 -5
  21. package/dist/adoption/wire.d.ts +4 -1
  22. package/dist/adoption/wire.js +1 -0
  23. package/dist/approval-ask-audit-store.d.ts +32 -14
  24. package/dist/approval-ask-audit-store.js +272 -74
  25. package/dist/approval-ask-machine.d.ts +15 -0
  26. package/dist/approval-ask-machine.js +6 -0
  27. package/dist/approval-ask-retention.d.ts +136 -0
  28. package/dist/approval-ask-retention.js +102 -0
  29. package/dist/approval-card.d.ts +83 -23
  30. package/dist/approval-card.js +45 -15
  31. package/dist/approval-content-kind.d.ts +5 -2
  32. package/dist/approval-content-kind.js +16 -3
  33. package/dist/approval-deny-reasons.d.ts +1 -1
  34. package/dist/approval-gate-currency.d.ts +72 -0
  35. package/dist/approval-gate-currency.js +94 -0
  36. package/dist/approval.d.ts +15 -0
  37. package/dist/approval.js +55 -17
  38. package/dist/audit.d.ts +27 -10
  39. package/dist/audit.js +12 -16
  40. package/dist/bake-runner/main.js +3 -2
  41. package/dist/boot/coordinators.d.ts +6 -1
  42. package/dist/boot/coordinators.js +6 -3
  43. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  44. package/dist/boot/execution-env.js +9 -7
  45. package/dist/boot/execution-lane.js +11 -0
  46. package/dist/boot/leader.d.ts +2 -0
  47. package/dist/boot/leader.js +4 -1
  48. package/dist/boot/memory-boundary.js +2 -2
  49. package/dist/boot/memory-consolidation.d.ts +5 -4
  50. package/dist/boot/memory-consolidation.js +7 -6
  51. package/dist/boot/org-delivery.d.ts +28 -0
  52. package/dist/boot/org-delivery.js +20 -0
  53. package/dist/boot/read-deny-anchor-audit.js +2 -2
  54. package/dist/boot/reapers.d.ts +3 -0
  55. package/dist/boot/reapers.js +21 -1
  56. package/dist/boot/resolve-spec.d.ts +3 -0
  57. package/dist/boot/resolve-spec.js +60 -81
  58. package/dist/boot/runner-deps.d.ts +18 -5
  59. package/dist/boot/runner-deps.js +10 -0
  60. package/dist/boot/session-faces.d.ts +1 -0
  61. package/dist/boot/session-faces.js +4 -2
  62. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  63. package/dist/boot/stage-06-runners.d.ts +6 -3
  64. package/dist/boot/stage-06-runners.js +20 -4
  65. package/dist/boot/stage-07-capability-layer.d.ts +4 -1
  66. package/dist/boot/stage-07-capability-layer.js +24 -3
  67. package/dist/boot/stage-08-reapers.d.ts +4 -1
  68. package/dist/boot/stage-08-reapers.js +2 -2
  69. package/dist/boot/stage-09-leader.d.ts +5 -1
  70. package/dist/boot/stage-09-leader.js +2 -2
  71. package/dist/boot/stage-10-http-server.d.ts +5 -1
  72. package/dist/boot/stage-10-http-server.js +6 -6
  73. package/dist/boot/stores.d.ts +8 -0
  74. package/dist/boot/stores.js +10 -14
  75. package/dist/boot/web-admin.d.ts +10 -0
  76. package/dist/boot/web-admin.js +162 -65
  77. package/dist/boot/workflow-orchestration.d.ts +2 -0
  78. package/dist/boot/workflow-orchestration.js +2 -1
  79. package/dist/brain.js +8 -3
  80. package/dist/breaker-key.d.ts +6 -0
  81. package/dist/breaker-key.js +29 -0
  82. package/dist/budget.js +5 -1
  83. package/dist/caller-text-echo.d.ts +11 -6
  84. package/dist/caller-text-echo.js +10 -12
  85. package/dist/canonical-json.d.ts +2 -41
  86. package/dist/canonical-json.js +2 -13
  87. package/dist/capabilities/center-plugins.d.ts +7 -0
  88. package/dist/capabilities/center-plugins.js +1 -1
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/execution-lane.js +2 -2
  92. package/dist/capabilities/hands-lane.d.ts +21 -0
  93. package/dist/capabilities/hands-lane.js +10 -0
  94. package/dist/capabilities/mcp-probe.d.ts +36 -4
  95. package/dist/capabilities/mcp-probe.js +29 -6
  96. package/dist/capabilities/scenarios.d.ts +63 -7
  97. package/dist/capabilities/scenarios.js +39 -7
  98. package/dist/capability-facts.d.ts +36 -4
  99. package/dist/capability-facts.js +30 -4
  100. package/dist/center-config-tier.d.ts +69 -0
  101. package/dist/center-config-tier.js +42 -0
  102. package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
  103. package/dist/checkpoint-ctx-seal-m28.js +19 -0
  104. package/dist/checkpoint-identity.d.ts +16 -0
  105. package/dist/checkpoint-identity.js +19 -0
  106. package/dist/config-catalog.d.ts +17 -10
  107. package/dist/config-catalog.js +43 -28
  108. package/dist/config-d-migration.d.ts +3 -1
  109. package/dist/config-d-migration.js +2 -2
  110. package/dist/config-dir-trust.d.ts +114 -0
  111. package/dist/config-dir-trust.js +388 -0
  112. package/dist/config-invariants.d.ts +18 -5
  113. package/dist/config-invariants.js +35 -3
  114. package/dist/config-provider.d.ts +6 -1
  115. package/dist/config-provider.js +6 -2
  116. package/dist/config-types.d.ts +71 -14
  117. package/dist/config-types.js +8 -0
  118. package/dist/config.d.ts +13 -0
  119. package/dist/config.js +121 -59
  120. package/dist/delegated-session-owner.d.ts +185 -0
  121. package/dist/delegated-session-owner.js +119 -0
  122. package/dist/device-protocol.d.ts +5 -3
  123. package/dist/device-protocol.js +1 -1
  124. package/dist/device-ws-hub.js +21 -2
  125. package/dist/device-ws-protocol.d.ts +70 -6
  126. package/dist/device-ws-protocol.js +50 -23
  127. package/dist/elicitation.js +3 -2
  128. package/dist/entry-problems.d.ts +34 -0
  129. package/dist/entry-problems.js +14 -0
  130. package/dist/execution-lane-caps.d.ts +49 -10
  131. package/dist/execution-lane-caps.js +43 -4
  132. package/dist/field-conflict.d.ts +44 -0
  133. package/dist/field-conflict.js +21 -0
  134. package/dist/file-history-disclosure.d.ts +34 -5
  135. package/dist/file-history-disclosure.js +2 -2
  136. package/dist/fleet/fleet-bus.d.ts +84 -6
  137. package/dist/fleet/fleet-bus.js +42 -9
  138. package/dist/hooks/classic-stations.d.ts +10 -5
  139. package/dist/hooks/classic-stations.js +4 -4
  140. package/dist/hooks/command-spawn.d.ts +57 -0
  141. package/dist/hooks/command-spawn.js +139 -0
  142. package/dist/hooks/hook-llm.js +2 -2
  143. package/dist/hooks/hook-runner.d.ts +127 -25
  144. package/dist/hooks/hook-runner.js +668 -287
  145. package/dist/hooks/hook-source.d.ts +44 -0
  146. package/dist/hooks/hook-source.js +40 -0
  147. package/dist/http/active-run-conflict.d.ts +5 -13
  148. package/dist/http/active-run-conflict.js +17 -27
  149. package/dist/http/admission.js +111 -60
  150. package/dist/http/approval-sweeps.js +58 -19
  151. package/dist/http/caller-trust.d.ts +77 -0
  152. package/dist/http/caller-trust.js +143 -0
  153. package/dist/http/checkpoint-ctx.d.ts +173 -18
  154. package/dist/http/checkpoint-ctx.js +171 -12
  155. package/dist/http/claimed-run.d.ts +4 -3
  156. package/dist/http/device-placement.d.ts +2 -4
  157. package/dist/http/device-placement.js +2 -1
  158. package/dist/http/dispatch.js +13 -7
  159. package/dist/http/durable-run-leg.d.ts +4 -32
  160. package/dist/http/durable-run-leg.js +37 -12
  161. package/dist/http/idempotency.d.ts +2 -2
  162. package/dist/http/idempotency.js +2 -2
  163. package/dist/http/owner-access.d.ts +56 -0
  164. package/dist/http/owner-access.js +42 -0
  165. package/dist/http/principal-gate.d.ts +78 -27
  166. package/dist/http/principal-gate.js +64 -14
  167. package/dist/http/readiness.d.ts +11 -5
  168. package/dist/http/readiness.js +10 -3
  169. package/dist/http/refusal-body.d.ts +12 -0
  170. package/dist/http/refusal-body.js +11 -0
  171. package/dist/http/request-guards.d.ts +16 -32
  172. package/dist/http/request-guards.js +31 -30
  173. package/dist/http/resume-ctx-read.d.ts +50 -6
  174. package/dist/http/resume-ctx-read.js +33 -7
  175. package/dist/http/resume-legs.d.ts +5 -5
  176. package/dist/http/resume-legs.js +163 -91
  177. package/dist/http/retired-service-deps.d.ts +43 -0
  178. package/dist/http/retired-service-deps.js +18 -0
  179. package/dist/http/route-ctx.d.ts +44 -37
  180. package/dist/http/route-ctx.js +4 -0
  181. package/dist/http/route-table.js +2 -0
  182. package/dist/http/routes/a2a-serve.js +3 -4
  183. package/dist/http/routes/admin-config-refresh.js +1 -1
  184. package/dist/http/routes/admin-drain.js +1 -1
  185. package/dist/http/routes/admin-memory-optout.js +5 -1
  186. package/dist/http/routes/adoption.js +2 -9
  187. package/dist/http/routes/agents-roster.js +2 -3
  188. package/dist/http/routes/approvals-assistant.js +91 -56
  189. package/dist/http/routes/background.js +3 -2
  190. package/dist/http/routes/capabilities.js +20 -4
  191. package/dist/http/routes/config-catalog.d.ts +3 -3
  192. package/dist/http/routes/config-catalog.js +1 -1
  193. package/dist/http/routes/devices.js +3 -17
  194. package/dist/http/routes/diagnostics.d.ts +3 -3
  195. package/dist/http/routes/diagnostics.js +6 -2
  196. package/dist/http/routes/fleet.js +4 -4
  197. package/dist/http/routes/images.js +6 -7
  198. package/dist/http/routes/leader.js +1 -8
  199. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  200. package/dist/http/routes/mcp-reconnect.js +3 -2
  201. package/dist/http/routes/memory-bundle.js +1 -1
  202. package/dist/http/routes/memory-compliance.js +1 -1
  203. package/dist/http/routes/memory-consolidation.js +1 -1
  204. package/dist/http/routes/memory-origin.d.ts +1 -1
  205. package/dist/http/routes/memory-origin.js +1 -1
  206. package/dist/http/routes/memory-policy.d.ts +1 -1
  207. package/dist/http/routes/memory-policy.js +3 -2
  208. package/dist/http/routes/notify-wake.js +8 -21
  209. package/dist/http/routes/observability.js +2 -2
  210. package/dist/http/routes/principal-inbox.d.ts +39 -0
  211. package/dist/http/routes/principal-inbox.js +76 -0
  212. package/dist/http/routes/retention-ops.js +2 -9
  213. package/dist/http/routes/rules.js +9 -22
  214. package/dist/http/routes/runs.d.ts +5 -0
  215. package/dist/http/routes/runs.js +63 -115
  216. package/dist/http/routes/session-sync.d.ts +3 -2
  217. package/dist/http/routes/session-sync.js +53 -48
  218. package/dist/http/routes/sessions-list.d.ts +1 -1
  219. package/dist/http/routes/sessions-list.js +3 -4
  220. package/dist/http/routes/sessions.js +33 -43
  221. package/dist/http/routes/side-query.js +6 -4
  222. package/dist/http/routes/tasks.js +71 -30
  223. package/dist/http/routes/trace-usage.js +7 -9
  224. package/dist/http/routes/workflows.d.ts +351 -0
  225. package/dist/http/routes/workflows.js +153 -119
  226. package/dist/http/run-declared-families.d.ts +16 -0
  227. package/dist/http/run-declared-families.js +12 -0
  228. package/dist/http/send.d.ts +24 -3
  229. package/dist/http/send.js +14 -2
  230. package/dist/http/server.d.ts +23 -18
  231. package/dist/http/server.js +20 -15
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +4 -3
  234. package/dist/http/submit-ctx.js +23 -6
  235. package/dist/http/submit-replay.d.ts +4 -3
  236. package/dist/http/submit-replay.js +5 -4
  237. package/dist/http/wire-types.d.ts +17 -10
  238. package/dist/index.d.ts +3 -1
  239. package/dist/index.js +1 -1
  240. package/dist/lane-home-probe.d.ts +78 -9
  241. package/dist/lane-home-probe.js +78 -12
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/leader/wire.d.ts +4 -0
  245. package/dist/leader/wire.js +8 -7
  246. package/dist/limit-refusal.d.ts +17 -5
  247. package/dist/limit-refusal.js +4 -1
  248. package/dist/main.js +1 -1
  249. package/dist/mcp-assertion-header.d.ts +31 -10
  250. package/dist/mcp-assertion-header.js +10 -3
  251. package/dist/memory-origin-fence.js +2 -2
  252. package/dist/memory-project-layer.d.ts +37 -0
  253. package/dist/memory-project-layer.js +46 -0
  254. package/dist/memory-scope.d.ts +23 -16
  255. package/dist/memory-scope.js +24 -8
  256. package/dist/memory-sync-client.d.ts +27 -13
  257. package/dist/memory-sync-client.js +107 -18
  258. package/dist/model-compat.d.ts +1 -1
  259. package/dist/model-entry-refusal.d.ts +9 -1
  260. package/dist/model-entry-refusal.js +6 -1
  261. package/dist/model-plane-face.d.ts +51 -0
  262. package/dist/model-plane-face.js +24 -0
  263. package/dist/model-provider.d.ts +5 -0
  264. package/dist/model-provider.js +4 -2
  265. package/dist/model-route-endpoint.d.ts +8 -11
  266. package/dist/model-route-endpoint.js +4 -7
  267. package/dist/model-route-env.d.ts +22 -0
  268. package/dist/model-route-env.js +2 -0
  269. package/dist/model-route-gap.d.ts +60 -30
  270. package/dist/model-route-gap.js +21 -15
  271. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  272. package/dist/observability/corrupt-read-seat.js +9 -0
  273. package/dist/observability/err-text.d.ts +6 -0
  274. package/dist/observability/err-text.js +18 -4
  275. package/dist/observability/fail-open.d.ts +35 -9
  276. package/dist/observability/fail-open.js +35 -9
  277. package/dist/observability/metrics.js +1 -0
  278. package/dist/observability/prompt-manifest.d.ts +22 -25
  279. package/dist/observability/prompt-manifest.js +54 -50
  280. package/dist/observability/tool-trace.js +9 -10
  281. package/dist/operator-ask.d.ts +10 -0
  282. package/dist/operator-ask.js +3 -0
  283. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  284. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  285. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  286. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  287. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  288. package/dist/orchestration/workflow-notify-journal.js +27 -34
  289. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  290. package/dist/orchestration/workflow-park-decision.js +119 -0
  291. package/dist/org-delivery-gate.d.ts +81 -0
  292. package/dist/org-delivery-gate.js +59 -0
  293. package/dist/panel-tool-names.d.ts +23 -0
  294. package/dist/panel-tool-names.js +8 -0
  295. package/dist/parked-decide.d.ts +43 -11
  296. package/dist/parked-decide.js +100 -51
  297. package/dist/parked-revive-surface.d.ts +9 -2
  298. package/dist/parked-revive-surface.js +11 -8
  299. package/dist/permission-rule-list.d.ts +1 -1
  300. package/dist/permission-rule-list.js +2 -2
  301. package/dist/permission-rule-vocab.d.ts +1 -23
  302. package/dist/permission-rule-vocab.js +0 -13
  303. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  304. package/dist/plugins/approval-ask-store-file.js +21 -0
  305. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  306. package/dist/plugins/approval-ask-store-memory.js +34 -2
  307. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  308. package/dist/plugins/approval-ask-store-sql.js +37 -1
  309. package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
  310. package/dist/plugins/approval-payload-fingerprint.js +1 -1
  311. package/dist/plugins/blob-backend.d.ts +38 -25
  312. package/dist/plugins/blob-backend.js +29 -19
  313. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  314. package/dist/plugins/breaker-state-sql.js +4 -4
  315. package/dist/plugins/caching-session-store.d.ts +4 -1
  316. package/dist/plugins/caching-session-store.js +7 -3
  317. package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
  318. package/dist/plugins/checkpoint-store-sql.js +65 -3
  319. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  320. package/dist/plugins/file-history-store-sql.js +3 -1
  321. package/dist/plugins/file-run-store.d.ts +5 -13
  322. package/dist/plugins/file-run-store.js +9 -0
  323. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  324. package/dist/plugins/fork-routing-session-store.js +12 -1
  325. package/dist/plugins/host-platform.d.ts +2 -0
  326. package/dist/plugins/host-platform.js +2 -1
  327. package/dist/plugins/local-checkpoint-store.d.ts +15 -2
  328. package/dist/plugins/local-checkpoint-store.js +32 -1
  329. package/dist/plugins/local-session-store.d.ts +13 -10
  330. package/dist/plugins/local-session-store.js +23 -14
  331. package/dist/plugins/local-session-window.d.ts +45 -0
  332. package/dist/plugins/local-session-window.js +38 -0
  333. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  334. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  335. package/dist/plugins/mailbox-store-sql.js +77 -52
  336. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  337. package/dist/plugins/memory-run-store.d.ts +5 -13
  338. package/dist/plugins/memory-run-store.js +8 -0
  339. package/dist/plugins/one-time-migrations.d.ts +121 -5
  340. package/dist/plugins/one-time-migrations.js +332 -8
  341. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  342. package/dist/plugins/org-delivery-quota-store.js +228 -0
  343. package/dist/plugins/permission-rule-store-file.js +10 -6
  344. package/dist/plugins/permission-rule-store-sql.js +8 -8
  345. package/dist/plugins/pg-pool.js +39 -7
  346. package/dist/plugins/pg-session-storage.d.ts +18 -5
  347. package/dist/plugins/pg-session-storage.js +68 -23
  348. package/dist/plugins/remote-env-adb.d.ts +6 -12
  349. package/dist/plugins/remote-env-adb.js +12 -2
  350. package/dist/plugins/remote-env-device.d.ts +14 -7
  351. package/dist/plugins/remote-env-device.js +23 -15
  352. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  353. package/dist/plugins/remote-env-k8s.js +23 -5
  354. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  355. package/dist/plugins/remote-env-local-docker.js +12 -9
  356. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  357. package/dist/plugins/remote-env-ssh.js +17 -11
  358. package/dist/plugins/run-store-sql.d.ts +16 -14
  359. package/dist/plugins/run-store-sql.js +22 -2
  360. package/dist/plugins/schema-indexes.js +2 -0
  361. package/dist/plugins/send-user-file.js +2 -2
  362. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  363. package/dist/plugins/session-epoch-anchor.js +2 -3
  364. package/dist/plugins/session-ownership.d.ts +11 -0
  365. package/dist/plugins/session-ownership.js +11 -0
  366. package/dist/plugins/session-placement.d.ts +12 -14
  367. package/dist/plugins/session-placement.js +2 -15
  368. package/dist/plugins/session-store.d.ts +18 -8
  369. package/dist/plugins/session-store.js +15 -4
  370. package/dist/plugins/sql-driver.d.ts +74 -11
  371. package/dist/plugins/sql-driver.js +210 -12
  372. package/dist/plugins/sql-errors.d.ts +23 -0
  373. package/dist/plugins/sql-errors.js +21 -0
  374. package/dist/plugins/store-backend.d.ts +36 -1
  375. package/dist/plugins/store-backend.js +40 -14
  376. package/dist/plugins/store-contracts.d.ts +42 -0
  377. package/dist/plugins/store-contracts.js +1 -0
  378. package/dist/plugins/tidb-pool.d.ts +6 -1
  379. package/dist/plugins/tidb-pool.js +44 -10
  380. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  381. package/dist/plugins/tidb-session-storage.js +2 -2
  382. package/dist/plugins/tidb-session-store.d.ts +25 -5
  383. package/dist/plugins/tidb-session-store.js +67 -21
  384. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  385. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  386. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  387. package/dist/plugins/workflow-run-store-sql.js +50 -9
  388. package/dist/posture-source.d.ts +18 -10
  389. package/dist/posture-source.js +4 -1
  390. package/dist/project-identity.d.ts +45 -6
  391. package/dist/project-identity.js +162 -8
  392. package/dist/project-layer-key.d.ts +28 -0
  393. package/dist/project-layer-key.js +29 -0
  394. package/dist/question.js +3 -2
  395. package/dist/read-deny-entry.d.ts +25 -0
  396. package/dist/read-deny-entry.js +12 -0
  397. package/dist/read-face-posture.d.ts +37 -11
  398. package/dist/read-face-posture.js +32 -3
  399. package/dist/request-key-closure.d.ts +7 -0
  400. package/dist/request-key-closure.js +9 -1
  401. package/dist/request-tool-axes.d.ts +12 -0
  402. package/dist/request-tool-axes.js +20 -0
  403. package/dist/request-value-closure.d.ts +5 -0
  404. package/dist/request-value-closure.js +11 -3
  405. package/dist/rule-entry-list.d.ts +26 -2
  406. package/dist/rule-entry-list.js +72 -12
  407. package/dist/rules-consent.js +3 -4
  408. package/dist/run-acceptance.d.ts +19 -3
  409. package/dist/run-acceptance.js +13 -1
  410. package/dist/run-local.js +37 -6
  411. package/dist/runs.d.ts +12 -10
  412. package/dist/runs.js +25 -6
  413. package/dist/runtime-caps-resolver.d.ts +16 -6
  414. package/dist/runtime-caps-resolver.js +18 -5
  415. package/dist/sandbox-pkg-source.d.ts +19 -1
  416. package/dist/sandbox-pkg-source.js +29 -7
  417. package/dist/sealed-key.d.ts +32 -0
  418. package/dist/sealed-key.js +55 -1
  419. package/dist/security.d.ts +95 -15
  420. package/dist/security.js +52 -9
  421. package/dist/session-error-wire.d.ts +31 -7
  422. package/dist/session-error-wire.js +9 -2
  423. package/dist/session-sync-kernel.d.ts +37 -10
  424. package/dist/session-sync-kernel.js +10 -0
  425. package/dist/session-titled-frame.d.ts +33 -0
  426. package/dist/session-titled-frame.js +4 -0
  427. package/dist/session-titler.d.ts +9 -1
  428. package/dist/session-titler.js +15 -4
  429. package/dist/spec-fields.js +21 -2
  430. package/dist/sql-engine-posture.d.ts +3 -1
  431. package/dist/task-a2a.js +4 -3
  432. package/dist/task-cwd.d.ts +1 -1
  433. package/dist/task-mcp.d.ts +5 -5
  434. package/dist/task-mcp.js +27 -74
  435. package/dist/task-settings.d.ts +93 -88
  436. package/dist/task-settings.js +71 -63
  437. package/dist/text-bidi.d.ts +0 -4
  438. package/dist/text-bidi.js +1 -3
  439. package/dist/tighten-only-seats.d.ts +150 -0
  440. package/dist/tighten-only-seats.js +196 -0
  441. package/dist/tool-approval.d.ts +451 -136
  442. package/dist/tool-approval.js +733 -256
  443. package/dist/tool-rule-names.d.ts +6 -0
  444. package/dist/trace/core-keyset-guard.d.ts +108 -25
  445. package/dist/trace/exit-seat.d.ts +40 -0
  446. package/dist/trace/exit-seat.js +130 -0
  447. package/dist/trace/ledger-events.d.ts +6 -3
  448. package/dist/trace/project.d.ts +98 -13
  449. package/dist/trace/project.js +57 -32
  450. package/dist/trace/projection-table.d.ts +100 -0
  451. package/dist/trace/projection-table.js +130 -0
  452. package/dist/trace/redact.d.ts +57 -0
  453. package/dist/trace/redact.js +962 -168
  454. package/dist/trace/self-minted-wire.d.ts +349 -1
  455. package/dist/trace/self-minted-wire.js +118 -1
  456. package/dist/trace/wire-projection-faces.d.ts +304 -2
  457. package/dist/trace/wire-projection-faces.js +160 -13
  458. package/dist/url-refusal.js +2 -0
  459. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  460. package/dist/web-admin-client/apply-effective.js +56 -5
  461. package/dist/web-admin-client/facade.d.ts +1 -1
  462. package/dist/web-admin-client/facade.js +1 -1
  463. package/dist/web-admin-client/read-face.js +5 -9
  464. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  465. package/dist/web-admin-client/skills-mcp.js +6 -8
  466. package/dist/web-admin-client/types.d.ts +1 -1
  467. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  468. package/package.json +8 -4
  469. package/scripts/drain-check-local.mjs +34 -2
  470. package/scripts/drain-check.mysql.sql +20 -2
  471. package/scripts/drain-check.pg.sql +20 -2
  472. package/dist/mcp-tool-faces.d.ts +0 -69
  473. package/dist/mcp-tool-faces.js +0 -106
@@ -23,7 +23,7 @@
23
23
  * - **不翻 `streamApproval` 能力位**([ref] 当时的裁 (c);⚠️ **这一位已由 S-384 翻真,不是被本店翻的**):
24
24
  * 当年不翻的理由是「该位在 SQL 车道隐含 durable park 兜底,local 给不了」+「local 的 ask 账是进程内
25
25
  * 易失形」。后半条已由 `FileApprovalAskStore` 消掉(持久账落地);前半条的答案一直在谓词里 ——
26
- * `resolveStreamApprovalGate` 的 `parkFacility` 合取项要求 `backend.checkpoint` 在场 ∧ `DURABLE_APPROVAL`,
26
+ * `resolveStreamApprovalGate` 的 park 设施(`checkpointStore`)合取项要求 `backend.checkpoint` 在场 ∧ `DURABLE_APPROVAL`,
27
27
  * 所以位报 true 的 local 部署**必然**配齐了 File 形 checkpoint 店(`durable-approval-local-e2e` 第一格
28
28
  * 实证:park 行跨双 kill 存活、重启后 decide 驱动 resume 真跑完)。本店与那一位自此无关:它治的是
29
29
  * **活卡窗内崩溃**(park 还没落盘)那一格的零痕迹病,而那一格无论位真位假都不复活 run。
@@ -166,11 +166,16 @@
166
166
  * 同源(`store-backend.ts:780` 的 `config.localDataRoot`),数据落 `<root>/approval-ask-audit/`。
167
167
  *
168
168
  * ## 体量与保留
169
- * 只在真出卡时写(人批一次 = 3 行),量级 = 人的手速;账本只增不删,压缩是未来件(workflow-notify
170
- * journal 同款成文)。读面列表按收敛时刻新前旧后、上限 {@link CRASH_CONVERGED_LIST_MAX}(有界 wire)。
169
+ * 只在真出卡时写(人批一次 = 3 行),量级 = 人的手速。保留 = 审批账本的留存律(律一处成文在 `approval-ask-retention.ts`;维护 tick 按
170
+ * `APPROVAL_ASK_RETENTION_MS` 调 {@link FileApprovalAskAuditStore.rotateOlderThan}):**整问**删 —— 一问不再欠下一次起服收敛一个答案
171
+ * (下面的收敛判官此刻不会把它收成孤儿)且它所有记录里最晚的时刻早于 cutoff,它的全部行(铸造 / 决议 / 收敛 / 迟到结算)一起离开文件;
172
+ * 腿记录(按 taskId)只在没有任何留下的问还认它、且它自己也过窗时才删,于是留下的问的收敛投影(成因 / `resumeSafe`)一字不变;
173
+ * 认不出的行证不出到期,原样留;发起它的 run 还能动(跑着 / 停驻)的问也留。**只删不改**:留下的行逐字节写回(原子换文件,0o600),删了多少进读数行。
174
+ * 读面列表按收敛时刻新前旧后、上限 {@link CRASH_CONVERGED_LIST_MAX}(有界 wire)。
171
175
  */
172
176
  import type { HostDecision } from "./host-decision.js";
173
177
  import { AppendLog } from "@sema-agent/core";
178
+ import type { AuditRotationReading } from "./approval-ask-retention.js";
174
179
  import { SETTLE_OUTCOME, type HolderGoneCause, type SettleCause } from "./approval-deny-reasons.js";
175
180
  /** 数据子目录名(挂在 local 数据根下,与 `workflow-notify/` 同层同形)。 */
176
181
  export declare const APPROVAL_ASK_AUDIT_DIR = "approval-ask-audit";
@@ -328,6 +333,8 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
328
333
  private log;
329
334
  /** 追加口的铸造座(测试注入席:单条写失败 / 半写的确定性构造;生产恒缺省 = `new AppendLog(path)`)。 */
330
335
  private readonly openLog;
336
+ /** 轮转换文件之后的目录 fsync(测试注入席:失败的确定性构造;生产恒缺省 = {@link fsyncDirectory})。 */
337
+ private readonly fsyncDir;
331
338
  /** boot 重放快照(冻结于构造时刻 = 前世账本;本进程新写的行不进它 —— 收敛只对前世行)。 */
332
339
  private readonly replayed;
333
340
  /** 前世账本里的腿闭事件(taskId + 行序;decided 臂按「决议行之后」判)。 */
@@ -369,12 +376,12 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
369
376
  */
370
377
  constructor(root: string, internals?: {
371
378
  appendLog?: (path: string) => AuditAppendPort;
379
+ fsyncDir?: (dir: string) => void;
372
380
  });
373
381
  /** 重放的坏值计数(`convergeCrashedAsks().corruptLines`):重放属主跳过的坏行(撕尾不计)+ 成因词表外的行(行在、结清照认,坏值照样计数)。 */
374
382
  private corruptLines;
375
383
  /** 重放前世账本(共用口 `replayJsonlSkipping`):撕尾 = 未落完的写,静默跳过;坏行跳过 + 逐条计数 / 探针;坏行数另暴露给收敛日志。 */
376
384
  private replay;
377
- private group;
378
385
  /** append + fsync(逐行落盘:进程猝死不丢已记的行 —— 本店的全部价值就在崩溃时刻;写口 = 共用的 `AppendLog`:单次 `writeSync` 一行、末段在打开与每次追加前修(撕尾截、完整末行补换行)、失败的写截回开写处)。
379
386
  * 运行期失败**响亮不阻断**:审批可用性不押在审计盘上(盘满/只读时人还得能批),但丢行必须在遥测
380
387
  * 显形([ref] 三件套,census 登记行同批)。
@@ -445,18 +452,29 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
445
452
  /** S-929 收敛行的成因注(判据见头注「收敛行的 `cause`」):组的最后一个事件行之后、收敛行(若已收敛)之前,有本 taskId 的
446
453
  * 有序关停记号 ⇒ `shutdown_before_park`;否则 `crashed_before_park`。 */
447
454
  private causeOf;
448
- /**
449
- * 🔴 **S-945([ref])—— 腿证据只对被追踪的 ask 行作数**:一处成文,三处读(pending 臂的腿闭反证门 / decided 臂 / 收敛行成因注)。
450
- * 腿闭行与有序关停记号都只按 `taskId` 落;委派 / 后台子代 ask 行的 `taskId` 是**宿主** run(出处),承载它的不是宿主腿(铸造时
451
- * `legTracked:false`)⇒ 宿主腿的这两类记录对它什么都不证明(修前反证门不看 `legTracked`:宿主腿闭把子代未结清卡判成 inconsistent、不列孤儿)。
452
- * 返回 `undefined` = 这一行没有可作证的腿;否则 = 本 taskId 在 `(afterLine, beforeLine)` 之间有没有该类记录。
453
- */
454
- private legEvidence;
455
455
  private projectRow;
456
- /** scope 门与 `listLivePending` 逐字同律:`undefined` = operator 全量(含 owner null 行);串 = 只见
457
- * `owner === scope` 的行(null-owner 行对 principal 不可见,fail-closed 宁少列不超范围;`"__none__"`
458
- * 未鉴权哨兵自然恒空)。 */
456
+ /** scope 门与 `listLivePending` 逐字同律(同一只 checkpoint scope 解码):`undefined` = operator 全量(含 owner null 行);
457
+ * `_` = 匿名那一组 = owner null 的行;其余串 = 只见 `owner === scope` 的行(null-owner 行对具名主体不列,宁少列不超范围)。 */
459
458
  listCrashConverged(scope: string | undefined): CrashConvergedRow[];
459
+ /**
460
+ * **留存轮转**(审批账本留存律的审计账半场;律一处成文在 `approval-ask-retention.ts`,判据见头注「体量与保留」)。维护 tick 是唯一调用方。
461
+ *
462
+ * 读的是**文件**(前世 + 本进程两段账,行序即语义序),不是构造时冻结的前世快照:本进程铸的问要按它此刻在盘上的样子判「结了没有」。
463
+ * 判「结了」= 它挂靠的格(铸造行的 `taskId` / `sessionId` / `sourceTaskId`)都不在 `keepAnchors`(还能动的东西的挂靠集,由清扫从 run 账与
464
+ * 后台子代账列出)∧ {@link judgeOrphan} 此刻不欠它答案 —— 停驻 run / 能动子代的问(窗到期转 durable、迟到结算还要这组前置事实)、活卡
465
+ * (铸了没决)与批了腿没闭的问多老都留。删的单位是**整问**:
466
+ * · 一问的最后动静 = 它所有记录(铸造 / 决议 / 收敛 / 迟到结算)里最晚的时刻;早于 cutoff ∧ 不欠答案 ⇒ 这一问的全部行删;
467
+ * · 腿记录(按 taskId)只在它自己也早于 cutoff ∧ 没有任何留下的问是这个 taskId ∧ 这个 taskId 不在挂靠集时才删 —— 留下的问的收敛投影(成因 / `resumeSafe`)读得到的腿证据一条不少;
468
+ * · 身份说不清的迟到结算(`approvalId:null`)按它自己的时刻;认不出的行(腐行 / 词表外)证不出到期 ⇒ 原样留;
469
+ * 末尾没换行的那一段原样留在末尾(不补换行),由追加口下次打开时按 core 的同一只判词修(解析成对象补换行、撕尾截断)。
470
+ * 只删不改:留下的每一行按**原字节**写回(按换行字节切段,不经解码 —— 非 UTF-8 的字节一个不变),原子换文件({@link replaceFileBytes}:
471
+ * 0o600;换上之前失败 ⇒ 原文件原样,错误抛给维护 tick 的节流 catch;换上之后只剩目录 fsync,失败走 F 类 tag、读数照交);
472
+ * 追加口先收,下一次 append 在新文件上惰性重开。没有可删的行 ⇒ 文件一字不动、不重写。
473
+ *
474
+ * 内存同步剪:被删的问离开迟到结算的反查索引(之后对它的迟到决议证不出「窗到期已转 durable」⇒ 一行不写 —— 盘上查无前置事实的行不许写)、
475
+ * 离开 `crashConverged` 读面与前世快照。前世快照里留下的组与腿记录的行序不动(它们只在起服收敛那一拍被读,彼此仍自洽)。
476
+ */
477
+ rotateOlderThan(cutoffMs: number, keepAnchors: ReadonlySet<string>): AuditRotationReading;
460
478
  /** 收追加口(优雅关闭腿;SIGKILL 下不跑也不丢 —— 每行已 fsync)。core `AppendLog.close()` 自己吞 `closeSync` 的错、不抛(全函数),本店不再包 catch。 */
461
479
  close(): void;
462
480
  }
@@ -1,7 +1,9 @@
1
- import { createHash } from "node:crypto";
2
- import { join } from "node:path";
3
- import { AppendLog, ensureDir, isHostDecider } from "@sema-agent/core";
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { closeSync, existsSync, fsyncSync, openSync, readFileSync, renameSync, unlinkSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { AppendLog, ensureDir, isHostDecider, writeThenLink } from "@sema-agent/core";
4
5
  import { recordFailOpen } from "./observability/fail-open.js";
6
+ import { ownerOfCheckpointScope } from "./security.js";
5
7
  import { replayJsonlSkipping } from "./observability/corrupt-read-seat.js";
6
8
  import { isSettleCause, SETTLE_OUTCOME } from "./approval-deny-reasons.js";
7
9
  export const APPROVAL_ASK_AUDIT_DIR = "approval-ask-audit";
@@ -168,10 +170,157 @@ const LEDGER_SHAPE = {
168
170
  return rec === undefined ? undefined : { rec, outOfSetCause };
169
171
  },
170
172
  };
173
+ function foldLedger(records) {
174
+ const groups = new Map();
175
+ const legClosed = [];
176
+ const shutdownMarks = [];
177
+ const group = (approvalId, line) => {
178
+ let g = groups.get(approvalId);
179
+ if (!g) {
180
+ g = { firstLine: line };
181
+ groups.set(approvalId, g);
182
+ }
183
+ return g;
184
+ };
185
+ for (const { rec, line } of records) {
186
+ switch (rec.kind) {
187
+ case "ask": {
188
+ const g = group(rec.approvalId, line);
189
+ if (g.ask === undefined) {
190
+ g.ask = rec;
191
+ g.askLine = line;
192
+ }
193
+ break;
194
+ }
195
+ case "settle": {
196
+ const g = group(rec.approvalId, line);
197
+ if (g.settle === undefined) {
198
+ g.settle = rec;
199
+ g.settleLine = line;
200
+ }
201
+ break;
202
+ }
203
+ case "late_settle":
204
+ break;
205
+ case "leg_closed":
206
+ legClosed.push({ taskId: rec.taskId, line });
207
+ break;
208
+ case "interrupted_by_shutdown":
209
+ shutdownMarks.push({ taskId: rec.taskId, line });
210
+ break;
211
+ case "crash_converged": {
212
+ const g = group(rec.approvalId, line);
213
+ g.converged = rec;
214
+ g.convergedLine = line;
215
+ break;
216
+ }
217
+ default: {
218
+ const unreachable = rec;
219
+ throw new Error(`approval-ask-audit fold: unreachable record ${String(unreachable)}`);
220
+ }
221
+ }
222
+ }
223
+ return { groups, legClosed, shutdownMarks };
224
+ }
225
+ function legEvidenceOf(g, records, afterLine, beforeLine = Number.POSITIVE_INFINITY) {
226
+ const ask = g.ask;
227
+ if (!ask.legTracked)
228
+ return undefined;
229
+ return records.some((r) => r.taskId === ask.taskId && r.line > afterLine && r.line < beforeLine);
230
+ }
231
+ function judgeOrphan(g, legClosed) {
232
+ if (g.ask === undefined || g.converged !== undefined)
233
+ return undefined;
234
+ if (g.settle === undefined) {
235
+ return legEvidenceOf(g, legClosed, g.askLine ?? 0) === true ? "inconsistent" : "pending";
236
+ }
237
+ if (g.settle.outcome === "allowed" && legEvidenceOf(g, legClosed, g.settleLine ?? 0) === false)
238
+ return "decided";
239
+ return undefined;
240
+ }
241
+ function readLedgerLine(raw) {
242
+ let parsed;
243
+ try {
244
+ parsed = JSON.parse(raw.toString("utf8"));
245
+ }
246
+ catch (err) {
247
+ return { unparsable: err };
248
+ }
249
+ return { rec: readLedgerRecord(parsed, () => { }) };
250
+ }
251
+ function recordOfLine(raw) {
252
+ const read = readLedgerLine(raw);
253
+ return "rec" in read ? read.rec : undefined;
254
+ }
255
+ function replaceFileBytes(target, bytes) {
256
+ const staging = join(dirname(target), ".tmp", `${APPROVAL_ASK_AUDIT_LEDGER}.${process.pid}.${randomBytes(6).toString("hex")}.rotate`);
257
+ try {
258
+ writeThenLink(staging, bytes);
259
+ renameSync(staging, target);
260
+ }
261
+ finally {
262
+ if (existsSync(staging))
263
+ unlinkSync(staging);
264
+ }
265
+ }
266
+ function fsyncDirectory(dir) {
267
+ const fd = openSync(dir, "r");
268
+ try {
269
+ fsyncSync(fd);
270
+ }
271
+ finally {
272
+ closeSync(fd);
273
+ }
274
+ }
275
+ function splitLedgerBytes(bytes) {
276
+ const lines = [];
277
+ let start = 0;
278
+ for (let i = bytes.indexOf(0x0a, start); i !== -1; i = bytes.indexOf(0x0a, start)) {
279
+ lines.push(bytes.subarray(start, i));
280
+ start = i + 1;
281
+ }
282
+ return { lines, tail: bytes.subarray(start) };
283
+ }
284
+ function approvalIdOf(rec) {
285
+ switch (rec.kind) {
286
+ case "ask":
287
+ case "settle":
288
+ case "crash_converged":
289
+ case "late_settle":
290
+ return rec.approvalId;
291
+ case "leg_closed":
292
+ case "interrupted_by_shutdown":
293
+ return undefined;
294
+ default: {
295
+ const unreachable = rec;
296
+ throw new Error(`approval-ask-audit: unreachable record ${String(unreachable)}`);
297
+ }
298
+ }
299
+ }
300
+ function atMsOf(rec) {
301
+ switch (rec.kind) {
302
+ case "ask":
303
+ return rec.mintedAtMs;
304
+ case "settle":
305
+ case "late_settle":
306
+ return rec.settledAtMs;
307
+ case "crash_converged":
308
+ return rec.convergedAtMs;
309
+ case "leg_closed":
310
+ return rec.closedAtMs;
311
+ case "interrupted_by_shutdown":
312
+ return rec.atMs;
313
+ default: {
314
+ const unreachable = rec;
315
+ throw new Error(`approval-ask-audit: unreachable record ${String(unreachable)}`);
316
+ }
317
+ }
318
+ }
171
319
  export class FileApprovalAskAuditStore {
172
320
  ledgerPath;
173
321
  log;
174
322
  openLog;
323
+ fsyncDir;
175
324
  replayed = new Map();
176
325
  replayedLegClosed = [];
177
326
  replayedShutdownMarks = [];
@@ -185,6 +334,7 @@ export class FileApprovalAskAuditStore {
185
334
  askTaskId = new Map();
186
335
  constructor(root, internals) {
187
336
  this.openLog = internals?.appendLog ?? ((p) => new AppendLog(p));
337
+ this.fsyncDir = internals?.fsyncDir ?? fsyncDirectory;
188
338
  const dir = join(root, APPROVAL_ASK_AUDIT_DIR);
189
339
  ensureDir(dir);
190
340
  this.ledgerPath = join(dir, APPROVAL_ASK_AUDIT_LEDGER);
@@ -193,59 +343,20 @@ export class FileApprovalAskAuditStore {
193
343
  corruptLines = 0;
194
344
  replay() {
195
345
  const { records, skipped } = replayJsonlSkipping(this.ledgerPath, "approval-ask-audit", LEDGER_SHAPE);
196
- this.corruptLines = skipped;
197
- let line = 0;
198
- for (const { rec, outOfSetCause } of records) {
199
- line += 1;
200
- if (outOfSetCause)
201
- this.corruptLines += 1;
202
- switch (rec.kind) {
203
- case "ask": {
204
- const g = this.group(rec.approvalId, line);
205
- if (g.ask === undefined) {
206
- g.ask = rec;
207
- g.askLine = line;
208
- }
209
- this.indexAsk(rec);
210
- break;
211
- }
212
- case "settle": {
213
- const g = this.group(rec.approvalId, line);
214
- if (g.settle === undefined) {
215
- g.settle = rec;
216
- g.settleLine = line;
217
- }
218
- this.indexSettle(rec);
219
- break;
220
- }
221
- case "late_settle":
222
- break;
223
- case "leg_closed":
224
- this.replayedLegClosed.push({ taskId: rec.taskId, line });
225
- break;
226
- case "interrupted_by_shutdown":
227
- this.replayedShutdownMarks.push({ taskId: rec.taskId, line });
228
- break;
229
- case "crash_converged": {
230
- const g = this.group(rec.approvalId, line);
231
- g.converged = rec;
232
- g.convergedLine = line;
233
- break;
234
- }
235
- default: {
236
- const unreachable = rec;
237
- throw new Error(`approval-ask-audit replay: unreachable record ${String(unreachable)}`);
238
- }
239
- }
240
- }
241
- }
242
- group(approvalId, line) {
243
- let g = this.replayed.get(approvalId);
244
- if (!g) {
245
- g = { firstLine: line };
346
+ this.corruptLines = skipped + records.filter((r) => r.outOfSetCause).length;
347
+ const fold = foldLedger(records.map(({ rec }, i) => ({ rec, line: i + 1 })));
348
+ for (const [approvalId, g] of fold.groups)
246
349
  this.replayed.set(approvalId, g);
350
+ for (const r of fold.legClosed)
351
+ this.replayedLegClosed.push(r);
352
+ for (const r of fold.shutdownMarks)
353
+ this.replayedShutdownMarks.push(r);
354
+ for (const { rec } of records) {
355
+ if (rec.kind === "ask")
356
+ this.indexAsk(rec);
357
+ else if (rec.kind === "settle")
358
+ this.indexSettle(rec);
247
359
  }
248
- return g;
249
360
  }
250
361
  append(rec) {
251
362
  try {
@@ -346,18 +457,12 @@ export class FileApprovalAskAuditStore {
346
457
  this.convergedRows.push({ row: this.projectRow(g, g.converged.orphanState, g.converged.convergedAtMs, this.causeOf(g)), owner: g.ask.owner });
347
458
  continue;
348
459
  }
349
- let orphanState;
350
- if (g.settle === undefined) {
351
- if (this.legEvidence(g, this.replayedLegClosed, g.askLine ?? 0) === true) {
352
- inconsistent += 1;
353
- continue;
354
- }
355
- orphanState = "pending";
356
- }
357
- else if (g.settle.outcome === "allowed" &&
358
- this.legEvidence(g, this.replayedLegClosed, g.settleLine ?? 0) === false) {
359
- orphanState = "decided";
460
+ const verdict = judgeOrphan(g, this.replayedLegClosed);
461
+ if (verdict === "inconsistent") {
462
+ inconsistent += 1;
463
+ continue;
360
464
  }
465
+ const orphanState = verdict;
361
466
  if (orphanState === undefined)
362
467
  continue;
363
468
  const convergedAtMs = Date.now();
@@ -379,13 +484,7 @@ export class FileApprovalAskAuditStore {
379
484
  causeOf(g) {
380
485
  const after = g.settleLine ?? g.askLine ?? 0;
381
486
  const before = g.convergedLine ?? Number.POSITIVE_INFINITY;
382
- return this.legEvidence(g, this.replayedShutdownMarks, after, before) === true ? "shutdown_before_park" : "crashed_before_park";
383
- }
384
- legEvidence(g, records, afterLine, beforeLine = Number.POSITIVE_INFINITY) {
385
- const ask = g.ask;
386
- if (!ask.legTracked)
387
- return undefined;
388
- return records.some((r) => r.taskId === ask.taskId && r.line > afterLine && r.line < beforeLine);
487
+ return legEvidenceOf(g, this.replayedShutdownMarks, after, before) === true ? "shutdown_before_park" : "crashed_before_park";
389
488
  }
390
489
  projectRow(g, orphanState, convergedAtMs, cause) {
391
490
  const ask = g.ask;
@@ -401,18 +500,117 @@ export class FileApprovalAskAuditStore {
401
500
  orphanState,
402
501
  ...(orphanState === "decided" ? { originalDecision: "approve", ...(g.settle !== undefined ? { decidedAtMs: g.settle.settledAtMs } : {}) } : {}),
403
502
  convergedAtMs,
404
- resumeSafe: orphanState === "pending" && this.legEvidence(g, this.replayedLegClosed, g.askLine ?? 0) === false,
503
+ resumeSafe: orphanState === "pending" && legEvidenceOf(g, this.replayedLegClosed, g.askLine ?? 0) === false,
405
504
  };
406
505
  }
407
506
  listCrashConverged(scope) {
408
507
  const rows = [];
508
+ const owner = scope === undefined ? undefined : ownerOfCheckpointScope(scope);
409
509
  for (const e of this.convergedRows) {
410
- if (scope !== undefined && e.owner !== scope)
510
+ if (owner !== undefined && e.owner !== owner)
411
511
  continue;
412
512
  rows.push(e.row);
413
513
  }
414
514
  return rows;
415
515
  }
516
+ rotateOlderThan(cutoffMs, keepAnchors) {
517
+ let bytes;
518
+ try {
519
+ bytes = readFileSync(this.ledgerPath);
520
+ }
521
+ catch (err) {
522
+ if (err.code === "ENOENT")
523
+ return { droppedAsks: 0, droppedRecords: 0, keptRecords: 0 };
524
+ throw err;
525
+ }
526
+ const { lines, tail } = splitLedgerBytes(bytes);
527
+ const entries = lines.map((raw) => ({ raw, terminated: true, rec: recordOfLine(raw) }));
528
+ if (tail.length > 0)
529
+ entries.push({ raw: tail, terminated: false, rec: recordOfLine(tail) });
530
+ const numbered = entries.flatMap((e, i) => (e.rec !== undefined ? [{ rec: e.rec, line: i + 1 }] : []));
531
+ const fold = foldLedger(numbered);
532
+ const lastAt = new Map();
533
+ const anchorsOf = new Map();
534
+ for (const { rec } of numbered) {
535
+ const id = approvalIdOf(rec);
536
+ if (typeof id !== "string")
537
+ continue;
538
+ lastAt.set(id, Math.max(lastAt.get(id) ?? Number.NEGATIVE_INFINITY, atMsOf(rec)));
539
+ const cells = rec.kind === "ask" ? [rec.taskId, rec.sessionId, rec.sourceTaskId] : rec.kind === "late_settle" ? [rec.taskId, rec.sessionId] : [];
540
+ const list = anchorsOf.get(id) ?? [];
541
+ for (const c of cells)
542
+ if (c !== undefined)
543
+ list.push(c);
544
+ anchorsOf.set(id, list);
545
+ }
546
+ const dropped = new Set();
547
+ for (const [id, at] of lastAt) {
548
+ if (at >= cutoffMs)
549
+ continue;
550
+ if ((anchorsOf.get(id) ?? []).some((a) => keepAnchors.has(a)))
551
+ continue;
552
+ const g = fold.groups.get(id);
553
+ const verdict = g === undefined ? undefined : judgeOrphan(g, fold.legClosed);
554
+ if (verdict === "pending" || verdict === "decided")
555
+ continue;
556
+ dropped.add(id);
557
+ }
558
+ const claimedTasks = new Set();
559
+ for (const [id, g] of fold.groups)
560
+ if (!dropped.has(id) && g.ask !== undefined)
561
+ claimedTasks.add(g.ask.taskId);
562
+ const keep = (rec) => {
563
+ if (rec === undefined)
564
+ return true;
565
+ switch (rec.kind) {
566
+ case "ask":
567
+ case "settle":
568
+ case "crash_converged":
569
+ return !dropped.has(rec.approvalId);
570
+ case "late_settle":
571
+ return rec.approvalId !== null ? !dropped.has(rec.approvalId) : rec.settledAtMs >= cutoffMs;
572
+ case "leg_closed":
573
+ case "interrupted_by_shutdown":
574
+ return atMsOf(rec) >= cutoffMs || claimedTasks.has(rec.taskId) || keepAnchors.has(rec.taskId);
575
+ default: {
576
+ const unreachable = rec;
577
+ throw new Error(`approval-ask-audit rotate: unreachable record ${String(unreachable)}`);
578
+ }
579
+ }
580
+ };
581
+ const kept = entries.filter((e) => keep(e.rec));
582
+ const droppedRecords = entries.length - kept.length;
583
+ if (droppedRecords === 0)
584
+ return { droppedAsks: 0, droppedRecords: 0, keptRecords: entries.length };
585
+ this.log?.close();
586
+ this.log = undefined;
587
+ const NEWLINE = Buffer.from([0x0a]);
588
+ replaceFileBytes(this.ledgerPath, Buffer.concat(kept.flatMap((e) => (e.terminated ? [e.raw, NEWLINE] : [e.raw]))));
589
+ for (const id of dropped) {
590
+ this.replayed.delete(id);
591
+ this.askTaskId.delete(id);
592
+ this.parkExpired.delete(id);
593
+ }
594
+ for (const bucket of [this.askByCallAnchor, this.askBySessionOnly]) {
595
+ for (const [key, ids] of bucket) {
596
+ for (const id of dropped)
597
+ ids.delete(id);
598
+ if (ids.size === 0)
599
+ bucket.delete(key);
600
+ }
601
+ }
602
+ const survivors = this.convergedRows.filter((e) => !dropped.has(e.row.approvalId));
603
+ this.convergedRows.length = 0;
604
+ for (const e of survivors)
605
+ this.convergedRows.push(e);
606
+ try {
607
+ this.fsyncDir(dirname(this.ledgerPath));
608
+ }
609
+ catch (err) {
610
+ recordFailOpen("server.approval-ask-audit.rotate-dir-fsync-failed", `path=${this.ledgerPath} err=${err instanceof Error ? err.message : String(err)}`);
611
+ }
612
+ return { droppedAsks: dropped.size, droppedRecords, keptRecords: kept.length };
613
+ }
416
614
  close() {
417
615
  this.log?.close();
418
616
  this.log = undefined;
@@ -15,6 +15,21 @@ export declare const BATCH_TERMINAL: ReadonlySet<BatchState>;
15
15
  * 都在这里),放这里不引新依赖边。
16
16
  */
17
17
  export declare const MAX_DECISION_NOTE_CHARS = 2048;
18
+ /**
19
+ * 回决回执上「理由记上了吗」(`noteRecorded`)一格的**唯一判官与唯一组句器** —— 两口回决(live
20
+ * `POST /v1/tool-approvals/:id/respond` 与耐久 `POST /v1/tasks/:taskId/asks/:askId/decision`)的每一个 200
21
+ * 回体(PARKED 行经赎回腿受理的那一腿除外:它的理由走检查点回决链、不写 ask 行,尚无「记在哪张行」的定义,契约里点名为未覆盖)都经这两只函数说这件事,
22
+ * 不在各自的回体字面量里手写第二份。
23
+ *
24
+ * 三态同一份契约:请求**没带** `note` ⇒ 键缺席(不是 `false`);带了 ⇒ `true | false`:`true` = **已确认**持久行上那段文本就是这次提交的
25
+ * (逐字相等才算 —— 文本真的相同就不是谎,哪怕是别人写的);`false` = **没确认**(行上是别人的理由 / 这台没有店 / 店抖动而确认读也读不到 ——
26
+ * 不知道不许说成成功),不是「这台部署有没有店」。耐久回决口手里恒有那一行,它的 `false` 就是「行上不是这次那段」。
27
+ */
28
+ export declare function noteLandedOnRow(requestNote: string | undefined, rowNote: string | null): boolean;
29
+ /** {@link noteLandedOnRow} 的组句器:只在请求带了 `note` 时铸 `noteRecorded`(`landed` 由调用方按各自能证明的事实给)。 */
30
+ export declare function noteRecordedReceipt(requestNote: string | undefined, landed: boolean): {
31
+ noteRecorded?: boolean;
32
+ };
18
33
  /** ask 转移合法性(表驱动,含拒绝同值自环——STREAM_PENDING→STREAM_PENDING 不在表里,故 false)。 */
19
34
  export declare function canAskTransition(from: AskState, to: AskState): boolean;
20
35
  /** 批转移合法性,同形。 */
@@ -2,6 +2,12 @@ import { createHash } from "node:crypto";
2
2
  export const ASK_TERMINAL = new Set(["DECIDED", "PARKED", "DENIED", "VOID"]);
3
3
  export const BATCH_TERMINAL = new Set(["ROUTING_BOUND", "ABORTED"]);
4
4
  export const MAX_DECISION_NOTE_CHARS = 2048;
5
+ export function noteLandedOnRow(requestNote, rowNote) {
6
+ return requestNote !== undefined && rowNote === requestNote;
7
+ }
8
+ export function noteRecordedReceipt(requestNote, landed) {
9
+ return requestNote === undefined ? {} : { noteRecorded: landed };
10
+ }
5
11
  const ASK_TRANSITIONS = {
6
12
  STREAM_PENDING: ["DECIDED", "PARKING", "VOID"],
7
13
  PARKING: ["PARKED", "DENIED", "VOID"],