@sema-agent/server 7.145.0 → 7.147.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/MIGRATION.md +876 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +374 -99
  5. package/deploy/facts/CHANGES.json +25 -0
  6. package/deploy/facts/README.md +57 -0
  7. package/deploy/facts/lanes.json +61 -0
  8. package/deploy/facts/lanes.schema.json +57 -0
  9. package/deploy/facts/sandbox-rbac.json +113 -0
  10. package/deploy/facts/sandbox-rbac.schema.json +74 -0
  11. package/deploy/facts/sealed-key.json +9 -0
  12. package/deploy/facts/sealed-key.schema.json +52 -0
  13. package/deploy/sema-up/README.md +2 -2
  14. package/deploy/sema-up/chart/templates/_helpers.tpl +41 -0
  15. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
  16. package/deploy/sema-up/chart/templates/server-v4pro.yaml +9 -4
  17. package/deploy/sema-up/chart/templates/server.yaml +9 -4
  18. package/deploy/sema-up/chart/values.yaml +8 -1
  19. package/deploy/sema-up/cluster-up.sh +2 -1
  20. package/deploy/sema-up/lib/flagshape.sh +4 -0
  21. package/deploy/sema-up/lib/lanes.json +2 -5
  22. package/deploy/sema-up/sema-up.sh +12 -9
  23. package/deploy/sema-up/stack/compose.yaml +5 -4
  24. package/deploy/sema-up/stack/sema-stack-cluster.yaml +34 -17
  25. package/dist/adoption/import-limits.d.ts +6 -0
  26. package/dist/adoption/import-limits.js +7 -0
  27. package/dist/adoption/import.d.ts +62 -0
  28. package/dist/adoption/import.js +107 -0
  29. package/dist/adoption/wire.d.ts +52 -0
  30. package/dist/adoption/wire.js +9 -0
  31. package/dist/approval-ask-machine.d.ts +2 -2
  32. package/dist/approval-card.d.ts +7 -16
  33. package/dist/approval-card.js +0 -4
  34. package/dist/approval-gate-currency.d.ts +1 -1
  35. package/dist/approval-gate-currency.js +1 -1
  36. package/dist/approval-reconciler.d.ts +1 -1
  37. package/dist/approval.d.ts +3 -3
  38. package/dist/audit.js +2 -2
  39. package/dist/bench/s1/live-deps.js +3 -1
  40. package/dist/boot/crash-last.js +2 -1
  41. package/dist/boot/deployment-mods.d.ts +11 -1
  42. package/dist/boot/deployment-mods.js +15 -2
  43. package/dist/boot/device-lane.js +7 -5
  44. package/dist/boot/engine-lease.d.ts +195 -22
  45. package/dist/boot/engine-lease.js +146 -20
  46. package/dist/boot/execution-env.d.ts +5 -0
  47. package/dist/boot/execution-env.js +57 -33
  48. package/dist/boot/execution-lane.d.ts +37 -9
  49. package/dist/boot/execution-lane.js +74 -20
  50. package/dist/boot/exit-boundary.d.ts +50 -0
  51. package/dist/boot/exit-boundary.js +32 -0
  52. package/dist/boot/exit-last.d.ts +20 -4
  53. package/dist/boot/exit-last.js +23 -5
  54. package/dist/boot/governance-seams.d.ts +2 -2
  55. package/dist/boot/governance-seams.js +1 -0
  56. package/dist/boot/leader.js +1 -1
  57. package/dist/boot/memory-boundary.d.ts +11 -11
  58. package/dist/boot/memory-boundary.js +3 -3
  59. package/dist/boot/memory-consolidation.d.ts +42 -41
  60. package/dist/boot/memory-consolidation.js +26 -28
  61. package/dist/boot/org-memory.js +3 -2
  62. package/dist/boot/parked-revive-gate.d.ts +1 -1
  63. package/dist/boot/parked-revive-gate.js +1 -1
  64. package/dist/boot/reapers.d.ts +12 -4
  65. package/dist/boot/reapers.js +40 -16
  66. package/dist/boot/resolve-spec.d.ts +2 -0
  67. package/dist/boot/resolve-spec.js +126 -123
  68. package/dist/boot/retention-lane.d.ts +4 -42
  69. package/dist/boot/runner-deps.js +1 -1
  70. package/dist/boot/session-faces.d.ts +1 -0
  71. package/dist/boot/session-faces.js +11 -3
  72. package/dist/boot/shutdown.js +27 -9
  73. package/dist/boot/stage-01-config.d.ts +1 -1
  74. package/dist/boot/stage-01-config.js +7 -3
  75. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  76. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  77. package/dist/boot/stage-03-store-backend.d.ts +2 -1
  78. package/dist/boot/stage-03-store-backend.js +2 -2
  79. package/dist/boot/stage-04-stores.d.ts +2 -1
  80. package/dist/boot/stage-05-execution-env.d.ts +4 -1
  81. package/dist/boot/stage-05-execution-env.js +6 -6
  82. package/dist/boot/stage-06-runners.d.ts +5 -2
  83. package/dist/boot/stage-06-runners.js +12 -13
  84. package/dist/boot/stage-07-capability-layer.d.ts +5 -2
  85. package/dist/boot/stage-07-capability-layer.js +7 -7
  86. package/dist/boot/stage-08-reapers.d.ts +5 -2
  87. package/dist/boot/stage-08-reapers.js +3 -3
  88. package/dist/boot/stage-09-leader.d.ts +6 -2
  89. package/dist/boot/stage-10-http-server.d.ts +6 -2
  90. package/dist/boot/stage-10-http-server.js +5 -3
  91. package/dist/boot/stores.d.ts +10 -0
  92. package/dist/boot/stores.js +53 -26
  93. package/dist/boot/web-admin.js +3 -3
  94. package/dist/boot/workflow-orchestration.d.ts +1 -1
  95. package/dist/boot/workflow-orchestration.js +2 -1
  96. package/dist/capabilities/center-plugins.d.ts +2 -0
  97. package/dist/capabilities/center-plugins.js +6 -2
  98. package/dist/capabilities/composite-members.d.ts +4 -1
  99. package/dist/capabilities/composite-members.js +4 -1
  100. package/dist/capabilities/execution-lane.d.ts +7 -7
  101. package/dist/capabilities/execution-lane.js +2 -2
  102. package/dist/capabilities/hands-lane.d.ts +1 -1
  103. package/dist/capabilities/scenarios.d.ts +34 -20
  104. package/dist/capabilities/scenarios.js +13 -9
  105. package/dist/capabilities/settings-contract.d.ts +29 -0
  106. package/dist/capabilities/settings-contract.js +14 -0
  107. package/dist/capabilities/skills.d.ts +5 -5
  108. package/dist/capability-facts.d.ts +56 -1
  109. package/dist/capability-facts.js +59 -8
  110. package/dist/center-credential-renewer.js +3 -2
  111. package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
  112. package/dist/config-catalog.js +19 -9
  113. package/dist/config-invariants.d.ts +18 -3
  114. package/dist/config-invariants.js +36 -19
  115. package/dist/config-lkg.d.ts +1 -1
  116. package/dist/config-lkg.js +5 -6
  117. package/dist/config-provider.d.ts +2 -2
  118. package/dist/config-provider.js +2 -0
  119. package/dist/config-types.d.ts +228 -185
  120. package/dist/config.d.ts +74 -6
  121. package/dist/config.js +146 -64
  122. package/dist/degenerate-instrument.js +1 -1
  123. package/dist/deleted-session-ids.d.ts +19 -0
  124. package/dist/deleted-session-ids.js +26 -0
  125. package/dist/deploy-facts.d.ts +155 -0
  126. package/dist/deploy-facts.js +95 -0
  127. package/dist/deployment-shape.d.ts +21 -12
  128. package/dist/deployment-shape.js +24 -6
  129. package/dist/device-ws-hub.d.ts +48 -3
  130. package/dist/device-ws-hub.js +48 -2
  131. package/dist/env-facts.d.ts +7 -5
  132. package/dist/env-facts.js +10 -6
  133. package/dist/error-code-family.d.ts +35 -0
  134. package/dist/error-code-family.js +26 -0
  135. package/dist/execution-config-root.d.ts +5 -5
  136. package/dist/execution-config-root.js +5 -5
  137. package/dist/execution-env-purpose.d.ts +14 -0
  138. package/dist/execution-env-purpose.js +29 -0
  139. package/dist/execution-lane-caps.d.ts +49 -86
  140. package/dist/execution-lane-caps.js +52 -62
  141. package/dist/execution-placement.d.ts +18 -2
  142. package/dist/execution-placement.js +19 -0
  143. package/dist/file-history-disclosure.d.ts +2 -2
  144. package/dist/fleet/drain-entry.d.ts +46 -3
  145. package/dist/fleet/drain-entry.js +6 -0
  146. package/dist/fleet/fleet-bus.d.ts +2 -1
  147. package/dist/fleet/serving-lease.js +3 -4
  148. package/dist/history-anchor.d.ts +22 -0
  149. package/dist/history-anchor.js +14 -0
  150. package/dist/hooks/branch-transcript.d.ts +1 -1
  151. package/dist/hooks/branch-transcript.js +1 -0
  152. package/dist/hooks/classic-stations.d.ts +25 -8
  153. package/dist/hooks/classic-stations.js +29 -3
  154. package/dist/hooks/command-spawn.d.ts +1 -4
  155. package/dist/hooks/command-spawn.js +0 -11
  156. package/dist/hooks/hook-runner.d.ts +85 -24
  157. package/dist/hooks/hook-runner.js +326 -109
  158. package/dist/hooks/hook-source.d.ts +14 -2
  159. package/dist/hooks/hook-source.js +8 -0
  160. package/dist/http/active-run-conflict.d.ts +1 -1
  161. package/dist/http/active-run-conflict.js +1 -1
  162. package/dist/http/admission.js +11 -1
  163. package/dist/http/approval-sweeps.d.ts +2 -5
  164. package/dist/http/approval-sweeps.js +3 -2
  165. package/dist/http/checkpoint-ctx.d.ts +76 -71
  166. package/dist/http/checkpoint-ctx.js +40 -40
  167. package/dist/http/claim-latency.d.ts +10 -0
  168. package/dist/http/claim-latency.js +12 -0
  169. package/dist/http/dispatch.js +19 -3
  170. package/dist/http/durable-run-leg.d.ts +5 -0
  171. package/dist/http/durable-run-leg.js +3 -1
  172. package/dist/http/execution-context.d.ts +7 -1
  173. package/dist/http/execution-context.js +13 -0
  174. package/dist/http/health-self-report.d.ts +6 -2
  175. package/dist/http/health-self-report.js +3 -2
  176. package/dist/http/memory-compliance-failure-reply.d.ts +2 -2
  177. package/dist/http/memory-compliance-failure-reply.js +5 -15
  178. package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
  179. package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
  180. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  181. package/dist/http/memory-store-refusal-reply.js +3 -0
  182. package/dist/http/owner-access.d.ts +11 -0
  183. package/dist/http/owner-access.js +7 -4
  184. package/dist/http/principal-gate.d.ts +28 -16
  185. package/dist/http/principal-gate.js +10 -19
  186. package/dist/http/request-guards.d.ts +2 -2
  187. package/dist/http/request-guards.js +5 -5
  188. package/dist/http/resume-legs.d.ts +29 -10
  189. package/dist/http/resume-legs.js +94 -56
  190. package/dist/http/rewind-files-reply.d.ts +34 -0
  191. package/dist/http/rewind-files-reply.js +36 -0
  192. package/dist/http/route-ctx.d.ts +43 -26
  193. package/dist/http/route-table.js +4 -0
  194. package/dist/http/routes/adoption.d.ts +11 -0
  195. package/dist/http/routes/adoption.js +80 -6
  196. package/dist/http/routes/agents-roster.js +1 -0
  197. package/dist/http/routes/approvals-assistant.js +7 -26
  198. package/dist/http/routes/background.js +1 -0
  199. package/dist/http/routes/capabilities.js +12 -3
  200. package/dist/http/routes/devices.js +1 -1
  201. package/dist/http/routes/diagnostics.d.ts +9 -14
  202. package/dist/http/routes/diagnostics.js +10 -20
  203. package/dist/http/routes/engine.d.ts +31 -0
  204. package/dist/http/routes/engine.js +81 -0
  205. package/dist/http/routes/memory-bundle.js +3 -0
  206. package/dist/http/routes/memory-consolidation.js +3 -5
  207. package/dist/http/routes/memory-origin.d.ts +2 -2
  208. package/dist/http/routes/memory-origin.js +2 -4
  209. package/dist/http/routes/memory-policy.js +5 -1
  210. package/dist/http/routes/notify-wake.js +2 -1
  211. package/dist/http/routes/observability.js +3 -6
  212. package/dist/http/routes/projects.d.ts +70 -0
  213. package/dist/http/routes/projects.js +86 -0
  214. package/dist/http/routes/rules.js +30 -2
  215. package/dist/http/routes/runs.js +15 -11
  216. package/dist/http/routes/session-sync.js +39 -35
  217. package/dist/http/routes/sessions-list.d.ts +1 -1
  218. package/dist/http/routes/sessions.d.ts +7 -1
  219. package/dist/http/routes/sessions.js +108 -2
  220. package/dist/http/routes/tasks.js +32 -8
  221. package/dist/http/routes/trace-usage.js +1 -1
  222. package/dist/http/run-concurrency-cap.d.ts +86 -0
  223. package/dist/http/run-concurrency-cap.js +54 -0
  224. package/dist/http/server.d.ts +31 -14
  225. package/dist/http/server.js +29 -3
  226. package/dist/http/stored-body-replay.d.ts +12 -7
  227. package/dist/http/stored-body-replay.js +28 -5
  228. package/dist/http/wire-types.d.ts +27 -13
  229. package/dist/index.d.ts +2 -2
  230. package/dist/index.js +1 -1
  231. package/dist/instruction-source-notice.d.ts +1 -1
  232. package/dist/json-body-limit.d.ts +8 -0
  233. package/dist/json-body-limit.js +2 -0
  234. package/dist/leader/diffout.d.ts +1 -1
  235. package/dist/local-data-root.d.ts +2 -2
  236. package/dist/memory-embedder-reembed.d.ts +38 -0
  237. package/dist/memory-embedder-reembed.js +20 -0
  238. package/dist/memory-incident-sink.d.ts +0 -28
  239. package/dist/memory-incident-sink.js +5 -0
  240. package/dist/memory-operator-faces.d.ts +9 -4
  241. package/dist/memory-scope-stores.d.ts +9 -7
  242. package/dist/memory-scope-stores.js +3 -14
  243. package/dist/memory-scope.d.ts +38 -2
  244. package/dist/memory-scope.js +33 -2
  245. package/dist/memory-store-refusal.d.ts +17 -4
  246. package/dist/memory-store-refusal.js +1 -1
  247. package/dist/memory-sync-client.d.ts +2 -0
  248. package/dist/memory-sync-client.js +13 -11
  249. package/dist/memory-sync.js +1 -1
  250. package/dist/model-compat.d.ts +35 -21
  251. package/dist/model-compat.js +49 -21
  252. package/dist/model-entry-refusal.d.ts +11 -1
  253. package/dist/model-entry-refusal.js +7 -0
  254. package/dist/namespaced-rule-name.d.ts +18 -1
  255. package/dist/namespaced-rule-name.js +12 -0
  256. package/dist/net-address.d.ts +53 -0
  257. package/dist/net-address.js +111 -0
  258. package/dist/observability/fail-open.d.ts +29 -17
  259. package/dist/observability/fail-open.js +29 -17
  260. package/dist/observability/metrics.d.ts +2 -0
  261. package/dist/observability/metrics.js +2 -0
  262. package/dist/observability/secret-env-scrub.d.ts +30 -4
  263. package/dist/observability/secret-env-scrub.js +15 -3
  264. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  265. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  266. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  267. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  268. package/dist/orchestration/workflow-notify-journal.js +2 -3
  269. package/dist/org-delivery-gate.js +1 -1
  270. package/dist/org-memory-admission.d.ts +5 -2
  271. package/dist/org-memory-admission.js +25 -10
  272. package/dist/parked-decide.d.ts +33 -26
  273. package/dist/parked-decide.js +36 -44
  274. package/dist/peer-directory.d.ts +6 -12
  275. package/dist/peer-directory.js +5 -1
  276. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  277. package/dist/plugins/approval-ask-store-file.js +37 -4
  278. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  279. package/dist/plugins/approval-ask-store-memory.js +11 -2
  280. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  281. package/dist/plugins/approval-ask-store-sql.js +3 -1
  282. package/dist/plugins/blob-backend.d.ts +38 -195
  283. package/dist/plugins/blob-backend.js +33 -229
  284. package/dist/plugins/caching-session-store.d.ts +12 -5
  285. package/dist/plugins/caching-session-store.js +3 -0
  286. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  287. package/dist/plugins/checkpoint-index-columns.js +3 -2
  288. package/dist/plugins/checkpoint-store-face.d.ts +426 -0
  289. package/dist/plugins/checkpoint-store-face.js +152 -0
  290. package/dist/plugins/device-store-sql.d.ts +2 -2
  291. package/dist/plugins/device-store-sql.js +5 -10
  292. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  293. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  294. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  295. package/dist/plugins/execution-placement-sql.js +94 -54
  296. package/dist/plugins/file-run-store.d.ts +26 -18
  297. package/dist/plugins/file-run-store.js +64 -75
  298. package/dist/plugins/fork-routing-session-store.d.ts +6 -2
  299. package/dist/plugins/fork-routing-session-store.js +2 -2
  300. package/dist/plugins/imported-layer-root-retirement.d.ts +22 -11
  301. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  302. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  303. package/dist/plugins/inbox-payload-column.js +13 -0
  304. package/dist/plugins/local-checkpoint-store.d.ts +7 -2
  305. package/dist/plugins/local-checkpoint-store.js +13 -8
  306. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  307. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  308. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  309. package/dist/plugins/local-engine-high-water.js +59 -0
  310. package/dist/plugins/local-session-store.d.ts +119 -30
  311. package/dist/plugins/local-session-store.js +156 -53
  312. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  313. package/dist/plugins/local-task-attachment-store.js +10 -11
  314. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  315. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  316. package/dist/plugins/memory-embedder.d.ts +1 -1
  317. package/dist/plugins/memory-embedder.js +2 -2
  318. package/dist/plugins/memory-engine-pg.d.ts +30 -6
  319. package/dist/plugins/memory-engine-pg.js +96 -214
  320. package/dist/plugins/memory-engine-sql-apply.d.ts +130 -0
  321. package/dist/plugins/memory-engine-sql-apply.js +358 -0
  322. package/dist/plugins/memory-engine-tidb.d.ts +38 -9
  323. package/dist/plugins/memory-engine-tidb.js +99 -230
  324. package/dist/plugins/memory-key-guards.d.ts +1 -1
  325. package/dist/plugins/memory-origin-law.d.ts +3 -3
  326. package/dist/plugins/one-time-migrations.d.ts +169 -83
  327. package/dist/plugins/one-time-migrations.js +295 -235
  328. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  329. package/dist/plugins/owner-only-file-mode.js +141 -0
  330. package/dist/plugins/permission-rule-store-file.d.ts +17 -3
  331. package/dist/plugins/permission-rule-store-file.js +20 -1
  332. package/dist/plugins/pg-pool.d.ts +2 -1
  333. package/dist/plugins/pg-pool.js +12 -5
  334. package/dist/plugins/release-version.d.ts +20 -0
  335. package/dist/plugins/release-version.js +28 -0
  336. package/dist/plugins/remote-env-adb.d.ts +20 -4
  337. package/dist/plugins/remote-env-adb.js +39 -11
  338. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  339. package/dist/plugins/remote-env-e2b.js +6 -4
  340. package/dist/plugins/remote-env-host.d.ts +9 -1
  341. package/dist/plugins/remote-env-host.js +6 -5
  342. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  343. package/dist/plugins/remote-env-k8s.js +15 -4
  344. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  345. package/dist/plugins/remote-env-local-docker.js +3 -3
  346. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  347. package/dist/plugins/remote-env-ssh.js +26 -24
  348. package/dist/plugins/remote-shell.d.ts +59 -30
  349. package/dist/plugins/remote-shell.js +175 -62
  350. package/dist/plugins/retention-declaration.d.ts +37 -0
  351. package/dist/plugins/retention-declaration.js +9 -0
  352. package/dist/plugins/retention-deployment.d.ts +126 -0
  353. package/dist/plugins/retention-deployment.js +88 -0
  354. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  355. package/dist/plugins/retention-lane-store-sql.js +103 -1
  356. package/dist/plugins/retention-sql.d.ts +29 -0
  357. package/dist/plugins/retention-sql.js +8 -0
  358. package/dist/plugins/run-store-sql.js +2 -2
  359. package/dist/plugins/schema-consistency.d.ts +0 -6
  360. package/dist/plugins/schema-consistency.js +1 -2
  361. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  362. package/dist/plugins/schema-ensure-legs.js +13 -3
  363. package/dist/plugins/session-ext-table.d.ts +74 -0
  364. package/dist/plugins/session-ext-table.js +121 -0
  365. package/dist/plugins/session-fork.d.ts +31 -9
  366. package/dist/plugins/session-fork.js +3 -2
  367. package/dist/plugins/session-placement.d.ts +4 -2
  368. package/dist/plugins/session-row-sql.d.ts +8 -7
  369. package/dist/plugins/session-row-sql.js +15 -7
  370. package/dist/plugins/session-store-sql.d.ts +131 -0
  371. package/dist/plugins/session-store-sql.js +298 -0
  372. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  373. package/dist/plugins/session-workspace-cell.js +2 -2
  374. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  375. package/dist/plugins/shared-memory-store-sql.js +13 -13
  376. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  377. package/dist/plugins/sql-driver.d.ts +23 -7
  378. package/dist/plugins/sql-driver.js +41 -8
  379. package/dist/plugins/sql-errors.d.ts +5 -2
  380. package/dist/plugins/sql-errors.js +4 -0
  381. package/dist/plugins/sql-json-column.d.ts +5 -1
  382. package/dist/plugins/store-backend.d.ts +46 -16
  383. package/dist/plugins/store-backend.js +192 -69
  384. package/dist/plugins/store-contracts.d.ts +10 -13
  385. package/dist/plugins/store-contracts.js +1 -9
  386. package/dist/plugins/store-sweep.d.ts +63 -0
  387. package/dist/plugins/store-sweep.js +48 -0
  388. package/dist/plugins/task-attachment-store.d.ts +6 -8
  389. package/dist/plugins/task-attachment-store.js +15 -10
  390. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  391. package/dist/plugins/text-column-capacity.d.ts +21 -0
  392. package/dist/plugins/text-column-capacity.js +5 -0
  393. package/dist/plugins/tidb-pool.d.ts +3 -2
  394. package/dist/plugins/tidb-pool.js +20 -32
  395. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  396. package/dist/prompt-screen.d.ts +6 -9
  397. package/dist/prompt-screen.js +2 -5
  398. package/dist/read-face-posture.d.ts +6 -6
  399. package/dist/read-face-posture.js +2 -2
  400. package/dist/request-value-closure.d.ts +5 -5
  401. package/dist/request-value-closure.js +1 -1
  402. package/dist/rules-consent.d.ts +48 -27
  403. package/dist/rules-consent.js +147 -23
  404. package/dist/run-cancel-context.d.ts +4 -1
  405. package/dist/run-cancel-context.js +2 -1
  406. package/dist/run-local.js +17 -13
  407. package/dist/runs.d.ts +48 -30
  408. package/dist/runs.js +27 -17
  409. package/dist/runtime-caps-resolver.d.ts +15 -8
  410. package/dist/runtime-caps-resolver.js +14 -10
  411. package/dist/sandbox-egress-policy.js +6 -11
  412. package/dist/sandbox-rbac-rules.d.ts +88 -0
  413. package/dist/sandbox-rbac-rules.js +80 -0
  414. package/dist/sealed-key-layout.d.ts +16 -0
  415. package/dist/sealed-key-layout.js +3 -0
  416. package/dist/sealed-key.js +8 -6
  417. package/dist/security.d.ts +43 -9
  418. package/dist/security.js +9 -2
  419. package/dist/sema-config-dir.js +2 -2
  420. package/dist/server-secret-env.d.ts +2 -0
  421. package/dist/service-version.d.ts +2 -1
  422. package/dist/service-version.js +2 -2
  423. package/dist/session-error-wire.d.ts +1 -1
  424. package/dist/session-incarnation.d.ts +8 -5
  425. package/dist/session-notify-door.d.ts +5 -3
  426. package/dist/session-resident-background.d.ts +110 -0
  427. package/dist/session-resident-background.js +88 -0
  428. package/dist/session-row.d.ts +1 -1
  429. package/dist/session-sync-kernel.d.ts +53 -14
  430. package/dist/session-sync-kernel.js +70 -1
  431. package/dist/session-sync.d.ts +5 -3
  432. package/dist/session-workspace.d.ts +12 -2
  433. package/dist/session-workspace.js +6 -0
  434. package/dist/sighup-idle.d.ts +9 -7
  435. package/dist/sighup-idle.js +4 -5
  436. package/dist/spec-fields.d.ts +16 -0
  437. package/dist/spec-fields.js +7 -0
  438. package/dist/store-posture.d.ts +2 -1
  439. package/dist/stored-request-env-credentials-m38.d.ts +3 -0
  440. package/dist/stored-request-env-credentials-m38.js +8 -0
  441. package/dist/stored-request-hooks-m20.d.ts +3 -2
  442. package/dist/stored-request-hooks-m20.js +19 -14
  443. package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
  444. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  445. package/dist/stores-sql/blob-index-sql.js +154 -0
  446. package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +14 -428
  447. package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +43 -220
  448. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  449. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  450. package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
  451. package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
  452. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +27 -67
  453. package/dist/{plugins → stores-sql}/pg-session-storage.js +82 -207
  454. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  455. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  456. package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
  457. package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
  458. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  459. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  460. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  461. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  462. package/dist/stores-sql/session-write-hooks.js +2 -0
  463. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  464. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  465. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +35 -112
  466. package/dist/{plugins → stores-sql}/tidb-session-store.js +73 -169
  467. package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +3 -3
  468. package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
  469. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  470. package/dist/stores-sql/windowed-session-storage.js +61 -0
  471. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
  472. package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
  473. package/dist/task-a2a.d.ts +7 -1
  474. package/dist/task-a2a.js +15 -14
  475. package/dist/task-cwd.d.ts +11 -3
  476. package/dist/task-cwd.js +17 -1
  477. package/dist/task-mcp.d.ts +10 -2
  478. package/dist/task-mcp.js +13 -16
  479. package/dist/task-settings.d.ts +68 -8
  480. package/dist/task-settings.js +63 -6
  481. package/dist/tool-approval.d.ts +23 -10
  482. package/dist/tool-approval.js +10 -6
  483. package/dist/trace/core-keyset-guard.d.ts +17 -10
  484. package/dist/trace/engine-notice-wire.d.ts +1 -1
  485. package/dist/trace/engine-notice-wire.js +4 -0
  486. package/dist/trace/exit-seat.d.ts +29 -1
  487. package/dist/trace/exit-seat.js +4 -0
  488. package/dist/trace/project.d.ts +33 -16
  489. package/dist/trace/project.js +21 -9
  490. package/dist/trace/redact.d.ts +13 -2
  491. package/dist/trace/redact.js +347 -78
  492. package/dist/trace/self-minted-wire.d.ts +587 -16
  493. package/dist/trace/self-minted-wire.js +215 -9
  494. package/dist/trace/sema-provenance.d.ts +45 -41
  495. package/dist/trace/sema-provenance.js +81 -10
  496. package/dist/trace/task-notification-facets.d.ts +70 -2
  497. package/dist/trace/task-notification-facets.js +71 -1
  498. package/dist/trace/wire-projection-faces.d.ts +39 -3
  499. package/dist/trace/wire-projection-faces.js +27 -2
  500. package/dist/unread-request-members.d.ts +66 -0
  501. package/dist/unread-request-members.js +41 -0
  502. package/dist/usage-analytics.d.ts +4 -0
  503. package/dist/user-input-ledger.d.ts +2 -2
  504. package/dist/web-admin-client/apply-effective.js +22 -26
  505. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  506. package/dist/web-admin-client/candidate-gate.js +53 -5
  507. package/dist/web-admin-client/center-request.d.ts +4 -1
  508. package/dist/web-admin-client/center-request.js +2 -1
  509. package/dist/web-admin-client/effective-keys.js +0 -1
  510. package/dist/web-admin-client/facade.d.ts +1 -1
  511. package/dist/web-admin-client/http-client.d.ts +1 -0
  512. package/dist/web-admin-client/http-client.js +17 -9
  513. package/dist/web-admin-client/restart-signal.js +5 -2
  514. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  515. package/dist/web-admin-client/skills-mcp.js +26 -21
  516. package/dist/web-admin-client/types.d.ts +34 -49
  517. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  518. package/package.json +22 -13
  519. package/scripts/drain-check-local.mjs +8 -55
  520. package/scripts/drain-check.mysql.sql +3 -40
  521. package/scripts/drain-check.pg.sql +3 -40
  522. package/skills/update-config.md +1 -1
  523. package/wire-changes/server@7.146.0.json +3221 -0
  524. package/wire-changes/server@7.147.0.json +813 -0
  525. package/dist/approval-batch-census.d.ts +0 -27
  526. package/dist/approval-batch-census.js +0 -27
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { PG_MEMORY_ENGINE_TABLES } from "./memory-engine-pg.js";
3
3
  import { createZodColumnReader, decodeJsonColumn, jsonColumnText, SqlJsonColumnError } from "./sql-json-column.js";
4
4
  import { echoCallerText } from "../caller-text-echo.js";
5
+ import { MEMORY_EMBEDDER_REEMBED_ENV, formatEmbedderIdentityToken, formatReembedAssignment } from "../memory-embedder-reembed.js";
5
6
  export const PG_MEMORY_ENGINE_META_TABLE = "agent_memory_engine_meta";
6
7
  export const EMBEDDER_IDENTITY_META_KEY = "embedder_identity";
7
8
  export const CAS_MAX_ROUNDS = 3;
@@ -18,12 +19,12 @@ export async function ensurePgMemoryEmbedderMetaSchema(query) {
18
19
  const readEmbedderIdentityColumn = createZodColumnReader(EmbedderIdentitySchema);
19
20
  function parseStoredText(text) {
20
21
  try {
21
- return { kind: "ok", value: decodeJsonColumn(text, readEmbedderIdentityColumn, `${PG_MEMORY_ENGINE_META_TABLE}.meta_value for key ${EMBEDDER_IDENTITY_META_KEY}`) };
22
+ return { kind: "ok", value: decodeJsonColumn(text, readEmbedderIdentityColumn, `${PG_MEMORY_ENGINE_META_TABLE}.meta_value for key ${EMBEDDER_IDENTITY_META_KEY}`), text };
22
23
  }
23
24
  catch (err) {
24
25
  if (!(err instanceof SqlJsonColumnError))
25
26
  throw err;
26
- return { kind: "unreadable", raw: `${echoCallerText(text, { maxChars: 160 })} [${err.problem}: ${echoCallerText(err.message, { maxChars: 120 })}]` };
27
+ return { kind: "unreadable", raw: `${echoCallerText(text, { maxChars: 160 })} [${err.problem}: ${echoCallerText(err.message, { maxChars: 120 })}]`, text };
27
28
  }
28
29
  }
29
30
  async function readStored(query) {
@@ -32,8 +33,9 @@ async function readStored(query) {
32
33
  if (row === undefined)
33
34
  return { kind: "absent" };
34
35
  const text = row.meta_value;
35
- if (typeof text !== "string")
36
- return { kind: "unreadable", raw: `[meta_value::text did not return text: ${typeof text}]` };
36
+ if (typeof text !== "string") {
37
+ throw new Error(`reconcileEmbedderFingerprint: ${PG_MEMORY_ENGINE_META_TABLE}.meta_value::text did not return text (${typeof text}) — the read leg is broken; refusing to start`);
38
+ }
37
39
  return parseStoredText(text);
38
40
  }
39
41
  async function hasUnattributedVectors(query) {
@@ -45,16 +47,51 @@ async function clearEmbeddings(query) {
45
47
  SELECT count(*)::int AS n FROM c`);
46
48
  return Number(r.rows[0]?.n ?? 0);
47
49
  }
48
- async function writeIdentity(query, identity) {
49
- await query(`INSERT INTO ${PG_MEMORY_ENGINE_META_TABLE} (meta_key, meta_value) VALUES ($1, $2::jsonb)
50
- ON CONFLICT (meta_key) DO UPDATE SET meta_value = EXCLUDED.meta_value`, [EMBEDDER_IDENTITY_META_KEY, JSON.stringify(identity)]);
50
+ async function writeIdentity(query, identity, judged) {
51
+ if (judged.kind === "absent") {
52
+ await query(`INSERT INTO ${PG_MEMORY_ENGINE_META_TABLE} (meta_key, meta_value) VALUES ($1, $2::jsonb)
53
+ ON CONFLICT (meta_key) DO NOTHING`, [EMBEDDER_IDENTITY_META_KEY, JSON.stringify(identity)]);
54
+ return;
55
+ }
56
+ await query(`UPDATE ${PG_MEMORY_ENGINE_META_TABLE} SET meta_value = $2::jsonb WHERE meta_key = $1 AND meta_value::text = $3`, [
57
+ EMBEDDER_IDENTITY_META_KEY,
58
+ JSON.stringify(identity),
59
+ judged.text,
60
+ ]);
51
61
  }
52
62
  function sameIdentity(a, b) {
53
63
  return a.model === b.model && a.dimensions === b.dimensions;
54
64
  }
55
65
  const SCALE_ZERO_NOTE = "change the embedder identity with the fleet stopped (scale to 0, then start): during a ROLLING window the old replicas keep writing vectors in the OLD space after this gate cleared the column";
66
+ export function buildEmbedderIdentityRefusal(state, recorded, want) {
67
+ const configured = formatEmbedderIdentityToken(want);
68
+ let what;
69
+ switch (state) {
70
+ case "changed":
71
+ what = `${PG_MEMORY_ENGINE_META_TABLE} records the embedder identity ${recorded !== null && "model" in recorded ? formatEmbedderIdentityToken(recorded) : "(none)"} but the configured embedder is ${configured}`;
72
+ break;
73
+ case "unattributed":
74
+ what = `${PG_MEMORY_ENGINE_META_TABLE} records no embedder identity while ${PG_MEMORY_ENGINE_TABLES.entry}.embedding holds vectors — their origin cannot be proven to be the configured embedder ${configured}`;
75
+ break;
76
+ case "unreadable":
77
+ what = `the embedder identity recorded in ${PG_MEMORY_ENGINE_META_TABLE} cannot be read (${recorded !== null && "unreadable" in recorded ? recorded.unreadable : "unreadable"}), so the vectors cannot be proven to come from the configured embedder ${configured}`;
78
+ break;
79
+ default: {
80
+ const unknown = state;
81
+ throw new Error(`unknown embedder mismatch state ${JSON.stringify(unknown)}`);
82
+ }
83
+ }
84
+ return (`memory embedder identity mismatch (state: ${state}) — refusing to start: ${what}. ` +
85
+ `The gate refuses on each of three states (changed: the recorded identity differs; unattributed: no recorded identity while vectors exist; unreadable: the recorded identity cannot be read) ` +
86
+ `and never clears the vector column on its own — clearing is irreversible (rows re-embed only when next written), refusing is not. Ways out: ` +
87
+ (state === "changed" ? "configure the recorded identity again (MEMORY_EMBEDDER_MODEL / MEMORY_EMBEDDER_DIM); or " : "") +
88
+ `confirm the re-embed — set ${formatReembedAssignment(want)} and restart with the fleet stopped (scale to 0): the column is cleared once and ${configured} recorded, after which the confirmation is inert; ` +
89
+ "or unset MEMORY_EMBEDDER_* to start on the lexical floor with the stored vectors left untouched.");
90
+ }
91
+ const CONFIRMED_NOTE = `re-embed confirmed by ${MEMORY_EMBEDDER_REEMBED_ENV} (inert from now on: this identity is recorded, so the next boot matches)`;
56
92
  export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
57
93
  const { log } = opts;
94
+ const confirmed = opts.reembedConfirmed === true;
58
95
  const now = opts.now ?? Date.now;
59
96
  const want = EmbedderIdentitySchema.parse(identity);
60
97
  const firstStartedAt = now();
@@ -71,7 +108,7 @@ export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
71
108
  reason: firstClear?.reason ?? firstChange?.reason ?? terminalState,
72
109
  rounds,
73
110
  elapsedMs,
74
- note: `${SCALE_ZERO_NOTE}; cleared vectors are NOT backfilled — rows re-embed only as they are next written, and until then each cleared row is reachable ONLY by a query sharing a literal term with it (the lexical floor drops a row with zero term overlap, whereas a row that still has a vector is scored by cosine as long as the query embeds too) — rewrite the corpus to restore vector reach immediately`,
111
+ note: `${CONFIRMED_NOTE}; ${SCALE_ZERO_NOTE}; cleared vectors are NOT backfilled — rows re-embed only as they are next written, and until then each cleared row is reachable ONLY by a query sharing a literal term with it (the lexical floor drops a row with zero term overlap, whereas a row that still has a vector is scored by cosine as long as the query embeds too) — rewrite the corpus to restore vector reach immediately`,
75
112
  });
76
113
  return;
77
114
  }
@@ -83,7 +120,7 @@ export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
83
120
  reason: firstChange.reason,
84
121
  rounds,
85
122
  elapsedMs,
86
- note: `${SCALE_ZERO_NOTE}; no vectors existed to clear on this boot — the identity itself changed, which is the event`,
123
+ note: `${CONFIRMED_NOTE}; ${SCALE_ZERO_NOTE}; no vectors existed to clear on this boot — the identity itself changed, which is the event`,
87
124
  });
88
125
  return;
89
126
  }
@@ -114,15 +151,18 @@ export async function reconcileEmbedderFingerprint(query, identity, opts = {}) {
114
151
  else {
115
152
  state = (await hasUnattributedVectors(query)) ? "unattributed" : "armed";
116
153
  }
154
+ const recorded = previous ?? (stored.kind === "unreadable" ? { unreadable: stored.raw } : null);
155
+ if (state !== "armed" && !confirmed)
156
+ throw new Error(buildEmbedderIdentityRefusal(state, recorded, want));
117
157
  if (state !== "armed" && firstChange === undefined) {
118
- firstChange = { reason: state, previous: previous ?? (stored.kind === "unreadable" ? { unreadable: stored.raw } : null) };
158
+ firstChange = { reason: state, previous: recorded };
119
159
  }
120
160
  const cleared = state === "armed" ? 0 : await clearEmbeddings(query);
121
161
  if (cleared > 0 && firstClear === undefined) {
122
- firstClear = { reason: state, previous: previous ?? (stored.kind === "unreadable" ? { unreadable: stored.raw } : null) };
162
+ firstClear = { reason: state, previous: recorded };
123
163
  }
124
164
  clearedTotal += cleared;
125
- await writeIdentity(query, want);
165
+ await writeIdentity(query, want, stored);
126
166
  const after = await readStored(query);
127
167
  if (after.kind === "ok" && sameIdentity(after.value, want)) {
128
168
  emitOutcome(state, round);
@@ -1,7 +1,7 @@
1
1
  import type { MemoryEmbedderConfig } from "../config-types.js";
2
2
  import type { PgEmbedder } from "./pg-query.js";
3
3
  /** 工厂入参 = 配置坐标(单一属主 `config-types.ts`)+ 部署腿(观测/注入)。 */
4
- export interface OpenAiCompatEmbedderOptions extends MemoryEmbedderConfig {
4
+ export interface OpenAiCompatEmbedderOptions extends Omit<MemoryEmbedderConfig, "reembedConfirmed"> {
5
5
  /** 注入 fetch(测试/代理场景);缺省全局 `fetch`。 */
6
6
  fetchImpl?: typeof fetch;
7
7
  /**
@@ -94,9 +94,9 @@ export function createOpenAiCompatEmbedder(opts) {
94
94
  };
95
95
  }
96
96
  export function memoryEmbedderFor(config, deps = {}) {
97
- const cfg = config.memoryEmbedder;
98
- if (cfg === undefined)
97
+ if (config.memoryEmbedder === undefined)
99
98
  return undefined;
99
+ const { reembedConfirmed: _confirmation, ...cfg } = config.memoryEmbedder;
100
100
  return createOpenAiCompatEmbedder({
101
101
  ...cfg,
102
102
  ...(deps.fetchImpl !== undefined ? { fetchImpl: deps.fetchImpl } : {}),
@@ -1,5 +1,6 @@
1
1
  import type { MemoryHistoryAppendRow } from "./memory-sync-store-pg.js";
2
2
  import type { PgEmbedder, PgQueryFn } from "./pg-query.js";
3
+ import { type SqlApplyOpts } from "./memory-engine-sql-apply.js";
3
4
  import type { MemoryBackend, MemoryEntry, MemoryEntryHeader, NotePatch, PatchReport, ScoredMemoryEntry } from "@sema-agent/core";
4
5
  import { type IndexSpec } from "./ensure-index.js";
5
6
  /** Table names (single source). Deliberately DISJOINT from the legacy `agent_memory*` tables —
@@ -54,6 +55,8 @@ export declare class PgMemoryEngineBackend implements MemoryBackend {
54
55
  private readonly history?;
55
56
  /** Cumulative lost-row count — audit-line breakage must itself be auditable. */
56
57
  private historyRowsLost;
58
+ /** 交给共享驱动器的读口 / 写口 / history 冲刷(构造末尾铸一次)。 */
59
+ private readonly leg;
57
60
  /** [ref] rung indicator — same semantics as PgMemoryStore.vectorMode. */
58
61
  get vectorMode(): "native" | "portable" | "lexical";
59
62
  constructor(query: PgQueryFn, opts?: PgMemoryEngineBackendOptions);
@@ -70,12 +73,33 @@ export declare class PgMemoryEngineBackend implements MemoryBackend {
70
73
  limit?: number;
71
74
  exposureBands?: boolean;
72
75
  }): Promise<ScoredMemoryEntry[]>;
73
- applyPatches(patches: readonly NotePatch[]): Promise<PatchReport>;
74
- private applyOne;
75
- /** When the conditional write returns zero rows (a write landed inside the
76
- * SELECT→write window), the report's `currentRev` must be the rev NOW — re-reporting the pre-race
77
- * SELECT value could claim `baseRev === currentRev` alongside a "rev mismatch" reason. */
78
- private freshRev;
76
+ /** core 落点问询协议的能力位:`applyPatches` 兑现 `opts.admit` / `opts.confirm`(读法见 `memory-engine-sql-apply.ts` 头注)。 */
77
+ readonly admitsLandings: true;
78
+ /** 判与驱动器只在 `memory-engine-sql-apply.ts` 一处(两只 SQL 腿共用);本腿只供读口、PG 方言写口(写语句绑定计划的投影)与 history 冲刷。
79
+ * `opts.anchoredRoot` 是带目录的后端的事,本腿没有目录 ⇒ 不读(core 契约原文:a backend without a directory ignores it)。 */
80
+ applyPatches(patches: readonly NotePatch[], opts?: SqlApplyOpts): Promise<PatchReport>;
81
+ private rowOf;
82
+ private idsAt;
83
+ /** 一个 patch 第一次要写之前算一次它的向量参数(撞名 / 被挪重试复用,不重调 embedder —— 改前 add 也只在后缀循环外算一次)。
84
+ * haystack 用调用方给的原形(add 的原名,不是撞名后缀),与改前同。 */
85
+ private prepareWrite;
86
+ /** 写不落之后的现读:这个 id 的行此刻的 rev 与投影(没了 ⇒ undefined)。 */
87
+ private freshRow;
88
+ /**
89
+ * add:`INSERT … ON CONFLICT (id)`,冲突靶 = 仅主键。计划时这个 id 已有行 ⇒ `DO UPDATE … WHERE` 行仍在计划的投影上(同 scope re-add 的
90
+ * 幂等覆盖;行被挪走就不覆盖 —— 被挪去的那个拼写没问过),add-if-absent 再绑计划读到的 rev(行被改写就不覆盖 —— 它判的是那一份内容);
91
+ * 计划时没有 ⇒ `DO NOTHING`(同 id 的行在判与写之间被别的副本插入就不覆盖)。两种「不覆盖」都让 `RETURNING` 交零行 ⇒ 现读确认后答
92
+ * `moved`(驱动器按现状重判)。剩下能撞的唯一键只有 `(scope, slug)` ⇒ `slug-taken`。
93
+ */
94
+ private writeAdd;
95
+ /** update:条件 = 判过的 rev **且**判过的投影(rev 是内容哈希、不含 scope / slug)。零行 ⇒ 现读:内容未变而投影变了 = `moved`;其余 =
96
+ * CAS 冲突,currentRev 报现值(行没了 ⇒ 判时的值)。 */
97
+ private writeUpdate;
98
+ /** delete:条件同 update。 */
99
+ private writeDelete;
100
+ /** BEST-EFFORT history append(见 PgMemoryEngineBackendOptions.history 的如实取舍):entry 写已提交,审计行追加失败不许让报告失败 ——
101
+ * 吞 + warn,永不抛;appendHistory 按 (id, rev) 幂等,调用方重试安全。 */
102
+ private appendHistory;
79
103
  getConsolidationCursor(scope: string): Promise<string | undefined>;
80
104
  setConsolidationCursor(scope: string, cursor: string): Promise<void>;
81
105
  }
@@ -2,10 +2,11 @@ import { cosineDistance, jaccardDistance, termSet } from "@sema-agent/core";
2
2
  import { isUniqueViolation, readEmbeddingColumn, readFrontmatterColumn } from "./memory-engine-vector-util.js";
3
3
  import { decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText } from "./sql-json-column.js";
4
4
  import { recordFailOpen } from "../observability/fail-open.js";
5
- import { computeEntryRev, serializeEntryFile } from "@sema-agent/core";
6
- import { pgSafeJsonStringify, pgHasUnstorable } from "./pg-safe-json.js";
7
- import { assertMemoryScopeWidth, memoryEntryKeyWidthRefusal } from "./memory-key-guards.js";
8
- import { ambiguousOriginRefusal, createBatchCommittedBaseline, exposureBandOf, exposureCarriage, originMarkedSqlPredicate, originWhitewashRefusal, rememberBatchCommitted, distilledWhitewashRefusal, distilledCarriage, unknownPatchOpRefusal, } from "./memory-origin-law.js";
5
+ import { serializeEntryFile } from "@sema-agent/core";
6
+ import { pgSafeJsonStringify } from "./pg-safe-json.js";
7
+ import { assertMemoryScopeWidth } from "./memory-key-guards.js";
8
+ import { exposureBandOf, exposureCarriage, originMarkedSqlPredicate, distilledCarriage } from "./memory-origin-law.js";
9
+ import { applySqlPatches, } from "./memory-engine-sql-apply.js";
9
10
  import { ensureIndexes } from "./ensure-index.js";
10
11
  export const PG_MEMORY_ENGINE_TABLES = {
11
12
  entry: "agent_memory_engine_entry",
@@ -72,6 +73,7 @@ export class PgMemoryEngineBackend {
72
73
  clock;
73
74
  history;
74
75
  historyRowsLost = 0;
76
+ leg;
75
77
  get vectorMode() {
76
78
  return this.pgvectorSql ? "native" : this.embedder ? "portable" : "lexical";
77
79
  }
@@ -83,6 +85,18 @@ export class PgMemoryEngineBackend {
83
85
  this.history = opts.history;
84
86
  if (this.pgvectorSql && !this.embedder)
85
87
  throw new Error("PgMemoryEngineBackend: pgvectorSql requires an embedder");
88
+ this.leg = {
89
+ reads: { rowOf: (id) => this.rowOf(id), idsAt: (scope, slug) => this.idsAt(scope, slug) },
90
+ writes: {
91
+ prepare: (entry) => this.prepareWrite(entry),
92
+ add: (w, embedding, confirm) => this.writeAdd(w, embedding, confirm),
93
+ update: (w, embedding, confirm) => this.writeUpdate(w, embedding, confirm),
94
+ remove: (w, confirm) => this.writeDelete(w, confirm),
95
+ },
96
+ unstorableReason: "unstorable_bytes (PG cannot store NUL/lone surrogates; strip them at the source — the store never rewrites content)",
97
+ now: () => this.clock(),
98
+ ...(this.history !== undefined ? { appendHistory: (rows) => this.appendHistory(rows) } : {}),
99
+ };
86
100
  }
87
101
  haystackOf(slug, fm, body) {
88
102
  return `${fm.name ?? slug} ${fm.description ?? ""} ${body}`;
@@ -181,224 +195,92 @@ export class PgMemoryEngineBackend {
181
195
  scored.sort(contractOrder);
182
196
  return scored.slice(0, limit);
183
197
  }
184
- async applyPatches(patches) {
185
- const report = { applied: [], conflicts: [] };
186
- const nonDeleteIds = new Set();
187
- const plannedSlugs = new Set();
188
- const historyRows = [];
189
- const originBaseline = createBatchCommittedBaseline();
190
- for (const patch of patches) {
191
- try {
192
- if (patch.op !== "delete") {
193
- if (nonDeleteIds.has(patch.id)) {
194
- report.conflicts.push({ op: patch.op, id: patch.id, reason: "duplicate id in batch: another add/update for this id is already planned (copied file keeping its frontmatter id?)" });
195
- continue;
196
- }
197
- nonDeleteIds.add(patch.id);
198
- }
199
- await this.applyOne(patch, report, plannedSlugs, historyRows, originBaseline);
200
- }
201
- catch (err) {
202
- report.conflicts.push({ op: patch.op, id: patch.id, reason: `io error: ${err instanceof Error ? err.message : String(err)}` });
203
- }
204
- }
205
- if (this.history && historyRows.length > 0) {
206
- try {
207
- await this.history.appendHistory(historyRows);
208
- }
209
- catch (err) {
210
- this.historyRowsLost += historyRows.length;
211
- console.warn(`PgMemoryEngineBackend: best-effort history append failed (${historyRows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
212
- }
213
- }
214
- return report;
198
+ admitsLandings = true;
199
+ async applyPatches(patches, opts) {
200
+ return applySqlPatches(patches, opts, this.leg);
201
+ }
202
+ async rowOf(id) {
203
+ const res = await this.query(`SELECT slug, rev, scope, ${jsonColumnText("pg", "frontmatter")} FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [id]);
204
+ const r = res.rows[0];
205
+ if (r === undefined)
206
+ return undefined;
207
+ return { scope: String(r.scope), slug: String(r.slug), rev: String(r.rev), frontmatter: readFrontmatter(r.frontmatter, id) };
208
+ }
209
+ async idsAt(scope, slug) {
210
+ const res = await this.query(`SELECT id FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE scope = $1 AND slug = $2`, [scope, slug]);
211
+ return res.rows.map((r) => String(r.id));
212
+ }
213
+ prepareWrite(entry) {
214
+ return this.embeddingParam(this.haystackOf(entry.slug, entry.frontmatter, entry.body));
215
215
  }
216
- async applyOne(patch, report, plannedSlugs, historyRows, originBaseline) {
216
+ async freshRow(id) {
217
+ const res = await this.query(`SELECT rev, scope, slug FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [id]);
218
+ const r = res.rows[0];
219
+ return r === undefined ? undefined : { rev: String(r.rev), scope: String(r.scope), slug: String(r.slug) };
220
+ }
221
+ async writeAdd({ stored, rev, prior }, embedding, confirm) {
217
222
  const T = PG_MEMORY_ENGINE_TABLES.entry;
218
- {
219
- const refusal = unknownPatchOpRefusal(patch.op);
220
- if (refusal !== undefined) {
221
- report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
222
- return;
223
- }
223
+ const params = [stored.id, stored.scope, stored.slug, pgSafeJsonStringify(stored.frontmatter), stored.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(stored), "utf8"), embedding];
224
+ const onConflict = prior !== undefined
225
+ ? `ON CONFLICT (id) DO UPDATE SET scope = $2, slug = $3, frontmatter = $4, body = $5, rev = $6, mtime_ms = $7, size_bytes = $8, embedding = $9 WHERE ${T}.scope = $10 AND ${T}.slug = $11${prior.rev !== undefined ? ` AND ${T}.rev = $12` : ""}`
226
+ : "ON CONFLICT (id) DO NOTHING";
227
+ if (prior !== undefined)
228
+ params.push(prior.scope, prior.slug, ...(prior.rev !== undefined ? [prior.rev] : []));
229
+ confirm();
230
+ let landed;
231
+ try {
232
+ const res = await this.query(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding)
233
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
234
+ ${onConflict}
235
+ RETURNING id`, params);
236
+ landed = res.rows.length > 0;
224
237
  }
225
- if (patch.op !== "delete" && patch.entry !== undefined && patch.entry.id !== patch.id) {
226
- report.conflicts.push({ op: patch.op, id: patch.id, reason: `patch id ${JSON.stringify(patch.id)} != entry id ${JSON.stringify(patch.entry.id)} (malformed patch refused)` });
227
- return;
238
+ catch (err) {
239
+ if (isUniqueViolation(err))
240
+ return { kind: "slug-taken" };
241
+ throw err;
228
242
  }
229
- if (patch.op !== "delete" && patch.entry !== undefined) {
230
- const refusal = memoryEntryKeyWidthRefusal(patch.entry.scope, patch.entry.slug);
231
- if (refusal !== undefined) {
232
- report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
233
- return;
234
- }
235
- }
236
- if (patch.op !== "delete" && patch.entry !== undefined) {
237
- const refusal = ambiguousOriginRefusal(patch.entry.frontmatter);
238
- if (refusal !== undefined) {
239
- report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
240
- return;
241
- }
242
- }
243
- if (patch.op === "add") {
244
- const rawEntry = patch.entry;
245
- if (!rawEntry) {
246
- report.conflicts.push({ op: "add", id: patch.id, reason: "add patch without an entry" });
247
- return;
248
- }
249
- if (pgHasUnstorable(rawEntry.frontmatter) || pgHasUnstorable(rawEntry.body) || pgHasUnstorable(rawEntry.slug)) {
250
- report.conflicts.push({ op: "add", id: rawEntry.id, reason: "unstorable_bytes (PG cannot store NUL/lone surrogates; strip them at the source — the store never rewrites content)" });
251
- return;
252
- }
253
- const entry = rawEntry;
254
- const prior = await this.query(`SELECT scope, slug, rev, ${jsonColumnText("pg", "frontmatter")} FROM ${T} WHERE id = $1`, [entry.id]);
255
- const priorRow = prior.rows.length > 0 ? prior.rows[0] : undefined;
256
- {
257
- const committedBaseFm = rememberBatchCommitted(originBaseline, entry.id, priorRow !== undefined ? readFrontmatter(priorRow.frontmatter, entry.id) : undefined);
258
- const refusal = originWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
259
- if (refusal !== undefined) {
260
- report.conflicts.push({ op: "add", id: entry.id, reason: refusal });
261
- return;
262
- }
263
- const dRefusal = distilledWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
264
- if (dRefusal !== undefined) {
265
- report.conflicts.push({ op: "add", id: entry.id, reason: dRefusal });
266
- return;
267
- }
268
- }
269
- if (patch.guard === "absent" && priorRow) {
270
- const currentRev = String(priorRow.rev);
271
- if (currentRev !== computeEntryRev(entry)) {
272
- report.conflicts.push({ op: "add", id: entry.id, reason: "add_guard_absent_conflict (id already exists at a different rev; add-if-absent refuses to overwrite)", currentRev });
273
- return;
274
- }
275
- if (String(priorRow.scope) !== entry.scope || String(priorRow.slug) !== entry.slug) {
276
- report.conflicts.push({ op: "add", id: entry.id, reason: `add_guard_absent_conflict (id already exists at the same rev but a different projection ${JSON.stringify(`${String(priorRow.scope)}/${String(priorRow.slug)}`)}; add-if-absent refuses to duplicate)`, currentRev });
277
- return;
278
- }
279
- }
280
- if (priorRow) {
281
- const held = String(priorRow.scope);
282
- if (held !== entry.scope) {
283
- report.conflicts.push({ op: "add", id: entry.id, reason: `id already exists in scope ${JSON.stringify(held)} (cross-scope add refused)` });
284
- return;
285
- }
286
- }
287
- const cEntry = entry;
288
- const embedding = await this.embeddingParam(this.haystackOf(cEntry.slug, cEntry.frontmatter, cEntry.body));
289
- let slug = cEntry.slug;
290
- for (let n = 2;; n++) {
291
- const derivedRefusal = memoryEntryKeyWidthRefusal(entry.scope, slug);
292
- if (derivedRefusal !== undefined) {
293
- report.conflicts.push({ op: "add", id: entry.id, reason: `${derivedRefusal} (slug collision suffix "-${n - 1}" no longer fits the column — shorten the entry name)` });
294
- return;
295
- }
296
- const key = `${entry.scope}|${slug}`;
297
- if (!plannedSlugs.has(key)) {
298
- const taken = await this.query(`SELECT id FROM ${T} WHERE scope = $1 AND slug = $2`, [entry.scope, slug]);
299
- const otherId = taken.rows.find((r) => String(r.id) !== entry.id);
300
- if (!otherId) {
301
- const stored = { ...cEntry, slug };
302
- const rev = computeEntryRev(stored);
303
- try {
304
- await this.query(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding)
305
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
306
- ON CONFLICT (id) DO UPDATE SET scope = $2, slug = $3, frontmatter = $4, body = $5, rev = $6, mtime_ms = $7, size_bytes = $8, embedding = $9`, [stored.id, stored.scope, stored.slug, pgSafeJsonStringify(stored.frontmatter), stored.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(stored), "utf8"), embedding]);
307
- }
308
- catch (err) {
309
- if (isUniqueViolation(err)) {
310
- slug = `${entry.slug}-${n}`;
311
- continue;
312
- }
313
- throw err;
314
- }
315
- plannedSlugs.add(key);
316
- report.applied.push({ op: "add", id: stored.id, slug: stored.slug });
317
- if (this.history)
318
- historyRows.push({ id: stored.id, rev, op: "add", scope: stored.scope, snapshot: { ...stored, rev }, writtenAtMs: this.clock() });
319
- return;
320
- }
321
- }
322
- slug = `${entry.slug}-${n}`;
323
- }
324
- }
325
- const cur = await this.query(`SELECT slug, rev, scope, ${jsonColumnText("pg", "frontmatter")} FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [patch.id]);
326
- if (cur.rows.length === 0) {
327
- report.conflicts.push({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
328
- return;
329
- }
330
- const currentRev = String(cur.rows[0].rev);
331
- const currentSlug = String(cur.rows[0].slug);
332
- const currentScope = String(cur.rows[0].scope);
333
- const committedFm = readFrontmatter(cur.rows[0].frontmatter, patch.id);
334
- const committedBaseFm = rememberBatchCommitted(originBaseline, patch.id, committedFm);
335
- if (patch.op === "update" && patch.entry !== undefined) {
336
- if (committedFm.provenance?.kind === "repo_file") {
337
- const next = patch.entry.frontmatter;
338
- const stripsProvenance = next.provenance === undefined;
339
- const stripsTrust = committedFm.trust !== undefined && next.trust === undefined;
340
- if (stripsProvenance || stripsTrust) {
341
- report.conflicts.push({
342
- op: "update",
343
- id: patch.id,
344
- reason: `repo_file provenance whitewash refused: update drops ${stripsProvenance ? "provenance" : "trust"} from a repo-ingested entry (malformed patch refused)`,
345
- });
346
- return;
347
- }
348
- }
349
- const refusal = originWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
350
- if (refusal !== undefined) {
351
- report.conflicts.push({ op: "update", id: patch.id, reason: refusal });
352
- return;
353
- }
354
- const dRefusal = distilledWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
355
- if (dRefusal !== undefined) {
356
- report.conflicts.push({ op: "update", id: patch.id, reason: dRefusal });
357
- return;
358
- }
359
- }
360
- if (patch.baseRev !== undefined && patch.baseRev !== currentRev) {
361
- report.conflicts.push({ op: patch.op, id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev });
362
- return;
363
- }
364
- if (patch.op === "delete") {
365
- const res = await this.query(`DELETE FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1 AND rev = $2 RETURNING id`, [patch.id, currentRev]);
366
- if (res.rows.length === 0) {
367
- report.conflicts.push({ op: "delete", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: await this.freshRev(patch.id, currentRev) });
368
- return;
369
- }
370
- report.applied.push({ op: "delete", id: patch.id, slug: currentSlug });
371
- if (this.history)
372
- historyRows.push({ id: patch.id, rev: `tombstone:${currentRev}`, prevRev: currentRev, op: "delete", scope: currentScope, writtenAtMs: this.clock() });
373
- return;
374
- }
375
- const entry = patch.entry;
376
- if (!entry) {
377
- report.conflicts.push({ op: "update", id: patch.id, reason: "update patch without an entry" });
378
- return;
379
- }
380
- if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
381
- report.conflicts.push({ op: "update", id: patch.id, reason: "unstorable_bytes (PG cannot store NUL/lone surrogates; strip them at the source — the store never rewrites content)" });
382
- return;
383
- }
384
- const cEntry = entry;
385
- const rev = computeEntryRev(cEntry);
386
- const embedding = await this.embeddingParam(this.haystackOf(cEntry.slug, cEntry.frontmatter, cEntry.body));
243
+ if (landed)
244
+ return { kind: "committed" };
245
+ const fresh = await this.freshRow(stored.id);
246
+ if (fresh !== undefined && (prior === undefined || fresh.scope !== prior.scope || fresh.slug !== prior.slug || (prior.rev !== undefined && fresh.rev !== prior.rev)))
247
+ return { kind: "moved" };
248
+ throw new Error(`memory-engine: the add of ${JSON.stringify(stored.id)} wrote no row, yet the row is ${fresh === undefined ? "absent" : "still where the write condition holds"} — refusing to report it either way`);
249
+ }
250
+ async writeUpdate({ entry, rev, currentRev, current, baseRev }, embedding, confirm) {
251
+ const params = [entry.id, entry.scope, entry.slug, pgSafeJsonStringify(entry.frontmatter), entry.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(entry), "utf8"), embedding, currentRev, current.scope, current.slug];
252
+ confirm();
387
253
  const res = await this.query(`UPDATE ${PG_MEMORY_ENGINE_TABLES.entry}
388
254
  SET scope = $2, slug = $3, frontmatter = $4, body = $5, rev = $6, mtime_ms = $7, size_bytes = $8, embedding = $9
389
- WHERE id = $1 AND rev = $10
390
- RETURNING id`, [cEntry.id, cEntry.scope, cEntry.slug, pgSafeJsonStringify(cEntry.frontmatter), cEntry.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(cEntry), "utf8"), embedding, currentRev]);
391
- if (res.rows.length === 0) {
392
- report.conflicts.push({ op: "update", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: await this.freshRev(patch.id, currentRev) });
255
+ WHERE id = $1 AND rev = $10 AND scope = $11 AND slug = $12
256
+ RETURNING id`, params);
257
+ if (res.rows.length > 0)
258
+ return { kind: "committed" };
259
+ const fresh = await this.freshRow(entry.id);
260
+ if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
261
+ return { kind: "moved" };
262
+ return { kind: "lost", conflict: { op: "update", id: entry.id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
263
+ }
264
+ async writeDelete({ id, currentRev, current, baseRev }, confirm) {
265
+ confirm();
266
+ const res = await this.query(`DELETE FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1 AND rev = $2 AND scope = $3 AND slug = $4 RETURNING id`, [id, currentRev, current.scope, current.slug]);
267
+ if (res.rows.length > 0)
268
+ return { kind: "committed" };
269
+ const fresh = await this.freshRow(id);
270
+ if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
271
+ return { kind: "moved" };
272
+ return { kind: "lost", conflict: { op: "delete", id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
273
+ }
274
+ async appendHistory(rows) {
275
+ if (!this.history)
393
276
  return;
277
+ try {
278
+ await this.history.appendHistory(rows);
279
+ }
280
+ catch (err) {
281
+ this.historyRowsLost += rows.length;
282
+ console.warn(`PgMemoryEngineBackend: best-effort history append failed (${rows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
394
283
  }
395
- report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
396
- if (this.history)
397
- historyRows.push({ id: entry.id, rev, prevRev: currentRev, op: "update", scope: entry.scope, snapshot: { ...entry, rev }, writtenAtMs: this.clock() });
398
- }
399
- async freshRev(id, fallback) {
400
- const res = await this.query(`SELECT rev FROM ${PG_MEMORY_ENGINE_TABLES.entry} WHERE id = $1`, [id]);
401
- return res.rows.length > 0 ? String(res.rows[0].rev) : fallback;
402
284
  }
403
285
  async getConsolidationCursor(scope) {
404
286
  const res = await this.query(`SELECT cursor FROM ${PG_MEMORY_ENGINE_TABLES.cursor} WHERE scope = $1`, [scope]);