@sema-agent/server 7.150.0 → 7.152.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 (514) hide show
  1. package/MIGRATION.md +451 -0
  2. package/README.md +15 -3
  3. package/README.zh-CN.md +10 -2
  4. package/USAGE.md +144 -87
  5. package/deploy/sema-up/README.md +11 -4
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  9. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  10. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  11. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  12. package/deploy/sema-up/chart/values.yaml +8 -1
  13. package/deploy/sema-up/cluster-up.sh +7 -6
  14. package/deploy/sema-up/kube-up.sh +6 -6
  15. package/deploy/sema-up/lib/flagshape.sh +36 -8
  16. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  17. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  18. package/deploy/sema-up/machines.example.yaml +3 -1
  19. package/deploy/sema-up/sema-up.sh +22 -16
  20. package/dist/adoption/import.js +3 -3
  21. package/dist/approval-ask-audit-store.d.ts +1 -1
  22. package/dist/approval-ask-machine.d.ts +4 -10
  23. package/dist/approval-ask-retention.d.ts +1 -1
  24. package/dist/approval-card.d.ts +12 -14
  25. package/dist/approval-gate-currency.d.ts +9 -9
  26. package/dist/approval-gate-currency.js +3 -4
  27. package/dist/approval-hmac.d.ts +17 -1
  28. package/dist/approval-hmac.js +7 -1
  29. package/dist/approval-queue-kind.d.ts +1 -1
  30. package/dist/approval.d.ts +2 -2
  31. package/dist/approval.js +2 -2
  32. package/dist/auth-bridge.d.ts +20 -0
  33. package/dist/auth-bridge.js +9 -0
  34. package/dist/background-session-reap.d.ts +1 -1
  35. package/dist/bake-runner/main.d.ts +4 -2
  36. package/dist/bind-host.d.ts +3 -6
  37. package/dist/bind-host.js +4 -7
  38. package/dist/boot/budget-tracing.js +1 -1
  39. package/dist/boot/coordinators.d.ts +1 -1
  40. package/dist/boot/coordinators.js +9 -10
  41. package/dist/boot/device-lane.js +2 -0
  42. package/dist/boot/engine-lease.d.ts +5 -0
  43. package/dist/boot/engine-lease.js +1 -0
  44. package/dist/boot/execution-env.d.ts +9 -14
  45. package/dist/boot/execution-env.js +85 -22
  46. package/dist/boot/execution-lane.js +32 -5
  47. package/dist/boot/late-binds.d.ts +8 -4
  48. package/dist/boot/late-binds.js +7 -1
  49. package/dist/boot/leader.d.ts +31 -30
  50. package/dist/boot/leader.js +38 -28
  51. package/dist/boot/leg-path-adjudication.d.ts +40 -0
  52. package/dist/boot/leg-path-adjudication.js +18 -0
  53. package/dist/boot/memory-consolidation.d.ts +3 -2
  54. package/dist/boot/memory-consolidation.js +6 -6
  55. package/dist/boot/parked-revive-gate.js +3 -15
  56. package/dist/boot/reapers.d.ts +6 -1
  57. package/dist/boot/reapers.js +13 -2
  58. package/dist/boot/resolve-spec.d.ts +3 -3
  59. package/dist/boot/resolve-spec.js +43 -48
  60. package/dist/boot/runner-deps.d.ts +46 -35
  61. package/dist/boot/runner-deps.js +94 -91
  62. package/dist/boot/session-age-out.d.ts +36 -0
  63. package/dist/boot/session-age-out.js +101 -0
  64. package/dist/boot/session-faces.d.ts +5 -14
  65. package/dist/boot/session-faces.js +9 -5
  66. package/dist/boot/shutdown.d.ts +6 -0
  67. package/dist/boot/shutdown.js +10 -4
  68. package/dist/boot/stage-01-config.js +2 -0
  69. package/dist/boot/stage-02-web-admin-pull.js +4 -5
  70. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  71. package/dist/boot/stage-05-execution-env.js +3 -2
  72. package/dist/boot/stage-06-runners.d.ts +9 -4
  73. package/dist/boot/stage-06-runners.js +24 -9
  74. package/dist/boot/stage-07-capability-layer.d.ts +8 -4
  75. package/dist/boot/stage-07-capability-layer.js +3 -2
  76. package/dist/boot/stage-08-reapers.d.ts +8 -4
  77. package/dist/boot/stage-08-reapers.js +4 -2
  78. package/dist/boot/stage-09-leader.d.ts +12 -5
  79. package/dist/boot/stage-09-leader.js +14 -5
  80. package/dist/boot/stage-10-http-server.d.ts +19 -5
  81. package/dist/boot/stage-10-http-server.js +14 -21
  82. package/dist/boot/stores.js +7 -4
  83. package/dist/boot/web-admin.js +5 -8
  84. package/dist/boot/workflow-orchestration.d.ts +7 -2
  85. package/dist/boot/workflow-orchestration.js +24 -7
  86. package/dist/bounded-rotation.d.ts +29 -0
  87. package/dist/bounded-rotation.js +24 -0
  88. package/dist/capabilities/approvals-push.d.ts +3 -3
  89. package/dist/capabilities/scenarios.d.ts +28 -13
  90. package/dist/capabilities/scenarios.js +2 -2
  91. package/dist/capability-facts.d.ts +43 -32
  92. package/dist/capability-facts.js +45 -51
  93. package/dist/card-rule-offers.d.ts +32 -0
  94. package/dist/card-rule-offers.js +130 -0
  95. package/dist/center-credential.d.ts +25 -6
  96. package/dist/center-credential.js +25 -5
  97. package/dist/config-catalog.d.ts +26 -7
  98. package/dist/config-catalog.js +26 -22
  99. package/dist/config-dir-trust.js +4 -2
  100. package/dist/config-invariants.d.ts +20 -8
  101. package/dist/config-invariants.js +55 -12
  102. package/dist/config-lkg.d.ts +5 -19
  103. package/dist/config-lkg.js +8 -62
  104. package/dist/config-provider.d.ts +1 -1
  105. package/dist/config-root-migration.d.ts +2 -2
  106. package/dist/config-types.d.ts +38 -42
  107. package/dist/config.d.ts +58 -7
  108. package/dist/config.js +90 -40
  109. package/dist/control-socket.d.ts +51 -0
  110. package/dist/control-socket.js +115 -0
  111. package/dist/deployment-governance.d.ts +2 -1
  112. package/dist/deployment-shape.d.ts +9 -1
  113. package/dist/deployment-shape.js +2 -1
  114. package/dist/device-protocol.d.ts +5 -4
  115. package/dist/device-protocol.js +1 -1
  116. package/dist/device-ws-hub.d.ts +7 -0
  117. package/dist/device-ws-hub.js +10 -3
  118. package/dist/device-ws-protocol.d.ts +63 -10
  119. package/dist/device-ws-protocol.js +56 -25
  120. package/dist/elicitation.js +2 -2
  121. package/dist/engine-identity.d.ts +19 -7
  122. package/dist/engine-identity.js +10 -2
  123. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  124. package/dist/entry-problems.d.ts +40 -3
  125. package/dist/entry-problems.js +3 -1
  126. package/dist/execution-env-refusal.d.ts +29 -0
  127. package/dist/execution-env-refusal.js +8 -0
  128. package/dist/execution-lane-caps.d.ts +3 -1
  129. package/dist/field-conflict.d.ts +1 -1
  130. package/dist/file-history-capture.d.ts +11 -4
  131. package/dist/file-history-capture.js +9 -6
  132. package/dist/file-history-disclosure.d.ts +7 -5
  133. package/dist/file-history-disclosure.js +7 -5
  134. package/dist/fleet/drain-entry.d.ts +4 -0
  135. package/dist/fleet/engine-signal.d.ts +12 -29
  136. package/dist/fleet/engine-signal.js +1 -7
  137. package/dist/fleet-client.js +2 -5
  138. package/dist/gate-settlement.d.ts +1 -8
  139. package/dist/gate-settlement.js +0 -4
  140. package/dist/history-anchor.js +1 -1
  141. package/dist/hitl-delivery.d.ts +2 -3
  142. package/dist/hitl-delivery.js +0 -2
  143. package/dist/hooks/hook-llm.js +4 -2
  144. package/dist/hooks/hook-runner.d.ts +3 -2
  145. package/dist/hooks/hook-runner.js +18 -3
  146. package/dist/host-decision.d.ts +11 -11
  147. package/dist/host-lsp-manager.d.ts +2 -2
  148. package/dist/http/active-run-conflict.d.ts +35 -2
  149. package/dist/http/active-run-conflict.js +48 -19
  150. package/dist/http/admission.js +17 -2
  151. package/dist/http/approval-sweeps.d.ts +1 -1
  152. package/dist/http/approval-sweeps.js +10 -7
  153. package/dist/http/checkpoint-ctx.d.ts +4 -0
  154. package/dist/http/checkpoint-ctx.js +2 -0
  155. package/dist/http/dispatch.d.ts +8 -3
  156. package/dist/http/dispatch.js +59 -32
  157. package/dist/http/durable-run-leg.js +16 -17
  158. package/dist/http/health-reader.d.ts +16 -9
  159. package/dist/http/health-reader.js +2 -1
  160. package/dist/http/health-self-report.d.ts +9 -1
  161. package/dist/http/health-self-report.js +3 -1
  162. package/dist/http/owner-access.d.ts +33 -14
  163. package/dist/http/owner-access.js +40 -10
  164. package/dist/http/principal-gate.d.ts +49 -21
  165. package/dist/http/principal-gate.js +61 -11
  166. package/dist/http/request-channel.d.ts +23 -0
  167. package/dist/http/request-channel.js +9 -0
  168. package/dist/http/request-guards.js +17 -2
  169. package/dist/http/resume-ctx-read.js +42 -3
  170. package/dist/http/resume-legs.d.ts +4 -3
  171. package/dist/http/resume-legs.js +367 -117
  172. package/dist/http/route-ctx.d.ts +91 -15
  173. package/dist/http/route-ctx.js +17 -0
  174. package/dist/http/route-table.d.ts +5 -1
  175. package/dist/http/route-table.js +4 -0
  176. package/dist/http/routes/admin-config-refresh.js +3 -3
  177. package/dist/http/routes/admin-drain.d.ts +3 -0
  178. package/dist/http/routes/admin-drain.js +7 -7
  179. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  180. package/dist/http/routes/admin-memory-optout.js +3 -3
  181. package/dist/http/routes/adoption.js +3 -5
  182. package/dist/http/routes/agents-roster.js +2 -3
  183. package/dist/http/routes/approvals-assistant.d.ts +2 -1
  184. package/dist/http/routes/approvals-assistant.js +99 -51
  185. package/dist/http/routes/background.d.ts +3 -3
  186. package/dist/http/routes/capabilities.d.ts +4 -0
  187. package/dist/http/routes/capabilities.js +38 -10
  188. package/dist/http/routes/config-catalog.js +2 -2
  189. package/dist/http/routes/devices.js +1 -1
  190. package/dist/http/routes/diagnostics.d.ts +3 -3
  191. package/dist/http/routes/diagnostics.js +19 -7
  192. package/dist/http/routes/fleet.js +10 -8
  193. package/dist/http/routes/images.js +10 -10
  194. package/dist/http/routes/memory-bundle.js +3 -3
  195. package/dist/http/routes/memory-compliance.js +3 -3
  196. package/dist/http/routes/memory-consolidation.js +2 -2
  197. package/dist/http/routes/memory-origin.js +3 -3
  198. package/dist/http/routes/memory-policy.js +2 -2
  199. package/dist/http/routes/observability.js +3 -3
  200. package/dist/http/routes/projects.d.ts +3 -2
  201. package/dist/http/routes/projects.js +4 -5
  202. package/dist/http/routes/retention-ops.js +3 -3
  203. package/dist/http/routes/rules.js +5 -5
  204. package/dist/http/routes/run-permission-mode.d.ts +2 -1
  205. package/dist/http/routes/run-permission-mode.js +2 -2
  206. package/dist/http/routes/runs.d.ts +4 -9
  207. package/dist/http/routes/runs.js +171 -65
  208. package/dist/http/routes/session-sync.d.ts +22 -9
  209. package/dist/http/routes/session-sync.js +204 -107
  210. package/dist/http/routes/sessions-list.js +13 -7
  211. package/dist/http/routes/sessions.js +30 -15
  212. package/dist/http/routes/tasks.js +46 -41
  213. package/dist/http/routes/trace-usage.js +2 -2
  214. package/dist/http/routes/workflows.js +1 -1
  215. package/dist/http/server.d.ts +30 -30
  216. package/dist/http/server.js +16 -4
  217. package/dist/http/submit-ctx.d.ts +1 -1
  218. package/dist/http/submit-ctx.js +7 -4
  219. package/dist/http/wire-types.d.ts +14 -4
  220. package/dist/human-facing-args.d.ts +33 -0
  221. package/dist/human-facing-args.js +33 -0
  222. package/dist/identity-source.d.ts +20 -3
  223. package/dist/identity-source.js +14 -0
  224. package/dist/index.d.ts +5 -1
  225. package/dist/k8s-api-credentials.d.ts +29 -0
  226. package/dist/k8s-api-credentials.js +25 -0
  227. package/dist/lane-home-probe.d.ts +3 -7
  228. package/dist/lane-home-probe.js +2 -2
  229. package/dist/leader/diffup.d.ts +19 -0
  230. package/dist/leader/diffup.js +7 -0
  231. package/dist/leader/leader.d.ts +116 -11
  232. package/dist/leader/leader.js +69 -5
  233. package/dist/leader/repair-wire.js +2 -2
  234. package/dist/leader/run-entry.d.ts +2 -1
  235. package/dist/leader/run-entry.js +1 -1
  236. package/dist/leader/wire.d.ts +42 -132
  237. package/dist/leader/wire.js +81 -67
  238. package/dist/leg-facts.d.ts +13 -5
  239. package/dist/leg-facts.js +2 -1
  240. package/dist/memory-scope.d.ts +23 -11
  241. package/dist/memory-scope.js +18 -6
  242. package/dist/memory-sync-client.d.ts +30 -2
  243. package/dist/memory-sync-client.js +16 -9
  244. package/dist/model-entry-headers.d.ts +9 -10
  245. package/dist/model-entry-headers.js +0 -4
  246. package/dist/model-entry-refusal.d.ts +7 -4
  247. package/dist/model-entry-refusal.js +11 -5
  248. package/dist/model-plane-face.d.ts +1 -1
  249. package/dist/model-plane-face.js +3 -1
  250. package/dist/model-route-endpoint.d.ts +13 -7
  251. package/dist/model-route-endpoint.js +14 -11
  252. package/dist/model-select.d.ts +22 -0
  253. package/dist/model-select.js +9 -0
  254. package/dist/model-unreachable-notice.d.ts +11 -0
  255. package/dist/model-unreachable-notice.js +4 -4
  256. package/dist/object-store-buckets.d.ts +640 -6
  257. package/dist/object-store-buckets.js +166 -0
  258. package/dist/observability/err-text.d.ts +7 -0
  259. package/dist/observability/err-text.js +5 -0
  260. package/dist/observability/fail-open.d.ts +25 -17
  261. package/dist/observability/fail-open.js +25 -17
  262. package/dist/observability/logger.js +3 -1
  263. package/dist/observability/metrics.js +1 -0
  264. package/dist/operator-roster.d.ts +68 -0
  265. package/dist/operator-roster.js +32 -0
  266. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  267. package/dist/orchestration/workflow-notify-journal.js +12 -1
  268. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  269. package/dist/orchestration/workflow-park-decision.js +49 -10
  270. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  271. package/dist/orchestration/workflow-park-holder.js +98 -0
  272. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  273. package/dist/orchestration/workflow-record-fence.js +42 -0
  274. package/dist/outbound-dispatcher.d.ts +71 -8
  275. package/dist/outbound-dispatcher.js +48 -7
  276. package/dist/owner-faces.d.ts +2 -2
  277. package/dist/parked-decide.d.ts +106 -55
  278. package/dist/parked-decide.js +153 -117
  279. package/dist/peer-directory.d.ts +2 -2
  280. package/dist/peer-inbound-face.d.ts +2 -6
  281. package/dist/peer-inbound-face.js +0 -3
  282. package/dist/permission-mode-admission.d.ts +74 -5
  283. package/dist/permission-mode-admission.js +56 -3
  284. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  285. package/dist/plugins/adoption-log-sql.js +7 -1
  286. package/dist/plugins/approval-ask-store-file.d.ts +14 -2
  287. package/dist/plugins/approval-ask-store-file.js +11 -0
  288. package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
  289. package/dist/plugins/approval-ask-store-memory.js +35 -10
  290. package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
  291. package/dist/plugins/approval-ask-store-sql.js +45 -5
  292. package/dist/plugins/approval-exemption-store.js +3 -0
  293. package/dist/plugins/approval-nonce-store.js +2 -0
  294. package/dist/plugins/blob-backend.d.ts +83 -7
  295. package/dist/plugins/blob-backend.js +57 -6
  296. package/dist/plugins/breaker-state-sql.js +2 -0
  297. package/dist/plugins/caching-session-store.d.ts +9 -15
  298. package/dist/plugins/caching-session-store.js +6 -0
  299. package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
  300. package/dist/plugins/checkpoint-index-columns.js +3 -6
  301. package/dist/plugins/checkpoint-store-face.d.ts +119 -61
  302. package/dist/plugins/checkpoint-store-face.js +134 -55
  303. package/dist/plugins/device-store-sql.js +6 -0
  304. package/dist/plugins/error-origin.d.ts +18 -0
  305. package/dist/plugins/error-origin.js +10 -0
  306. package/dist/plugins/execution-placement-sql.js +6 -6
  307. package/dist/plugins/image-bake-store-sql.js +6 -0
  308. package/dist/plugins/image-index-sql.js +4 -0
  309. package/dist/plugins/landed-attendants.d.ts +212 -0
  310. package/dist/plugins/landed-attendants.js +161 -0
  311. package/dist/plugins/leader-run-store-sql.js +4 -0
  312. package/dist/plugins/local-checkpoint-store.d.ts +13 -3
  313. package/dist/plugins/local-checkpoint-store.js +38 -49
  314. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  315. package/dist/plugins/local-session-live-reference.js +39 -0
  316. package/dist/plugins/local-session-store.d.ts +71 -33
  317. package/dist/plugins/local-session-store.js +129 -27
  318. package/dist/plugins/memory-engine-pg.js +4 -0
  319. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  320. package/dist/plugins/memory-engine-tidb.js +4 -0
  321. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  322. package/dist/plugins/memory-sync-store-pg.js +5 -0
  323. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  324. package/dist/plugins/one-time-migrations.d.ts +104 -80
  325. package/dist/plugins/one-time-migrations.js +226 -132
  326. package/dist/plugins/org-delivery-quota-store.js +4 -1
  327. package/dist/plugins/outcome-ledger-sql.js +2 -0
  328. package/dist/plugins/permission-rule-store-sql.js +11 -4
  329. package/dist/plugins/pg-cost-quota.js +4 -0
  330. package/dist/plugins/pg-pool.js +35 -10
  331. package/dist/plugins/pg-rate-limiter.js +2 -0
  332. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  333. package/dist/plugins/posix-shell-fs.js +4 -1
  334. package/dist/plugins/remote-env-adb.d.ts +19 -15
  335. package/dist/plugins/remote-env-adb.js +41 -15
  336. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  337. package/dist/plugins/remote-env-connect-seat.js +72 -0
  338. package/dist/plugins/remote-env-device.d.ts +22 -5
  339. package/dist/plugins/remote-env-device.js +106 -8
  340. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  341. package/dist/plugins/remote-env-e2b.js +42 -32
  342. package/dist/plugins/remote-env-file-error.js +6 -2
  343. package/dist/plugins/remote-env-host.d.ts +46 -10
  344. package/dist/plugins/remote-env-host.js +124 -52
  345. package/dist/plugins/remote-env-k8s.d.ts +109 -41
  346. package/dist/plugins/remote-env-k8s.js +160 -54
  347. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  348. package/dist/plugins/remote-env-local-docker.js +34 -41
  349. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  350. package/dist/plugins/remote-env-ssh.js +60 -59
  351. package/dist/plugins/remote-shell.d.ts +98 -1
  352. package/dist/plugins/remote-shell.js +218 -0
  353. package/dist/plugins/replica-registration.d.ts +1 -1
  354. package/dist/plugins/replica-registration.js +1 -1
  355. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  356. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  357. package/dist/plugins/retention-lane-store-sql.js +4 -0
  358. package/dist/plugins/retention-sql.d.ts +20 -2
  359. package/dist/plugins/retention-sql.js +11 -0
  360. package/dist/plugins/run-store-sql.d.ts +21 -2
  361. package/dist/plugins/run-store-sql.js +31 -7
  362. package/dist/plugins/s3-presign.d.ts +23 -0
  363. package/dist/plugins/s3-presign.js +37 -3
  364. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  365. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  366. package/dist/plugins/scheduler-support.d.ts +2 -2
  367. package/dist/plugins/scheduler-support.js +0 -3
  368. package/dist/plugins/schema-consistency.d.ts +4 -2
  369. package/dist/plugins/schema-consistency.js +19 -2
  370. package/dist/plugins/schema-indexes.js +2 -0
  371. package/dist/plugins/send-file-ledger.d.ts +2 -2
  372. package/dist/plugins/send-file-ledger.js +5 -2
  373. package/dist/plugins/send-user-file.d.ts +3 -4
  374. package/dist/plugins/send-user-file.js +56 -52
  375. package/dist/plugins/serving-requirement.d.ts +26 -7
  376. package/dist/plugins/serving-requirement.js +11 -4
  377. package/dist/plugins/session-birth.d.ts +6 -2
  378. package/dist/plugins/session-blob-claim-token.d.ts +15 -0
  379. package/dist/plugins/session-blob-claim-token.js +20 -0
  380. package/dist/plugins/session-blob-namespace.d.ts +46 -0
  381. package/dist/plugins/session-blob-namespace.js +116 -0
  382. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  383. package/dist/plugins/session-ext-table.d.ts +14 -1
  384. package/dist/plugins/session-ext-table.js +5 -1
  385. package/dist/plugins/session-row-sql.d.ts +49 -2
  386. package/dist/plugins/session-row-sql.js +56 -13
  387. package/dist/plugins/session-store-sql.d.ts +34 -18
  388. package/dist/plugins/session-store-sql.js +98 -17
  389. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  390. package/dist/plugins/shared-memory-store-sql.js +6 -2
  391. package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
  392. package/dist/plugins/snapshot-bucket-presence.js +8 -2
  393. package/dist/plugins/sql-driver.d.ts +2 -1
  394. package/dist/plugins/sql-driver.js +18 -3
  395. package/dist/plugins/sql-errors.d.ts +11 -6
  396. package/dist/plugins/sql-errors.js +5 -6
  397. package/dist/plugins/sql-json-column.d.ts +1 -1
  398. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  399. package/dist/plugins/stop-then-start-sentence.js +14 -10
  400. package/dist/plugins/stop-then-start.d.ts +109 -0
  401. package/dist/plugins/stop-then-start.js +104 -0
  402. package/dist/plugins/store-backend.d.ts +84 -15
  403. package/dist/plugins/store-backend.js +236 -72
  404. package/dist/plugins/store-boundary.d.ts +57 -0
  405. package/dist/plugins/store-boundary.js +139 -0
  406. package/dist/plugins/store-contracts.d.ts +17 -0
  407. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  408. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  409. package/dist/plugins/store-fault.d.ts +26 -7
  410. package/dist/plugins/store-fault.js +18 -2
  411. package/dist/plugins/task-attachment-store.d.ts +2 -1
  412. package/dist/plugins/task-attachment-store.js +14 -1
  413. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  414. package/dist/plugins/task-list-store-sql.js +10 -8
  415. package/dist/plugins/tidb-cost-quota.js +4 -0
  416. package/dist/plugins/tidb-pool.js +21 -25
  417. package/dist/plugins/tidb-rate-limiter.js +4 -0
  418. package/dist/plugins/user-input-ledger-sql.js +4 -0
  419. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  420. package/dist/plugins/workflow-run-store-sql.js +64 -4
  421. package/dist/plugins/workspace-custody.d.ts +4 -3
  422. package/dist/plugins/workspace-fill.d.ts +4 -7
  423. package/dist/plugins/workspace-fill.js +2 -1
  424. package/dist/plugins/write-behind-counter.js +5 -0
  425. package/dist/project-context.d.ts +0 -2
  426. package/dist/project-context.js +4 -8
  427. package/dist/project-registry.d.ts +46 -0
  428. package/dist/project-registry.js +44 -0
  429. package/dist/question.d.ts +2 -1
  430. package/dist/question.js +5 -13
  431. package/dist/request-form.d.ts +6 -1
  432. package/dist/request-form.js +4 -1
  433. package/dist/request-key-closure.js +1 -1
  434. package/dist/request-value-closure.d.ts +4 -0
  435. package/dist/request-value-closure.js +10 -0
  436. package/dist/rule-issue-reading.d.ts +1 -1
  437. package/dist/rules-consent.d.ts +1 -1
  438. package/dist/run-acceptance.d.ts +3 -2
  439. package/dist/run-acceptance.js +4 -6
  440. package/dist/run-local.js +9 -9
  441. package/dist/runs.d.ts +54 -16
  442. package/dist/runs.js +67 -13
  443. package/dist/runtime-governance.d.ts +5 -4
  444. package/dist/security.d.ts +30 -32
  445. package/dist/security.js +41 -7
  446. package/dist/sema-config-dir.d.ts +2 -1
  447. package/dist/server-secret-env.d.ts +12 -10
  448. package/dist/server-secret-env.js +24 -15
  449. package/dist/session-bindings.d.ts +82 -0
  450. package/dist/session-bindings.js +18 -0
  451. package/dist/session-children-retire.d.ts +2 -2
  452. package/dist/session-children-retire.js +2 -6
  453. package/dist/session-deletion.d.ts +16 -1
  454. package/dist/session-error-wire.d.ts +3 -3
  455. package/dist/session-error-wire.js +3 -3
  456. package/dist/session-incarnation.d.ts +10 -0
  457. package/dist/session-incarnation.js +10 -1
  458. package/dist/session-kind.d.ts +57 -0
  459. package/dist/session-kind.js +22 -0
  460. package/dist/session-row.d.ts +21 -1
  461. package/dist/session-row.js +7 -1
  462. package/dist/session-sync-kernel.d.ts +24 -14
  463. package/dist/session-sync-kernel.js +3 -6
  464. package/dist/session-sync.d.ts +25 -103
  465. package/dist/session-sync.js +14 -76
  466. package/dist/session-titler.d.ts +10 -3
  467. package/dist/session-titler.js +19 -6
  468. package/dist/ssh-host-key.d.ts +5 -0
  469. package/dist/ssh-host-key.js +3 -0
  470. package/dist/stores-sql/blob-index-sql.d.ts +30 -9
  471. package/dist/stores-sql/blob-index-sql.js +40 -21
  472. package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
  473. package/dist/stores-sql/checkpoint-store-sql.js +70 -146
  474. package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
  475. package/dist/stores-sql/file-history-store-sql.js +205 -95
  476. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  477. package/dist/stores-sql/pg-session-storage.js +37 -13
  478. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  479. package/dist/stores-sql/retention-store-sql.js +5 -19
  480. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  481. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  482. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  483. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  484. package/dist/stores-sql/tidb-session-store.js +37 -13
  485. package/dist/submission-exit.d.ts +3 -2
  486. package/dist/submission-exit.js +9 -1
  487. package/dist/task-cwd.d.ts +2 -2
  488. package/dist/task-settings.d.ts +7 -5
  489. package/dist/task-settings.js +3 -3
  490. package/dist/terminal.d.ts +33 -2
  491. package/dist/terminal.js +139 -9
  492. package/dist/tool-approval.d.ts +465 -507
  493. package/dist/tool-approval.js +606 -1222
  494. package/dist/trace/core-keyset-guard.d.ts +1 -1
  495. package/dist/trace/ledger-events.d.ts +3 -3
  496. package/dist/trace/project.d.ts +2 -3
  497. package/dist/trace/redact.js +3 -2
  498. package/dist/trace/self-minted-wire.d.ts +571 -178
  499. package/dist/trace/self-minted-wire.js +189 -56
  500. package/dist/web-admin-client/apply-effective.js +2 -2
  501. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  502. package/dist/web-admin-client/read-warnings.js +1 -1
  503. package/dist/web-admin-client/types.d.ts +1 -1
  504. package/dist/workspace-space.d.ts +10 -4
  505. package/dist/workspace-space.js +4 -1
  506. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
  507. package/package.json +7 -3
  508. package/scripts/embed-minimal.mjs +3 -3
  509. package/wire-changes/server@7.151.0.json +762 -0
  510. package/wire-changes/server@7.152.0.json +900 -0
  511. package/dist/config-d-migration.d.ts +0 -37
  512. package/dist/config-d-migration.js +0 -60
  513. package/dist/http/session-inherit-env.d.ts +0 -36
  514. package/dist/http/session-inherit-env.js +0 -6
@@ -5,6 +5,8 @@ import { dialectProtocolJsonEncoder } from "./sql-driver.js";
5
5
  import { SCHEMA_STATEMENTS, acquireEnsureSchemaLock, releaseEnsureSchemaLock } from "./tidb-pool.js";
6
6
  import { PG_SCHEMA_STATEMENTS, acquirePgEnsureSchemaLock, releasePgEnsureSchemaLock } from "./pg-pool.js";
7
7
  import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, isJsonColumnBodyProblem, jsonColumnText, jsonColumnTextExpr, readOpaqueJsonValueColumn, } from "./sql-json-column.js";
8
+ import { rewrittenBackgroundRecordM53, rewrittenToolEndDataM53 } from "./store-fault-sentence-m53.js";
9
+ import { pgSafeJsonStringify } from "./pg-safe-json.js";
8
10
  import { incarnationFromCell, sessionFaceFromRow } from "../session-incarnation.js";
9
11
  import { StoreBootRefusalError } from "./store-contracts.js";
10
12
  import { decodeRunResultCellM44 } from "./run-store-sql.js";
@@ -31,8 +33,9 @@ import { IDENTITY_COLUMN_NAME, SCENARIO_PREFIX_LIKE, SCENARIO_PREFIX_MARKER_ID,
31
33
  import { MIGRATION_MARKER_TABLE, SKILL_EXEMPTION_CUTOFF_ID, markIfAbsentSql, migrationMarkerDdl } from "./one-time-migration-marker.js";
32
34
  import { describeUpgradeDriftTail, expectedTableShapes } from "./schema-consistency.js";
33
35
  import { olderReplicaEvidenceSentence, stopThenStartAction } from "./stop-then-start-sentence.js";
34
- import { buildThisReplicaRegistration, knowsCapability, readReplicaRegistrations, registerReplica } from "./replica-registration.js";
35
- import { assertReplicaTablesPresent, assertServingRequirementsMet } from "./serving-requirement.js";
36
+ import { buildThisReplicaRegistration, registerReplica } from "./replica-registration.js";
37
+ import { assertReplicaTablesPresent, assertServingRequirementsMet, recordServingRequirement } from "./serving-requirement.js";
38
+ import { assertStopThenStartDeclarations, guardOwedStopThenStart, readOlderReplicaEvidence } from "./stop-then-start.js";
36
39
  const RETIRED_SESSION_RULE_BUCKETS = ["commandAllow", "commandDeny"];
37
40
  export function buildMigrationReceipts() {
38
41
  return {
@@ -67,6 +70,8 @@ export function buildMigrationReceipts() {
67
70
  scenarioPrefixSourcesScanned: 0,
68
71
  withdrawMarkWritten: 0,
69
72
  sessionDeletingSwitchMarked: 0,
73
+ storeFaultSentencesRewritten: 0,
74
+ checkpointDisplayColumnsDropped: 0,
70
75
  runErrorCodeColumnRewritten: 0,
71
76
  runObjectivePreviewRewritten: 0,
72
77
  shellSentinelOwnersCleared: 0,
@@ -129,6 +134,8 @@ function changedAnything(r) {
129
134
  r.sessionMetaColumnsDropped > 0 ||
130
135
  r.withdrawMarkWritten > 0 ||
131
136
  r.sessionDeletingSwitchMarked > 0 ||
137
+ r.storeFaultSentencesRewritten > 0 ||
138
+ r.checkpointDisplayColumnsDropped > 0 ||
132
139
  r.runErrorCodeColumnRewritten > 0 ||
133
140
  r.runObjectivePreviewRewritten > 0 ||
134
141
  r.shellSentinelOwnersCleared > 0 ||
@@ -198,45 +205,9 @@ const RETIRED_SESSION_RULES_COLUMN = "rules";
198
205
  const OLD_GRAMMAR_SESSION_RULES_COLUMN = "rule_entries_old_grammar";
199
206
  const RETIRED_ASK_CAUSE_COLUMN = "denied_reason";
200
207
  const ASK_EXECUTION_LANE_COLUMN = "execution_lane";
208
+ const RETIRED_CHECKPOINT_DISPLAY_COLUMNS = ["tool_name", "tool_input", "risk_descriptor", "rule_suggestions", "has_bidi_controls"];
209
+ const CHECKPOINT_DISPLAY_COLUMNS_DROP_M54 = { kind: "drop", table: "checkpoint", columns: RETIRED_CHECKPOINT_DISPLAY_COLUMNS };
201
210
  export const ONE_TIME_MIGRATIONS = [
202
- {
203
- id: "M13",
204
- introducedIn: "7.123.0",
205
- releasedOn: "2026-10-10",
206
- removableAfter: "2026-11-09",
207
- removal: "删 `config-lkg.ts` 的 formatVersion 2 读回迁移:`migrateV2Lkg` / `migrateDroppedIdentityRow` / `RETIRED_CATALOG_COORDINATE` 与其上的窗注;`loadLkg` 的 2 臂" +
208
- "(版本判据里的 `2` 与 `formatVersion === 2 ? migrateV2Lkg(…)` 那一支 —— 2 回到「unknown formatVersion」拒)、返回型的 `migrated` 位与 JSDoc 里说它的那一行、" +
209
- "文件头注「2 读回时一次性迁移」那一句;`boot/web-admin.ts` 读 `read.migrated` 打 `config_lkg_migrated` 的那一行(这一行与 M15 / M22 的读回迁移共用 —— 三条都删完才整段删,先删 M13 时只去掉信封 2 → 3 那一路的 `migrated` 来源);契约 §A.1d " +
210
- "`droppedEntries` 一节「升级窗(如实)」那一条与 §A.1d `[config.model_refused_name_minted]` 那一条里「LKG 载体 `droppedIdentities` 读回时一次性迁移」那半句;手写 formatVersion 2 信封的测试夹具" +
211
- "(`test/config-lkg.test.ts`、`test/config-hot/batch1-version-ordinal.test.ts` 改写成 3;`test/models-dropped-entries-s1295.test.ts` 的旧 LKG 迁移格改钉 2 读回不可用)",
212
- afterRemoval: "既有响亮臂 `config_lkg_unusable`(`loadLkg` 对 2 答「unknown formatVersion 2」):2 读回 ⇒ 不可用,中心可达照拉(整拉,读腿铸出完整载体,新 LKG 按 3 覆盖)、" +
213
- "断着则 env 兜底,下一份干净候选重写 —— 与回滚到 7.122.0 读 3 同一种处置",
214
- reportKeys: [],
215
- },
216
- {
217
- id: "M15",
218
- introducedIn: "7.124.0",
219
- releasedOn: "2026-10-11",
220
- removableAfter: "2026-11-10",
221
- removal: "删 `config-lkg.ts` 的载荷迁移:`migrateLkgPayload` 与其上的窗注、`loadLkg` 里调它的那一段(载荷照旧过 `lkgPayloadJudged`)、`LkgReadMigration.receipts`" +
222
- "(信封 2 → 3 的 M13 若已先删,`LkgReadMigration` 与 `migrated` 位一并删)、对 `@sema-agent/settings-schema/one-time-migrations` 的 import;`loadLkg` 的版本判据收成" +
223
- "只认 4(3 回到「unknown formatVersion」拒);`boot/web-admin.ts` 读回后按 4 写回的那一段;文件头注 formatVersion 4 一段里「每次读回都过迁移」那一句;" +
224
- "`test/ss11-stored-migrations.test.ts` 的 M15 组(4 原样读回那一格留)",
225
- afterRemoval: "既有响亮臂 `config_lkg_unusable`(`loadLkg` 对 3 答「unknown formatVersion 3」):旧载荷的 LKG 读回 ⇒ 不可用,中心可达照拉(整拉,新 LKG 按 4 覆盖)、" +
226
- "断着则 env 兜底 —— 与回滚到 7.123.0 读 4 同一种处置",
227
- reportKeys: [],
228
- },
229
- {
230
- id: "M16",
231
- introducedIn: "7.124.0",
232
- releasedOn: "2026-10-11",
233
- removableAfter: "2026-11-10",
234
- removal: "删 `config-d-migration.ts` 整只文件与两个入口的调用(`boot/web-admin.ts` 建本地配置源之后、`run-local.ts` 建配置源之后各一行 + import);" +
235
- "`test/ss11-stored-migrations.test.ts` 的 M16 组;部署文档里「起服自动迁 config.d」那一句(运维仍可手跑契约命令行,直到契约删族)",
236
- afterRemoval: "契约读腿的墓碑(永久):config.d 里还带旧形的域文档 —— `runtime.json` 带事实 ⇒ `RetiredDomainError` 整份读不出;`atModelAllowlist` / `models.default` ⇒ " +
237
- "models 域降级、rosters 整份读不出 —— 拒句点名迁移 id;出路是运维手跑契约命令行(契约删族之后只剩手改)",
238
- reportKeys: [],
239
- },
240
211
  {
241
212
  id: "M17",
242
213
  introducedIn: "7.129.0",
@@ -253,6 +224,7 @@ export const ONE_TIME_MIGRATIONS = [
253
224
  "`config.schema_mismatch`(缺 `rule_entries`、多那一列)—— " +
254
225
  "出路是先在一只带本条的版本上起服一次;② 行里仍带退役命令桶:SQL 店读回照旧答 `corrupt`(引擎的形读法点名那只桶,与本条在场时同一个结局),只是起服日志不再逐行点名 —— " +
255
226
  "运维在库里把那一行改写成引擎文法或删掉它(删会话即删规则);③ 跳过本条直接升的库同样没有改名那一拍的条目判读 —— 由 ① 的拒启接住(出路同 ①)",
227
+ stopThenStart: null,
256
228
  reportKeys: ["sessionRuleColumn", "sessionRuleRowsWithRetiredBuckets", "sessionRuleRowsWithOldGrammarEntries", "sessionRuleRowsWithUnreadableDeny"],
257
229
  shapeChanges: [{ kind: "rename", table: SESSION_POLICY_TABLE, from: [RETIRED_SESSION_RULES_COLUMN, OLD_GRAMMAR_SESSION_RULES_COLUMN], to: SESSION_RULES_COLUMN.name }],
258
230
  },
@@ -271,6 +243,7 @@ export const ONE_TIME_MIGRATIONS = [
271
243
  "幂等重入走 park、回决口按要人;仍带它们的待决停驻行(把 `APPROVAL_TERMINAL_BACKSTOP_MS` 调长的部署、local 车道引擎 File 店里窗关仍未决的 —— 停驻行从来不由本服务改写," +
272
244
  "窗内靠读侧改写读,窗关后读侧改写删)由本服务的读面按坏行处置:运维队列行缺那一位 + `server.approval-card.closed-word-out-of-set` 计数、耐久 `/decide` 的 remember 按强制(只放行这一次)。" +
273
245
  "引擎续跑不受影响:续跑入口读行摘要、不按今日闭集重判停驻行上的这两座,行字节引擎怎么写的还是怎么在",
246
+ stopThenStart: null,
274
247
  reportKeys: ["retiredCardWordAskRowsRewritten", "retiredCardWordRowsUnreadable"],
275
248
  },
276
249
  {
@@ -298,6 +271,7 @@ export const ONE_TIME_MIGRATIONS = [
298
271
  "批准后撞 `resume.tool_unavailable`(拒绝照常可出)—— 出路是拒绝那张卡,用改好的 `toolAxes` 重新提交。会撞上它的是活过窗的升级前停驻行:发布后才升级的部署、" +
299
272
  "调长了 `APPROVAL_TERMINAL_BACKSTOP_MS` 的部署、滚动升级里旧副本在窗内新写的行(头注 M19 段)。A2A 一面同:存量体里 `a2aPeers[].toolAxes` 判不过的对端续跑整条不挂," +
300
273
  "运维 warn `a2a_injection_dropped` 点名,停驻在它 skill 上的审批批准后撞 `resume.tool_unavailable` —— 出路同上:拒绝那张卡,改好声明重新提交",
274
+ stopThenStart: null,
301
275
  reportKeys: [],
302
276
  },
303
277
  {
@@ -315,6 +289,7 @@ export const ONE_TIME_MIGRATIONS = [
315
289
  afterRemoval: "没有新的臂,接住它的是今天的读法(删码零行为变化:窗关那一刻起重读臂已经不生效):升级前存下的请求体里带这两形的 `settings.hooks`,在会采纳 hooks 的车道上续跑被拒 —— " +
316
290
  "「请求成员读不出」判据(`src/unread-request-members.ts`)答 409 `resume_blocked_by_policy`(`blockedBy: request.field_invalid`,`field: settings.hooks`),卡仍待决、行不动(7.147.0 起;此前是整份不采纳照跑)—— " +
317
291
  "出路是取消这类停驻任务、删掉那个未知字段 / `__proto__` 键后重新提交。会撞上它的是活过窗的升级前停驻行:发布后才升级的部署、调长了 `APPROVAL_TERMINAL_BACKSTOP_MS` 的部署、滚动升级里旧副本在窗内新写的行(头注 M20 段)",
292
+ stopThenStart: null,
318
293
  reportKeys: [],
319
294
  },
320
295
  {
@@ -330,6 +305,7 @@ export const ONE_TIME_MIGRATIONS = [
330
305
  "队列行不带卡词(壳显示通用审批卡),到期走 SLA 拒扫腿(模型读到「拒」),决断口仍按工具名认问答(`approve` 必须带 `answer`,否则 400);出路 = 升级前答完或拒掉;" +
331
306
  "② `gate_kind` 为 NULL 的停驻行:既有响亮臂 —— 运维待批队列(`listPending`)不列它、计 `server.approvals.queue-row-gate-kind-missing`(决断口按门型绑定取行,本来就不认它);" +
332
307
  "出路是运维把那一行置 expired 或删掉会话(终局收割照旧在 `terminal_at_ms` 收它)",
308
+ stopThenStart: null,
333
309
  reportKeys: ["parkedQuestionCardsWritten", "parkedQuestionRowsLeftAsWritten", "parkedRowGateKindsBackfilled", "parkedRowsUnresumableExpired"],
334
310
  },
335
311
  {
@@ -337,11 +313,12 @@ export const ONE_TIME_MIGRATIONS = [
337
313
  introducedIn: "7.132.0",
338
314
  releasedOn: "2026-10-18",
339
315
  removableAfter: "2026-11-17",
340
- removal: "删 `config-lkg.ts` 的 formatVersion 4 读回迁移:`migrateV4Lkg` 与其上的窗注;`loadLkg` 里调它的那一支(`formatVersion !== 5` 那一段)与版本判据里的 `4`" +
341
- "(4 回到「unknown formatVersion」拒;若 M13 / M15 仍在窗内,先删到期的那几条再删本条,版本判据收成只认 5)、`LkgReadMigration.fromFormat` 的 `4`;" +
316
+ removal: "删 `config-lkg.ts` 的 formatVersion 4 读回迁移:`migrateV4Lkg` 与其上的窗注;`loadLkg` 里调它的那一支(`formatVersion === 4` 那一段)与版本判据里的 `4`" +
317
+ "(4 回到「unknown formatVersion」拒,版本判据收成只认 5)、`LkgReadMigration` 与 `loadLkg` 返回型的 `migrated` 位(它只服务这一条)、`boot/web-admin.ts` 打 `config_lkg_migrated` 并按当期信封写回的那一段;" +
342
318
  "文件头注 formatVersion 5 一段里「4 的载荷 …」那两句;`test/center-artifact-v3-lane.test.ts` 的两格 4 读回(5 原样读回那一格留)",
343
319
  afterRemoval: "既有响亮臂 `config_lkg_unusable`(`loadLkg` 对 4 答「unknown formatVersion 4」):4 读回 ⇒ 不可用,中心可达照拉(整拉,新 LKG 按 5 覆盖)、断着则 env 兜底 —— " +
344
320
  "与回滚到 7.131.x 读 5 同一种处置",
321
+ stopThenStart: null,
345
322
  reportKeys: [],
346
323
  },
347
324
  {
@@ -360,6 +337,7 @@ export const ONE_TIME_MIGRATIONS = [
360
337
  "其余调用方答 404(与别人的行同体)—— 出路是升级时先过一次带本条的版本,或运维按 `placement_root_session_id`(缺则 `placement_parent_session_id`)那一行的属主手工回填、" +
361
338
  "推不出的写一个任何主体都不匹配的值;停驻挂点只比对宿主行属主与引擎交来的属主(复活腿交那一行自己的属主),不写无主行;" +
362
339
  "建行那一笔记 `placement.owner` 不随本条删(那是常设的写法 —— core 盒义务 7,不是迁移)",
340
+ stopThenStart: null,
363
341
  reportKeys: ["placedSessionOwnersInherited", "placedSessionOwnersOrphaned", "placedSessionOwnersRemaining"],
364
342
  },
365
343
  {
@@ -374,6 +352,7 @@ export const ONE_TIME_MIGRATIONS = [
374
352
  "`test/one-time-migrations.test.ts` 的 M24 组与 `test/one-time-migrations-db-integration.test.ts` 的 M24 格。**不随本条删**:属主表、行主键里的令牌与店的写面 / 读面墙(那是常设的数据形)",
375
353
  afterRemoval: "起服对账一族的列集探针接住(`schema-consistency.ts` 的 `assertSchemaMatchesCode`,常设):跳过了带本条的版本直接升的库,`workflow_journal` 上仍带 scope 列、没有 incarnation 列 = 库与代码列集不符 ⇒ " +
376
354
  "响亮拒启(`config.schema_mismatch`),拒句点名两列;出路是先在带本条的版本(7.133.x)起服一次让它走完,再升",
355
+ stopThenStart: null,
377
356
  reportKeys: ["workflowJournalScopeColumn", "workflowJournalOwnersBackfilled", "workflowJournalForeignScopeRowsRemoved"],
378
357
  shapeChanges: [{ kind: "rebuild", table: WORKFLOW_JOURNAL_TABLE, whilePresent: RETIRED_JOURNAL_SCOPE_COLUMN, supplies: [WORKFLOW_JOURNAL_SUPPLIED_COLUMN] }],
379
358
  },
@@ -387,6 +366,7 @@ export const ONE_TIME_MIGRATIONS = [
387
366
  "`test/memory-project-layer-fold.test.ts` 的 ① 格与 `test/memory-project-layer-fold-db-integration.test.ts` 整份、" +
388
367
  "`test/project-identity.test.ts` 的 `repo:` 金样格(公式金样改钉 `p` 档摘要)",
389
368
  afterRemoval: "没有新的臂(如实):窗内一次都没跑过任务的项目,它的 `repo:` 层留在库里、不再被任何读列表包含(不读、不删;起服拒只管运维点名这一族);出路 = 升级时先过一次带本条的版本并在每个项目跑一次任务",
369
+ stopThenStart: null,
390
370
  reportKeys: [],
391
371
  },
392
372
  {
@@ -399,6 +379,7 @@ export const ONE_TIME_MIGRATIONS = [
399
379
  "**不随本条删**:键的铸点 `breakerKeyOf` / `routeDigestOf`(常设的键形)与新表 `breaker_state`",
400
380
  afterRemoval: "没有新的臂(如实):跳过了带本条的版本直接升的库,退役表 `circuit_breaker` 留在库里、没有读者也没有写者(断路器只读写 `breaker_state`)—— " +
401
381
  "出路 = 升级时先过一次带本条的版本(它起服删掉退役表);不先过也无害 —— 退役表没有读者也没有写者,留在库里只占空间(建议性状态,无数据价值)",
382
+ stopThenStart: null,
402
383
  reportKeys: ["retiredBreakerTablesDropped"],
403
384
  },
404
385
  {
@@ -411,6 +392,7 @@ export const ONE_TIME_MIGRATIONS = [
411
392
  "`MAILBOX_KEYED_TABLES` / `mailboxKeyDeleteSql`(`drop` 的常设语句)",
412
393
  afterRemoval: "没有新的臂(如实):跳过了带本条的版本直接升的库,判官拒的键的行留在库里,任何入口对它都按「箱不在」答(不读、不投、不清)—— 出路 = 升级时先过一次带本条的版本," +
413
394
  "或照 `docs/DEPLOY-PREREQS.md` 7.133.0 SQL 节的查法按键手工删",
395
+ stopThenStart: null,
414
396
  reportKeys: ["mailboxRejectedKeyRowsRemoved"],
415
397
  },
416
398
  {
@@ -428,6 +410,7 @@ export const ONE_TIME_MIGRATIONS = [
428
410
  "**不随本条删**:凭据位密封的常设规则(封口 / 开口 / 闭集 / 读口第四态 / 409 码 / 装配期拒启)",
429
411
  afterRemoval: "读口对凭据位上明文的常设拒臂接住:跳过了带本条的版本直接升的库,带明文凭据的停驻行续跑答 409 `conflict.checkpoint_ctx_unsealable`(`reason:\"plaintext\"`)," +
430
412
  "行字节不动 —— 出路 = 作为新任务重提(仍停驻的先取消),或升级时先过一次带本条的版本",
413
+ stopThenStart: null,
431
414
  reportKeys: [],
432
415
  },
433
416
  {
@@ -440,6 +423,7 @@ export const ONE_TIME_MIGRATIONS = [
440
423
  "`test/checkpoint-index-columns-db-integration.test.ts` 的 M29 格。**不随本条删**:`approval_card` 列、写口的派生、到期 facet 的生成谓词(常设)",
441
424
  afterRemoval: "没有新的臂(如实):跳过了带本条的版本直接升的库,升级前停驻、升级后仍挂着的行卡列是 NULL —— 生成谓词读门型的 facet(审批门 ⇒ SLA 拒扫腿),问答行到期被拒扫" +
442
425
  "(引擎对问答拒收 `sla_timeout`,拒扫腿每拍一条失败,由 `terminal_at_ms` 兜底收割);运维队列行不带卡词。出路 = 升级前答完 / 拒掉停驻的问答,或升级时先过一次带本条的版本",
426
+ stopThenStart: null,
443
427
  reportKeys: ["parkedApprovalCardsBackfilled", "parkedApprovalCardRowsUnreadable", "parkedApprovalCardRowsTooLong"],
444
428
  },
445
429
  {
@@ -468,6 +452,7 @@ export const ONE_TIME_MIGRATIONS = [
468
452
  "**不随本条删**:续跑判据的第四问(退役请求键闭集 `RETIRED_REQUEST_KEYS` / `retiredRequestKeyOf` / `retiredRequestKeyRefusal`,常设)",
469
453
  afterRemoval: "续跑判据第四问的常设拒臂接住:跳过了带本条的版本直接升的库(或窗内从没起过本版的部署),体里仍带 `promptProfile` 的停驻行续跑在五个问点上答 409 `checkpoint.unsupported_version`" +
470
454
  "(判据 `retired_request_key`,`http/stored-body-replay.ts`)、行字节不动 —— 出路 = 作为新任务重提(`promptLean` 代替 `promptProfile`;仍停驻的先取消),或升级时先过一次带本条的版本并在窗内起服",
455
+ stopThenStart: null,
471
456
  reportKeys: [],
472
457
  },
473
458
  {
@@ -481,6 +466,7 @@ export const ONE_TIME_MIGRATIONS = [
481
466
  "`test/memory-sync-client.test.ts` 里标题以 `🔴 M31:` 或 `M31 ` 起头的格、对 `relocateSyncCursorsM31` 的引入与常量 `LEGACY_PEER_DIR`,常量 `CURSOR_FILE` 的行注改成「没有读者」(用它的格随删后无人用它 ⇒ 常量一起删)",
482
467
  afterRemoval: "没有新的臂(如实):跳过了带本条的版本直接升的数据根,升级前的游标还在 `sync-cursors/central/` 与 `sync-cursor-central.json`,没有读者 ⇒ 那几层以空基线首轮同步" +
483
468
  "(两边都改过的条目按冲突上报,上一轮之后在一侧删掉的条目从另一侧回来)。出路 = 升级时先过一次带本条的版本并在窗内跑一轮同步,或升级前在旧版上跑完一轮同步、再删掉这些文件",
469
+ stopThenStart: null,
484
470
  reportKeys: [],
485
471
  },
486
472
  {
@@ -502,6 +488,7 @@ export const ONE_TIME_MIGRATIONS = [
502
488
  "**不随本条删**:执行放置八列、会话店的执行席、设备店的首绑 / 换绑两只写(常设的数据形)",
503
489
  afterRemoval: "起服对账一族的跳版库拒启臂接住:删码同版把 `device_session` / `device_session_retired` 两张表加进退役 schema 判据(`schema-consistency.ts` 的跳版库探针,先于建表)⇒ " +
504
490
  "跳过了带本条的版本直接升的库响亮拒启,出路 = 先在带本条的版本起服一次让切换走完,再升;缺执行放置列的库由列集对账缺列拒启(`config.schema_mismatch`,拒句给 ALTER),同一出路",
491
+ stopThenStart: null,
505
492
  reportKeys: ["executionPlacementColumnsAdded", "deviceBindingsMoved", "deviceBindingsOrphaned", "deviceBindingTablesDropped", "executionPlacementsBackfilled", "askExecutionLanesBackfilled", "executionPlacementSessionsUnreadable"],
506
493
  shapeChanges: [{ kind: "add", table: APPROVAL_ASK_TABLE, column: ASK_EXECUTION_LANE_COLUMN, whilePresent: { table: "session_meta", anyOf: SESSION_EXT_MOVED_COLUMNS.map((c) => c.name) } }],
507
494
  },
@@ -523,6 +510,7 @@ export const ONE_TIME_MIGRATIONS = [
523
510
  "`session-error-wire.ts` 的 `StampedSessionArchiveError` / `STAMPED_SESSION_ARCHIVE_SENTENCE` / `sessionErrorWireOf` 与本店带戳判的唯一读口 `assertArchiveAnonymous`(fork 的源、改日志推送的落点、会话同步导入第一阶段的早拒三处问它)、行上缺建档时刻的 F 类读法(`server.local-session-row.created-at-absent`)",
524
511
  afterRemoval: "三只常设臂接住:① 数据根下的快照目录非空 ⇒ 拒启(`config.local_archive_snapshot_present`,点名文件与两条出路);② 跳过了带本条的版本直接升的数据根(或本条留着的存档),带属主戳的存档被 fork、改日志的推送与会话同步导入第一阶段对 fork / stale 的早拒同一只具名拒(409 `conflict.session_archive_stamped` + 固定句,零写 / 行格净零写)," +
525
512
  "读 / 续跑 / 拉取照常 —— 出路 = 删掉会话后重推,或升级时先过一次带本条的版本并在窗内起服;③ 行上没有建档时刻的格(同一类数据根)⇒ 列表 / 会话视图 / 交出的元数据读纪元(F 类 tag 计数)",
513
+ stopThenStart: null,
526
514
  reportKeys: ["localArchiveRowFactsBackfilled", "localArchivesAnonymized", "localArchivesKeptStamped", "localArchivesUnreadable", "localArchiveSnapshotsRecovered"],
527
515
  },
528
516
  {
@@ -539,6 +527,7 @@ export const ONE_TIME_MIGRATIONS = [
539
527
  afterRemoval: "两只常设臂接住:① SQL —— 删码同版把 `approval_ask.denied_reason` 加进退役 schema 判据(`schema-consistency.ts` 的跳版库探针,先于建表)⇒ 跳过了带本条的版本直接升的库响亮拒启," +
540
528
  "出路 = 先在带本条的版本起服一次让迁移走完,再升(列册对账见幽灵列 / 缺列同样拒启,但它的拒句给的是加列,不是这一出路 —— 所以退役判据要在删码同版加上);" +
541
529
  "② local —— 信封号 1 的日志记录走 File 问账店「认不出的信封号」拒启(`unknown envelope version`,点名文件与出路:用写下它的那一版起服一次,或移开文件)",
530
+ stopThenStart: null,
542
531
  reportKeys: ["askCauseColumnsChanged", "askParkTriggersMoved", "askJournalRecordsUpgraded"],
543
532
  shapeChanges: [
544
533
  { kind: "rename", table: APPROVAL_ASK_TABLE, from: [RETIRED_ASK_CAUSE_COLUMN], to: APPROVAL_ASK_ENDING_CAUSE_COLUMN.name },
@@ -555,6 +544,7 @@ export const ONE_TIME_MIGRATIONS = [
555
544
  "**不随本条删**:模型面闸 `env-model-table-gate.ts`、`LocalConfigProvider` 读决定(etag 覆盖)、目录信任判官的根级文档名单(常设)",
556
545
  afterRemoval: "常设的模型面闸接住:跳过了带本条的版本直接升的本地根(或运行记录在场而决定缺席的根),决定缺席读作 kept ⇒ env 模型表已声明时管模型面的本地目录被组拒 " +
557
546
  "`config.catalog_replaces_env_models`,拒句点名被顶替的 env 模型与两条出路(在配置根写 `config.env-models.json` = `{\"envModels\":\"replaced\"}`,或撤掉 MODEL_ID / MODEL_CHEAP_ID)",
547
+ stopThenStart: null,
558
548
  reportKeys: [],
559
549
  },
560
550
  {
@@ -572,6 +562,7 @@ export const ONE_TIME_MIGRATIONS = [
572
562
  "**不随本条删**:`SqlDurableRulePartitionProvider` 收「方言 + 执行口」的那一形(`BucketSql`;常设,池照旧满足它)",
573
563
  afterRemoval: "没有响亮臂(如实):删码之后,跳过了带本条的版本直接升的库(或回滚到引擎 7.61.0 之前、在其上又导入过的库),存量的这种全局 `/x` allow 照旧在每个项目根放行,本服务不再点名 —— " +
574
564
  "出路 = 升级时先过一次带本条的版本并起服;或运维列出桶里出处为导入(`adds[].origin` = `imported-cc`)、scope 为全局、从 `/` 写起的 allow(`GET /v1/rules`)并撤掉(`DELETE /v1/rules`,撤的是这条规则的全部批准)",
565
+ stopThenStart: null,
575
566
  reportKeys: ["importedLayerRootAllowsRetired", "importedLayerRootBucketsSkipped", "importedLayerRootBucketsUnnamed"],
576
567
  },
577
568
  {
@@ -584,6 +575,7 @@ export const ONE_TIME_MIGRATIONS = [
584
575
  "`test/approval-card-source-key-m37.test.ts` 整只文件、本文件头注 M37 段",
585
576
  afterRemoval: "既有坏行臂接住(响亮,不再改名):仍带旧键的存卡(跳过了带本条的版本直接升的库、窗关之后还在写的 7.142.x 副本)整卡读不出 —— 断连重放跳过 + 一次 warn、" +
586
577
  "幂等重入走 park、回决口按要人",
578
+ stopThenStart: null,
587
579
  reportKeys: [],
588
580
  },
589
581
  {
@@ -598,6 +590,7 @@ export const ONE_TIME_MIGRATIONS = [
598
590
  "`test/settings-env-credential.test.ts` 里窗开的三格(剥键照续 / 剥空登记空表 / 预判窗开不拦)与「窗关当天仍开」那格、`withM38Window` 助手(窗关的几格改成不注入窗直接断言拒)、M38 登记行那一格;本文件头注 M38 段",
599
591
  afterRemoval: "没有新的臂,接住它的是窗关之后的读法(删码零行为变化:窗关那一刻起剥键臂已经不生效):存体 `settings.env` 里仍带凭据条目的停驻行,续跑前的预判拒(409 `resume_blocked_by_policy`,`blockedBy: request.env_credential_refused`,机读位点名键与命中类),卡仍 pending —— " +
600
592
  "出路是取消那条 run,把凭据挪进引擎进程环境后重新提交。会撞上它的是活过窗的升级前停驻行:发布后才升级的部署、调长了 `APPROVAL_TERMINAL_BACKSTOP_MS` 的部署、滚动升级里旧副本在窗内新写的行、窗内续跑过又停驻到窗外的任务(头注 M38 段)",
593
+ stopThenStart: null,
601
594
  reportKeys: [],
602
595
  },
603
596
  {
@@ -611,6 +604,7 @@ export const ONE_TIME_MIGRATIONS = [
611
604
  "**不随本条删**:数据根建目录只经 `ensureDir` 这条律本身(常设)、`plugins/owner-only-file-mode.ts`(本服务文件的 `0600` 唯一值与原子写的两个出口:异步出口常设,同步出口按它自己的退役条件 —— core 的原子写改成独占新建 tmp —— 走,不随本条)及它们的钉 —— `test/data-dir-law-census.test.ts`(`src/**` 零裸 mkdir、零手写 0o700、文件模式只认一个名字、tmp 只在一只写口里铸)与 `test/data-dir-modes.test.ts`(每只 local 店首建目录 0700、旧 tmp 不被复用)",
612
605
  afterRemoval: "没有响亮臂(如实,也无需):删码之后,跳过了带本条的版本直接升的数据根,升级前铸成的 0755 目录原样留着(新建的目录一律 0700,不受影响;里面的文件多半仍是 0600),本服务不再点名 —— " +
613
606
  "出路 = 运维一次 `chmod 700` 数据根下 `runs`(及其子目录)· `space-commits` · `checkpoint-ctx` · `.tmp` · `attachments` · `scratchpad`(及其子目录)· `plugin-cache`(及其子目录)· `<记忆引擎根>/sync-cursors`,或升级时先过一次带本条的版本并起服",
607
+ stopThenStart: null,
614
608
  reportKeys: [],
615
609
  },
616
610
  {
@@ -618,7 +612,7 @@ export const ONE_TIME_MIGRATIONS = [
618
612
  introducedIn: "7.147.0",
619
613
  releasedOn: "2026-11-07",
620
614
  removableAfter: "2026-12-07",
621
- removal: "删 `src/plugins/execution-lane-rename-m40.ts` 整只文件;本文件的 M40 步(`renameRetiredExecutionLaneWordsM40` / `refuseWhileRunsHeartbeat`〔读证据的那一处调用;证据读法 `readOlderReplicaEvidence` 与判活窗输入归 M52 行〕/ `ExecutionLaneRenameRefusedError` / " +
615
+ removal: "删 `src/plugins/execution-lane-rename-m40.ts` 整只文件;本文件的 M40 步(`renameRetiredExecutionLaneWordsM40` / `refuseExecutionLaneRenameM40`〔本行 `stopThenStart.refuse`;证据读法 `readOlderReplicaEvidence`、判活窗输入与守卫段归 `stop-then-start.ts`,常设,不随本行删〕/ `ExecutionLaneRenameRefusedError` / " +
622
616
  "`EXECUTION_LANE_RENAME_REFUSED_CODE`,`migrateStepsOn` 第一步那一行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `executionLaneWordsRenamed`、头注 M40 段;" +
623
617
  "`store-backend.ts` 的 `LocalBackend.ensureSchema` 第一步与 `executionLaneWordsRenamed` 字段;" +
624
618
  "`local-session-store.ts` 的内核 `renameRetiredExecutionLaneWordsInCellsM40` 与数据根准入的具名读者 `readSessionMetaSidecarInWindow`(在内存里套的那一步;准入的解码点改用 `readSessionMetaSidecar`);" +
@@ -629,6 +623,8 @@ export const ONE_TIME_MIGRATIONS = [
629
623
  stopThenStart: {
630
624
  reason: "renames the retired execution-lane word \"in-process\" to \"none\" on stored approval asks and sessions; a replica of an earlier version would keep writing the old word after the rename",
631
625
  owedOn: owesExecutionLaneRenameM40,
626
+ refuse: refuseExecutionLaneRenameM40,
627
+ fence: { kind: "accepted", residual: "an earlier replica keeps writing the old word after the rename; this version's readers refuse such a row loudly, and the next boot inside the window renames it again" },
632
628
  },
633
629
  reportKeys: ["executionLaneWordsRenamed"],
634
630
  },
@@ -637,8 +633,8 @@ export const ONE_TIME_MIGRATIONS = [
637
633
  introducedIn: "7.147.0",
638
634
  releasedOn: "2026-11-07",
639
635
  removableAfter: "2026-12-07",
640
- removal: "删本文件的 M41 步(`moveSessionCellsToSideTable` / `refuseSessionExtMoveWhileRunsHeartbeat` / `deploymentColumnsOnMeta` / `SessionExtMoveRefusedError` / `SESSION_EXT_MOVE_REFUSED_CODE` / " +
641
- "`SessionExtMoveRefusalReason` / `sameCell` / `SESSION_EXT_MOVE_PAGE`,`migrateStepsOn` 里那两行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `sessionExtRowsMoved` / `sessionMetaColumnsDropped`、头注 M41 段;" +
636
+ removal: "删本文件的 M41 步(`moveSessionCellsToSideTable` / `refuseSessionExtMoveM41`〔本行 `stopThenStart.refuse`〕/ `deploymentColumnsOnMeta` / `SessionExtMoveRefusedError` / `SESSION_EXT_MOVE_REFUSED_CODE` / " +
637
+ "`SessionExtMoveRefusalReason` / `sameCell` / `SESSION_EXT_MOVE_PAGE`,`migrateStepsOn` 里那一行)、报告 / 收据 / 日志 / `NO_SQL_MIGRATIONS` 的 `sessionExtRowsMoved` / `sessionMetaColumnsDropped`、头注 M41 段;" +
642
638
  "M32 读形里的 `cellsOnSideTable` 判(它读本条的 `deploymentColumnsOnMeta`):M32 还在时改成恒旁表形 —— 删 M32 写 `session_meta` 八列的那些臂(② ④ ④b ⑥ 与 ③ 的 `migrateDeviceBindingsStatement` 臂)," +
643
639
  "留 ③ 的旁表臂(`migrateDeviceBindingsOntoSideTableStatements`:围栏拒句的「采旧」在任何库上仍要能落到执行格);M32 先于本条删码时这些随 M32 一并删;`test/session-ext-move-db-integration.test.ts` 整只文件。能力名单 `REPLICA_CAPABILITIES` 里的 `M41` 不删(只增)",
644
640
  afterRemoval: "跳过了带本条的版本直接升上来的库:`session_meta` 上仍带部署格列 ⇒ 起服列册对账拒启(`config.schema_mismatch`,那几列是本树之外的多余列,拒句不给 ALTER —— 出路是带本条的版本);" +
@@ -646,6 +642,8 @@ export const ONE_TIME_MIGRATIONS = [
646
642
  stopThenStart: {
647
643
  reason: "moves the session deployment cells from session_meta to session_ext and then retires the old columns; a cell an earlier replica writes between the copy and the retirement is lost, and every cell write it makes afterwards fails",
648
644
  owedOn: owesSessionExtMoveM41,
645
+ refuse: refuseSessionExtMoveM41,
646
+ fence: { kind: "accepted", residual: "a cell an earlier replica writes between the copy and the column drop is lost; after the drop every cell write it makes fails" },
649
647
  },
650
648
  reportKeys: ["sessionExtRowsMoved", "sessionMetaColumnsDropped"],
651
649
  shapeChanges: [{ kind: "drop", table: "session_meta", columns: SESSION_EXT_MOVED_COLUMNS.map((c) => c.name) }],
@@ -655,7 +653,7 @@ export const ONE_TIME_MIGRATIONS = [
655
653
  introducedIn: "7.148.0",
656
654
  releasedOn: "2026-11-08",
657
655
  removableAfter: "2026-12-08",
658
- removal: "删 `src/plugins/scenario-prefix-switch-m42.ts` 整只文件;本文件的 M42 步(`switchScenarioPrefixM42` / `scannedIdentityColumnsM42`,`migrateStepsOn` 第一步那一行)、报告 / 收据 / 日志的 `scenarioPrefixSourcesScanned`、头注 M42 段;" +
656
+ removal: "删 `src/plugins/scenario-prefix-switch-m42.ts` 整只文件;本文件的 M42 步(`switchScenarioPrefixM42` / `scannedIdentityColumnsM42` / `refuseScenarioPrefixSwitchM42`〔本行 `stopThenStart.refuse`〕,`migrateStepsOn` 第一步那一行)、报告 / 收据 / 日志的 `scenarioPrefixSourcesScanned`、头注 M42 段;" +
659
657
  "`store-backend.ts` 的 `LocalBackend.runOneTimeMigrations` 里 M42 那一腿(`switchLocalScenarioPrefixM42`)与四只 File 店的 `scenarioPrefixOwnerRowsM42`(run / 会话 / 问 / 附件);`test/scenario-prefix-switch-m42.test.ts` 与 `test/scenario-prefix-switch-db-integration.test.ts` 两只文件。" +
660
658
  "标记表 `one-time-migration-marker.ts` 不随删(常设:中央建表语句建它,`Skill` 豁免截点那一行的家);库里留下的 `M42` 标记行 / 数据根里的标记文件无人再读,不删",
661
659
  afterRemoval: "没有响亮臂(如实):跳过了带本条的版本直接升的库,存量里以 `_scn:` 开头的身份被恢复管线读作某个人的场景(拆不出合文法的场景与人的 ⇒ `owner.malformed_subject` 响亮)。" +
@@ -663,6 +661,8 @@ export const ONE_TIME_MIGRATIONS = [
663
661
  stopThenStart: {
664
662
  reason: "scans stored identities for the reserved scenario prefix and records a marker; an earlier replica does not reserve the prefix and would keep accepting such identities after the scan",
665
663
  owedOn: owesScenarioPrefixSwitchM42,
664
+ refuse: refuseScenarioPrefixSwitchM42,
665
+ fence: { kind: "accepted", residual: "an earlier replica keeps accepting identities that start with the reserved scenario prefix after the scan; this version reads such an identity as someone else's scenario" },
666
666
  },
667
667
  reportKeys: ["scenarioPrefixSourcesScanned"],
668
668
  },
@@ -676,6 +676,7 @@ export const ONE_TIME_MIGRATIONS = [
676
676
  "local 会话元数据格「没有 `clientWrites` 位 ⇒ upgrade_pending」那一臂;库里留下的标记行无人再读,不删(与 M42 同一张标记表)",
677
677
  afterRemoval: "窗 30 天之后更早版本的副本早已不在;标记行不再被任何读者读(留着无害)。跳过了带本条的版本直接升上来的库:撤回出口从第一次起服就启用 —— " +
678
678
  "跨两版以上的混跑本就不被支持(7.147.0 起的停-迁-起)。出路 = 升级时先过一次带本条的版本并起服",
679
+ stopThenStart: null,
679
680
  reportKeys: ["withdrawMarkWritten"],
680
681
  },
681
682
  {
@@ -689,6 +690,7 @@ export const ONE_TIME_MIGRATIONS = [
689
690
  afterRemoval: "没有响亮臂(如实):跳过了带本条的版本直接升上来的库,旧行按列答 —— 停驻两口在列建立之前写下的 `needs_review` 行 `errorCode` 缺席(`review.pending` 仍在 `result` 里)、" +
690
691
  "列里是没折过的原码的旧行答原码;`result.terminal.code` 仍在 `result` 里。调长了停驻终局兜底(`APPROVAL_TERMINAL_BACKSTOP_MS` > 30 天)的部署,窗关时还可能有更早版本写下的停驻没结清,读法同上。" +
691
692
  "出路 = 升级时先过一次带本条的版本并起服",
693
+ stopThenStart: null,
692
694
  reportKeys: ["runErrorCodeColumnRewritten"],
693
695
  },
694
696
  {
@@ -701,6 +703,7 @@ export const ONE_TIME_MIGRATIONS = [
701
703
  "`test/run-preview-m45.test.ts` 与 `test/helpers/run-preview-m45-rows.ts` 整个文件、`test/session-preview-single-source-db-integration.test.ts` 的 M45 组",
702
704
  afterRemoval: "没有响亮臂(如实):跳过了带本条的版本直接升上来的库,7.124.0 之前写下的、以注入块起头的预览照旧按列答 —— 会话列表 / `GET /v1/tasks` / 助手任务行名 / 收件箱上显示那段块文本。" +
703
705
  "出路 = 升级时先过一次带本条的版本并起服",
706
+ stopThenStart: null,
704
707
  reportKeys: ["runObjectivePreviewRewritten"],
705
708
  },
706
709
  {
@@ -720,6 +723,7 @@ export const ONE_TIME_MIGRATIONS = [
720
723
  "SQL 在 `ensureSchema()` 建表之前(`LegacySkillExemptionsPresentError`,与退役 schema 探针同一处),local 在数据根准入(读数种别 `skipped-required-migration`)。" +
721
724
  "出路 = 先用一个仍带本条、不低于 7.148.0(local 还要不低于拒句里已记的引擎高水位)的版本对这只库完整起一次,再升;SQL 另可手工 `DELETE FROM approval_exemption WHERE tool_name = 'Skill'`。" +
722
725
  "T0 由常设的一步落(SQL:`ensureSchema()` 建表之后的种子行;local:准入的锁内一步):判过、缺席才落 —— 删码之后全新的库照样有 T0,不会被自己写下的合法行拒",
726
+ stopThenStart: null,
723
727
  reportKeys: ["legacySkillExemptionsDropped"],
724
728
  },
725
729
  {
@@ -736,6 +740,7 @@ export const ONE_TIME_MIGRATIONS = [
736
740
  afterRemoval: "跳版拒启臂接住(常设,数据根准入的一格:只读、本进程第一笔写之前、引擎高水位抬之前):(打开之前的引擎高水位早于 7.148.0 或缺席 ∨ 数据根里的收令牌欠账标记还在 —— 带本条的版本打开过、没收完)" +
737
741
  "∧ 根里有存档在而会话元数据格缺的会话 ⇒ 拒启 `config.schema_mismatch`(读数种别 `skipped-required-migration`,点名会话数与版本),零写、不抬高水位 —— " +
738
742
  "出路 = 先用一个仍带本条、不低于 7.148.0 且不低于已记高水位的版本(服务或 run-local)完整起一次,再升",
743
+ stopThenStart: null,
739
744
  reportKeys: ["localArchiveTokensAdopted", "localArchiveTokensMinted"],
740
745
  },
741
746
  {
@@ -750,6 +755,7 @@ export const ONE_TIME_MIGRATIONS = [
750
755
  afterRemoval: "没有响亮臂(如实):没有身份边界的部署跳过了带本条的版本直接升上来,哨兵属主的存量行仍记着那个字面量,属主面表已不认它 —— 不带主体的本地单用户读不到、续不上那些会话与 run(404)," +
751
756
  "带同一个头的请求仍读得到(属主相同)。出路 = 升级时先过一次带本条的版本并起服(或运维手工 `UPDATE <表> SET owner = NULL WHERE owner = 'anon:shell-live'`,三张表见删法)。" +
752
757
  "有身份边界的部署本条本来就零改写,删码前后同答(哨兵是一位普通的具名属主)",
758
+ stopThenStart: null,
753
759
  reportKeys: ["shellSentinelOwnersCleared", "shellSentinelOwnerRowsRetained"],
754
760
  },
755
761
  {
@@ -763,6 +769,7 @@ export const ONE_TIME_MIGRATIONS = [
763
769
  afterRemoval: "没有响亮臂(如实):跳过了带本条的版本直接升上来的库,升级前停下、升级后仍挂着的卡归属为空 —— 按 run 找卡的读口找不到它:取消那条 run 不作废它、" +
764
770
  "两条停驻收割把那条 run 当成「卡已不在」收掉(`approval.expired`)、决断答 409 `conflict.resume_context_unavailable`,卡由终局兜底收割收走。出路 = 升级前答完 / 拒掉停驻的卡," +
765
771
  "或升级时先过一次带本条的版本并起服(或运维手工 `UPDATE checkpoint SET host_session_id = session_id WHERE host_session_id IS NULL`)",
772
+ stopThenStart: null,
766
773
  reportKeys: ["checkpointHostSessionsBackfilled"],
767
774
  },
768
775
  {
@@ -775,6 +782,7 @@ export const ONE_TIME_MIGRATIONS = [
775
782
  "`approval-ask-store-memory.ts` 的 `deleteByTaskM50`;`test/approval-ask-session-cascade.test.ts` 的 M50 组(窗内 / 窗关当天 / 窗关次日 / 坏记录四格与 `withM50Window` 助手);本文件头注 M50 段",
776
783
  afterRemoval: "既有的词表外动词拒启(`approval-ask-store-file.ts` 重放的动词闭集判,拒句点名账本路径,出路 = 用写下它的那一版起服一次或把文件挪开)—— 与窗关之后本条自己的拒启同一个结局,删码零行为变化。" +
777
784
  "会撞上它的是窗内一次都没在带本条的版本上起过服的 local 数据根(跳过本版直接升的),账本里又恰好留着一条嵌入方写下的这只词",
785
+ stopThenStart: null,
778
786
  reportKeys: [],
779
787
  },
780
788
  {
@@ -782,28 +790,49 @@ export const ONE_TIME_MIGRATIONS = [
782
790
  introducedIn: "7.148.0",
783
791
  releasedOn: "2026-11-08",
784
792
  removableAfter: "2026-12-08",
785
- removal: "删本文件的 M51 步(`switchSessionDeletingM51` / `SessionDeletingSwitchRefusedError` / `SESSION_DELETING_SWITCH_REFUSED_CODE` / `SESSION_DELETING_MARK_ID`,`migrateStepsOn` 里那一行)、" +
793
+ removal: "删本文件的 M51 步(`switchSessionDeletingM51` / `refuseSessionDeletingSwitchM51`〔本行 `stopThenStart.refuse`〕/ `SessionDeletingSwitchRefusedError` / `SESSION_DELETING_SWITCH_REFUSED_CODE` / `SESSION_DELETING_MARK_ID`,`migrateStepsOn` 里那一行)、" +
786
794
  "报告 / 收据 / `changedAnything` / `readingFields` / `NO_SQL_MIGRATIONS` 的 `sessionDeletingSwitchMarked`、头注 M51 段;`test/session-deleting-state-db-integration.test.ts` 的 M51 组;" +
787
795
  "库里留下的 `M51` 标记行无人再读,不删。**不随本条删**:在删态本身(列、围栏、规则 L 的在删半、终刀判令牌 —— 常设)、标记表 `one-time-migration-marker.ts`(常设)",
788
796
  afterRemoval: "没有响亮臂(也无需):窗 30 天之后更早版本的副本早已不在;跳过了带本条的版本直接升上来的库 —— 跨两版以上的混跑本就不被支持(7.147.0 起的停-迁-起)。出路 = 升级时先过一次带本条的版本并起服",
789
797
  stopThenStart: {
790
798
  reason: "switches session deletion to a deleting state that every replica must read; an earlier replica does not read it and would accept a submission on a session this version is deleting",
791
799
  owedOn: owesSessionDeletingSwitchM51,
800
+ refuse: refuseSessionDeletingSwitchM51,
801
+ fence: { kind: "accepted", residual: "an earlier replica does not read the deleting state and may accept a submission on a session this version is deleting" },
792
802
  },
793
803
  reportKeys: ["sessionDeletingSwitchMarked"],
794
804
  },
795
805
  {
796
- id: "M52",
797
- introducedIn: "7.150.0",
798
- releasedOn: "2026-11-09",
799
- removableAfter: "2026-12-09",
800
- removal: "删 `readOlderReplicaEvidence` 的心跳一半(按 `instance_id` 分组读 `task_run` 心跳的那一句、减去登记为知道该迁移的持有者那一步)与它的判活窗输入:`LiveRunWindowInput`、`SqlOneTimeMigrationInput` 里的那一半、" +
801
- "`store-backend.ts` 的 `buildSqlOneTimeMigrationInput` 读 `runStaleSec` 的那一半、夹具 `test/helpers/db-schema-boot.ts` 的 `liveRunWindowMs`;停-迁-起守卫若已全部删码(M40 / M41 / M42 / M43 / M51 的窗都早于本条关)," +
802
- "连同 `readOlderReplicaEvidence` 与 `stop-then-start-sentence.ts` 的 `OlderReplicaEvidence` / `OlderReplicaHolder` / `olderReplicaEvidenceSentence` 一并删;" +
803
- "`test/run-liveness-single-source-gate.test.ts` ② 的 `one-time-migrations.ts` 白名单行与 ③ `store-backend.ts` 理由里「一次性迁移守卫」半句;`test/older-replica-evidence-db-integration.test.ts` 的证据组;头注 M52 段。" +
804
- "**不随本条删**:副本能力登记(`replica-registration.ts`,能力名单只增)与起服准入(`serving-requirement.ts`)—— 常设",
805
- afterRemoval: "没有响亮臂(如实):早于副本登记的副本不登记,删码之后它们对停-迁-起守卫完全不可见,忙与闲同 —— 发布日之后的天数不证明旧进程不在;出路只有运维:起带停-迁-起迁移的版本之前停光早于本条的副本",
806
- reportKeys: [],
806
+ id: "M53",
807
+ introducedIn: "7.151.0",
808
+ releasedOn: "2026-11-10",
809
+ removableAfter: "2026-12-10",
810
+ removal: "删本文件的 M53 步(`rewriteStoreFaultSentencesM53` / `rewriteBackgroundAgentRowsM53` / `rewriteToolEndEventsM53` / `M53_PAGE` / `M53_BACKGROUND_AGENT_TABLE`,`migrateStepsOn` 里那两行)、整只 `store-fault-sentence-m53.ts`、" +
811
+ "报告 / 收据 / `changedAnything` / `readingFields` / `NO_SQL_MIGRATIONS` 的 `storeFaultSentencesRewritten`、头注 M53 段;`test/store-fault-sentence-m53.test.ts` 与 `test/store-fault-sentence-m53-db-integration.test.ts`(`scripts/db-integration-files.json` 里它那一行同删)。" +
812
+ "**不随本条删**:店边界本身(`terminal.ts` 的 `storeBoundaryFault`、`store-boundary.ts` 的封口 —— 常设)",
813
+ afterRemoval: "没有响亮臂(如实):跳过了带本条的版本直接升的库上,换句之前落盘的后台子代行与 run 事件卡格仍带库驱动的原句(回读 / 回放照原样渲染);出路只有运维:按留存清理,或手删那些行",
814
+ stopThenStart: null,
815
+ reportKeys: ["storeFaultSentencesRewritten"],
816
+ },
817
+ {
818
+ id: "M54",
819
+ introducedIn: "7.152.0",
820
+ releasedOn: "2026-11-11",
821
+ removableAfter: "2026-12-11",
822
+ removal: "删本文件的 M54 步(`dropCheckpointDisplayColumnsM54` / `owesCheckpointDisplayColumnsDropM54` / `refuseCheckpointDisplayColumnsDropM54`〔本行 `stopThenStart.owedOn` / `refuse`〕/ `CheckpointDisplayColumnsDropRefusedError` / " +
823
+ "`CHECKPOINT_DISPLAY_COLUMNS_DROP_REFUSED_CODE` / `RETIRED_CHECKPOINT_DISPLAY_COLUMNS` / `CHECKPOINT_DISPLAY_COLUMNS_DROP_M54`,`migrateStepsOn` 里那一行)、报告 / 收据 / `changedAnything` / `readingFields` / `NO_SQL_MIGRATIONS` 的 " +
824
+ "`checkpointDisplayColumnsDropped`、头注 M54 段;`test/checkpoint-display-columns-drop-m54.test.ts` 与 `test/checkpoint-display-columns-drop-m54-db-integration.test.ts`(`scripts/db-integration-files.json` 里它那一行同删)。" +
825
+ "能力名单 `REPLICA_CAPABILITIES` 里的 `M54` 不删(只增)。**不随本条删**:读时投影 `buildQueueActionFacts` / `boundedToolInput` 与给人看的入参的读法 `src/human-facing-args.ts`(常设)",
826
+ afterRemoval: "跳过了带本条的版本直接升上来的库:`checkpoint` 上仍带那几列 ⇒ 起服列册对账拒启(`config.schema_mismatch`,它们是本树之外的多余列,拒句不给 ALTER —— 出路是带本条的版本);" +
827
+ "列上的值不被任何读者读。出路 = 升级时先过一次带本条的版本并起服",
828
+ stopThenStart: {
829
+ reason: "retires the checkpoint display-copy columns (the approval queue reads a pending call's tool name, input, risk descriptor, rule offers and bidi bit from the suspended checkpoint itself); after the retirement every approval an earlier replica parks and every approval-queue read it serves fails",
830
+ owedOn: owesCheckpointDisplayColumnsDropM54,
831
+ refuse: refuseCheckpointDisplayColumnsDropM54,
832
+ fence: { kind: "structural", fencedBy: CHECKPOINT_DISPLAY_COLUMNS_DROP_M54 },
833
+ },
834
+ reportKeys: ["checkpointDisplayColumnsDropped"],
835
+ shapeChanges: [CHECKPOINT_DISPLAY_COLUMNS_DROP_M54],
807
836
  },
808
837
  ];
809
838
  export function migrationWindowOpen(window, today) {
@@ -821,7 +850,7 @@ export function migrationCarried(id) {
821
850
  return ONE_TIME_MIGRATIONS.some((w) => w.id === id);
822
851
  }
823
852
  export function stopThenStartMigrations(registry = ONE_TIME_MIGRATIONS) {
824
- return registry.flatMap((row) => (row.stopThenStart === undefined ? [] : [{ id: row.id, ...row.stopThenStart }]));
853
+ return registry.flatMap((row) => row.stopThenStart === null ? [] : [{ id: row.id, introducedIn: row.introducedIn, ...(row.shapeChanges !== undefined ? { shapeChanges: row.shapeChanges } : {}), ...row.stopThenStart }]);
825
854
  }
826
855
  export const NO_SQL_MIGRATIONS = {
827
856
  sessionRuleColumn: "file-store",
@@ -853,6 +882,8 @@ export const NO_SQL_MIGRATIONS = {
853
882
  sessionMetaColumnsDropped: 0,
854
883
  withdrawMarkWritten: 0,
855
884
  sessionDeletingSwitchMarked: 0,
885
+ storeFaultSentencesRewritten: 0,
886
+ checkpointDisplayColumnsDropped: 0,
856
887
  askCauseColumnsChanged: 0,
857
888
  askParkTriggersMoved: 0,
858
889
  };
@@ -912,6 +943,8 @@ export function createSqlImportedLayerRootSource(exec) {
912
943
  return { candidateOwners: async () => ({ owners: await listRuleBucketOwners(exec), unnamedBuckets: 0 }), durable: new SqlDurableRulePartitionProvider(exec), isWholeBucketRefusal: isSqlBucketRefusal, isVanishedBucket: isSqlBucketVanished };
913
944
  }
914
945
  export async function runSqlOneTimeMigrations(dialect, pool, input, me = buildThisReplicaRegistration()) {
946
+ const stopThenStart = stopThenStartMigrations();
947
+ assertStopThenStartDeclarations(stopThenStart);
915
948
  const head = async (db) => {
916
949
  await assertReplicaTablesPresent(db, dialect, me);
917
950
  await registerReplica(db, dialect, me, Date.now());
@@ -919,6 +952,7 @@ export async function runSqlOneTimeMigrations(dialect, pool, input, me = buildTh
919
952
  };
920
953
  const locked = async (db) => {
921
954
  await assertServingRequirementsMet(db, me);
955
+ await guardOwedStopThenStart(db, dialect, input, stopThenStart);
922
956
  return migrateOn(db, dialect, input);
923
957
  };
924
958
  return dialect === "mysql" ? withMysqlLock(pool, head, locked) : withPgLock(pool, head, locked);
@@ -966,10 +1000,9 @@ async function migrateOn(db, dialect, input) {
966
1000
  return completedReport(receipts);
967
1001
  }
968
1002
  async function migrateStepsOn(db, dialect, receipts, input) {
969
- await switchScenarioPrefixM42(db, dialect, receipts, input);
970
- await renameRetiredExecutionLaneWordsM40(db, dialect, receipts, input);
971
- await refuseSessionExtMoveWhileRunsHeartbeat(db, dialect, input);
972
- await switchSessionDeletingM51(db, dialect, receipts, input);
1003
+ await switchScenarioPrefixM42(db, dialect, receipts);
1004
+ await renameRetiredExecutionLaneWordsM40(db, dialect, receipts);
1005
+ await switchSessionDeletingM51(db, dialect, receipts);
973
1006
  await rewriteRunErrorCodeColumnM44(db, dialect, receipts);
974
1007
  await rewriteRunObjectivePreviewM45(db, dialect, receipts);
975
1008
  await clearShellSentinelOwnersM48(db, dialect, receipts, input);
@@ -979,6 +1012,7 @@ async function migrateStepsOn(db, dialect, receipts, input) {
979
1012
  await migrateSessionRuleGrammar(db, dialect, receipts);
980
1013
  await repairParkedRows(db, dialect, receipts);
981
1014
  await backfillParkedApprovalCards(db, dialect, receipts);
1015
+ await dropCheckpointDisplayColumnsM54(db, dialect, receipts);
982
1016
  if (await tableExists(db, dialect, "session_meta"))
983
1017
  await inheritPlacedSessionOwners(db, dialect, receipts);
984
1018
  if ((await tableExists(db, dialect, PERMISSION_RULE_TABLE)) && (await columnExists(db, dialect, PERMISSION_RULE_TABLE, "grammar"))) {
@@ -992,6 +1026,7 @@ async function migrateStepsOn(db, dialect, receipts, input) {
992
1026
  await moveSessionCellsToSideTable(db, dialect, receipts);
993
1027
  await markWithdrawEnabledM43(db, dialect, receipts, input);
994
1028
  await dropLegacySkillExemptionsM46(db, dialect, receipts);
1029
+ await rewriteStoreFaultSentencesM53(db, dialect, receipts);
995
1030
  }
996
1031
  const M44_PAGE = 500;
997
1032
  async function rewriteRunErrorCodeColumnM44(db, dialect, receipts) {
@@ -1035,6 +1070,71 @@ async function rewriteOneRunErrorCodeM44(db, dialect, row) {
1035
1070
  ? "UPDATE task_run SET error_code = ? WHERE task_id = ? AND status = ? AND updated_at = ? AND error_code <=> ?"
1036
1071
  : "UPDATE task_run SET error_code = $1 WHERE task_id = $2 AND status = $3 AND updated_at = $4 AND error_code IS NOT DISTINCT FROM $5", [target, taskId, String(row["status"]), row["updated_at"], storedCode]);
1037
1072
  }
1073
+ const M53_PAGE = 500;
1074
+ const M53_BACKGROUND_AGENT_TABLE = "background_agent";
1075
+ async function rewriteStoreFaultSentencesM53(db, dialect, receipts) {
1076
+ if (await tableExists(db, dialect, M53_BACKGROUND_AGENT_TABLE))
1077
+ await rewriteBackgroundAgentRowsM53(db, dialect, receipts);
1078
+ if (await tableExists(db, dialect, "task_event"))
1079
+ await rewriteToolEndEventsM53(db, dialect, receipts);
1080
+ }
1081
+ async function rewriteBackgroundAgentRowsM53(db, dialect, receipts) {
1082
+ let after;
1083
+ for (;;) {
1084
+ const cursor = after === undefined ? "" : dialect === "mysql" ? " AND (scope_key, handle) > (?, ?)" : " AND (scope_key, handle) > ($1, $2)";
1085
+ const page = await db.rows(`SELECT scope_key, handle, rev, ${jsonColumnText(dialect, "record_json")} FROM ${M53_BACKGROUND_AGENT_TABLE} WHERE ${jsonColumnTextExpr(dialect, "record_json")} LIKE '%"errorCode"%'${cursor} ORDER BY scope_key, handle LIMIT ${M53_PAGE}`, after === undefined ? [] : [after.scope, after.handle]);
1086
+ for (const row of page) {
1087
+ let record;
1088
+ try {
1089
+ record = decodeJsonColumn(row["record_json"], readJsonObjectColumn, `${M53_BACKGROUND_AGENT_TABLE}.record_json for handle ${String(row["handle"])}`);
1090
+ }
1091
+ catch (err) {
1092
+ if (isJsonColumnBodyProblem(err))
1093
+ continue;
1094
+ throw err;
1095
+ }
1096
+ const rewritten = rewrittenBackgroundRecordM53(record);
1097
+ if (rewritten === undefined)
1098
+ continue;
1099
+ const rev = Number(row["rev"]);
1100
+ const next = { ...rewritten, rev: rev + 1 };
1101
+ receipts.storeFaultSentencesRewritten += await db.exec(dialect === "mysql"
1102
+ ? `UPDATE ${M53_BACKGROUND_AGENT_TABLE} SET record_json = ?, rev = ? WHERE scope_key = ? AND handle = ? AND rev = ?`
1103
+ : `UPDATE ${M53_BACKGROUND_AGENT_TABLE} SET record_json = $1, rev = $2 WHERE scope_key = $3 AND handle = $4 AND rev = $5`, [dialect === "mysql" ? JSON.stringify(next) : pgSafeJsonStringify(next), rev + 1, row["scope_key"], row["handle"], row["rev"]]);
1104
+ }
1105
+ if (page.length < M53_PAGE)
1106
+ return;
1107
+ const last = page[page.length - 1];
1108
+ after = { scope: last["scope_key"], handle: last["handle"] };
1109
+ }
1110
+ }
1111
+ async function rewriteToolEndEventsM53(db, dialect, receipts) {
1112
+ const carded = dialect === "mysql" ? "JSON_EXTRACT(data, '$.structured.errorCode') IS NOT NULL" : "data->'structured'->>'errorCode' IS NOT NULL";
1113
+ let after;
1114
+ for (;;) {
1115
+ const cursor = after === undefined ? "" : dialect === "mysql" ? " AND (task_id, seq) > (?, ?)" : " AND (task_id, seq) > ($1, $2)";
1116
+ const page = await db.rows(`SELECT task_id, seq, ${jsonColumnText(dialect, "data")} FROM task_event WHERE type = 'tool_end' AND ${carded}${cursor} ORDER BY task_id, seq LIMIT ${M53_PAGE}`, after === undefined ? [] : [after.taskId, after.seq]);
1117
+ for (const row of page) {
1118
+ let data;
1119
+ try {
1120
+ data = decodeJsonColumn(row["data"], readJsonObjectColumn, `task_event.data for task ${String(row["task_id"])} seq ${String(row["seq"])}`);
1121
+ }
1122
+ catch (err) {
1123
+ if (isJsonColumnBodyProblem(err))
1124
+ continue;
1125
+ throw err;
1126
+ }
1127
+ const next = rewrittenToolEndDataM53(data);
1128
+ if (next === undefined)
1129
+ continue;
1130
+ receipts.storeFaultSentencesRewritten += await db.exec(dialect === "mysql" ? "UPDATE task_event SET data = ? WHERE task_id = ? AND seq = ?" : "UPDATE task_event SET data = $1::jsonb WHERE task_id = $2 AND seq = $3", [dialect === "mysql" ? JSON.stringify(next) : pgSafeJsonStringify(next), String(row["task_id"]), row["seq"]]);
1131
+ }
1132
+ if (page.length < M53_PAGE)
1133
+ return;
1134
+ const last = page[page.length - 1];
1135
+ after = { taskId: String(last["task_id"]), seq: last["seq"] };
1136
+ }
1137
+ }
1038
1138
  const M45_PAGE = 500;
1039
1139
  async function rewriteRunObjectivePreviewM45(db, dialect, receipts) {
1040
1140
  if (!(await tableExists(db, dialect, "task_run")))
@@ -1140,6 +1240,18 @@ async function owesSessionExtMoveM41(read, dialect) {
1140
1240
  async function owesScenarioPrefixSwitchM42(read, dialect) {
1141
1241
  return !(await migrationMarked(read, dialect, SCENARIO_PREFIX_MARKER_ID));
1142
1242
  }
1243
+ async function owesCheckpointDisplayColumnsDropM54(read, dialect) {
1244
+ return (await retiredDisplayColumnsPresent({ rows: read }, dialect)).length > 0;
1245
+ }
1246
+ async function retiredDisplayColumnsPresent(db, dialect) {
1247
+ if (!(await tableExists(db, dialect, "checkpoint")))
1248
+ return [];
1249
+ const present = [];
1250
+ for (const column of RETIRED_CHECKPOINT_DISPLAY_COLUMNS)
1251
+ if (await columnExists(db, dialect, "checkpoint", column))
1252
+ present.push(column);
1253
+ return present;
1254
+ }
1143
1255
  async function owesSessionDeletingSwitchM51(read, dialect) {
1144
1256
  return !(await migrationMarked(read, dialect, SESSION_DELETING_MARK_ID));
1145
1257
  }
@@ -1157,14 +1269,15 @@ export class SessionDeletingSwitchRefusedError extends StoreBootRefusalError {
1157
1269
  this.name = "SessionDeletingSwitchRefusedError";
1158
1270
  }
1159
1271
  }
1160
- async function switchSessionDeletingM51(db, dialect, receipts, input) {
1272
+ async function refuseSessionDeletingSwitchM51(evidence, read, dialect) {
1273
+ return new SessionDeletingSwitchRefusedError(evidence, await describeUpgradeDriftTail(read, dialect));
1274
+ }
1275
+ async function switchSessionDeletingM51(db, dialect, receipts) {
1161
1276
  if (!(await tableExists(db, dialect, MIGRATION_MARKER_TABLE)))
1162
1277
  await execUntil(db, migrationMarkerDdl(dialect), () => tableExists(db, dialect, MIGRATION_MARKER_TABLE));
1163
1278
  if (!(await owesSessionDeletingSwitchM51((sql) => db.rows(sql), dialect)))
1164
1279
  return;
1165
- const evidence = await readOlderReplicaEvidence(db, dialect, input, "M51");
1166
- if (evidence !== undefined)
1167
- throw new SessionDeletingSwitchRefusedError(evidence, await describeUpgradeDriftTail((sql) => db.rows(sql), dialect));
1280
+ await recordServingRequirement(db, dialect, "M51", Date.now());
1168
1281
  receipts.sessionDeletingSwitchMarked += await db.exec(markIfAbsentSql(dialect), [SESSION_DELETING_MARK_ID, Date.now()]);
1169
1282
  }
1170
1283
  export async function scannedIdentityColumnsM42(db, dialect) {
@@ -1181,9 +1294,10 @@ export async function scannedIdentityColumnsM42(db, dialect) {
1181
1294
  }
1182
1295
  return out.sort((a, b) => `${a.table}.${a.column}`.localeCompare(`${b.table}.${b.column}`));
1183
1296
  }
1184
- export async function switchScenarioPrefixM42(db, dialect, receipts, input) {
1185
- if (!(await tableExists(db, dialect, MIGRATION_MARKER_TABLE)))
1186
- await execUntil(db, migrationMarkerDdl(dialect), () => tableExists(db, dialect, MIGRATION_MARKER_TABLE));
1297
+ async function refuseScenarioPrefixSwitchM42(evidence, read, dialect) {
1298
+ return new ScenarioPrefixSwitchRefusedError("older_replica", [], evidence, await describeUpgradeDriftTail(read, dialect));
1299
+ }
1300
+ export async function switchScenarioPrefixM42(db, dialect, receipts) {
1187
1301
  if (!(await owesScenarioPrefixSwitchM42((sql) => db.rows(sql), dialect)))
1188
1302
  return;
1189
1303
  const columns = await scannedIdentityColumnsM42(db, dialect);
@@ -1197,9 +1311,9 @@ export async function switchScenarioPrefixM42(db, dialect, receipts, input) {
1197
1311
  receipts.scenarioPrefixSourcesScanned += columns.length;
1198
1312
  if (hits.length > 0)
1199
1313
  throw new ScenarioPrefixSwitchRefusedError("stored_prefix", hits, undefined, await describeUpgradeDriftTail((sql) => db.rows(sql), dialect));
1200
- const evidence = await readOlderReplicaEvidence(db, dialect, input, "M42");
1201
- if (evidence !== undefined)
1202
- throw new ScenarioPrefixSwitchRefusedError("older_replica", [], evidence, await describeUpgradeDriftTail((sql) => db.rows(sql), dialect));
1314
+ if (!(await tableExists(db, dialect, MIGRATION_MARKER_TABLE)))
1315
+ await execUntil(db, migrationMarkerDdl(dialect), () => tableExists(db, dialect, MIGRATION_MARKER_TABLE));
1316
+ await recordServingRequirement(db, dialect, "M42", Date.now());
1203
1317
  await db.exec(markIfAbsentSql(dialect), [SCENARIO_PREFIX_MARKER_ID, Date.now()]);
1204
1318
  }
1205
1319
  export const EXECUTION_LANE_RENAME_REFUSED_CODE = "config.execution_lane_rename_refused";
@@ -1244,64 +1358,46 @@ async function executionLaneWordRowsM40(read, dialect) {
1244
1358
  }
1245
1359
  return { tables, pendingRows };
1246
1360
  }
1247
- export async function renameRetiredExecutionLaneWordsM40(db, dialect, receipts, input) {
1361
+ export async function renameRetiredExecutionLaneWordsM40(db, dialect, receipts) {
1248
1362
  const { tables, pendingRows } = await executionLaneWordRowsM40((sql) => db.rows(sql), dialect);
1249
1363
  if (pendingRows === 0)
1250
1364
  return;
1251
- await refuseWhileRunsHeartbeat(db, dialect, pendingRows, input);
1365
+ await recordServingRequirement(db, dialect, "M40", Date.now());
1252
1366
  for (const table of tables) {
1253
1367
  receipts.executionLaneWordsRenamed += await db.exec(dialect === "mysql" ? `UPDATE ${table} SET execution_lane = ? WHERE execution_lane = ?` : `UPDATE ${table} SET execution_lane = $1 WHERE execution_lane = $2`, [RENAMED_EXECUTION_LANE_M40, RETIRED_EXECUTION_LANE_WORD_M40]);
1254
1368
  }
1255
1369
  }
1256
- export async function readOlderReplicaEvidence(db, dialect, input, migrationId) {
1257
- if (!(await tableExists(db, dialect, "task_run")))
1258
- return undefined;
1259
- const since = new Date(Date.now() - input.liveRunWindowMs);
1260
- const groups = (await db.rows(`SELECT instance_id, COUNT(*) AS n, MAX(updated_at) AS newest FROM task_run WHERE status = 'running' AND updated_at >= ${dialect === "mysql" ? "?" : "$1"} GROUP BY instance_id`, [since]))
1261
- .map((r) => ({ holder: typeof r["instance_id"] === "string" ? r["instance_id"] : undefined, runs: Number(r["n"] ?? 0), newest: r["newest"] }))
1262
- .filter((g) => g.runs > 0);
1263
- if (groups.length === 0)
1264
- return undefined;
1265
- const registered = await readReplicaRegistrations({ query: async (sql, params) => ({ rows: await db.rows(sql, params), affected: 0 }) }, dialect, groups.flatMap((g) => (g.holder === undefined ? [] : [g.holder])));
1266
- let unregisteredRuns = 0;
1267
- let newestMs = Number.NaN;
1268
- const registeredWithout = [];
1269
- for (const g of groups) {
1270
- const r = g.holder === undefined ? undefined : registered.get(g.holder);
1271
- if (r !== undefined && knowsCapability(r.capabilities, migrationId))
1272
- continue;
1273
- if (r === undefined)
1274
- unregisteredRuns += g.runs;
1275
- else
1276
- registeredWithout.push({ instanceId: r.instanceId, releaseLine: r.releaseLine, hostName: r.hostName, pid: r.pid, runs: g.runs });
1277
- const cell = g.newest instanceof Date ? g.newest : new Date(String(g.newest));
1278
- if (!Number.isNaN(cell.getTime()) && !(cell.getTime() <= newestMs))
1279
- newestMs = cell.getTime();
1280
- }
1281
- const liveRuns = unregisteredRuns + registeredWithout.reduce((n, h) => n + h.runs, 0);
1282
- if (liveRuns === 0)
1283
- return undefined;
1284
- const now = Date.now();
1285
- const restartAtMs = (Number.isNaN(newestMs) ? now : newestMs) + input.liveRunWindowMs;
1286
- return {
1287
- migration: migrationId,
1288
- liveRuns,
1289
- windowSec: Math.round(input.liveRunWindowMs / 1000),
1290
- restartAfter: new Date(restartAtMs).toISOString(),
1291
- after: `${new Date(restartAtMs).toISOString()} (${Math.max(0, Math.ceil((restartAtMs - now) / 1000))}s from now)`,
1292
- unregisteredRuns,
1293
- registeredWithout: registeredWithout.sort((a, b) => a.instanceId.localeCompare(b.instanceId)),
1294
- };
1295
- }
1296
- async function refuseWhileRunsHeartbeat(db, dialect, pendingRows, input) {
1297
- const evidence = await readOlderReplicaEvidence(db, dialect, input, "M40");
1298
- if (evidence === undefined)
1299
- return;
1300
- throw new ExecutionLaneRenameRefusedError(pendingRows, evidence.liveRuns, evidence.restartAfter, `${pendingRows} stored rows (approval asks / sessions) carry the execution lane word "${RETIRED_EXECUTION_LANE_WORD_M40}", the name an earlier version gave the lane with no execution environment, ` +
1370
+ async function refuseExecutionLaneRenameM40(evidence, read, dialect) {
1371
+ const { pendingRows } = await executionLaneWordRowsM40(read, dialect);
1372
+ return new ExecutionLaneRenameRefusedError(pendingRows, evidence.liveRuns, evidence.restartAfter, `${pendingRows} stored rows (approval asks / sessions) carry the execution lane word "${RETIRED_EXECUTION_LANE_WORD_M40}", the name an earlier version gave the lane with no execution environment, ` +
1301
1373
  `which this version calls "${RENAMED_EXECUTION_LANE_M40}" and does not read; this boot renames them (one-time migration M40), but ${olderReplicaEvidenceSentence(evidence)} ` +
1302
1374
  `— a replica of an earlier version may still be serving, and it would keep writing the old word after the rename. No stored row was changed. ` +
1303
1375
  stopThenStartAction(evidence.after) +
1304
- (await describeUpgradeDriftTail((sql) => db.rows(sql), dialect)));
1376
+ (await describeUpgradeDriftTail(read, dialect)));
1377
+ }
1378
+ export const CHECKPOINT_DISPLAY_COLUMNS_DROP_REFUSED_CODE = "config.checkpoint_display_columns_drop_refused";
1379
+ export class CheckpointDisplayColumnsDropRefusedError extends StoreBootRefusalError {
1380
+ code = CHECKPOINT_DISPLAY_COLUMNS_DROP_REFUSED_CODE;
1381
+ reason = "older_replica";
1382
+ constructor(evidence, tail = "") {
1383
+ super(`${CHECKPOINT_DISPLAY_COLUMNS_DROP_REFUSED_CODE} (reason: older_replica): this version reads a suspended approval's tool name, input, risk descriptor, rule offers and ` +
1384
+ `bidi bit from the checkpoint itself and drops the checkpoint columns ${RETIRED_CHECKPOINT_DISPLAY_COLUMNS.join(", ")} on this boot (one-time migration M54), but ${olderReplicaEvidenceSentence(evidence)} — ` +
1385
+ "a replica of an earlier version may still be serving; after the drop every approval it parks and every approval-queue read it serves fails. Nothing was changed. " +
1386
+ stopThenStartAction(evidence.after) +
1387
+ tail);
1388
+ this.name = "CheckpointDisplayColumnsDropRefusedError";
1389
+ }
1390
+ }
1391
+ async function refuseCheckpointDisplayColumnsDropM54(evidence, read, dialect) {
1392
+ return new CheckpointDisplayColumnsDropRefusedError(evidence, await describeUpgradeDriftTail(read, dialect));
1393
+ }
1394
+ export async function dropCheckpointDisplayColumnsM54(db, dialect, receipts) {
1395
+ const present = await retiredDisplayColumnsPresent(db, dialect);
1396
+ if (present.length === 0)
1397
+ return;
1398
+ await recordServingRequirement(db, dialect, "M54", Date.now());
1399
+ await execUntil(db, `ALTER TABLE checkpoint ${present.map((c) => `DROP COLUMN ${c}`).join(", ")}`, async () => (await retiredDisplayColumnsPresent(db, dialect)).length === 0);
1400
+ receipts.checkpointDisplayColumnsDropped += present.length;
1305
1401
  }
1306
1402
  export const SESSION_EXT_MOVE_REFUSED_CODE = "config.session_ext_move_refused";
1307
1403
  export class SessionExtMoveRefusedError extends StoreBootRefusalError {
@@ -1327,23 +1423,19 @@ const sameCell = (dialect, column) => {
1327
1423
  return dialect === "mysql" ? `sm.${column.name} <=> ${side}` : `sm.${column.name} IS NOT DISTINCT FROM ${side}`;
1328
1424
  };
1329
1425
  const SESSION_EXT_MOVE_PAGE = 500;
1330
- export async function refuseSessionExtMoveWhileRunsHeartbeat(db, dialect, input) {
1331
- const columns = await deploymentColumnsOnMeta(db, dialect);
1332
- if (columns.length === 0)
1333
- return;
1334
- const evidence = await readOlderReplicaEvidence(db, dialect, input, "M41");
1335
- if (evidence === undefined)
1336
- return;
1337
- throw new SessionExtMoveRefusedError("older_replica", `${columns.length} session cells (${columns.map((c) => c.name).join(", ")}) still live on session_meta; this version keeps them on the side table ${SESSION_EXT_TABLE} and moves them on this boot ` +
1426
+ async function refuseSessionExtMoveM41(evidence, read, dialect) {
1427
+ const columns = await deploymentColumnsOnMeta({ rows: read }, dialect);
1428
+ return new SessionExtMoveRefusedError("older_replica", `${columns.length} session cells (${columns.map((c) => c.name).join(", ")}) still live on session_meta; this version keeps them on the side table ${SESSION_EXT_TABLE} and moves them on this boot ` +
1338
1429
  `(one-time migration M41: copy, verify, then drop the columns), but ${olderReplicaEvidenceSentence(evidence)} — ` +
1339
1430
  "a replica of an earlier version may still be serving; a cell it writes between the copy and the drop would be lost, and every cell write it makes after the drop fails. Nothing was changed. " +
1340
1431
  stopThenStartAction(evidence.after) +
1341
- (await describeUpgradeDriftTail((sql) => db.rows(sql), dialect)));
1432
+ (await describeUpgradeDriftTail(read, dialect)));
1342
1433
  }
1343
1434
  export async function moveSessionCellsToSideTable(db, dialect, receipts) {
1344
1435
  const columns = await deploymentColumnsOnMeta(db, dialect);
1345
1436
  if (columns.length === 0)
1346
1437
  return;
1438
+ await recordServingRequirement(db, dialect, "M41", Date.now());
1347
1439
  const names = columns.map((c) => c.name);
1348
1440
  const p = dialect === "mysql" ? () => "?" : (n) => `$${n}`;
1349
1441
  const upsert = `INSERT INTO ${SESSION_EXT_TABLE} (session_id, ${names.join(", ")}) SELECT session_id, ${names.join(", ")} FROM session_meta ` +
@@ -2017,13 +2109,13 @@ export async function repairParkedRows(db, dialect, receipts) {
2017
2109
  const kinds = APPROVAL_GATE_KINDS;
2018
2110
  const kindSlots = kinds.map((_, i) => ph(i + 1)).join(", ");
2019
2111
  const scan = `SELECT token, session_id, gate_kind, ${jsonColumnText(dialect, "checkpoint", M21_GATE)}, ${jsonColumnText(dialect, "checkpoint", M21_PENDING_ACTION)} FROM checkpoint ` +
2020
- `WHERE status = 'pending' AND (gate_kind IS NULL OR (gate_kind IN (${kindSlots}) AND tool_name = ${ph(kinds.length + 1)})) AND token > ${ph(kinds.length + 2)} ` +
2112
+ `WHERE status = 'pending' AND (gate_kind IS NULL OR gate_kind IN (${kindSlots})) AND token > ${ph(kinds.length + 1)} ` +
2021
2113
  `ORDER BY token LIMIT ${PARKED_ROW_REPAIR_PAGE}`;
2022
2114
  const docText = jsonColumnTextExpr(dialect, "checkpoint");
2023
2115
  const encode = dialectProtocolJsonEncoder(dialect);
2024
2116
  let after = "";
2025
2117
  for (;;) {
2026
- const page = await db.rows(scan, [...kinds, ASK_USER_QUESTION_TOOL_NAME, after]);
2118
+ const page = await db.rows(scan, [...kinds, after]);
2027
2119
  for (const r of page) {
2028
2120
  const token = String(r.token);
2029
2121
  after = token;
@@ -2214,6 +2306,8 @@ function readingFields(r) {
2214
2306
  scenarioPrefixSourcesScanned: r.scenarioPrefixSourcesScanned,
2215
2307
  withdrawMarkWritten: r.withdrawMarkWritten,
2216
2308
  sessionDeletingSwitchMarked: r.sessionDeletingSwitchMarked,
2309
+ storeFaultSentencesRewritten: r.storeFaultSentencesRewritten,
2310
+ checkpointDisplayColumnsDropped: r.checkpointDisplayColumnsDropped,
2217
2311
  runErrorCodeColumnRewritten: r.runErrorCodeColumnRewritten,
2218
2312
  runObjectivePreviewRewritten: r.runObjectivePreviewRewritten,
2219
2313
  shellSentinelOwnersCleared: r.shellSentinelOwnersCleared,