@sema-agent/server 7.134.0 → 7.135.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 (458) hide show
  1. package/MIGRATION.md +134 -0
  2. package/USAGE.md +98 -30
  3. package/dist/adoption/plan.d.ts +1 -1
  4. package/dist/approval-ask-audit-store.d.ts +24 -24
  5. package/dist/approval-ask-machine.d.ts +2 -2
  6. package/dist/approval-card.d.ts +62 -150
  7. package/dist/approval-card.js +33 -51
  8. package/dist/approval-content-kind.d.ts +22 -5
  9. package/dist/approval-content-kind.js +8 -1
  10. package/dist/approval-deny-reasons.d.ts +1 -1
  11. package/dist/approval-gate-currency.d.ts +22 -3
  12. package/dist/approval-gate-currency.js +44 -18
  13. package/dist/approval-hmac.d.ts +7 -7
  14. package/dist/approval-policy-settlement.d.ts +2 -2
  15. package/dist/approval-reconciler.d.ts +3 -3
  16. package/dist/approval.d.ts +8 -8
  17. package/dist/approval.js +4 -2
  18. package/dist/auth-bridge.d.ts +1 -1
  19. package/dist/auto-mode-face.d.ts +4 -4
  20. package/dist/background-session-reap.d.ts +2 -2
  21. package/dist/bake-runner/main.d.ts +2 -2
  22. package/dist/bake-runner/runner.d.ts +4 -4
  23. package/dist/bench/s1/live-deps.d.ts +1 -1
  24. package/dist/bench/s1/run-firm.d.ts +1 -1
  25. package/dist/boot/coordinators.d.ts +2 -2
  26. package/dist/boot/coordinators.js +2 -2
  27. package/dist/boot/deferred-sandbox-path-env.d.ts +0 -6
  28. package/dist/boot/deferred-sandbox-path-env.js +0 -5
  29. package/dist/boot/engine-lease.d.ts +5 -5
  30. package/dist/boot/execution-env.d.ts +16 -15
  31. package/dist/boot/execution-env.js +19 -21
  32. package/dist/boot/fatal-exit.d.ts +2 -2
  33. package/dist/boot/late-binds.d.ts +1 -1
  34. package/dist/boot/leader.d.ts +1 -1
  35. package/dist/boot/memory-boundary.d.ts +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +15 -15
  37. package/dist/boot/parked-revive-gate.d.ts +3 -3
  38. package/dist/boot/parked-revive-gate.js +3 -2
  39. package/dist/boot/reapers.d.ts +4 -4
  40. package/dist/boot/resolve-spec.d.ts +1 -1
  41. package/dist/boot/resolve-spec.js +28 -24
  42. package/dist/boot/runner-deps.d.ts +11 -11
  43. package/dist/boot/runner-deps.js +3 -2
  44. package/dist/boot/session-faces.d.ts +3 -3
  45. package/dist/boot/session-faces.js +11 -30
  46. package/dist/boot/shutdown.d.ts +5 -5
  47. package/dist/boot/side-query-lane.d.ts +2 -2
  48. package/dist/boot/stage-05-execution-env.js +4 -4
  49. package/dist/boot/stage-06-runners.js +0 -2
  50. package/dist/boot/stores.js +2 -1
  51. package/dist/boot/web-admin.d.ts +17 -17
  52. package/dist/boot/web-admin.js +5 -10
  53. package/dist/boot/workflow-orchestration.js +2 -9
  54. package/dist/brain.d.ts +11 -11
  55. package/dist/budget.d.ts +4 -4
  56. package/dist/capabilities/approvals-push.d.ts +4 -4
  57. package/dist/capabilities/builtin-tools.d.ts +5 -5
  58. package/dist/capabilities/center-plugins.d.ts +5 -5
  59. package/dist/capabilities/center-plugins.js +1 -1
  60. package/dist/capabilities/center-prompts.d.ts +1 -1
  61. package/dist/capabilities/center-wiring.d.ts +1 -1
  62. package/dist/capabilities/composite-members.d.ts +1 -1
  63. package/dist/capabilities/execution-lane.d.ts +5 -5
  64. package/dist/capabilities/execution-lane.js +2 -2
  65. package/dist/capabilities/hands-lane.d.ts +5 -5
  66. package/dist/capabilities/mcp-probe.d.ts +10 -7
  67. package/dist/capabilities/sandbox-file-send.d.ts +1 -18
  68. package/dist/capabilities/sandbox-file-send.js +0 -7
  69. package/dist/capabilities/scenarios.d.ts +28 -10
  70. package/dist/capabilities/scenarios.js +15 -5
  71. package/dist/capabilities/send-user-file-tool.d.ts +1 -1
  72. package/dist/capabilities/skills.d.ts +31 -12
  73. package/dist/capabilities/skills.js +23 -17
  74. package/dist/capabilities/tool-defer.d.ts +1 -1
  75. package/dist/capability-facts.d.ts +26 -25
  76. package/dist/capability-facts.js +14 -16
  77. package/dist/center-config-tier.d.ts +1 -1
  78. package/dist/center-credential.d.ts +4 -4
  79. package/dist/checkpoint-identity.d.ts +5 -0
  80. package/dist/checkpoint-identity.js +14 -0
  81. package/dist/config-catalog.d.ts +12 -12
  82. package/dist/config-invariants.d.ts +4 -4
  83. package/dist/config-invariants.js +3 -2
  84. package/dist/config-lkg.d.ts +1 -1
  85. package/dist/config-provider.d.ts +13 -13
  86. package/dist/config-provider.js +2 -1
  87. package/dist/config-types.d.ts +83 -83
  88. package/dist/config.d.ts +26 -24
  89. package/dist/config.js +12 -10
  90. package/dist/cross-session-settings.d.ts +1 -1
  91. package/dist/delegated-session-owner.d.ts +16 -13
  92. package/dist/delegated-session-owner.js +9 -10
  93. package/dist/deployment-governance.d.ts +16 -16
  94. package/dist/deployment-shape.d.ts +127 -0
  95. package/dist/deployment-shape.js +72 -0
  96. package/dist/device-store.d.ts +1 -1
  97. package/dist/device-ws-hub.d.ts +1 -1
  98. package/dist/egress-redirect.d.ts +1 -1
  99. package/dist/entry-mode-clamp-notice.d.ts +2 -2
  100. package/dist/env-facts.d.ts +10 -9
  101. package/dist/env-facts.js +1 -1
  102. package/dist/env-name-allowlist-knobs.d.ts +5 -5
  103. package/dist/exec-bounds.d.ts +2 -2
  104. package/dist/execution-lane-caps.d.ts +31 -43
  105. package/dist/execution-lane-caps.js +0 -13
  106. package/dist/file-history-capture.d.ts +9 -9
  107. package/dist/file-history-disclosure.d.ts +23 -11
  108. package/dist/file-history-disclosure.js +7 -12
  109. package/dist/fleet/drain-entry.d.ts +2 -2
  110. package/dist/fleet/fleet-bus.d.ts +22 -14
  111. package/dist/fleet/fleet-bus.js +5 -5
  112. package/dist/fleet/fleet-reconciler.d.ts +9 -9
  113. package/dist/fleet/subagent-tail-bus.d.ts +4 -4
  114. package/dist/fleet-client.d.ts +13 -13
  115. package/dist/fleet-lease.d.ts +16 -16
  116. package/dist/governance-http-status.d.ts +2 -2
  117. package/dist/hooks/hook-llm.d.ts +7 -7
  118. package/dist/hooks/hook-runner.d.ts +57 -30
  119. package/dist/hooks/hook-runner.js +36 -18
  120. package/dist/host-decision.d.ts +5 -5
  121. package/dist/host-lsp-manager.d.ts +5 -5
  122. package/dist/hosted-posture.d.ts +23 -13
  123. package/dist/hosted-posture.js +4 -9
  124. package/dist/http/admission.d.ts +2 -2
  125. package/dist/http/admission.js +20 -5
  126. package/dist/http/approval-sweeps.d.ts +1 -1
  127. package/dist/http/approval-sweeps.js +2 -1
  128. package/dist/http/checkpoint-ctx.d.ts +39 -13
  129. package/dist/http/checkpoint-ctx.js +74 -35
  130. package/dist/http/dispatch.d.ts +3 -3
  131. package/dist/http/durable-run-leg.js +4 -3
  132. package/dist/http/idempotency.d.ts +2 -2
  133. package/dist/http/mcp-dial-deadline.d.ts +7 -5
  134. package/dist/http/memory-compliance-failure-reply.d.ts +4 -4
  135. package/dist/http/owner-access.d.ts +4 -6
  136. package/dist/http/owner-access.js +1 -1
  137. package/dist/http/principal-gate.d.ts +7 -7
  138. package/dist/http/principal-gate.js +3 -2
  139. package/dist/http/readiness.d.ts +1 -1
  140. package/dist/http/request-guards.d.ts +4 -4
  141. package/dist/http/request-guards.js +2 -1
  142. package/dist/http/resume-ctx-read.d.ts +7 -7
  143. package/dist/http/resume-ctx-read.js +1 -1
  144. package/dist/http/resume-legs.d.ts +3 -3
  145. package/dist/http/resume-legs.js +11 -8
  146. package/dist/http/route-ctx.d.ts +29 -29
  147. package/dist/http/route-table.d.ts +9 -9
  148. package/dist/http/routes/agents-roster.d.ts +1 -1
  149. package/dist/http/routes/approvals-assistant.d.ts +5 -5
  150. package/dist/http/routes/approvals-assistant.js +55 -15
  151. package/dist/http/routes/background.d.ts +3 -3
  152. package/dist/http/routes/background.js +2 -2
  153. package/dist/http/routes/capabilities.d.ts +1 -1
  154. package/dist/http/routes/capabilities.js +16 -8
  155. package/dist/http/routes/config-catalog.d.ts +1 -1
  156. package/dist/http/routes/devices.d.ts +1 -1
  157. package/dist/http/routes/diagnostics.d.ts +3 -3
  158. package/dist/http/routes/fleet.d.ts +1 -1
  159. package/dist/http/routes/fleet.js +2 -1
  160. package/dist/http/routes/mcp-reconnect.d.ts +4 -4
  161. package/dist/http/routes/mcp-reconnect.js +3 -3
  162. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  163. package/dist/http/routes/notify-wake.d.ts +1 -1
  164. package/dist/http/routes/notify-wake.js +2 -2
  165. package/dist/http/routes/rules.d.ts +1 -1
  166. package/dist/http/routes/runs.js +22 -10
  167. package/dist/http/routes/session-sync.d.ts +1 -1
  168. package/dist/http/routes/session-sync.js +73 -44
  169. package/dist/http/routes/sessions-list.js +1 -1
  170. package/dist/http/routes/sessions.js +30 -44
  171. package/dist/http/routes/tasks.d.ts +1 -1
  172. package/dist/http/routes/trace-usage.d.ts +1 -1
  173. package/dist/http/routes/workflows.d.ts +3 -0
  174. package/dist/http/routes/workflows.js +31 -28
  175. package/dist/http/send.d.ts +5 -5
  176. package/dist/http/server.d.ts +34 -34
  177. package/dist/http/session-inherit-env.d.ts +3 -3
  178. package/dist/http/sse-lifecycle.d.ts +1 -1
  179. package/dist/http/sse-log.d.ts +2 -2
  180. package/dist/http/submit-ctx.js +1 -1
  181. package/dist/http/sync-submit-body.d.ts +1 -1
  182. package/dist/http/verify-rounds.d.ts +1 -1
  183. package/dist/http/wire-types.d.ts +28 -21
  184. package/dist/instruction-source-notice.d.ts +2 -2
  185. package/dist/key-resolver.d.ts +3 -3
  186. package/dist/lane-home-probe.d.ts +1 -1
  187. package/dist/leader/diffout.d.ts +1 -1
  188. package/dist/leader/diffup.d.ts +2 -2
  189. package/dist/leader/endpoint.d.ts +1 -1
  190. package/dist/leader/fanout.d.ts +1 -1
  191. package/dist/leader/leader.d.ts +4 -4
  192. package/dist/leader/merge.d.ts +3 -3
  193. package/dist/leader/repair-wire.d.ts +1 -1
  194. package/dist/leader/wire.d.ts +6 -6
  195. package/dist/list-entry-display.d.ts +1 -1
  196. package/dist/lsp-evict.d.ts +1 -1
  197. package/dist/mcp-assertion-header.d.ts +1 -1
  198. package/dist/memory-layer-legacy-lock.d.ts +1 -1
  199. package/dist/memory-operator-faces.d.ts +1 -1
  200. package/dist/memory-posture.js +4 -2
  201. package/dist/memory-project-layer.d.ts +1 -1
  202. package/dist/memory-scope.d.ts +19 -19
  203. package/dist/memory-store-refusal.d.ts +4 -4
  204. package/dist/model-entry-headers.d.ts +2 -2
  205. package/dist/model-entry-refusal.d.ts +17 -17
  206. package/dist/model-provider.d.ts +10 -10
  207. package/dist/model-reach-scope.d.ts +1 -1
  208. package/dist/model-route-endpoint.d.ts +6 -6
  209. package/dist/model-route-url.d.ts +5 -5
  210. package/dist/model-select.d.ts +15 -6
  211. package/dist/model-select.js +5 -0
  212. package/dist/model-unreachable-notice.d.ts +3 -3
  213. package/dist/namespaced-rule-name.d.ts +15 -5
  214. package/dist/namespaced-rule-name.js +3 -2
  215. package/dist/observability/corrupt-read-seat.d.ts +9 -9
  216. package/dist/observability/cost-taxonomy.d.ts +1 -1
  217. package/dist/observability/err-text.d.ts +1 -1
  218. package/dist/observability/fail-open.d.ts +12 -8
  219. package/dist/observability/fail-open.js +12 -8
  220. package/dist/observability/metrics.d.ts +3 -3
  221. package/dist/observability/run-terminal.d.ts +36 -36
  222. package/dist/observability/secret-env-scrub.d.ts +3 -3
  223. package/dist/observability/tool-trace.d.ts +1 -1
  224. package/dist/operator-ask.d.ts +4 -4
  225. package/dist/orchestration/workflow-agent-session-index.d.ts +3 -3
  226. package/dist/orchestration/workflow-completion-inbox.d.ts +20 -5
  227. package/dist/orchestration/workflow-completion-inbox.js +29 -7
  228. package/dist/orchestration/workflow-notify-journal.d.ts +43 -19
  229. package/dist/orchestration/workflow-notify-journal.js +17 -0
  230. package/dist/outbound-dispatcher.d.ts +4 -4
  231. package/dist/parent-watch.d.ts +4 -4
  232. package/dist/parked-decide.d.ts +16 -15
  233. package/dist/parked-decide.js +5 -4
  234. package/dist/parked-revive-surface.d.ts +7 -7
  235. package/dist/parked-revive-surface.js +2 -3
  236. package/dist/peer-directory.d.ts +3 -3
  237. package/dist/peer-directory.js +1 -1
  238. package/dist/permission-rule-list.d.ts +10 -1
  239. package/dist/permission-rule-list.js +7 -5
  240. package/dist/permission-rule-vocab.d.ts +2 -2
  241. package/dist/plugins/adoption-log-sql.d.ts +1 -1
  242. package/dist/plugins/approval-ask-store-file.d.ts +8 -1
  243. package/dist/plugins/approval-ask-store-file.js +6 -3
  244. package/dist/plugins/approval-ask-store-memory.d.ts +11 -7
  245. package/dist/plugins/approval-ask-store-memory.js +11 -7
  246. package/dist/plugins/approval-ask-store-sql.d.ts +34 -15
  247. package/dist/plugins/approval-ask-store-sql.js +18 -5
  248. package/dist/plugins/approval-exemption-store.d.ts +3 -3
  249. package/dist/plugins/approval-nonce-store.d.ts +3 -3
  250. package/dist/plugins/background-agent-store-sql.d.ts +1 -1
  251. package/dist/plugins/background-shell-support.d.ts +2 -2
  252. package/dist/plugins/blob-backend.d.ts +1 -1
  253. package/dist/plugins/caching-session-store.d.ts +23 -32
  254. package/dist/plugins/caching-session-store.js +5 -17
  255. package/dist/plugins/checkpoint-index-columns.d.ts +81 -0
  256. package/dist/plugins/checkpoint-index-columns.js +62 -0
  257. package/dist/plugins/checkpoint-store-sql.d.ts +44 -66
  258. package/dist/plugins/checkpoint-store-sql.js +55 -102
  259. package/dist/plugins/device-store-sql.d.ts +7 -6
  260. package/dist/plugins/e2b-orphan-reclaim.d.ts +1 -1
  261. package/dist/plugins/ensure-schema-lock-policy.d.ts +1 -1
  262. package/dist/plugins/file-history-store-sql.d.ts +9 -7
  263. package/dist/plugins/file-history-store-sql.js +27 -15
  264. package/dist/plugins/file-run-store.d.ts +8 -8
  265. package/dist/plugins/fork-routing-session-store.d.ts +2 -2
  266. package/dist/plugins/fork-routing-session-store.js +1 -1
  267. package/dist/plugins/host-platform.d.ts +10 -10
  268. package/dist/plugins/image-bake-store-sql.d.ts +1 -1
  269. package/dist/plugins/image-index-sql.d.ts +1 -1
  270. package/dist/plugins/leader-run-store-sql.d.ts +1 -1
  271. package/dist/plugins/local-checkpoint-store.d.ts +10 -10
  272. package/dist/plugins/local-checkpoint-store.js +3 -4
  273. package/dist/plugins/local-session-store.d.ts +34 -38
  274. package/dist/plugins/local-session-store.js +20 -39
  275. package/dist/plugins/local-session-window.d.ts +1 -1
  276. package/dist/plugins/mailbox-store-sql.d.ts +2 -2
  277. package/dist/plugins/memory-engine-pg.d.ts +1 -1
  278. package/dist/plugins/memory-run-store.d.ts +4 -4
  279. package/dist/plugins/memory-sync-store-pg.d.ts +3 -3
  280. package/dist/plugins/one-time-migrations.d.ts +66 -40
  281. package/dist/plugins/one-time-migrations.js +115 -34
  282. package/dist/plugins/outcome-ledger-sql.d.ts +1 -1
  283. package/dist/plugins/park-commit-watch.d.ts +3 -3
  284. package/dist/plugins/permission-rule-store-file.d.ts +5 -5
  285. package/dist/plugins/permission-rule-store-file.js +12 -19
  286. package/dist/plugins/permission-rule-store-sql.d.ts +38 -4
  287. package/dist/plugins/permission-rule-store-sql.js +67 -24
  288. package/dist/plugins/pg-cost-quota.d.ts +1 -1
  289. package/dist/plugins/pg-pool.d.ts +2 -2
  290. package/dist/plugins/pg-pool.js +5 -2
  291. package/dist/plugins/pg-rate-limiter.d.ts +1 -1
  292. package/dist/plugins/pg-session-storage.d.ts +8 -20
  293. package/dist/plugins/pg-session-storage.js +14 -27
  294. package/dist/plugins/remote-env-adb.d.ts +10 -10
  295. package/dist/plugins/remote-env-device.d.ts +10 -9
  296. package/dist/plugins/remote-env-device.js +6 -2
  297. package/dist/plugins/remote-env-e2b.d.ts +3 -3
  298. package/dist/plugins/remote-env-host.d.ts +16 -16
  299. package/dist/plugins/remote-env-k8s.d.ts +8 -8
  300. package/dist/plugins/remote-env-local-docker.d.ts +2 -2
  301. package/dist/plugins/remote-env-ssh.d.ts +4 -4
  302. package/dist/plugins/remote-scratchpad.d.ts +2 -3
  303. package/dist/plugins/remote-scratchpad.js +0 -4
  304. package/dist/plugins/remote-shell.d.ts +6 -6
  305. package/dist/plugins/retention-lane-store-sql.d.ts +4 -4
  306. package/dist/plugins/retention-store-sql.d.ts +4 -4
  307. package/dist/plugins/roster-store-sql.d.ts +1 -1
  308. package/dist/plugins/run-store-sql.d.ts +8 -8
  309. package/dist/plugins/schema-consistency.d.ts +2 -2
  310. package/dist/plugins/schema-ensure-legs.d.ts +3 -3
  311. package/dist/plugins/schema-indexes.d.ts +1 -1
  312. package/dist/plugins/schema-live-columns.d.ts +1 -1
  313. package/dist/plugins/session-event-payload.d.ts +4 -4
  314. package/dist/plugins/session-fork.d.ts +34 -0
  315. package/dist/plugins/session-fork.js +29 -0
  316. package/dist/plugins/session-ownership.js +1 -1
  317. package/dist/plugins/session-placement.d.ts +1 -1
  318. package/dist/plugins/session-policy-store-sql.d.ts +12 -12
  319. package/dist/plugins/session-store.d.ts +2 -2
  320. package/dist/plugins/session-store.js +2 -2
  321. package/dist/plugins/shared-memory-store-sql.d.ts +2 -2
  322. package/dist/plugins/sql-driver.d.ts +8 -8
  323. package/dist/plugins/sql-errors.d.ts +1 -1
  324. package/dist/plugins/sql-json-column.d.ts +21 -21
  325. package/dist/plugins/sql-row-helpers.d.ts +2 -2
  326. package/dist/plugins/store-backend.d.ts +17 -16
  327. package/dist/plugins/store-backend.js +3 -3
  328. package/dist/plugins/store-contracts.d.ts +21 -21
  329. package/dist/plugins/task-attachment-store.d.ts +2 -2
  330. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  331. package/dist/plugins/tidb-pool.d.ts +2 -2
  332. package/dist/plugins/tidb-pool.js +9 -2
  333. package/dist/plugins/tidb-session-store.d.ts +16 -26
  334. package/dist/plugins/tidb-session-store.js +15 -27
  335. package/dist/plugins/tool-result-store-sql.d.ts +1 -1
  336. package/dist/plugins/usage-window-store-sql.d.ts +3 -3
  337. package/dist/plugins/user-input-ledger-file.d.ts +1 -1
  338. package/dist/plugins/user-input-ledger-sql.d.ts +3 -3
  339. package/dist/plugins/web-search.d.ts +19 -5
  340. package/dist/plugins/web-search.js +19 -4
  341. package/dist/{orchestration/workflow-journal-entry.d.ts → plugins/workflow-journal-payload.d.ts} +23 -32
  342. package/dist/plugins/workflow-journal-payload.js +32 -0
  343. package/dist/plugins/workflow-journal-store-sql.d.ts +28 -14
  344. package/dist/plugins/workflow-journal-store-sql.js +34 -15
  345. package/dist/plugins/workflow-run-store-sql.d.ts +4 -4
  346. package/dist/posture-source.d.ts +11 -11
  347. package/dist/principal-jwt.d.ts +6 -6
  348. package/dist/project-identity.d.ts +3 -3
  349. package/dist/project-memory.d.ts +4 -4
  350. package/dist/read-face-posture.d.ts +7 -7
  351. package/dist/request-key-closure.d.ts +1 -1
  352. package/dist/request-key-closure.js +1 -1
  353. package/dist/request-value-closure.d.ts +15 -8
  354. package/dist/request-value-closure.js +2 -0
  355. package/dist/router/route-orchestration.d.ts +11 -16
  356. package/dist/router/route-orchestration.js +2 -12
  357. package/dist/rule-entry-list.d.ts +8 -7
  358. package/dist/rule-entry-list.js +2 -9
  359. package/dist/rules-consent.d.ts +6 -6
  360. package/dist/rules-consent.js +2 -0
  361. package/dist/run-cancel-context.d.ts +5 -5
  362. package/dist/run-local.d.ts +10 -10
  363. package/dist/runs.d.ts +13 -11
  364. package/dist/runs.js +15 -1
  365. package/dist/runtime-caps-resolver.d.ts +6 -6
  366. package/dist/runtime-governance.d.ts +9 -9
  367. package/dist/sandbox-pkg-source.d.ts +9 -31
  368. package/dist/sandbox-pkg-source.js +14 -8
  369. package/dist/sealed-key.d.ts +3 -3
  370. package/dist/security.d.ts +23 -26
  371. package/dist/security.js +12 -9
  372. package/dist/server-secret-env.d.ts +10 -10
  373. package/dist/session-children-retire.d.ts +1 -1
  374. package/dist/session-error-wire.d.ts +7 -7
  375. package/dist/session-incarnation.d.ts +52 -35
  376. package/dist/session-incarnation.js +23 -8
  377. package/dist/session-policy-wire.d.ts +27 -5
  378. package/dist/session-policy-wire.js +15 -1
  379. package/dist/session-records-skipped-notice.d.ts +1 -1
  380. package/dist/session-sync-kernel.d.ts +4 -4
  381. package/dist/session-sync.d.ts +49 -6
  382. package/dist/session-sync.js +52 -10
  383. package/dist/session-titler.d.ts +7 -6
  384. package/dist/session-titler.js +8 -13
  385. package/dist/session-watch.d.ts +3 -3
  386. package/dist/session-watch.js +4 -4
  387. package/dist/sighup-idle.d.ts +2 -2
  388. package/dist/spec-fields.d.ts +4 -4
  389. package/dist/sql-engine-posture.d.ts +3 -3
  390. package/dist/store-posture.d.ts +2 -2
  391. package/dist/stored-request-tool-axes-m19.d.ts +1 -1
  392. package/dist/task-a2a.d.ts +3 -1
  393. package/dist/task-a2a.js +34 -2
  394. package/dist/task-cwd.d.ts +7 -88
  395. package/dist/task-cwd.js +2 -15
  396. package/dist/task-mcp.d.ts +12 -8
  397. package/dist/task-mcp.js +19 -4
  398. package/dist/task-settings.d.ts +30 -18
  399. package/dist/task-settings.js +33 -3
  400. package/dist/task-workflow.d.ts +0 -24
  401. package/dist/task-workflow.js +2 -1
  402. package/dist/terminal.d.ts +5 -5
  403. package/dist/tighten-only-seats.d.ts +7 -6
  404. package/dist/tighten-only-seats.js +1 -1
  405. package/dist/tool-approval.d.ts +143 -197
  406. package/dist/tool-approval.js +13 -28
  407. package/dist/tool-rule-names.d.ts +2 -2
  408. package/dist/trace/core-keyset-guard.d.ts +12 -7
  409. package/dist/trace/engine-notice-wire.d.ts +5 -5
  410. package/dist/trace/engine-notice-wire.js +1 -0
  411. package/dist/trace/exit-seat.d.ts +31 -4
  412. package/dist/trace/exit-seat.js +41 -63
  413. package/dist/trace/ledger-events.d.ts +3 -3
  414. package/dist/trace/ledger-sink.d.ts +1 -1
  415. package/dist/trace/model-segment.d.ts +3 -3
  416. package/dist/trace/project.d.ts +47 -45
  417. package/dist/trace/project.js +33 -1
  418. package/dist/trace/redact.d.ts +44 -30
  419. package/dist/trace/redact.js +191 -89
  420. package/dist/trace/self-minted-wire.d.ts +35 -14
  421. package/dist/trace/self-minted-wire.js +8 -0
  422. package/dist/trace/sema-provenance.d.ts +1 -1
  423. package/dist/trace/task-notification-facets.d.ts +4 -4
  424. package/dist/trace/wire-projection-faces.d.ts +3 -3
  425. package/dist/trace/wire-projection-faces.js +1 -1
  426. package/dist/unattended-permission-mode.d.ts +5 -5
  427. package/dist/url-credential.d.ts +52 -0
  428. package/dist/url-credential.js +49 -0
  429. package/dist/url-refusal.d.ts +6 -2
  430. package/dist/url-refusal.js +8 -1
  431. package/dist/usage-analytics.d.ts +2 -2
  432. package/dist/user-input-ledger.d.ts +23 -23
  433. package/dist/web-admin-client/apply-effective.d.ts +5 -5
  434. package/dist/web-admin-client/apply-effective.js +2 -1
  435. package/dist/web-admin-client/apply-ledger.d.ts +2 -2
  436. package/dist/web-admin-client/center-request.d.ts +2 -2
  437. package/dist/web-admin-client/facade.d.ts +5 -5
  438. package/dist/web-admin-client/facade.js +1 -1
  439. package/dist/web-admin-client/hot-keys-registry.d.ts +2 -2
  440. package/dist/web-admin-client/http-client.d.ts +4 -4
  441. package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
  442. package/dist/web-admin-client/pull-state.d.ts +1 -1
  443. package/dist/web-admin-client/read-face.d.ts +2 -2
  444. package/dist/web-admin-client/read-warnings.d.ts +5 -5
  445. package/dist/web-admin-client/restart-signal.d.ts +6 -6
  446. package/dist/web-admin-client/skills-mcp.d.ts +28 -3
  447. package/dist/web-admin-client/skills-mcp.js +29 -1
  448. package/dist/web-admin-client/types.d.ts +16 -9
  449. package/dist/workspace-space.d.ts +5 -3
  450. package/dist/write-protection.d.ts +2 -2
  451. package/package.json +4 -3
  452. package/scripts/drain-check-local.mjs +2 -1
  453. package/scripts/drain-check.mysql.sql +4 -2
  454. package/scripts/drain-check.pg.sql +4 -2
  455. package/skills/loop.md +1 -1
  456. package/dist/http/run-declared-families.d.ts +0 -16
  457. package/dist/http/run-declared-families.js +0 -12
  458. package/dist/orchestration/workflow-journal-entry.js +0 -27
@@ -1,5 +1,5 @@
1
1
  /**
2
- * S-776 —— server 进程出网的**唯一**一只 dispatcher:回环目标恒直连,其余按 `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`
2
+ * [ref] —— server 进程出网的**唯一**一只 dispatcher:回环目标恒直连,其余按 `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`
3
3
  * 交给 undici `EnvHttpProxyAgent`。**一只 dispatcher、一处安装、零旋钮** —— 代理变量本身就是配置通道。
4
4
  *
5
5
  * ── 病(test 黑盒追出,core 直讯 09-26)────────────────────────────────────────────────────────────
@@ -29,7 +29,7 @@
29
29
  * ⇒ `HTTPS_PROXY` 设了而 `NO_PROXY` 没写 localhost 时,`127.0.0.1` 上的本机网关 / 本机中心会被送进代理 —— 代理够不到本进程的回环,
30
30
  * 那是静默全断。所以回环目标在这里**先于** `NO_PROXY` 判、恒走直连 Agent;不看拓扑、不看客户端表态、没有旋钮(旋钮 = 让运维
31
31
  * 能把本机流量送进公司代理,没有任何部署形需要它)。判据集与 sema-cli 1.0.136 `src/utils/proxy.ts:104` `isLoopbackHost`
32
- * (壳 → 本机引擎那一跳的同形修 `LoopbackDirectDispatcher`,L-587)同一集,两段一致。
32
+ * (壳 → 本机引擎那一跳的同形修 `LoopbackDirectDispatcher`,[ref])同一集,两段一致。
33
33
  * **unix socket**:undici 的 `socketPath` 是连接器(`Agent` / `Client` 构造)选项,不是逐请求选项 ⇒ 打 unix socket 的调用必然自带
34
34
  * dispatcher,**结构上**不经过全局槽 —— 本模块没有、也不需要一条 unix 臂。
35
35
  *
@@ -60,7 +60,7 @@
60
60
  * 包装层就是链上多一节、`cause` 那一节换成同形副本)。隧道建好之后的失败(目标的 TLS、
61
61
  * 目标的响应)不经这个接缝,不冠代理 —— 那是目标的事。
62
62
  *
63
- * ── http 目标:绝对 URL 形,不建隧道(S-804;test 黑盒验收 A1)──────────────────────────────────────────────────
63
+ * ── http 目标:绝对 URL 形,不建隧道([ref];test 黑盒验收 A1)──────────────────────────────────────────────────
64
64
  * 病:undici `ProxyAgent` 的 `proxyTunnel` **代码缺省是 true**(7.30.0 `lib/dispatcher/proxy-agent.js` 构造器 `const { proxyTunnel = true } = opts`;它的文档写缺省 false,
65
65
  * 两处相反,以代码为准)⇒ 修前连 **http 网关**也被对代理发 `CONNECT host:80`;只放行 `:443` CONNECT 的代理(squid 缺省)拒掉它,run 约 175 s 后失败。
66
66
  * 现在构造 `EnvHttpProxyAgent` 时显式 `proxyTunnel:false`:**http 目标 ⇒ 绝对 URL 形请求**(`GET http://host/path`,undici 的 `Http1ProxyWrapper`),**https 目标 ⇒ 照旧 CONNECT**。
@@ -86,7 +86,7 @@
86
86
  * **拒启**(与 Node 24 `NODE_USE_ENV_PROXY=1` 遇坏值的行为同向)—— 静默直连 = 运维以为出网走了代理而实际没有,那是出网策略面的
87
87
  * fail-open;拒因只回显 display-safe 值。
88
88
  *
89
- * ── 建连失败的观察(S-925,7.108.0;test [ref] ② Windows 用户 VPN 中途切换)──────────────────────────────
89
+ * ── 建连失败的观察([ref],7.108.0;test [ref] ② Windows 用户 VPN 中途切换)──────────────────────────────
90
90
  * 病:建连失败(`UND_ERR_CONNECT_TIMEOUT` 一族)只有 undici 原句,不点名起服时读进的代理、不给「环境变了要重启」的出路。
91
91
  * 观察点 = undici 的**公开诊断通道**(`undici:request:create` / `:headers` / `:error`,进程级按名订阅,npm undici 与 Node 内建那一份
92
92
  * 同名同发):不包 handler、不动 dispatch 的热路径。{@link installOutboundDispatcher} 装一次:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 引擎 **parent 监视**([ref] 建座,S-292 改判据)。
2
+ * 引擎 **parent 监视**([ref] 建座,[ref] 改判据)。
3
3
  *
4
4
  * ## 防的是什么
5
5
  *
@@ -11,7 +11,7 @@
11
11
  * 的是「壳崩过一次以后就再也起不来了」。持锁 pid 不存在时 core 已自动剪陈旧锁,缺的只有「父死、子活」
12
12
  * 这一形。所以引擎给自己装一只**自查**腿:定期问一句"生我的那个还在吗"。
13
13
  *
14
- * ## 本腿**不**做什么(S-306,硬 breaking)
14
+ * ## 本腿**不**做什么([ref],硬 breaking)
15
15
  *
16
16
  * 它**不判死、不 drain、不退进程**。父没了只说明这台引擎成了**孤儿**,而「孤儿该不该退」是**租约**
17
17
  * 的问题:还有没有人附着、有没有在飞的 turn、静默够不够久 —— 那是 `boot/engine-lease.ts` 那一条腿,
@@ -45,7 +45,7 @@
45
45
  *
46
46
  * 强身份支**先判**:它成立时这一拍连探活都不发 —— 弱判据没有资格给一个已经被过继走的进程改口
47
47
  * (僵尸父那一形里 `kill(pid,0)` 恰恰恒成功)。
48
- * 3. **单拍即判,不去抖**。[ref] 定稿是「15s 一拍、连续两拍才判定」(上界 30s),S-292 整条退役:
48
+ * 3. **单拍即判,不去抖**。[ref] 定稿是「15s 一拍、连续两拍才判定」(上界 30s),[ref] 整条退役:
49
49
  * 部署面的判据是「壳挂了以后数据根要在秒级重新可用」,而 `ESRCH` / `ppid` 都不是会抖的读数(两者
50
50
  * 都是内核的直答,不是采样值)。去抖买不到确定性,只买到 15s 的延迟和一个 30s 长的 pid-复用窗口。
51
51
  * 4. **命中一次即停探**(父不会复活),出口是 {@link ParentWatchDeps.onOrphaned} —— 装配层据此记下
@@ -88,7 +88,7 @@ export interface ParentWatchDeps {
88
88
  * 只会给一次计划内的停机添一条误导的 warn。 */
89
89
  isStopped: () => boolean;
90
90
  /**
91
- * **唯一出口**(S-306):父不在了 ⇒ 把这台引擎标成孤儿。**至多调用一次**(命中即停探)。
91
+ * **唯一出口**([ref]):父不在了 ⇒ 把这台引擎标成孤儿。**至多调用一次**(命中即停探)。
92
92
  *
93
93
  * 🔴 它**不是** drain:退不退由 `boot/engine-lease.ts` 的租约律按「无附着 ∧ 无在飞 ∧ 静默满
94
94
  * `orphanLingerMs`」判。装配层拿到 reason 之后要做的只有一件事 —— 记下孤儿态(时刻 + 缘由)。
@@ -15,13 +15,13 @@ import type { ParkedReviveSurfaceFactory } from "./parked-revive-surface.js";
15
15
  import type { RebuiltInheritedGate } from "./boot/parked-revive-gate.js";
16
16
  import { type WorkflowRunParkKey, type WorkflowAgentSessionIndex } from "./orchestration/workflow-agent-session-index.js";
17
17
  import type { WorkflowParkDecisionStore, WorkflowParkOutcome } from "./orchestration/workflow-park-decision.js";
18
- import { type SessionFaceReader } from "./session-incarnation.js";
18
+ import { type HeadRead } from "./session-incarnation.js";
19
19
  export interface ParkedAgentMatch {
20
20
  handle: string;
21
21
  row: BackgroundAgentRecord;
22
22
  }
23
23
  /**
24
- * S-185 车CM —— **park 的出身判别式**(全仓唯一的那一个)。
24
+ * [ref] 车CM —— **park 的出身判别式**(全仓唯一的那一个)。
25
25
  *
26
26
  * 一条 pending checkpoint 落到 `/decide` 时,它可能来自三种出身:①一只 parked 的**后台委派子代**
27
27
  * ([ref] 的第一条腿)、②一只 parked 的 **workflow 子代**(core 7.10.0 [ref] 开的第二条车道)、③一条
@@ -54,7 +54,7 @@ export type ParkOrigin = {
54
54
  park: WorkflowRunParkKey;
55
55
  }
56
56
  /**
57
- * **这条决定证不了属于哪一条记录**(core 7.44.0 #1319 的「没有持有者」两臂;判决属主 = 索引模块的 `routeWorkflowPark`)。
57
+ * **这条决定证不了属于哪一条记录**(core 7.44.0 [ref] 的「没有持有者」两臂;判决属主 = 索引模块的 `routeWorkflowPark`)。
58
58
  * `cause`:`unreadable` = 某一条点名这个子会话的记录 `parks[]` 读不出(条目形坏 / 这一位在场却不是列表;缺席 = 没有条目,不在此列)—— 它可能正是持有者;
59
59
  * `older_engine` = 点名它的条目没有持有者位(写于不带 `parkedBy` / `generation` 的引擎,升级那一刻还停驻着的存量记录)。
60
60
  * 两种都**响亮拒**(409 `decide.workflow_parks_unreadable`,码一个、句子按成因两句),一步都不驱动;出路按成因:`older_engine` = 去续跑 `runId` 那条 run
@@ -81,7 +81,7 @@ export type ParkOrigin = {
81
81
  /** 判别式的两个源。各自可缺席(部署没接就是没接)—— 缺席 ⇒ 那条臂不判,不是失败。 */
82
82
  export interface ParkOriginSources {
83
83
  agentStore?: BackgroundAgentStore;
84
- /** S-185:workflow 出身的**有界** join 索引(契约见 orchestration/workflow-agent-session-index.ts)。 */
84
+ /** [ref]:workflow 出身的**有界** join 索引(契约见 orchestration/workflow-agent-session-index.ts)。 */
85
85
  workflowIndex?: WorkflowAgentSessionIndex;
86
86
  /** 索引只回答「去哪条 run 找」,条目本体(含赎回键)仍以 run 记录的 `parks[]` 为准 ⇒ 两件必须成对在场。 */
87
87
  workflowRunStore?: Pick<WorkflowRunStore, "get">;
@@ -145,17 +145,18 @@ export interface ParkedDecideDeps {
145
145
  checkpointStore: Pick<CheckpointStore, "get">;
146
146
  /** 与 reaper/scenarios 同一个 registry(claim/rollback 的 CAS 与 in-memory handle 收敛在同处)。 */
147
147
  registry: Pick<TaskRegistry, "claimParkedAgent" | "rollbackParkedClaim">;
148
- /** #1110(core 7.32.0):按**行**解析赎回面 —— 驱动哪一只 Agent 工具(生产装配,与 spawn 同源:subRunner / bg opts /
148
+ /** [ref](core 7.32.0):按**行**解析赎回面 —— 驱动哪一只 Agent 工具(生产装配,与 spawn 同源:subRunner / bg opts /
149
149
  * checkpointStore 同实例,[ref] 设计稿 §4),以及与它同出一张列表的继承座 `mountsCallerTool`(一层行才有;属主与全部判据
150
150
  * 在 `parked-revive-surface.ts`)。修前是 boot 期的一只裸 Agent 工具、从不交座 ⇒ 7.32.0 起停在继承工具上的 allow 恒 422。 */
151
151
  reviveSurface: ParkedReviveSurfaceFactory;
152
152
  /**
153
- * S-790([ref] §4)—— 会话面读口(`sessionStorage.sessionFaceOf`:属主 + 化身一次读)。**必填**:本腿对根会话读两次 ——
153
+ * [ref]([ref] §4)—— 会话店按 id 读一行的唯一读口(`sessionStorage.headOf`:属主 + 化身 + 叶子一次读;活住客经 `sessionFaceOfHead`
154
+ * 投影,空化身响亮拒)。**必填**:本腿对根会话读两次 ——
154
155
  * claim 之前一次、claim 成功之后一次 —— 会话不在或两次不是同一位住客 ⇒ 回滚 claim、答既有的 `409 decide.not_parked`;赎回面只在
155
156
  * 属主相等且两次是同一位住客时交继承座。读抛 ⇒ claim 前原样上抛(没有东西要回滚),claim 后先回滚再上抛。
156
- * (#1110 那只可选的 `sessionOwnerOf` 退役:可选 ⇒ 缺席时静默不复核,正是 S-790 那个窗的形。)
157
+ * ([ref] 那只可选的 `sessionOwnerOf` 退役:可选 ⇒ 缺席时静默不复核,正是 [ref] 那个窗的形。)
157
158
  */
158
- sessionFaceOf: SessionFaceReader;
159
+ headOf: HeadRead;
159
160
  /** revive args 的 `subagent_type` 成员性判定集([ref] Q1 修正:非 roster 成员必须省略,否则
160
161
  * unknown subagent_type 拒;字面比对 general-purpose 在 roster 撞名时会错省)。缺省空集=恒省略。 */
161
162
  knownAgentTypes?: ReadonlySet<string>;
@@ -173,7 +174,7 @@ export interface ParkedDecideDeps {
173
174
  principal: string | undefined;
174
175
  }) => Promise<RebuiltInheritedGate | undefined>;
175
176
  /**
176
- * 🔴 S-877 四续 ⑪ —— 复活子代**自己的**审批席(`ToolExecuteContext.onAsk`:core 的委派工具把它转给子代,子代自己的引擎问 —— 模式写门 /
177
+ * 🔴 [ref] 四续 ⑪ —— 复活子代**自己的**审批席(`ToolExecuteContext.onAsk`:core 的委派工具把它转给子代,子代自己的引擎问 —— 模式写门 /
177
178
  * 形状层 —— 在这里答)。本腿直接调 `execute`,不经 Runner,ctx 由本腿铸;不给 ⇒ 子代自己的问落 subRunner 的 `deps.onAsk`(协调器
178
179
  * `ask()` 的无 ALS 上下文臂,没有会话身份 ⇒ 读不了会话授权 ⇒ 每条非只读命令 / 每次写都再 park,`remember:"session"` 对复活子代无效;
179
180
  * 子代活着时同一问落父的席、带身份、读得到授权 —— 同一个子代两种答案)。生产 = 协调器的窗 0 席 `boundUnattendedAsk`(与 bg run 腿给父任务
@@ -194,7 +195,7 @@ export interface ParkedDecideRequest {
194
195
  /** cp.pendingAction 原样(outcome 铸造的 persisted 回落源,与 legacy 腿 D-1 姿势逐字同形)。 */
195
196
  pendingAction: unknown;
196
197
  decision: "approve" | "deny";
197
- /** [ref] 件6③ / S-136(core 7.6.0 S6-A):**这次结算的事实**,由调用方陈述(必填,理由与 legacy 腿
198
+ /** [ref] 件6③ / [ref](core 7.6.0 S6-A):**这次结算的事实**,由调用方陈述(必填,理由与 legacy 腿
198
199
  * `resumeCheckpoint` 的同名参数逐字同源 —— 本函数分辨不出谁在叫它,漏报要是编译错而不是假出处)。
199
200
  * 🔴 宿主报**事实**(谁结束的 + 通道自报的归属),core 铸**词**:`human_allowed` / `human_refused` /
200
201
  * `park_sla_expired` 由 core 在 resume 入口铸出来,写进行的 `resolvedOutcome.gateOutcome` 与那次调用的
@@ -227,7 +228,7 @@ export interface ParkedDecideResult {
227
228
  body: Record<string, unknown>;
228
229
  }
229
230
  /**
230
- * 两条 park 车道(bg 赎回 / workflow 驱动)共用的 **`ResumeOutcome` 铸点**(S-185 车CM 单点化)。
231
+ * 两条 park 车道(bg 赎回 / workflow 驱动)共用的 **`ResumeOutcome` 铸点**([ref] 车CM 单点化)。
231
232
  *
232
233
  * 判据一字未改,只是从 bg 腿里提出来:两条腿结算的是**同一种门**(core gateMatch 的 `policy_ask`),
233
234
  * 各铸一份必然漂移,而漂的是「人到底批了什么」这条审计事实。
@@ -249,7 +250,7 @@ export interface ParkedDecideResult {
249
250
  */
250
251
  export declare function buildParkedResumeOutcome(req: ParkedDecideRequest): WorkflowParkOutcome;
251
252
  /**
252
- * S-185 车CM —— **第三条车道的计划**(纯函数;驱动本身归 resume 家族的那条腿,见下方「为什么不自建驱动」)。
253
+ * [ref] 车CM —— **第三条车道的计划**(纯函数;驱动本身归 resume 家族的那条腿,见下方「为什么不自建驱动」)。
253
254
  *
254
255
  * ## 这条车道为什么长这样(亲读 core 实现后的结论,不是从类型面推的)
255
256
  * 任务书原案是「server 直接 `startWorkflow({resumeFromRunId, parkedResume})`」。亲读安装的 core
@@ -309,14 +310,14 @@ export type WorkflowParkedDecidePlan = {
309
310
  * `readRunParks`)。续跑**不是**出路:读不出的那条记录的指针不随任何后继记录消失,续跑之后规则 ① 照旧整卡拒(条目形坏的记录引擎本来也拒续跑);
310
311
  * 出路 = 运维修好那条记录(`runId`),之后在这里决就正常。
311
312
  *
312
- * 🔴 **S-376(词域门)**:句子不提 `checkpointToken`(契约 D-1 逐字:server-INTERNAL、合规 SDK 绝不发送)与内部机件名;判据与冻结钉见
313
+ * 🔴 **[ref](词域门)**:句子不提 `checkpointToken`(契约 D-1 逐字:server-INTERNAL、合规 SDK 绝不发送)与内部机件名;判据与冻结钉见
313
314
  * `test/api-error-text-lexicon.test.ts` / `test/api-error-text-freeze.test.ts`。
314
315
  */
315
316
  export declare function denyWorkflowParksUnreadable(origin: Extract<ParkOrigin, {
316
317
  kind: "workflow_parks_unreadable";
317
318
  }>): ParkedDecideResult;
318
319
  /**
319
- * **分叉**的响亮拒(core 7.44.0 #1319:引擎准入同一条 run 的两次先后续跑,把拒交给消费方)。同一张卡上并列着两条以上同代次的
320
+ * **分叉**的响亮拒(core 7.44.0 [ref]:引擎准入同一条 run 的两次先后续跑,把拒交给消费方)。同一张卡上并列着两条以上同代次的
320
321
  * 持有记录 ⇒ 没有唯一一条可以交付;不猜、不按写序取。体带并列的 `runIds`(升序;与同族 `runId` 同为顶层键)。出路 = 续跑其中一条:
321
322
  * 它走到这张停驻时代次更高,之后在这里决就正常。卡仍 pending,什么都没投递。
322
323
  */
@@ -329,7 +330,7 @@ export declare function planWorkflowParkedDecide(origin: Extract<ParkOrigin, {
329
330
  /**
330
331
  * `/decide` parked 赎回腿([ref] 件3d server 半场;[ref]/[ref]/[ref] core 裁定形)。
331
332
  *
332
- * 调用方先经 {@link findParkOrigin} 判出 `kind:"background"` 再进来(S-185 车CM:判别只做一次);
333
+ * 调用方先经 {@link findParkOrigin} 判出 `kind:"background"` 再进来([ref] 车CM:判别只做一次);
333
334
  * 返回的结果对象 = 赎回腿已受理/已拒,调用方直接回 HTTP。
334
335
  *
335
336
  * 链:`claimParkedAgent`(access = 行镜像双轴
@@ -1,10 +1,11 @@
1
+ import { compareOccupants } from "@sema-agent/core";
1
2
  import { readClosedWordSeat } from "./approval-card.js";
2
3
  import { routeWorkflowPark } from "./orchestration/workflow-agent-session-index.js";
3
4
  import { recordFailOpen } from "./observability/fail-open.js";
4
5
  import { defaultSubagentTailBus } from "./fleet/subagent-tail-bus.js";
5
6
  import { backgroundScopesForCheckpointScope, decodeCheckpointScope, ownerOfCheckpointScope } from "./security.js";
6
7
  import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
7
- import { sameSessionOccupant } from "./session-incarnation.js";
8
+ import { sessionFaceOfHead } from "./session-incarnation.js";
8
9
  import { refusalBody, resumeRefusalFacts } from "./http/refusal-body.js";
9
10
  export async function findParkOrigin(sources, cp) {
10
11
  if (sources.agentStore !== undefined) {
@@ -247,7 +248,7 @@ export async function decideParkedAgent(deps, req, match) {
247
248
  if (root === undefined) {
248
249
  return { status: 409, body: refusalBody({ errorCode: "decide.row_unrevivable", message: "this agent's row carries no root session anchor — the revive path cannot tell which session this approval belongs to (row damaged?)", facts: { taskId: match.handle } }) };
249
250
  }
250
- const faceBefore = await deps.sessionFaceOf(root);
251
+ const faceBefore = sessionFaceOfHead(root, await deps.headOf(root));
251
252
  if (faceBefore === undefined)
252
253
  return sessionGone(match.handle);
253
254
  const inheritedGate = deps.rebuildInheritedGate ? await deps.rebuildInheritedGate(row, { principal: decodeCheckpointScope(req.scope) }) : undefined;
@@ -287,13 +288,13 @@ export async function decideParkedAgent(deps, req, match) {
287
288
  };
288
289
  let faceAfter;
289
290
  try {
290
- faceAfter = await deps.sessionFaceOf(root);
291
+ faceAfter = sessionFaceOfHead(root, await deps.headOf(root));
291
292
  }
292
293
  catch (e) {
293
294
  await rollback("session_face_unreadable");
294
295
  throw e;
295
296
  }
296
- if (!sameSessionOccupant(faceBefore, faceAfter)) {
297
+ if (compareOccupants(faceBefore, faceAfter) !== "same") {
297
298
  await rollback("session_occupant_changed");
298
299
  return sessionGone(match.handle);
299
300
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * #1110(core 7.32.0)—— `/decide` parked 赎回腿的**赎回面**:驱动哪一只 Agent 工具,以及交不交继承座
2
+ * [ref](core 7.32.0)—— `/decide` parked 赎回腿的**赎回面**:驱动哪一只 Agent 工具,以及交不交继承座
3
3
  * `ToolExecuteContext.mountsCallerTool`。
4
4
  *
5
5
  * core 7.32.0 起 Agent 子代按**身份**继承场景层工具(bundle 交给 Agent 的 `inheritedTools` ∩ 父 run 的 `spec.tools`),由宿主
@@ -11,20 +11,20 @@
11
11
  * 给那个会话的 run 组 `spec.tools` 的同一只工厂、同一个会话分区(任务清单店 `taskListStoreFor(root)` 与领队那一张是同一张;
12
12
  * 多租户的 WebFetch 过滤同样生效 ⇒ 子代同样拿不到)。座 = `(t) => tools.includes(t)`(身份判:同名副本不算)。
13
13
  * · **禁**用 boot 期单例填座:那只 bundle 没有会话,它的任务清单是一张私有表 —— 填了座,每个会话 / 租户的复活队友都会共用它。
14
- * · **根会话现在还是这张卡的那一位住客**才填座(codex r1 [high] + S-790 加严):任务清单店只按会话 id 分区,而会话 id 由调用方自选、
14
+ * · **根会话现在还是这张卡的那一位住客**才填座(codex r1 [high] + [ref] 加严):任务清单店只按会话 id 分区,而会话 id 由调用方自选、
15
15
  * 删后可被别人(或同一个人)重领 —— 根会话删了(或删了重建)之后赎回一张旧卡,按 id 重解出来的是**下一位住客**的清单。判据两条都要:
16
16
  * ① 根会话的属主与卡的权威 principal 逐字相等;② 赎回腿 claim 前 / 后两次读到的是**同一位住客**(化身逐字相等,
17
- * `session-incarnation.ts` 的 `sameSessionOccupant`)—— 只比属主比不出「同一个人删了重建」。任一条不成立 / 读数缺席 ⇒ 不交座
17
+ * core 的 `compareOccupants` 答 `same`;`unknown` 不算)—— 只比属主比不出「同一个人删了重建」。任一条不成立 / 读数缺席 ⇒ 不交座
18
18
  * (fail-closed:子代不继承,继承工具上的 allow 回 422、审批待决,deny 照结)。赎回腿自己在两次读不一致时整条拒(`409 decide.not_parked`),
19
- * 这里的第 ② 条是同一条事实在交座这一处的判据(规则只写在这里,腿只负责读两次)。根删除时把子孙的 parked 卡一并作废 = S-790 件 B
19
+ * 这里的第 ② 条是同一条事实在交座这一处的判据(规则只写在这里,腿只负责读两次)。根删除时把子孙的 parked 卡一并作废 = [ref] 件 B
20
20
  * (`boot/session-faces.ts` 的删除协调器)。
21
21
  * · 只对**一层**行填座(`rootSessionId` 在场且 = `parentSessionId`:派它的 run 就是根会话的 run,列表正是那个 run 的挂载)。更深的行
22
22
  * (孙代:派它的是一个子代,它的挂载是继承裁剪后的子集,行上读不出来)不填 —— 无座 = core 的 fail-closed 臂;
23
- * 行上带继承组成是 core #1112(7.32.x)的半场,到货再改读行。
23
+ * 行上带继承组成是 core [ref](7.32.x)的半场,到货再改读行。
24
24
  * 近似如实记:重解的列表是**部署缺省**那一份,读不回那一 run 的逐请求差异(`settings.webSearch` 后端、center overlay 场景)——
25
25
  * 座只判 bundle 实例的成员性,继承面是 `[...web, ...scaffolds]`,那两项差异不改变谁在面内。
26
26
  *
27
- * **属主来源(S-1770 / S-1808)与交座是两个独立判据**:赎回工具的停驻挂点(复活的子代再要审批时停驻,`plugins/session-store.ts`)按委派继承律定宿主行属主,
27
+ * **属主来源([ref] / [ref])与交座是两个独立判据**:赎回工具的停驻挂点(复活的子代再要审批时停驻,`plugins/session-store.ts`)按委派继承律定宿主行属主,
28
28
  * 律要的是**委派树根的见证**:根 id(行上本来就带 `rootSessionId`)+ 判断那一刻读到的根行住客(赎回腿 claim 前后两读的那一位 —— 两读不是同一位时赎回腿整条拒,
29
29
  * 走不到这里;读数缺席 ⇒ 见证不带住客,挂点那一刻根行在 ⇒ 停驻否决)。所以**每一行**都交出它({@link ScenarioContext} 的 `delegationRoot`):交座的一层行以
30
30
  * `{ sessionId: root, delegationRoot }` 重解,不交座的行(更深的行、根住客已变的一层行、读数缺席)以 `{ delegationRoot }` 重解 —— 只喂停驻挂点,不挂任何会话级设施、
@@ -33,7 +33,7 @@
33
33
  */
34
34
  import { type BackgroundAgentRecord, type ToolSpec } from "@sema-agent/core";
35
35
  import type { Scenario } from "./capabilities/scenarios.js";
36
- import { type SessionFace } from "./session-incarnation.js";
36
+ import type { SessionFace } from "./session-incarnation.js";
37
37
  /** 一次赎回用的面:驱动的 Agent 工具(它的停驻挂点绑着行上的根)+ (交座时)与它同出一张列表的继承座。 */
38
38
  export interface ParkedReviveSurface {
39
39
  readonly reviveTool: ToolSpec;
@@ -1,5 +1,4 @@
1
- import { DEFAULT_SUBAGENT_TOOL_NAME } from "@sema-agent/core";
2
- import { sameSessionOccupant } from "./session-incarnation.js";
1
+ import { DEFAULT_SUBAGENT_TOOL_NAME, compareOccupants } from "@sema-agent/core";
3
2
  const agentOf = (tools) => tools.find((t) => t.name === DEFAULT_SUBAGENT_TOOL_NAME);
4
3
  export function createParkedReviveSurface(defaultScenario) {
5
4
  const bootTool = agentOf(defaultScenario({}).tools);
@@ -20,7 +19,7 @@ export function createParkedReviveSurface(defaultScenario) {
20
19
  }
21
20
  function holdsSeat(oneLevel, identity) {
22
21
  const face = identity.root;
23
- if (!oneLevel || face === undefined || !sameSessionOccupant(face.before, face.after))
22
+ if (!oneLevel || face === undefined || compareOccupants(face.before, face.after) !== "same")
24
23
  return false;
25
24
  return (face.before.owner ?? undefined) === identity.principal && (face.after.owner ?? undefined) === identity.principal;
26
25
  }
@@ -11,7 +11,7 @@
11
11
  * ## 为什么复用那只 lister,而不是自己写一条 JOIN(设计稿 §2 给的是 SQL 形,这里收得更紧)
12
12
  *
13
13
  * 设计稿 §4-1 的承重条款是「**成员资格 = 会话读面的那一只属主可读谓词,一字不另写**」。自己写一条 JOIN
14
- * 就必须自己带一份属主谓词 —— 那正是兔子洞 S-487「属主判定单一存取器」要消灭的第 10 处手抄,而且两份
14
+ * 就必须自己带一份属主谓词 —— 那正是兔子洞 [ref]「属主判定单一存取器」要消灭的第 10 处手抄,而且两份
15
15
  * 谓词**一定**会漂(存量 `owner IS NULL` 的窄互认臂、`placement_kind IS NULL` 的 [ref] 义务、keyset 排序
16
16
  * 口径三条都要各抄一遍)。改读同一只 `listSessions` 之后,**成员资格**不再是一条需要测试盯住的断言,
17
17
  * 而是结构上的同一次调用;SQL 面因此也一个字节都不用改。
@@ -31,7 +31,7 @@
31
31
  * ⚠️ 与设计稿的第二处收紧(亲读实现推翻稿面):稿里把谓词写成 `principal-gate.ts runOwnerReadable`。
32
32
  * 亲读两只函数后不成立 —— `runOwnerReadable(p, owner, cfg)` 对 `owner === null` **无条件**放行
33
33
  * (`principal-gate.ts:136-137`,函数体第一行),而**列表面**的第三条件由 store 的
34
- * `owner = ? OR owner IS NULL` 承载,开关是 `legacyUnownedAmnestyOpen(requirePrincipal, gateOwner)`
34
+ * `owner = ? OR owner IS NULL` 承载,开关是 `legacyUnownedAmnestyOpen(deployment, gateOwner)`
35
35
  * (`security.ts:119`,它的头注逐字:
36
36
  * 「单独存在的唯一理由是**列表面**……单实体读/写点一律用三条件齐的 `legacyUnownedSessionOk`」)。
37
37
  * 拿 `runOwnerReadable` 当列表谓词会让目录比 `GET /v1/sessions` **多列出**别人的无主会话 —— 正好违反
@@ -56,7 +56,7 @@
56
56
  * 墓碑随箱亡,级联跑完之后那个 id 就是「不存在」—— 理由全文在 `plugins/mailbox-recipient-lifecycle.ts`),
57
57
  * 同句柄上**墓碑压过活行**;**`"dead"` v1 不铸**
58
58
  * (core `list-agents-tool.js` 的清单过滤:deleted 行跳过、dead 行在缺省 `includeDead` 下也跳过
59
- * —— ⚠️ S-516:这里**不写 dist 行号**,那批坐标每次提货都漂(7.23.5→7.24.2 就整段搬了家);
59
+ * —— ⚠️ [ref]:这里**不写 dist 行号**,那批坐标每次提货都漂(7.23.5→7.24.2 就整段搬了家);
60
60
  * 要复核请按符号名搜。⇒ 把闲置会话映成 dead
61
61
  * 等于把用户自己的闲置会话从 `ListAgents` 里藏掉,正是本席要解的那个面。忙闲一律走 `tempo`);
62
62
  * · `tempo` = `sessionTempoOfRunStatus(lastStatus)`(`plugins/store-contracts.ts` 的那**一张**表,
@@ -13,7 +13,7 @@ export function createPeerDirectory(ctx) {
13
13
  return {
14
14
  listPeerSessions: async (access) => {
15
15
  const scope = access.scope;
16
- const includeUnowned = legacyUnownedAmnestyOpen(requirePrincipal, scope);
16
+ const includeUnowned = legacyUnownedAmnestyOpen({ requirePrincipal }, scope);
17
17
  const rows = await lister({ owner: scope, ...(includeUnowned ? { includeUnowned: true } : {}), limit: PEER_DIRECTORY_CAP + 1 });
18
18
  const truncated = rows.length > PEER_DIRECTORY_CAP;
19
19
  if (truncated) {
@@ -8,10 +8,19 @@
8
8
  *
9
9
  * 为什么住在一只叶模块里(不留在 `task-settings.ts`):本模块只 import core 与契约包 settings-schema(纯叶),读者引它不成环。
10
10
  */
11
- import { type PathRuleBases, type PermissionRule, type ToolPolicy } from "@sema-agent/core";
11
+ import { type PathRuleBases, type PermissionRule, type PermissionRulePolicyOptions, type ToolPolicy } from "@sema-agent/core";
12
12
  /** 一张表里规则条数的上限 —— 请求腿 wire 门(`task-settings.ts` 的 deny / ask 两桶判形)读的也是这一个名字:core 的缺省帽是 256,
13
13
  * 不对齐的话第 257 条起编译当场抛,等于服务端自己收下的东西自己反悔。 */
14
14
  export declare const MAX_PERMISSION_RULES_PER_LIST = 1000;
15
+ /**
16
+ * **一张规则表的判据选项** —— 编译口({@link createRuleListPolicy})与预判口(`config.ts` 的 `uncompilableRuleGuidance`:请求 / 存体重放 422 之前的那一问)读的
17
+ * 是这同一份,于是「这条规则文本编不编得出来、编出来是什么」只有一个答案:预判拒 ⇔ 编译抛,码与句相同(`test/core755-host-rule-deny-faces.test.ts` ④)。
18
+ *
19
+ * 型只开 `caps` / `pathBases` 两位,**不含 `ruleFaces`**:规则表在请求受理时编译,那时没有一条腿的名册;引擎不带名册的那条路自己读目录面
20
+ * (`catalogRuleFaceView`,core 7.55.0 [ref] 起目录给每一行声明参数词表 ⇒ 无面参数 `unsupported.param_unknown`),目录面只在引擎里取这一处。
21
+ * 交一只名册解析器会多出一种读法:目录没有的名字成 `unsupported.tool_unknown` —— 本仓自铸的工具(`repo_read_file(path:…)`)上一条编得出、真判的规则会在受理口被拒。
22
+ */
23
+ export declare function buildRuleListJudgeOptions(pathBases: PathRuleBases | undefined): Pick<PermissionRulePolicyOptions, "caps" | "pathBases">;
15
24
  /** A name-keyed rule-list ToolPolicy: a tool named by `names` gets `behavior` (`ask` tightens to an approval gate;
16
25
  * `deny` hard-blocks); every other tool is out of scope (`defaultAction: "allow"` = this policy has no opinion about
17
26
  * anything it does not name — core 7.42.0: it states nothing and clears nothing). Composed deny-wins with the rest of
@@ -1,13 +1,15 @@
1
1
  import { createPermissionRulePolicy } from "@sema-agent/core";
2
2
  import { stripControlAndBidi } from "@sema-agent/settings-schema";
3
3
  export const MAX_PERMISSION_RULES_PER_LIST = 1_000;
4
+ export function buildRuleListJudgeOptions(pathBases) {
5
+ return {
6
+ caps: { maxRules: MAX_PERMISSION_RULES_PER_LIST },
7
+ ...(pathBases !== undefined ? { pathBases } : {}),
8
+ };
9
+ }
4
10
  export function createRuleListPolicy(names, behavior, source, pathBases) {
5
11
  try {
6
- return createPermissionRulePolicy(names.map((name) => ({ rule: name, behavior, source })), {
7
- defaultAction: "allow",
8
- caps: { maxRules: MAX_PERMISSION_RULES_PER_LIST },
9
- ...(pathBases !== undefined ? { pathBases } : {}),
10
- });
12
+ return createPermissionRulePolicy(names.map((name) => ({ rule: name, behavior, source })), { defaultAction: "allow", ...buildRuleListJudgeOptions(pathBases) });
11
13
  }
12
14
  catch (e) {
13
15
  const coreMsg = stripControlAndBidi(e instanceof Error ? e.message : String(e));
@@ -10,7 +10,7 @@ import type { RuleBehavior } from "@sema-agent/core";
10
10
  */
11
11
  export declare function isPersistedRuleTool(name: string): boolean;
12
12
  /**
13
- * S-511 —— `RuleBehavior` 每一员在**无同意仪式的直接写口**(`POST /v1/rules`)上的逐员表态。
13
+ * [ref] —— `RuleBehavior` 每一员在**无同意仪式的直接写口**(`POST /v1/rules`)上的逐员表态。
14
14
  *
15
15
  * 为什么是一张**表**而不是一句 `behavior !== "allow"`:后者对 core 加员是**静默放行** —— 将来多一个
16
16
  * 放宽方向的态,它会直接从这条收紧口写进店,而没有任何一行代码会红。`Record<RuleBehavior, boolean>`
@@ -41,7 +41,7 @@ export declare function isDirectWritableRuleBehavior(behavior: RuleBehavior): be
41
41
  * `"unknown"` = **回答这一问的那次读回没做成** —— 这个域唯一不肯说的那句话是「看不见 ⇒ 没有」,
42
42
  * 第三个词就是它的反面。
43
43
  *
44
- * 🔴 **型从 core 的包根导出接过来,本仓零抄**(core 7.26.0 S-538 ⓐ:`RemovalLiveness` 随请托上了导出面)。
44
+ * 🔴 **型从 core 的包根导出接过来,本仓零抄**(core 7.26.0 [ref] ⓐ:`RemovalLiveness` 随请托上了导出面)。
45
45
  * 上一版是 `Extract<RemoveResult, {status:"removed"}>["stillLive"]` —— 那是派生而非手抄(值不会漂),但它把
46
46
  * 一只**独立的闭集**寄生在某一个臂的形状上:core 哪天给 `removed` 臂改名、或让这只词表先在别的臂上落地,
47
47
  * 派生式就会指向一个与词表无关的东西。现在两者同名同源。
@@ -107,7 +107,7 @@ export interface AdoptionLogStore {
107
107
  /** MySQL 协议方言的建表语句(展开进 tidb-pool 的中央 `SCHEMA_STATEMENTS`,与 approval-ask 同姿势:
108
108
  * 跟着中央 ensureSchema 在 named-lock 的那条 conn 上建,不绕开 DDL 串行化)。 */
109
109
  export declare const TIDB_ADOPTION_LOG_STATEMENTS: readonly string[];
110
- /** S-287:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgAdoptionLogSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
110
+ /** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgAdoptionLogSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
111
111
  export declare const ADOPTION_LOG_INDEXES: readonly IndexSpec[];
112
112
  /** PostgreSQL 孪生(由 `ensurePgSchema` 在 advisory lock 的那条 client 上调用)。 */
113
113
  export declare function ensurePgAdoptionLogSchema(q: (text: string, params?: unknown[]) => Promise<unknown>): Promise<void>;
@@ -174,7 +174,14 @@ export declare class FileApprovalAskStore implements ApprovalAskStore {
174
174
  * 「没带编辑」的记录,而活路径那一侧是抛。编码抛 ⇒ 账本一个字节没写、内核一个字节没动(与内核自己的
175
175
  * 「先编码、编码成功才一次性提交」同一条原子性)。
176
176
  */
177
- decideAsk(askId: string, batchId: string, decision: DecideAskInput): Promise<DecideResult>;
177
+ /**
178
+ * 🔴 [ref] —— **出域的一次决议不落账本**。作用域的属主维(`owner`,判据 {@link askRowCarriesOwner})不在记录上:行此刻不带着门判过的那位属主
179
+ * ⇒ 内核上这一笔必输、零写(读钟也在判定之后,不开账本窗)⇒ 没有要重放的东西,直调内核拿它的输者答案(与留存两动词「空的一次不落」同一条先例)。
180
+ * 判定、落账、内核调用都在同一个同步前缀里,其间行不可能换属主。于是**落了账的每一条决议都在域内**,重放按行自己的属主喂属主维
181
+ * ({@link FileApprovalAskStore.replayOp})—— 记录形一个字节不变:升级前写下的账本、升级后写下的账本、降级回老版本时老读者读新账本,三者同读,
182
+ * 零迁移、零双读。
183
+ */
184
+ decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
178
185
  claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent, opts?: AskTerminalClaimOpts): Promise<AskTerminalClaimOutcome>;
179
186
  expireAsk(askId: string, batchId: string): Promise<ExpireResult>;
180
187
  bindBatch(batchId: string, askId: string, gate: BindGateInput): Promise<BindResult>;
@@ -5,6 +5,7 @@ import { replayJsonlSkipping } from "../observability/corrupt-read-seat.js";
5
5
  import { recordFailOpen } from "../observability/fail-open.js";
6
6
  import { StoreBootRefusalError } from "./store-contracts.js";
7
7
  import { InMemoryApprovalAskStore, encodeDecideUpdatedInput, encodeStoreJsonPayload } from "./approval-ask-store-memory.js";
8
+ import { askRowCarriesOwner } from "./approval-ask-store-sql.js";
8
9
  export const APPROVAL_ASK_DIR = "approval-asks";
9
10
  export const APPROVAL_ASK_JOURNAL_FILE = "asks.jsonl";
10
11
  export const ASK_JOURNAL_COMPACT_MIN_RECORDS = 2_000;
@@ -187,7 +188,7 @@ export class FileApprovalAskStore {
187
188
  case "transitionAsk":
188
189
  return this.core.transitionAsk(rec.askId, rec.from, rec.to, rec.patch);
189
190
  case "decideAsk":
190
- return this.core.decideAsk(rec.askId, rec.batchId, rec.decision);
191
+ return this.core.decideAsk(rec.askId, rec.batchId, this.core.peekAsk(rec.askId)?.owner ?? null, rec.decision);
191
192
  case "claimTerminal":
192
193
  return this.core.claimTerminal(rec.askId, rec.batchId, rec.intent, rec.cause !== undefined ? { cause: rec.cause } : undefined);
193
194
  case "claimTerminalRefuse":
@@ -220,9 +221,11 @@ export class FileApprovalAskStore {
220
221
  async transitionAsk(askId, from, to, patch) {
221
222
  return this.write({ op: "transitionAsk", askId, from, to, patch }, (c) => this.core.transitionAsk(c.askId, c.from, c.to, c.patch));
222
223
  }
223
- async decideAsk(askId, batchId, decision) {
224
+ async decideAsk(askId, batchId, owner, decision) {
224
225
  const journalled = decision.updatedInput === undefined ? decision : { ...decision, updatedInput: encodeDecideUpdatedInput(decision.updatedInput) };
225
- return this.write({ op: "decideAsk", askId, batchId, decision: journalled }, (c) => this.core.decideAsk(c.askId, c.batchId, c.decision));
226
+ if (!askRowCarriesOwner(this.core.peekAsk(askId), owner))
227
+ return this.core.decideAsk(askId, batchId, owner, journalled);
228
+ return this.write({ op: "decideAsk", askId, batchId, decision: journalled }, (c) => this.core.decideAsk(c.askId, c.batchId, owner, c.decision));
226
229
  }
227
230
  async claimTerminal(askId, batchId, intent, opts) {
228
231
  switch (intent) {
@@ -4,7 +4,7 @@
4
4
  * Node 单线程下这就是天然原子:`Promise.all` 发起的并发调用不会在方法体内部交错执行,与
5
5
  * `approval-ask-store-sql.ts` 的 CAS UPDATE 语义逐字段一致(SQL twin 对拆套件的基准就是这份实现)。
6
6
  *
7
- * 🔴 **S-384:本类同时是 `FileApprovalAskStore` 的内核**(local 车道的持久形不再是「第二份手抄」——
7
+ * 🔴 **[ref]:本类同时是 `FileApprovalAskStore` 的内核**(local 车道的持久形不再是「第二份手抄」——
8
8
  * 它把本类**原样**包起来,每次写前先把**调用本身**落 JSONL、重放时用同一只内核重放同一串调用)。
9
9
  * 为此本类多了这几件、且**只**多这几件(全是数据面,零转移判定):
10
10
  * · {@link InMemoryApprovalAskStore.constructor} 的可注入钟 `now` —— 五个动词(decideAsk / claimTerminal /
@@ -18,6 +18,8 @@
18
18
  * File 形里另写一套「哪些行还算数」的判据 —— 那才是第二份手抄。
19
19
  * · {@link InMemoryApprovalAskStore.planReapSettledAsks} / {@link InMemoryApprovalAskStore.planReapEmptyBatches} —— 两只留存动词的
20
20
  * **纯读选择**(删哪些行)。File 形据它判「这一次有没有东西可删」,空的一次不落账本;删除本身仍是接口动词,与选择共用这一只。
21
+ * · {@link InMemoryApprovalAskStore.peekAsk} —— 一行的**同步**点读(纯读,零判定)。File 形在写口的同步前缀里据它判「这次决议在不在
22
+ * 属主域内」(出域的一次不落账本)、重放时据它喂行自己的属主([ref],理由在 File 形的 `decideAsk`)。
21
23
  *
22
24
  * 行为口径与 `SqlApprovalAskStore` 逐条对齐:
23
25
  * - ensureAsk 幂等 upsert(ask_id 已在 ⇒ 返回既有行,不改写;batch 行若不存在则以 OPEN 补齐)。
@@ -35,7 +37,7 @@ import type { AskCallCoordinate, AskDecision, AskRow, AskTerminalClaimIntent, As
35
37
  * 循环引用 ⇒ `JSON.stringify` 抛(两侧同抛);顶层函数 / `undefined` ⇒ `stringify` 交出 `undefined`
36
38
  * (「编出来什么都不是」)⇒ 本函数**响亮拒**,而不是让它在库里变成 NULL、在内存里变成活函数。
37
39
  *
38
- * 🔴 为什么必须是一只**导出**函数而不是 `decideAsk` 里的内联段(S-384):`FileApprovalAskStore` 要在
40
+ * 🔴 为什么必须是一只**导出**函数而不是 `decideAsk` 里的内联段([ref]):`FileApprovalAskStore` 要在
39
41
  * **落日志之前**把这一步做掉 —— 它的日志本身就是 JSON,而 `JSON.stringify` 对顶层函数是**静默丢键**
40
42
  * 不是抛。内联在 decideAsk 里的话,File 形只能在自己那侧再写一遍同样的判定(第二份手抄),或者
41
43
  * 让「活路径抛 / 重放路径成功 DECIDE」这条真分岔活下来。
@@ -49,7 +51,7 @@ export declare function encodeStoreJsonPayload(what: string, value: unknown): un
49
51
  /** [ref] `updatedInput` 的入店编码 = 上面那只的一次具名调用(词固定在一处,两 twin 与 File 形账本共用)。 */
50
52
  export declare function encodeDecideUpdatedInput(updatedInput: unknown): unknown;
51
53
  /** {@link InMemoryApprovalAskStore.exportRows} 的产出 / {@link InMemoryApprovalAskStore.importRows} 的入参
52
- * —— **纯行**,零判定。压实(S-384 File 形)与测试的状态对拆共用。 */
54
+ * —— **纯行**,零判定。压实([ref] File 形)与测试的状态对拆共用。 */
53
55
  export interface ApprovalAskRowsSnapshot {
54
56
  asks: readonly AskRow[];
55
57
  batches: readonly BatchRow[];
@@ -57,20 +59,22 @@ export interface ApprovalAskRowsSnapshot {
57
59
  export declare class InMemoryApprovalAskStore implements ApprovalAskStore {
58
60
  private readonly asks;
59
61
  private readonly batches;
60
- /** 店钟(S-384)。缺省 = 本进程墙钟,与本类落地以来逐字同值;File 形注入一只**钉住的**钟,让
62
+ /** 店钟([ref])。缺省 = 本进程墙钟,与本类落地以来逐字同值;File 形注入一只**钉住的**钟,让
61
63
  * 「同一串调用重放出同一份状态」成立。读钟纪律见类顶注(只许在同步前缀里读)。 */
62
64
  private readonly now;
63
65
  constructor(opts?: {
64
66
  now?: () => number;
65
67
  });
66
68
  /**
67
- * S-384:整本行快照(压实用)。**深拷到行级**(与每个读口交出 `{ ...row }` 同一条纪律:交出去的行
69
+ * [ref]:整本行快照(压实用)。**深拷到行级**(与每个读口交出 `{ ...row }` 同一条纪律:交出去的行
68
70
  * 不再是店内那一份,调用方改它碰不到店)。行内的 `cardJson`/`updatedInput`/`decisionActor` 仍是引用 ——
69
71
  * 与 `getAsk`/`listByState` 逐字同宽,不在这一口上单独加深拷(那会让快照口与读口对同一份 blob 给出
70
72
  * 两种可变性)。
71
73
  */
72
74
  exportRows(): ApprovalAskRowsSnapshot;
73
- /** S-384:把快照里的行**原样**装回两张 Map(同键覆盖)。零谓词、零状态机 —— 它不是一条转移,是重放
75
+ /** [ref]:一行的**同步**点读(拷贝;纯读,零判定)—— File 形在写口的同步前缀里用它(见类顶注)。 */
76
+ peekAsk(askId: string): AskRow | null;
77
+ /** [ref]:把快照里的行**原样**装回两张 Map(同键覆盖)。零谓词、零状态机 —— 它不是一条转移,是重放
74
78
  * 的起手状态。压实产物与本口是一对:压实写出 {@link exportRows} 的行,启动时由本口装回。 */
75
79
  importRows(snapshot: {
76
80
  asks?: readonly AskRow[];
@@ -78,7 +82,7 @@ export declare class InMemoryApprovalAskStore implements ApprovalAskStore {
78
82
  }): void;
79
83
  ensureAsk(row: NewAskRow): Promise<EnsureAskResult>;
80
84
  transitionAsk(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
81
- decideAsk(askId: string, batchId: string, decision: DecideAskInput): Promise<DecideResult>;
85
+ decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
82
86
  /**
83
87
  * [ref] 原子终局 claim(接口契约见 SQL 侧 {@link ApprovalAskStore.claimTerminal})。**委托形**:CAS 走
84
88
  * 既有 verb(expire ⇒ `this.expireAsk`;cancel ⇒ `this.transitionAsk(STREAM_PENDING→VOID)`)——律 2
@@ -1,6 +1,6 @@
1
1
  import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
2
2
  import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
3
- import { askRowOnCall, assertDecideSettledBy, assertIdempotencyKeyShape, assertIntegralEpochMs, assertReapBounds, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./approval-ask-store-sql.js";
3
+ import { askRowCarriesOwner, askRowOnCall, assertDecideSettledBy, assertIdempotencyKeyShape, assertIntegralEpochMs, assertReapBounds, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth, projectDecideReading } from "./approval-ask-store-sql.js";
4
4
  function applyPatch(row, patch) {
5
5
  if (patch.decision !== undefined)
6
6
  row.decision = patch.decision;
@@ -41,6 +41,10 @@ export class InMemoryApprovalAskStore {
41
41
  exportRows() {
42
42
  return { asks: [...this.asks.values()].map((r) => ({ ...r })), batches: [...this.batches.values()].map((b) => ({ ...b })) };
43
43
  }
44
+ peekAsk(askId) {
45
+ const row = this.asks.get(askId);
46
+ return row ? { ...row } : null;
47
+ }
44
48
  importRows(snapshot) {
45
49
  for (const r of snapshot.asks ?? [])
46
50
  this.asks.set(r.askId, { ...r, settledBy: r.settledBy ?? null });
@@ -112,19 +116,18 @@ export class InMemoryApprovalAskStore {
112
116
  row.updatedAtMs = patch.updatedAtMs;
113
117
  return true;
114
118
  }
115
- async decideAsk(askId, batchId, decision) {
119
+ async decideAsk(askId, batchId, owner, decision) {
116
120
  if (decision.idempotencyKey != null)
117
121
  assertIdempotencyKeyShape(decision.idempotencyKey);
118
122
  assertDecideSettledBy(decision);
119
- const now = this.now();
123
+ const reading = (row) => projectDecideReading(row ? { ...row } : null, owner);
120
124
  const batch = this.batches.get(batchId);
121
125
  if (!batch || batch.state !== "OPEN") {
122
- const row = this.asks.get(askId);
123
- return { ok: false, reason: "batch_closed", row: row ? { ...row } : null };
126
+ return { ok: false, reason: "batch_closed", row: reading(this.asks.get(askId)) };
124
127
  }
125
128
  const ask = this.asks.get(askId);
126
- if (!ask || ask.state !== "STREAM_PENDING" || ask.batchId !== batchId) {
127
- return { ok: false, reason: "ask_not_pending", row: ask ? { ...ask } : null };
129
+ if (!ask || ask.state !== "STREAM_PENDING" || ask.batchId !== batchId || !askRowCarriesOwner(ask, owner)) {
130
+ return { ok: false, reason: "ask_not_pending", row: reading(ask) };
128
131
  }
129
132
  if (decision.idempotencyKey != null) {
130
133
  for (const [id, r] of this.asks) {
@@ -136,6 +139,7 @@ export class InMemoryApprovalAskStore {
136
139
  let encodedUpdatedInput;
137
140
  if (decision.updatedInput !== undefined)
138
141
  encodedUpdatedInput = encodeDecideUpdatedInput(decision.updatedInput);
142
+ const now = this.now();
139
143
  batch.rev += 1;
140
144
  batch.updatedAtMs = now;
141
145
  ask.state = "DECIDED";