@sema-agent/server 7.150.0 → 7.151.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 (341) hide show
  1. package/MIGRATION.md +185 -0
  2. package/USAGE.md +53 -25
  3. package/deploy/sema-up/README.md +7 -1
  4. package/deploy/sema-up/chart/Chart.yaml +1 -1
  5. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  6. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  7. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  8. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  9. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  10. package/deploy/sema-up/chart/values.yaml +8 -1
  11. package/deploy/sema-up/cluster-up.sh +1 -0
  12. package/deploy/sema-up/kube-up.sh +1 -1
  13. package/deploy/sema-up/lib/flagshape.sh +1 -1
  14. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  15. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  16. package/dist/adoption/import.js +3 -3
  17. package/dist/approval-ask-machine.d.ts +1 -1
  18. package/dist/approval-card.d.ts +2 -2
  19. package/dist/approval-gate-currency.d.ts +1 -1
  20. package/dist/auth-bridge.d.ts +20 -0
  21. package/dist/auth-bridge.js +9 -0
  22. package/dist/background-session-reap.d.ts +1 -1
  23. package/dist/bake-runner/main.d.ts +4 -2
  24. package/dist/bind-host.d.ts +2 -3
  25. package/dist/bind-host.js +2 -4
  26. package/dist/boot/budget-tracing.js +1 -1
  27. package/dist/boot/engine-lease.d.ts +5 -0
  28. package/dist/boot/engine-lease.js +1 -0
  29. package/dist/boot/execution-env.d.ts +8 -14
  30. package/dist/boot/execution-env.js +54 -17
  31. package/dist/boot/execution-lane.js +32 -5
  32. package/dist/boot/late-binds.d.ts +8 -4
  33. package/dist/boot/late-binds.js +7 -1
  34. package/dist/boot/memory-consolidation.d.ts +3 -2
  35. package/dist/boot/memory-consolidation.js +6 -6
  36. package/dist/boot/reapers.d.ts +5 -0
  37. package/dist/boot/reapers.js +12 -1
  38. package/dist/boot/resolve-spec.d.ts +3 -3
  39. package/dist/boot/resolve-spec.js +31 -22
  40. package/dist/boot/runner-deps.d.ts +9 -2
  41. package/dist/boot/runner-deps.js +3 -3
  42. package/dist/boot/session-age-out.d.ts +36 -0
  43. package/dist/boot/session-age-out.js +101 -0
  44. package/dist/boot/session-faces.d.ts +5 -14
  45. package/dist/boot/session-faces.js +9 -5
  46. package/dist/boot/stage-01-config.js +2 -0
  47. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  48. package/dist/boot/stage-05-execution-env.js +2 -2
  49. package/dist/boot/stage-06-runners.d.ts +7 -4
  50. package/dist/boot/stage-06-runners.js +15 -6
  51. package/dist/boot/stage-07-capability-layer.d.ts +7 -4
  52. package/dist/boot/stage-07-capability-layer.js +2 -1
  53. package/dist/boot/stage-08-reapers.d.ts +7 -4
  54. package/dist/boot/stage-08-reapers.js +4 -2
  55. package/dist/boot/stage-09-leader.d.ts +11 -5
  56. package/dist/boot/stage-09-leader.js +12 -3
  57. package/dist/boot/stage-10-http-server.d.ts +11 -5
  58. package/dist/boot/stage-10-http-server.js +3 -6
  59. package/dist/boot/web-admin.js +3 -1
  60. package/dist/boot/workflow-orchestration.d.ts +7 -2
  61. package/dist/boot/workflow-orchestration.js +24 -7
  62. package/dist/bounded-rotation.d.ts +29 -0
  63. package/dist/bounded-rotation.js +24 -0
  64. package/dist/capability-facts.d.ts +22 -13
  65. package/dist/capability-facts.js +28 -18
  66. package/dist/center-credential.d.ts +25 -6
  67. package/dist/center-credential.js +25 -5
  68. package/dist/config-catalog.d.ts +26 -7
  69. package/dist/config-catalog.js +14 -11
  70. package/dist/config-invariants.d.ts +2 -1
  71. package/dist/config-invariants.js +4 -4
  72. package/dist/config-types.d.ts +10 -4
  73. package/dist/config.d.ts +51 -2
  74. package/dist/config.js +35 -24
  75. package/dist/deployment-shape.d.ts +9 -1
  76. package/dist/deployment-shape.js +2 -1
  77. package/dist/device-protocol.d.ts +5 -4
  78. package/dist/device-protocol.js +1 -1
  79. package/dist/device-ws-hub.js +3 -2
  80. package/dist/device-ws-protocol.d.ts +63 -10
  81. package/dist/device-ws-protocol.js +56 -25
  82. package/dist/engine-identity.d.ts +19 -7
  83. package/dist/engine-identity.js +10 -2
  84. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  85. package/dist/execution-env-refusal.d.ts +23 -0
  86. package/dist/execution-env-refusal.js +5 -0
  87. package/dist/execution-lane-caps.d.ts +3 -1
  88. package/dist/field-conflict.d.ts +1 -1
  89. package/dist/file-history-capture.d.ts +11 -4
  90. package/dist/file-history-capture.js +9 -6
  91. package/dist/file-history-disclosure.d.ts +7 -5
  92. package/dist/file-history-disclosure.js +7 -5
  93. package/dist/fleet/drain-entry.d.ts +4 -0
  94. package/dist/hooks/hook-runner.js +2 -2
  95. package/dist/host-lsp-manager.d.ts +2 -2
  96. package/dist/http/admission.js +17 -2
  97. package/dist/http/approval-sweeps.js +5 -5
  98. package/dist/http/checkpoint-ctx.d.ts +2 -0
  99. package/dist/http/checkpoint-ctx.js +1 -0
  100. package/dist/http/dispatch.d.ts +2 -1
  101. package/dist/http/dispatch.js +34 -27
  102. package/dist/http/durable-run-leg.js +16 -16
  103. package/dist/http/health-self-report.d.ts +9 -1
  104. package/dist/http/health-self-report.js +2 -0
  105. package/dist/http/owner-access.d.ts +31 -11
  106. package/dist/http/owner-access.js +37 -6
  107. package/dist/http/resume-ctx-read.js +25 -3
  108. package/dist/http/resume-legs.d.ts +2 -1
  109. package/dist/http/resume-legs.js +259 -79
  110. package/dist/http/route-ctx.d.ts +18 -8
  111. package/dist/http/route-table.d.ts +1 -1
  112. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  113. package/dist/http/routes/agents-roster.js +2 -3
  114. package/dist/http/routes/approvals-assistant.js +4 -3
  115. package/dist/http/routes/background.d.ts +3 -3
  116. package/dist/http/routes/capabilities.js +8 -5
  117. package/dist/http/routes/fleet.js +10 -8
  118. package/dist/http/routes/projects.d.ts +3 -2
  119. package/dist/http/routes/projects.js +4 -5
  120. package/dist/http/routes/runs.js +102 -36
  121. package/dist/http/routes/session-sync.d.ts +4 -3
  122. package/dist/http/routes/session-sync.js +172 -77
  123. package/dist/http/routes/sessions-list.js +13 -7
  124. package/dist/http/routes/sessions.js +10 -6
  125. package/dist/http/routes/tasks.js +30 -16
  126. package/dist/http/routes/trace-usage.js +2 -2
  127. package/dist/http/server.d.ts +21 -27
  128. package/dist/http/server.js +2 -2
  129. package/dist/http/submit-ctx.js +5 -4
  130. package/dist/http/wire-types.d.ts +14 -4
  131. package/dist/identity-source.d.ts +20 -3
  132. package/dist/identity-source.js +14 -0
  133. package/dist/index.d.ts +4 -0
  134. package/dist/lane-home-probe.d.ts +3 -7
  135. package/dist/lane-home-probe.js +0 -1
  136. package/dist/leader/leader.d.ts +2 -1
  137. package/dist/leg-facts.d.ts +13 -5
  138. package/dist/leg-facts.js +2 -1
  139. package/dist/memory-scope.d.ts +5 -4
  140. package/dist/memory-scope.js +4 -4
  141. package/dist/memory-sync-client.d.ts +30 -2
  142. package/dist/memory-sync-client.js +16 -9
  143. package/dist/observability/err-text.d.ts +7 -0
  144. package/dist/observability/err-text.js +5 -0
  145. package/dist/observability/fail-open.d.ts +7 -3
  146. package/dist/observability/fail-open.js +7 -3
  147. package/dist/observability/metrics.js +1 -0
  148. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  149. package/dist/orchestration/workflow-notify-journal.js +12 -1
  150. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  151. package/dist/orchestration/workflow-park-decision.js +49 -10
  152. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  153. package/dist/orchestration/workflow-park-holder.js +98 -0
  154. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  155. package/dist/orchestration/workflow-record-fence.js +42 -0
  156. package/dist/owner-faces.d.ts +1 -1
  157. package/dist/parked-decide.d.ts +104 -53
  158. package/dist/parked-decide.js +153 -117
  159. package/dist/peer-directory.d.ts +2 -2
  160. package/dist/peer-inbound-face.d.ts +2 -6
  161. package/dist/peer-inbound-face.js +0 -3
  162. package/dist/permission-mode-admission.d.ts +41 -5
  163. package/dist/permission-mode-admission.js +29 -3
  164. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  165. package/dist/plugins/adoption-log-sql.js +7 -1
  166. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  167. package/dist/plugins/approval-ask-store-file.js +8 -0
  168. package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
  169. package/dist/plugins/approval-ask-store-memory.js +28 -9
  170. package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
  171. package/dist/plugins/approval-ask-store-sql.js +34 -5
  172. package/dist/plugins/approval-exemption-store.js +3 -0
  173. package/dist/plugins/approval-nonce-store.js +2 -0
  174. package/dist/plugins/breaker-state-sql.js +2 -0
  175. package/dist/plugins/caching-session-store.d.ts +9 -15
  176. package/dist/plugins/caching-session-store.js +6 -0
  177. package/dist/plugins/device-store-sql.js +6 -0
  178. package/dist/plugins/error-origin.d.ts +18 -0
  179. package/dist/plugins/error-origin.js +10 -0
  180. package/dist/plugins/execution-placement-sql.js +6 -6
  181. package/dist/plugins/image-bake-store-sql.js +6 -0
  182. package/dist/plugins/image-index-sql.js +4 -0
  183. package/dist/plugins/landed-attendants.d.ts +212 -0
  184. package/dist/plugins/landed-attendants.js +161 -0
  185. package/dist/plugins/leader-run-store-sql.js +4 -0
  186. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  187. package/dist/plugins/local-session-live-reference.js +39 -0
  188. package/dist/plugins/local-session-store.d.ts +71 -33
  189. package/dist/plugins/local-session-store.js +129 -27
  190. package/dist/plugins/memory-engine-pg.js +4 -0
  191. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  192. package/dist/plugins/memory-engine-tidb.js +4 -0
  193. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  194. package/dist/plugins/memory-sync-store-pg.js +5 -0
  195. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  196. package/dist/plugins/one-time-migrations.d.ts +57 -63
  197. package/dist/plugins/one-time-migrations.js +162 -90
  198. package/dist/plugins/org-delivery-quota-store.js +4 -1
  199. package/dist/plugins/outcome-ledger-sql.js +2 -0
  200. package/dist/plugins/permission-rule-store-sql.js +11 -4
  201. package/dist/plugins/pg-cost-quota.js +4 -0
  202. package/dist/plugins/pg-pool.js +24 -1
  203. package/dist/plugins/pg-rate-limiter.js +2 -0
  204. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  205. package/dist/plugins/posix-shell-fs.js +4 -1
  206. package/dist/plugins/remote-env-adb.d.ts +19 -15
  207. package/dist/plugins/remote-env-adb.js +41 -15
  208. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  209. package/dist/plugins/remote-env-connect-seat.js +72 -0
  210. package/dist/plugins/remote-env-device.d.ts +22 -5
  211. package/dist/plugins/remote-env-device.js +106 -8
  212. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  213. package/dist/plugins/remote-env-e2b.js +42 -32
  214. package/dist/plugins/remote-env-file-error.js +6 -2
  215. package/dist/plugins/remote-env-host.d.ts +17 -0
  216. package/dist/plugins/remote-env-host.js +30 -38
  217. package/dist/plugins/remote-env-k8s.d.ts +41 -39
  218. package/dist/plugins/remote-env-k8s.js +53 -30
  219. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  220. package/dist/plugins/remote-env-local-docker.js +34 -41
  221. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  222. package/dist/plugins/remote-env-ssh.js +60 -59
  223. package/dist/plugins/remote-shell.d.ts +98 -1
  224. package/dist/plugins/remote-shell.js +218 -0
  225. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  226. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  227. package/dist/plugins/retention-lane-store-sql.js +4 -0
  228. package/dist/plugins/retention-sql.d.ts +20 -2
  229. package/dist/plugins/retention-sql.js +11 -0
  230. package/dist/plugins/run-store-sql.d.ts +21 -2
  231. package/dist/plugins/run-store-sql.js +31 -7
  232. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  233. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  234. package/dist/plugins/schema-consistency.d.ts +4 -2
  235. package/dist/plugins/schema-consistency.js +19 -2
  236. package/dist/plugins/send-file-ledger.js +3 -0
  237. package/dist/plugins/serving-requirement.d.ts +26 -7
  238. package/dist/plugins/serving-requirement.js +11 -4
  239. package/dist/plugins/session-birth.d.ts +6 -2
  240. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  241. package/dist/plugins/session-ext-table.d.ts +14 -1
  242. package/dist/plugins/session-ext-table.js +5 -1
  243. package/dist/plugins/session-row-sql.d.ts +49 -2
  244. package/dist/plugins/session-row-sql.js +56 -13
  245. package/dist/plugins/session-store-sql.d.ts +34 -18
  246. package/dist/plugins/session-store-sql.js +98 -17
  247. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  248. package/dist/plugins/shared-memory-store-sql.js +6 -2
  249. package/dist/plugins/sql-driver.d.ts +2 -1
  250. package/dist/plugins/sql-driver.js +18 -3
  251. package/dist/plugins/sql-errors.d.ts +11 -6
  252. package/dist/plugins/sql-errors.js +5 -6
  253. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  254. package/dist/plugins/stop-then-start-sentence.js +14 -10
  255. package/dist/plugins/stop-then-start.d.ts +109 -0
  256. package/dist/plugins/stop-then-start.js +104 -0
  257. package/dist/plugins/store-backend.d.ts +40 -13
  258. package/dist/plugins/store-backend.js +169 -27
  259. package/dist/plugins/store-boundary.d.ts +57 -0
  260. package/dist/plugins/store-boundary.js +139 -0
  261. package/dist/plugins/store-contracts.d.ts +17 -0
  262. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  263. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  264. package/dist/plugins/store-fault.d.ts +26 -7
  265. package/dist/plugins/store-fault.js +18 -2
  266. package/dist/plugins/task-attachment-store.js +9 -0
  267. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  268. package/dist/plugins/task-list-store-sql.js +10 -8
  269. package/dist/plugins/tidb-cost-quota.js +4 -0
  270. package/dist/plugins/tidb-pool.js +2 -1
  271. package/dist/plugins/tidb-rate-limiter.js +4 -0
  272. package/dist/plugins/user-input-ledger-sql.js +4 -0
  273. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  274. package/dist/plugins/workflow-run-store-sql.js +64 -4
  275. package/dist/plugins/workspace-fill.d.ts +4 -7
  276. package/dist/plugins/workspace-fill.js +2 -1
  277. package/dist/plugins/write-behind-counter.js +5 -0
  278. package/dist/project-context.d.ts +0 -2
  279. package/dist/project-context.js +4 -8
  280. package/dist/project-registry.d.ts +46 -0
  281. package/dist/project-registry.js +44 -0
  282. package/dist/request-key-closure.js +1 -1
  283. package/dist/request-value-closure.d.ts +4 -0
  284. package/dist/request-value-closure.js +10 -0
  285. package/dist/run-acceptance.d.ts +3 -2
  286. package/dist/run-acceptance.js +4 -6
  287. package/dist/run-local.js +1 -0
  288. package/dist/runs.d.ts +37 -8
  289. package/dist/runs.js +53 -12
  290. package/dist/runtime-governance.d.ts +5 -4
  291. package/dist/security.d.ts +30 -32
  292. package/dist/security.js +41 -7
  293. package/dist/server-secret-env.d.ts +12 -10
  294. package/dist/server-secret-env.js +24 -15
  295. package/dist/session-bindings.d.ts +82 -0
  296. package/dist/session-bindings.js +18 -0
  297. package/dist/session-children-retire.d.ts +2 -2
  298. package/dist/session-children-retire.js +2 -6
  299. package/dist/session-deletion.d.ts +16 -1
  300. package/dist/session-error-wire.d.ts +3 -3
  301. package/dist/session-error-wire.js +3 -3
  302. package/dist/session-incarnation.d.ts +10 -0
  303. package/dist/session-incarnation.js +10 -1
  304. package/dist/session-kind.d.ts +57 -0
  305. package/dist/session-kind.js +22 -0
  306. package/dist/session-row.d.ts +21 -1
  307. package/dist/session-row.js +7 -1
  308. package/dist/session-sync-kernel.d.ts +24 -14
  309. package/dist/session-sync-kernel.js +3 -6
  310. package/dist/session-sync.d.ts +4 -98
  311. package/dist/session-sync.js +1 -71
  312. package/dist/session-titler.d.ts +10 -3
  313. package/dist/session-titler.js +19 -6
  314. package/dist/ssh-host-key.d.ts +5 -0
  315. package/dist/ssh-host-key.js +3 -0
  316. package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
  317. package/dist/stores-sql/file-history-store-sql.js +108 -70
  318. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  319. package/dist/stores-sql/pg-session-storage.js +37 -13
  320. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  321. package/dist/stores-sql/retention-store-sql.js +2 -10
  322. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  323. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  324. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  325. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  326. package/dist/stores-sql/tidb-session-store.js +37 -13
  327. package/dist/submission-exit.d.ts +3 -2
  328. package/dist/submission-exit.js +9 -1
  329. package/dist/task-cwd.d.ts +2 -2
  330. package/dist/task-settings.d.ts +6 -5
  331. package/dist/terminal.d.ts +33 -2
  332. package/dist/terminal.js +139 -9
  333. package/dist/tool-approval.d.ts +140 -6
  334. package/dist/tool-approval.js +165 -72
  335. package/dist/trace/self-minted-wire.d.ts +290 -27
  336. package/dist/trace/self-minted-wire.js +101 -13
  337. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +78 -27
  338. package/package.json +2 -2
  339. package/wire-changes/server@7.151.0.json +762 -0
  340. package/dist/http/session-inherit-env.d.ts +0 -36
  341. package/dist/http/session-inherit-env.js +0 -6
@@ -31,7 +31,7 @@
31
31
  */
32
32
  import { type AskState, type BatchState } from "../approval-ask-machine.js";
33
33
  import type { ExecutionLane } from "../execution-lane-caps.js";
34
- import type { AskCallCoordinate, AskDecision, AskRow, AskTerminalClaimIntent, AskTerminalClaimOpts, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, EnsureAskResult, DecideResult, ExpireResult, NewAskRow } from "./approval-ask-store-sql.js";
34
+ import type { AskCallCoordinate, AskDecision, AskDecisionRecord, AskRow, AskTerminalClaimIntent, AskTerminalClaimOpts, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, EnsureAskResult, DecideResult, ExpireResult, NewAskRow, RecordParkedDecisionResult } from "./approval-ask-store-sql.js";
35
35
  /**
36
36
  * [ref] 的 `updatedInput` **入店编码**——两 twin 共用的那一只(本函数是唯一真源)。
37
37
  *
@@ -99,6 +99,11 @@ export declare class InMemoryApprovalAskStore implements ApprovalAskStore {
99
99
  ensureAsk(row: NewAskRow): Promise<EnsureAskResult>;
100
100
  transitionAsk(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
101
101
  decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
102
+ /**
103
+ * 停驻形的人决落行(接口契约见 SQL 侧 {@link ApprovalAskStore.recordParkedDecision})。判定序照 SQL twin:行在 ∧ `PARKED` ∧ 属主维(UPDATE 谓词)→ 才轮到撞键
104
+ * (UNIQUE `(task_id, idempotency_key)` 的内存镜像,与 `decideAsk` 同一段;本行自己占着同一把键不算撞)。态不变。
105
+ */
106
+ recordParkedDecision(askId: string, owner: string | null, record: AskDecisionRecord): Promise<RecordParkedDecisionResult>;
102
107
  /**
103
108
  * [ref] 原子终局 claim(接口契约见 SQL 侧 {@link ApprovalAskStore.claimTerminal})。**委托形**:CAS 走
104
109
  * 既有 verb(expire ⇒ `this.expireAsk`;cancel ⇒ `this.transitionAsk(STREAM_PENDING→VOID)`)——律 2
@@ -1,6 +1,17 @@
1
1
  import { ASK_TERMINAL, canAskTransition } from "../approval-ask-machine.js";
2
2
  import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
3
3
  import { askAttachedToSession, askRowCarriesOwner, askRowOnCall, assertDecideSource, assertIdempotencyKeyShape, assertIntegralEpochMs, assertReapBounds, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth, projectDecideReading } from "./approval-ask-store-sql.js";
4
+ function applyDecisionRecord(row, record, now) {
5
+ row.decision = record.decision;
6
+ row.decisionActor = record.decisionActor ?? null;
7
+ row.decisionNote = record.decisionNote ?? null;
8
+ row.settledBy = record.settledBy ?? null;
9
+ row.decidedVia = record.decidedVia ?? null;
10
+ row.decidedAtMs = now;
11
+ row.idempotencyKey = record.idempotencyKey ?? null;
12
+ row.rev += 1;
13
+ row.updatedAtMs = now;
14
+ }
4
15
  function applyPatch(row, patch) {
5
16
  if (patch.decision !== undefined)
6
17
  row.decision = patch.decision;
@@ -181,19 +192,27 @@ export class InMemoryApprovalAskStore {
181
192
  batch.rev += 1;
182
193
  batch.updatedAtMs = now;
183
194
  ask.state = "DECIDED";
184
- ask.decision = decision.decision;
185
- ask.decisionActor = decision.decisionActor ?? null;
186
- ask.decisionNote = decision.decisionNote ?? null;
187
- ask.settledBy = decision.settledBy ?? null;
188
- ask.decidedVia = decision.decidedVia ?? null;
195
+ applyDecisionRecord(ask, decision, now);
189
196
  if (decision.updatedInput === undefined)
190
197
  delete ask.updatedInput;
191
198
  else
192
199
  ask.updatedInput = encodedUpdatedInput;
193
- ask.decidedAtMs = now;
194
- ask.idempotencyKey = decision.idempotencyKey ?? null;
195
- ask.rev += 1;
196
- ask.updatedAtMs = now;
200
+ return { ok: true, row: { ...ask } };
201
+ }
202
+ async recordParkedDecision(askId, owner, record) {
203
+ if (record.idempotencyKey != null)
204
+ assertIdempotencyKeyShape(record.idempotencyKey);
205
+ assertDecideSource(record);
206
+ const ask = this.asks.get(askId);
207
+ if (!ask || ask.state !== "PARKED" || !askRowCarriesOwner(ask, owner))
208
+ return { ok: false, reason: "ask_not_parked", row: projectDecideReading(ask ? { ...ask } : null, owner) };
209
+ if (record.idempotencyKey != null) {
210
+ for (const [id, r] of this.asks) {
211
+ if (id !== askId && r.taskId === ask.taskId && r.idempotencyKey === record.idempotencyKey)
212
+ return { ok: false, reason: "idempotency_conflict", row: { ...ask } };
213
+ }
214
+ }
215
+ applyDecisionRecord(ask, record, this.now());
197
216
  return { ok: true, row: { ...ask } };
198
217
  }
199
218
  async claimTerminal(askId, batchId, intent, opts) {
@@ -249,11 +249,17 @@ export interface AskTransitionPatch {
249
249
  provisional?: boolean;
250
250
  updatedAtMs: number;
251
251
  }
252
- export interface DecideAskInput {
252
+ /**
253
+ * 一次人对一张卡的决定**落行的那一份记录** —— live 与停驻两形同一份、同一张列、同一只映射(SQL twin {@link SqlApprovalAskStore} 的 `decisionRecordValues`、
254
+ * 内存 twin 的 `applyDecisionRecord`):决议向 · 署名 · 理由 · 回决幂等键 · 出处两格(+ 决定时刻,店铸)。
255
+ * live 形随 `STREAM_PENDING → DECIDED` 那一笔单赢者 CAS 落({@link ApprovalAskStore.decideAsk});停驻形在停驻门受理之后落在仍 `PARKED` 的行上
256
+ * ({@link ApprovalAskStore.recordParkedDecision})。两形唯一的写者 = 协调器的回决写者(`ToolApprovalCoordinator.writeAskDecision`)。
257
+ */
258
+ export interface AskDecisionRecord {
253
259
  decision: AskDecision;
254
260
  decisionActor?: unknown;
255
261
  decisionNote?: string | null;
256
- /** 车4 §12-E:回决幂等键,赢 CAS 时随决议一起落列(见 `AskRow.idempotencyKey`)。缺席 ⇒ 列保持 NULL。 */
262
+ /** 车4 §12-E:回决幂等键,随决议一起落列(见 `AskRow.idempotencyKey`)。缺席 ⇒ 列 NULL。 */
257
263
  idempotencyKey?: string | null;
258
264
  /**
259
265
  * 🔴 [ref]:本次回决的**结算来源**,与决议同一条 UPDATE 落列 `settled_by`(语义/两态读法/为什么是
@@ -265,6 +271,9 @@ export interface DecideAskInput {
265
271
  settledBy?: HostSettledBy;
266
272
  /** core 7.61.0([ref]):`settledBy:"policy"` 旁的机器座位,与决议同一条 UPDATE 落列 `decided_via`(语义见 {@link AskRow.decidedVia});缺席 ⇒ 列 NULL。 */
267
273
  decidedVia?: DecidedVia;
274
+ }
275
+ /** live 形的决定 = 那份记录 + 随决议交给在等那条腿的编辑实参(停驻形的编辑走停驻门的绑定,不落问行)。 */
276
+ export interface DecideAskInput extends AskDecisionRecord {
268
277
  /** [ref]:ctrl+g 编辑实参,与决议同一条 UPDATE 落列(语义三态见 {@link AskRow.updatedInput})。
269
278
  * 缺席 / `undefined` ⇒ 列 NULL(没带编辑);**`null` 是值**(编辑成 null),照存 JSON `"null"`。
270
279
  * 调用方纪律:deny 不传(店不替调用方判决议方向,写什么存什么)。 */
@@ -285,6 +294,18 @@ export type DecideResult = {
285
294
  reason: "batch_closed" | "ask_not_pending" | "idempotency_conflict";
286
295
  row: AskRow | null;
287
296
  };
297
+ /**
298
+ * {@link ApprovalAskStore.recordParkedDecision} 的结局:`ok` ⇒ 落后的行;`ask_not_parked` ⇒ 行不在 / 不在 `PARKED` / 已出了门判过的属主域;
299
+ * `idempotency_conflict` ⇒ 这把键已被同 task 另一只问占着(UNIQUE `(task_id, idempotency_key)`)。`row` 与 {@link DecideResult} 同一只属主维投影。
300
+ */
301
+ export type RecordParkedDecisionResult = {
302
+ ok: true;
303
+ row: AskRow;
304
+ } | {
305
+ ok: false;
306
+ reason: "ask_not_parked" | "idempotency_conflict";
307
+ row: AskRow | null;
308
+ };
288
309
  /**
289
310
  * 幂等键的入店卫生门(属主兜底轮 F2,三 twin 同判——SQL 双方言与 InMemory 都从这里过)。
290
311
  *
@@ -513,6 +534,15 @@ export interface ApprovalAskStore {
513
534
  * 缺省等于不绑属主,安全轴上那是静默放行。
514
535
  */
515
536
  decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
537
+ /**
538
+ * **停驻形的人决落行**(一张卡一条记录:停驻卡的决定记在它的问行上,行仍 `PARKED`)—— 停驻门(checkpoint 上的那道门,单赢者是续跑腿的门 CAS)
539
+ * **已经受理**这次决定之后,把它的记录({@link AskDecisionRecord})落到这只问的行上。态不变:停驻形的终局恒是那道门,不是这一笔。
540
+ * 谓词 = 行在 ∧ `state = 'PARKED'` ∧ 门判过的那位属主还在行上([ref],与 {@link decideAsk} 同一只属主维)。
541
+ * **覆写**:门被引擎重开(同一把 token 翻回待决、世代号前进)之后又被受理的那一次再落一次 —— 记录恒是「门上此刻站着的那次决定」的那一份
542
+ * (决议向、谁、带哪把键);读者只在门已决时认它(`ToolApprovalCoordinator` 的停驻形读法)。
543
+ * 唯一调用方 = 协调器的回决写者,只在赎回席 2xx 之后调。三 twin 同答。
544
+ */
545
+ recordParkedDecision(askId: string, owner: string | null, record: AskDecisionRecord): Promise<RecordParkedDecisionResult>;
516
546
  /**
517
547
  * [ref]:原子终局 claim —— 把「争终局」与「读真相」并成**一次**店往返(胜负判定与败方 `current` 读数
518
548
  * 在同一原子单元内,语义见 {@link AskTerminalClaimOutcome})。[ref]-R1 的病根「CAS 与读真相是两次店
@@ -751,6 +781,17 @@ export declare class SqlApprovalAskStore implements ApprovalAskStore {
751
781
  ensureAsk(row: NewAskRow): Promise<EnsureAskResult>;
752
782
  transitionAsk(askId: string, from: AskState, to: AskState, patch: AskTransitionPatch): Promise<boolean>;
753
783
  decideAsk(askId: string, batchId: string, owner: string | null, decision: DecideAskInput): Promise<DecideResult>;
784
+ /**
785
+ * 一份决定记录({@link AskDecisionRecord})的前五格列值,序 = `decision, decision_actor, decision_note, settled_by, decided_via` ——
786
+ * live 形({@link decideAsk})与停驻形({@link recordParkedDecision})两条 UPDATE 共用这**一只**映射(一个事实一处铸列值)。
787
+ */
788
+ private decisionRecordValues;
789
+ /**
790
+ * 停驻形的人决落行(接口契约见 {@link ApprovalAskStore.recordParkedDecision})。单条 UPDATE,谓词 `state='PARKED'` + 属主维([ref] 的同一只方言镜像);
791
+ * `rev = rev + 1` 照 CAS 铁则②(MySQL 同值 UPDATE 的 affectedRows=0 坑:覆写同一份记录时列值可以逐字节相同)。
792
+ * `(task_id, idempotency_key)` 撞键 ⇒ typed 臂 `idempotency_conflict`(方言错误不出店,与 `decideAsk` 同一只判别)。
793
+ */
794
+ recordParkedDecision(askId: string, owner: string | null, record: AskDecisionRecord): Promise<RecordParkedDecisionResult>;
754
795
  /**
755
796
  * [ref] 原子终局 claim(接口契约见 {@link ApprovalAskStore.claimTerminal};类型语义见
756
797
  * {@link AskTerminalClaimOutcome})。expire 意图 = 既有 `expireAsk` 事务**原体**(步⓪-③ 逐字保留,
@@ -9,6 +9,7 @@ import { decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn,
9
9
  import { ensureIndexes } from "./ensure-index.js";
10
10
  import { isExecutionLane } from "../execution-lane-caps.js";
11
11
  import { retiredExecutionLaneHintM40 } from "./execution-lane-rename-m40.js";
12
+ import { sealStoreClass } from "./store-boundary.js";
12
13
  export function assertIntegralEpochMs(field, value) {
13
14
  if (!Number.isSafeInteger(value)) {
14
15
  throw new TypeError(`approval-ask store: ${field} must be an integer epoch-ms (BIGINT column), got ${String(value)}`);
@@ -565,11 +566,7 @@ export class SqlApprovalAskStore {
565
566
  let askRes;
566
567
  try {
567
568
  askRes = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='DECIDED', decision=${ph(dialect, 1)}, decision_actor=${ph(dialect, 2)}, decision_note=${ph(dialect, 3)}, settled_by=${ph(dialect, 4)}, decided_via=${ph(dialect, 5)}, updated_input=${ph(dialect, 6)}, decided_at_ms=${ph(dialect, 7)}, idempotency_key=${ph(dialect, 8)}, rev=rev+1, updated_at_ms=${ph(dialect, 9)} WHERE ${pendingClaimWhere(dialect, 10)} AND ${ownerWhere.sql}`, [
568
- decision.decision,
569
- decision.decisionActor == null ? null : this.json(decision.decisionActor),
570
- decision.decisionNote ?? null,
571
- decision.settledBy ?? null,
572
- decision.decidedVia ?? null,
569
+ ...this.decisionRecordValues(decision),
573
570
  decision.updatedInput === undefined ? null : this.json(decision.updatedInput),
574
571
  now,
575
572
  decision.idempotencyKey ?? null,
@@ -608,6 +605,32 @@ export class SqlApprovalAskStore {
608
605
  throw new Error(`decideAsk: row vanished after commit (askId=${askId})`);
609
606
  return { ok: true, row };
610
607
  }
608
+ decisionRecordValues(record) {
609
+ return [record.decision, record.decisionActor == null ? null : this.json(record.decisionActor), record.decisionNote ?? null, record.settledBy ?? null, record.decidedVia ?? null];
610
+ }
611
+ async recordParkedDecision(askId, owner, record) {
612
+ if (record.idempotencyKey != null)
613
+ assertIdempotencyKeyShape(record.idempotencyKey);
614
+ assertDecideSource(record);
615
+ const now = Date.now();
616
+ const dialect = this.db.dialect;
617
+ const ownerWhere = decideOwnerWhere(dialect, owner, 10);
618
+ let res;
619
+ try {
620
+ res = await this.db.query(`UPDATE ${APPROVAL_ASK_TABLE} SET decision=${ph(dialect, 1)}, decision_actor=${ph(dialect, 2)}, decision_note=${ph(dialect, 3)}, settled_by=${ph(dialect, 4)}, decided_via=${ph(dialect, 5)}, decided_at_ms=${ph(dialect, 6)}, idempotency_key=${ph(dialect, 7)}, rev=rev+1, updated_at_ms=${ph(dialect, 8)} WHERE ask_id = ${ph(dialect, 9)} AND state = 'PARKED' AND ${ownerWhere.sql}`, [...this.decisionRecordValues(record), now, record.idempotencyKey ?? null, now, askId, ...ownerWhere.params]);
621
+ }
622
+ catch (err) {
623
+ if (this.isDupKey(err))
624
+ return { ok: false, reason: "idempotency_conflict", row: projectDecideReading(await this.getAsk(askId), owner) };
625
+ throw err;
626
+ }
627
+ const row = projectDecideReading(await this.getAsk(askId), owner);
628
+ if (res.affected !== 1)
629
+ return { ok: false, reason: "ask_not_parked", row };
630
+ if (row === null)
631
+ throw new Error(`recordParkedDecision: row vanished after write (askId=${askId})`);
632
+ return { ok: true, row };
633
+ }
611
634
  async claimTerminal(askId, batchId, intent, opts) {
612
635
  const to = claimTargetState(intent);
613
636
  if (!canAskTransition("STREAM_PENDING", to)) {
@@ -877,6 +900,12 @@ export class SqlApprovalAskStore {
877
900
  return rows[0] ? mapBatchRow(rows[0]) : null;
878
901
  }
879
902
  }
903
+ sealStoreClass(SqlApprovalAskStore, "sql-approval-ask-store", {
904
+ ensureAsk: "exit", transitionAsk: "exit", decideAsk: "exit", claimTerminal: "exit", expireAsk: "exit", bindBatch: "exit", abortBatch: "exit",
905
+ listByState: "exit", listPendingByTask: "exit", listPendingBySession: "exit", listByCall: "exit", listParkingBySourceSession: "exit", getAsk: "exit",
906
+ getByIdempotencyKey: "exit", deferReconcile: "exit", resolveProvisional: "exit", deleteBySession: "exit", reapSettledAsks: "exit", reapEmptyBatches: "exit",
907
+ getBatch: "exit", recordParkedDecision: "exit",
908
+ });
880
909
  export class TiDBApprovalAskStore extends SqlApprovalAskStore {
881
910
  constructor(pool) {
882
911
  super(mysqlDriver(pool));
@@ -2,6 +2,7 @@ import { join } from "node:path";
2
2
  import { existsSync, readdirSync, rmSync } from "node:fs";
3
3
  import { AppendLog, ensureDir, sanitizePathComponent } from "@sema-agent/core";
4
4
  import { replayJsonlGuarded } from "../observability/corrupt-read-seat.js";
5
+ import { sealStoreClass } from "./store-boundary.js";
5
6
  export const APPROVAL_EXEMPTED_EVENT = "approval_exempted";
6
7
  export class TiDBApprovalExemptionStore {
7
8
  pool;
@@ -33,6 +34,7 @@ export class TiDBApprovalExemptionStore {
33
34
  return r.affectedRows;
34
35
  }
35
36
  }
37
+ sealStoreClass(TiDBApprovalExemptionStore, "tidb-approval-exemption-store", { grant: "exit", has: "exit", list: "exit", revoke: "exit", deleteBySession: "exit" });
36
38
  export class PgApprovalExemptionStore {
37
39
  pool;
38
40
  constructor(pool) {
@@ -69,6 +71,7 @@ export class PgApprovalExemptionStore {
69
71
  return res.rowCount ?? 0;
70
72
  }
71
73
  }
74
+ sealStoreClass(PgApprovalExemptionStore, "pg-approval-exemption-store", { grant: "exit", has: "exit", list: "exit", revoke: "exit", deleteBySession: "exit" });
72
75
  export class MemoryApprovalExemptionStore {
73
76
  bySession = new Map();
74
77
  async grant(sessionId, toolName, grantedBy) {
@@ -4,6 +4,7 @@ import { mysqlDriver, pgDriver, SQL_DB_NOW_MS } from "./sql-driver.js";
4
4
  import { isDupKeyError } from "./sql-errors.js";
5
5
  import { replayJsonlGuarded } from "../observability/corrupt-read-seat.js";
6
6
  import { createLogger } from "../observability/logger.js";
7
+ import { sealStoreClass } from "./store-boundary.js";
7
8
  export const APPROVAL_NONCE_TABLE = "approval_nonce";
8
9
  export const MAX_APPROVAL_NONCE_CHARS = 190;
9
10
  export const APPROVAL_NONCE_FLOOR_TABLE = "approval_nonce_floor";
@@ -62,6 +63,7 @@ export class SqlApprovalNonceStore {
62
63
  return res.affected;
63
64
  }
64
65
  }
66
+ sealStoreClass(SqlApprovalNonceStore, "sql-approval-nonce-store", { nowMs: "exit", consume: "exit", reapExpired: "exit" });
65
67
  export class TiDBApprovalNonceStore extends SqlApprovalNonceStore {
66
68
  constructor(pool, opts) {
67
69
  super(mysqlDriver(pool), opts);
@@ -1,4 +1,5 @@
1
1
  import { mysqlDriver, pgDriver } from "./sql-driver.js";
2
+ import { sealStoreClass } from "./store-boundary.js";
2
3
  export const PG_BREAKER_STATE_SCHEMA = [
3
4
  `CREATE TABLE IF NOT EXISTS breaker_state (
4
5
  breaker_key VARCHAR(190) COLLATE "C" NOT NULL,
@@ -91,6 +92,7 @@ export class SqlBreakerState {
91
92
  this.timer = undefined;
92
93
  }
93
94
  }
95
+ sealStoreClass(SqlBreakerState, "sql-breaker-state", { get: "exit", set: "exit", refresh: "exit", startRefresh: "exit", stop: "exit" });
94
96
  export class TiDBBreakerState extends SqlBreakerState {
95
97
  constructor(pool, onWriteFail) {
96
98
  super(mysqlDriver(pool), onWriteFail);
@@ -1,4 +1,5 @@
1
1
  import { type AcquiredSession, type PlacedSessionRow, type RetentionDeclaration, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry } from "@sema-agent/core";
2
+ import type { EntriesStreamOptions } from "../session-sync-kernel.js";
2
3
  import type { LocalSessionDeletionSection } from "../session-erase.js";
3
4
  import type { OwnerAwareSessionStore, SessionListItem } from "../security.js";
4
5
  import type { StagingHandle } from "../session-sync-kernel.js";
@@ -7,6 +8,7 @@ import { type PlacementAcquireOpts } from "./session-placement.js";
7
8
  import type { InstructionSourceStore } from "../instruction-source-notice.js";
8
9
  import type { SessionWorkspaceStore } from "../session-workspace.js";
9
10
  import { type SessionBirthFace, type SessionWithdrawFace } from "./session-birth.js";
11
+ import type { SessionFace } from "../session-incarnation.js";
10
12
  export interface CachingOptions {
11
13
  /** Idle seconds a woken session is kept warm. 0 disables caching (pure passthrough). */
12
14
  ttlSec: number;
@@ -72,18 +74,13 @@ export declare class CachingSessionStore implements SessionStore {
72
74
  readonly withdrawBirth?: SessionWithdrawFace["withdrawBirth"];
73
75
  /** Delegated SessionRepo seam (§0.5) — list/fork/delete operate on the DURABLE tables directly (they bypass the
74
76
  * warm cache by design; a fork/delete must read/write durable state, not a possibly-stale cached view). */
75
- readonly listSessions?: (opts: {
76
- owner?: string;
77
- includeUnowned?: boolean;
78
- cursor?: {
79
- lastActivityAt: string;
80
- sessionId: string;
81
- };
82
- limit: number;
83
- q?: string;
84
- }) => Promise<SessionListItem[]>;
77
+ readonly listSessions?: OwnerAwareSessionStore["listSessions"];
85
78
  /** 带住客的同一只列表面(原样转发;理由同 listSessions)。 */
86
79
  readonly listSessionRows?: OwnerAwareSessionStore["listSessionRows"];
80
+ /** 按 id 的种类读(`session-kind.ts`;纯转发、不经暖缓存 —— 答的是行)。🔴 必须转发:授权口的种类判与能力位读的是本类。 */
81
+ readonly sessionKindOf?: OwnerAwareSessionStore["sessionKindOf"];
82
+ /** 老化候选面(纯转发;读的是持久行)。🔴 必须转发:能力位 `sessionKinds` 与老化腿读的是本类。 */
83
+ readonly listIdleOfKind?: OwnerAwareSessionStore["listIdleOfKind"];
87
84
  readonly fork?: OwnerAwareSessionStore["fork"];
88
85
  /** fork 续写的店契约(原样转发;与 fork 同理绕过暖缓存 —— 读写的是持久行,新 id 本来就不在缓存里)。 */
89
86
  readonly forkTo?: OwnerAwareSessionStore["forkTo"];
@@ -99,7 +96,7 @@ export declare class CachingSessionStore implements SessionStore {
99
96
  readonly sessionSummaryOf?: (sessionId: string) => Promise<SessionListItem | undefined>;
100
97
  readonly writeSessionRowCells?: OwnerAwareSessionStore["writeSessionRowCells"];
101
98
  /** The auto-titler's NULL-only title write (SQL twins + local sidecar carry it; pure pass-through). */
102
- readonly setTitleIfNull?: (sessionId: string, title: string) => Promise<boolean>;
99
+ readonly setTitleIfNull?: (sessionId: string, title: string, landed: SessionFace) => Promise<boolean>;
103
100
  readonly probeTitle?: (sessionId: string) => Promise<"none" | "untitled" | "titled">;
104
101
  /** [ref] —— 换源通告的基线面(`session_ext.instruction_source` / local sidecar),纯转发、不经暖缓存。
105
102
  * 🔴 必须转发(与 retention / placements 同一条教训):默认 `SESSION_CACHE_TTL_SEC=300` 把真店包进本类,
@@ -117,10 +114,7 @@ export declare class CachingSessionStore implements SessionStore {
117
114
  * (read straight from the durable log, bypassing the warm cache, like exportEntries). The stream's per-batch query
118
115
  * discipline (one pooled query per page) lives in the inner store; this wrapper just forwards. */
119
116
  readonly listEntryIds?: (sessionId: string) => Promise<string[] | null>;
120
- readonly exportEntriesStream?: (sessionId: string, opts?: {
121
- afterSeq?: number;
122
- batchSize?: number;
123
- }) => Promise<AsyncIterable<SessionTreeEntry> | null>;
117
+ readonly exportEntriesStream?: (sessionId: string, opts: EntriesStreamOptions) => Promise<AsyncIterable<SessionTreeEntry> | null>;
124
118
  /** 轴A #1(1.254):core B-17 forget 面(evict 本地 + 转发 inner 可选面)。 */
125
119
  forget?: (sessionId: string) => void | Promise<void>;
126
120
  readonly importEntries?: (sessionId: string, owner: string | null, entries: SessionTreeEntry[]) => Promise<void>;
@@ -15,6 +15,8 @@ export class CachingSessionStore {
15
15
  withdrawBirth;
16
16
  listSessions;
17
17
  listSessionRows;
18
+ sessionKindOf;
19
+ listIdleOfKind;
18
20
  fork;
19
21
  forkTo;
20
22
  executionPlacement;
@@ -82,6 +84,10 @@ export class CachingSessionStore {
82
84
  this.listSessions = ownerAware.listSessions.bind(inner);
83
85
  if (ownerAware.listSessionRows)
84
86
  this.listSessionRows = ownerAware.listSessionRows.bind(inner);
87
+ if (ownerAware.sessionKindOf)
88
+ this.sessionKindOf = ownerAware.sessionKindOf.bind(inner);
89
+ if (ownerAware.listIdleOfKind)
90
+ this.listIdleOfKind = ownerAware.listIdleOfKind.bind(inner);
85
91
  if (ownerAware.sessionSummaryOf)
86
92
  this.sessionSummaryOf = ownerAware.sessionSummaryOf.bind(inner);
87
93
  if (ownerAware.writeSessionRowCells)
@@ -5,6 +5,7 @@ import { WRITABLE, boundDeviceOf, settledDeviceBindOutcome, settledDeviceRebindO
5
5
  import { bindDeviceStatement, countDeviceBindingsOn, lockRootAndReadClaim, placeWriterStatement, readPlacementOn, rebindDeviceStatement, rowsOnSqlExec, writeCellOn } from "./execution-placement-sql.js";
6
6
  import { ensureIndexes } from "./ensure-index.js";
7
7
  import { decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn } from "./sql-json-column.js";
8
+ import { sealStoreClass } from "./store-boundary.js";
8
9
  export const DEVICES_TABLE = "device";
9
10
  export const DEVICE_ENROLL_TOKENS_TABLE = "device_enroll_token";
10
11
  export const DEVICE_AUDIT_TABLE = "device_audit";
@@ -616,6 +617,11 @@ export class SqlDeviceStore {
616
617
  return rows.map(mapAuditRow);
617
618
  }
618
619
  }
620
+ sealStoreClass(SqlDeviceStore, "sql-device-store", {
621
+ issueEnrollToken: "exit", getEnrollToken: "exit", consumeEnrollToken: "exit", readDeviceForAdmission: "exit", getDeviceUnscoped: "exit",
622
+ listDevicesByOwner: "exit", listDevicesUnscoped: "exit", revokeDevice: "exit", acquireConnection: "exit", heartbeatConnection: "exit",
623
+ releaseConnection: "exit", placeDeviceExecution: "exit", rebindDeviceExecution: "exit", countDeviceBindings: "exit", appendAudit: "exit", listAudit: "exit",
624
+ });
619
625
  export class TiDBDeviceStore extends SqlDeviceStore {
620
626
  constructor(pool) {
621
627
  super(mysqlDriver(pool));
@@ -0,0 +1,18 @@
1
+ /**
2
+ * **错误出身记号** —— 「这只错是谁交出来的」这件事的唯一属主(叶:零 import)。词是闭集两只({@link ErrorOrigin}),读者一只:店边界 `terminal.ts` 的 `storeBoundaryFault`。
3
+ * · `driver` —— 数据库驱动交出的错。写者两只、都是池座,都只**记**(不改错误对象、不记日志、不改控制流):
4
+ * MySQL 协议 `sql-driver.ts` 的 `createCloseAwarePool`(借连接、池上其余返回承诺的成员)与守卫租约 `leaseOf`(语句与事务动词);
5
+ * PostgreSQL `pg-pool.ts` 的 `createPgPool` 拦截层(`pool.query` / `pool.connect` 与借出 client 的 `query`)。
6
+ * 边界沿 `cause` 链查它 —— 与词法扳机(码出了本仓词法)是边界的两条扳机;它补的是词法看不见的那一类:驱动交出的**无码**错。
7
+ * · `caller` —— 调用方自己的抛出物,店把它原样还给调用方(店在自己的体里已经把它与库错分开了:记忆补丁落地的 `confirm` 钩抛出物)。
8
+ * 边界见它即同一引用放行:它不是店的失败,它的类、码、身份都是调用方的(码长什么样都不换句)。写者 = 店里分开调用方抛出物的那一处(`memory-engine-sql-apply.ts`)。
9
+ *
10
+ * 为什么记号住在这只叶子里:边界函数在 `terminal.ts`,`sql-driver.ts` 的连接初始化拒句要先读边界(`terminal.ts` → `sql-driver.ts` 再反向就成环,
11
+ * 运行时值图零环由 `test/module-cycle-gate.test.ts` 守);池座、店与边界都只依赖这一张表。
12
+ */
13
+ export type ErrorOrigin = "driver" | "caller";
14
+ /** 打记号(原样交回,便于 `throw markErrorOrigin(err, "driver")`);非对象的抛出值记不了,原样交回。先打的词为准(同一只错不改出身)。 */
15
+ export declare function markErrorOrigin<E>(err: E, origin: ErrorOrigin): E;
16
+ /** 这一只对象的出身词(只看它本身;沿 `cause` 链查是读者的事);没记过 ⇒ `undefined`。 */
17
+ export declare function errorOriginOf(err: unknown): ErrorOrigin | undefined;
18
+ //# sourceMappingURL=error-origin.d.ts.map
@@ -0,0 +1,10 @@
1
+ const ORIGIN = new WeakMap();
2
+ export function markErrorOrigin(err, origin) {
3
+ if (typeof err === "object" && err !== null && !ORIGIN.has(err))
4
+ ORIGIN.set(err, origin);
5
+ return err;
6
+ }
7
+ export function errorOriginOf(err) {
8
+ return typeof err === "object" && err !== null ? ORIGIN.get(err) : undefined;
9
+ }
10
+ //# sourceMappingURL=error-origin.js.map
@@ -3,12 +3,13 @@ import { retiredExecutionLaneHintM40 } from "./execution-lane-rename-m40.js";
3
3
  import { sessionFaceFromRow } from "../session-incarnation.js";
4
4
  import { toIso } from "./sql-row-helpers.js";
5
5
  import { SESSION_EXT_TABLE, ensureSessionExtRowStatement, ensureSessionExtRowsStatement } from "./session-ext-table.js";
6
+ import { lockSessionRootOn } from "./session-row-sql.js";
6
7
  import { WRITABLE, assertPlaceableLane, boundDeviceOf, settledMirrorOutcome, settledPlaceOutcome, } from "../execution-placement.js";
8
+ import { sealStoreObject } from "./store-boundary.js";
7
9
  const WRITER = "writer";
8
10
  const MIRROR = "mirror";
9
11
  const NOT_WRITER = "(execution_role IS NULL OR execution_role <> 'writer')";
10
12
  const EXECUTION_CELL_COLUMNS = "execution_role, execution_lane, execution_device_id, execution_device_owner_tenant, execution_device_owner_subject, execution_placed_at, execution_rev";
11
- const OCCUPANT_COLUMNS = "owner, incarnation, placement_kind";
12
13
  const READING_COLUMNS = `sm.owner, sm.incarnation, sm.placement_kind, ${EXECUTION_CELL_COLUMNS.split(", ").map((c) => `se.${c}`).join(", ")}`;
13
14
  function binder(dialect) {
14
15
  const values = [];
@@ -174,9 +175,8 @@ export function placementReadingFromRow(root, row) {
174
175
  export function rowsOnSqlExec(exec) {
175
176
  return async (sql, values) => (await exec.query(sql, [...values])).rows;
176
177
  }
177
- async function lockRootOn(conn, dialect, root) {
178
- const ph = dialect === "pg" ? "$1" : "?";
179
- return (await conn(`SELECT ${OCCUPANT_COLUMNS} FROM session_meta WHERE session_id = ${ph} FOR UPDATE`, [root]))[0];
178
+ function lockRootOn(conn, dialect, root) {
179
+ return lockSessionRootOn(conn, dialect, root);
180
180
  }
181
181
  export async function readClaimOn(conn, dialect, root) {
182
182
  const ph = dialect === "pg" ? "$1" : "?";
@@ -214,7 +214,7 @@ export function createSqlExecutionPlacementSeat(db) {
214
214
  const s = readPlacementRowStatement(db.dialect, root);
215
215
  return placementReadingFromRow(root, (await db.query(s.text, [...s.values])).rows[0]);
216
216
  };
217
- return {
217
+ return sealStoreObject({
218
218
  read,
219
219
  async place(root, occupant, cell) {
220
220
  assertPlaceableLane(root, cell);
@@ -269,6 +269,6 @@ export function createSqlExecutionPlacementSeat(db) {
269
269
  conn.release();
270
270
  }
271
271
  },
272
- };
272
+ }, "sql-execution-placement-seat", { read: "exit", place: "exit", markMirror: "exit" });
273
273
  }
274
274
  //# sourceMappingURL=execution-placement-sql.js.map
@@ -7,6 +7,7 @@ import { decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, jsonColumnT
7
7
  import {} from "./store-contracts.js";
8
8
  import { isDupKeyError } from "./sql-errors.js";
9
9
  import { ensureIndexes } from "./ensure-index.js";
10
+ import { sealStoreClass } from "./store-boundary.js";
10
11
  export const PG_IMAGE_BAKE_SCHEMA = [
11
12
  `CREATE TABLE IF NOT EXISTS image_bake (
12
13
  bake_id VARCHAR(64) COLLATE "C" NOT NULL,
@@ -521,6 +522,11 @@ export class SqlImageBake {
521
522
  }
522
523
  }
523
524
  }
525
+ sealStoreClass(SqlImageBake, "sql-image-bake", {
526
+ createBake: "exit", createBakeIfIdle: "exit", getBake: "exit", getBakeByIdem: "exit", findActiveByArgv: "exit", findActiveAny: "exit",
527
+ findNextQueuedId: "exit", claimBake: "exit", appendEvent: "exit", maxSeq: "exit", getEvents: "exit", setStatus: "exit", setState: "exit", setTerminal: "exit",
528
+ setIndexId: "exit", heartbeatLease: "exit", requestCancel: "exit", isCancelRequested: "exit", reapStaleBakes: "exit",
529
+ });
524
530
  export class TiDBImageBake extends SqlImageBake {
525
531
  constructor(pool, poolName = "standard") {
526
532
  super(mysqlDriver(pool), poolName);
@@ -5,6 +5,7 @@ import { mysqlDriver, pgDriver } from "./sql-driver.js";
5
5
  import { createObjectColumnReader, decodeNullableJsonColumn, foldJsonColumn, jsonColumnText, readJsonArrayColumn, readJsonObjectColumn } from "./sql-json-column.js";
6
6
  import { normalizeIsoOrNull as isoOrNull } from "./sql-row-helpers.js";
7
7
  import { ensureIndexes } from "./ensure-index.js";
8
+ import { sealStoreClass } from "./store-boundary.js";
8
9
  export const PG_IMAGE_INDEX_SCHEMA = [
9
10
  `CREATE TABLE IF NOT EXISTS sandbox_image_index (
10
11
  id VARCHAR(64) COLLATE "C" NOT NULL,
@@ -381,6 +382,9 @@ export class SqlImageIndex {
381
382
  await this.db.query(`UPDATE sandbox_image_index SET ${sets.join(", ")} WHERE id = $${idx}`, params);
382
383
  }
383
384
  }
385
+ sealStoreClass(SqlImageIndex, "sql-image-index", {
386
+ upsert: "exit", registerBuilding: "exit", getById: "exit", getByDigest: "exit", latestPublished: "exit", list: "exit", setStatus: "exit",
387
+ });
384
388
  export class TiDBImageIndex extends SqlImageIndex {
385
389
  constructor(pool) {
386
390
  super(mysqlDriver(pool));