@sema-agent/server 7.147.0 → 7.149.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 (790) hide show
  1. package/MIGRATION.md +1468 -24
  2. package/README.md +35 -7
  3. package/README.zh-CN.md +18 -8
  4. package/USAGE.md +444 -193
  5. package/deploy/sema-up/README.md +16 -5
  6. package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +20 -4
  8. package/deploy/sema-up/chart/values.yaml +3 -2
  9. package/deploy/sema-up/cluster-up.sh +74 -176
  10. package/deploy/sema-up/kube-up.sh +29 -49
  11. package/deploy/sema-up/lib/chart-run.sh +23 -0
  12. package/deploy/sema-up/lib/dataroot.sh +3 -3
  13. package/deploy/sema-up/lib/health.sh +62 -13
  14. package/deploy/sema-up/lib/helm-values-cluster.py +18 -0
  15. package/deploy/sema-up/lib/helm-values-kube.py +35 -0
  16. package/deploy/sema-up/lib/regcred.py +8 -0
  17. package/deploy/sema-up/lib/remote/helm-install.sh +3 -0
  18. package/deploy/sema-up/lib/remote/image-import.sh +6 -0
  19. package/deploy/sema-up/lib/remote/machine-precheck.sh +11 -0
  20. package/deploy/sema-up/lib/remote/region-probe.sh +3 -0
  21. package/deploy/sema-up/lib/remote/stack-ready.sh +26 -0
  22. package/deploy/sema-up/lib/remote/vxlan-guard.sh +8 -0
  23. package/deploy/sema-up/lib/render-stack.py +17 -0
  24. package/deploy/sema-up/lib/shell-text.sh +87 -0
  25. package/deploy/sema-up/lib/usage-flags.txt +10 -0
  26. package/deploy/sema-up/lib/usage-head.txt +1 -0
  27. package/deploy/sema-up/lib/usage-tail.txt +13 -0
  28. package/deploy/sema-up/preflight.sh +10 -8
  29. package/deploy/sema-up/sema-up.sh +14 -39
  30. package/deploy/sema-up/smoke.sh +7 -6
  31. package/deploy/sema-up/stack/compose.dataroot.yaml +3 -0
  32. package/deploy/sema-up/stack/compose.yaml +13 -1
  33. package/deploy/sema-up/stack/sema-stack-cluster.yaml +21 -0
  34. package/dist/adoption/plan.d.ts +24 -0
  35. package/dist/adoption/plan.js +53 -1
  36. package/dist/adoption/runner.d.ts +10 -1
  37. package/dist/adoption/runner.js +36 -16
  38. package/dist/approval-card.d.ts +36 -38
  39. package/dist/approval-gate-currency.js +3 -2
  40. package/dist/approval-leg-origin.d.ts +33 -0
  41. package/dist/approval-leg-origin.js +4 -0
  42. package/dist/approval-reconciler.d.ts +4 -13
  43. package/dist/approval-reconciler.js +2 -2
  44. package/dist/approval.d.ts +13 -11
  45. package/dist/approval.js +3 -3
  46. package/dist/audit.d.ts +10 -3
  47. package/dist/audit.js +15 -7
  48. package/dist/auth-bridge.d.ts +9 -15
  49. package/dist/auth-bridge.js +4 -11
  50. package/dist/auth-keys.d.ts +10 -1
  51. package/dist/auth-keys.js +8 -0
  52. package/dist/auto-mode-face.d.ts +10 -7
  53. package/dist/auto-mode-face.js +7 -4
  54. package/dist/background-agent-name.d.ts +19 -1
  55. package/dist/background-agent-name.js +12 -2
  56. package/dist/background-session-reap.d.ts +1 -1
  57. package/dist/bake-runner/main.js +9 -6
  58. package/dist/bench/s1/arms.js +6 -5
  59. package/dist/bench/s1/live-deps.js +5 -2
  60. package/dist/bench/s1/run-firm.js +6 -5
  61. package/dist/bind-host.d.ts +25 -0
  62. package/dist/bind-host.js +25 -0
  63. package/dist/boot/adoption.d.ts +3 -0
  64. package/dist/boot/adoption.js +1 -0
  65. package/dist/boot/deployment-mods.d.ts +1 -1
  66. package/dist/boot/execution-env.d.ts +17 -7
  67. package/dist/boot/execution-env.js +47 -42
  68. package/dist/boot/execution-lane.d.ts +6 -4
  69. package/dist/boot/execution-lane.js +3 -1
  70. package/dist/boot/exit-boundary.d.ts +2 -2
  71. package/dist/boot/exit-boundary.js +6 -5
  72. package/dist/boot/fatal-exit.d.ts +3 -5
  73. package/dist/boot/fatal-exit.js +2 -2
  74. package/dist/boot/leader.d.ts +15 -0
  75. package/dist/boot/leader.js +17 -15
  76. package/dist/boot/memory-consolidation.d.ts +37 -29
  77. package/dist/boot/memory-consolidation.js +11 -5
  78. package/dist/boot/org-delivery.d.ts +3 -2
  79. package/dist/boot/org-memory.js +1 -1
  80. package/dist/boot/parked-revive-gate.js +2 -2
  81. package/dist/boot/reapers.d.ts +4 -3
  82. package/dist/boot/reapers.js +19 -16
  83. package/dist/boot/resolve-spec.d.ts +5 -3
  84. package/dist/boot/resolve-spec.js +60 -70
  85. package/dist/boot/retention-lane.d.ts +4 -4
  86. package/dist/boot/retention-lane.js +2 -2
  87. package/dist/boot/runner-deps.d.ts +28 -7
  88. package/dist/boot/runner-deps.js +14 -5
  89. package/dist/boot/runtime-caps.d.ts +2 -2
  90. package/dist/boot/runtime-caps.js +16 -2
  91. package/dist/boot/session-faces.d.ts +16 -7
  92. package/dist/boot/session-faces.js +114 -94
  93. package/dist/boot/shutdown.d.ts +5 -4
  94. package/dist/boot/shutdown.js +6 -4
  95. package/dist/boot/stage-01-config.d.ts +1 -0
  96. package/dist/boot/stage-01-config.js +13 -4
  97. package/dist/boot/stage-02-web-admin-pull.d.ts +2 -0
  98. package/dist/boot/stage-02-web-admin-pull.js +16 -3
  99. package/dist/boot/stage-03-store-backend.d.ts +4 -0
  100. package/dist/boot/stage-03-store-backend.js +4 -3
  101. package/dist/boot/stage-04-stores.d.ts +3 -0
  102. package/dist/boot/stage-04-stores.js +2 -2
  103. package/dist/boot/stage-05-execution-env.d.ts +8 -3
  104. package/dist/boot/stage-05-execution-env.js +2 -2
  105. package/dist/boot/stage-06-runners.d.ts +12 -13
  106. package/dist/boot/stage-06-runners.js +23 -15
  107. package/dist/boot/stage-07-capability-layer.d.ts +13 -9
  108. package/dist/boot/stage-07-capability-layer.js +5 -3
  109. package/dist/boot/stage-08-reapers.d.ts +13 -9
  110. package/dist/boot/stage-08-reapers.js +3 -3
  111. package/dist/boot/stage-09-leader.d.ts +14 -16
  112. package/dist/boot/stage-09-leader.js +12 -4
  113. package/dist/boot/stage-10-http-server.d.ts +14 -16
  114. package/dist/boot/stage-10-http-server.js +7 -4
  115. package/dist/boot/store-evidence.d.ts +20 -0
  116. package/dist/boot/store-evidence.js +13 -0
  117. package/dist/boot/stores.d.ts +6 -0
  118. package/dist/boot/stores.js +41 -27
  119. package/dist/boot/task-list-lane.d.ts +4 -4
  120. package/dist/boot/web-admin.d.ts +4 -2
  121. package/dist/boot/web-admin.js +55 -35
  122. package/dist/boot/webfetch-summarize-lane.d.ts +1 -1
  123. package/dist/boot-reclaim.d.ts +3 -1
  124. package/dist/boot-reclaim.js +1 -1
  125. package/dist/brain.d.ts +7 -18
  126. package/dist/brain.js +5 -17
  127. package/dist/budget.js +6 -6
  128. package/dist/capabilities/center-plugins.d.ts +7 -1
  129. package/dist/capabilities/center-plugins.js +32 -10
  130. package/dist/capabilities/center-wiring.js +1 -1
  131. package/dist/capabilities/composite-members.d.ts +2 -2
  132. package/dist/capabilities/composite-members.js +2 -2
  133. package/dist/capabilities/repo-tools.d.ts +2 -0
  134. package/dist/capabilities/repo-tools.js +14 -12
  135. package/dist/capabilities/scenarios.d.ts +6 -15
  136. package/dist/capabilities/scenarios.js +11 -16
  137. package/dist/capabilities/skills.d.ts +1 -1
  138. package/dist/capabilities/tool-defer.d.ts +1 -1
  139. package/dist/capability-facts.d.ts +39 -11
  140. package/dist/capability-facts.js +35 -7
  141. package/dist/card-settle-stored-scope.d.ts +56 -0
  142. package/dist/card-settle-stored-scope.js +27 -0
  143. package/dist/card-void.d.ts +8 -13
  144. package/dist/card-void.js +2 -7
  145. package/dist/center-credential-renewer.d.ts +6 -2
  146. package/dist/center-credential-renewer.js +7 -3
  147. package/dist/config-catalog.d.ts +28 -1
  148. package/dist/config-catalog.js +95 -85
  149. package/dist/config-dir-trust.d.ts +37 -4
  150. package/dist/config-dir-trust.js +88 -44
  151. package/dist/config-invariants.d.ts +43 -3
  152. package/dist/config-invariants.js +69 -5
  153. package/dist/config-lkg.d.ts +23 -1
  154. package/dist/config-lkg.js +17 -3
  155. package/dist/config-provider.d.ts +9 -9
  156. package/dist/config-provider.js +25 -110
  157. package/dist/config-pull-failure.d.ts +50 -0
  158. package/dist/config-pull-failure.js +48 -0
  159. package/dist/config-types.d.ts +62 -21
  160. package/dist/config.d.ts +14 -21
  161. package/dist/config.js +141 -64
  162. package/dist/context-window-notice.d.ts +31 -0
  163. package/dist/context-window-notice.js +28 -0
  164. package/dist/delegated-session-owner.d.ts +1 -1
  165. package/dist/deleted-session-ids.d.ts +3 -2
  166. package/dist/deployment-governance.d.ts +3 -3
  167. package/dist/deployment-shape.d.ts +46 -11
  168. package/dist/deployment-shape.js +8 -0
  169. package/dist/egress-redirect.d.ts +25 -7
  170. package/dist/egress-redirect.js +20 -2
  171. package/dist/elicitation.d.ts +6 -5
  172. package/dist/elicitation.js +23 -22
  173. package/dist/engine-identity.d.ts +28 -0
  174. package/dist/engine-identity.js +10 -0
  175. package/dist/entry-problems.d.ts +5 -7
  176. package/dist/entry-problems.js +1 -1
  177. package/dist/env-facts.js +2 -1
  178. package/dist/env-name-allowlist-knobs.d.ts +6 -5
  179. package/dist/env-name-allowlist-knobs.js +5 -0
  180. package/dist/env-witness.d.ts +7 -0
  181. package/dist/env-witness.js +16 -0
  182. package/dist/execution-lane-caps.d.ts +25 -23
  183. package/dist/execution-lane-caps.js +18 -26
  184. package/dist/execution-placement.d.ts +58 -18
  185. package/dist/execution-placement.js +41 -2
  186. package/dist/field-conflict.d.ts +7 -11
  187. package/dist/field-conflict.js +3 -3
  188. package/dist/file-history-capture.d.ts +3 -3
  189. package/dist/file-history-disclosure.js +1 -0
  190. package/dist/fleet/fleet-bus.d.ts +21 -3
  191. package/dist/fleet/fleet-bus.js +35 -25
  192. package/dist/fleet/fleet-reconciler.js +2 -2
  193. package/dist/fleet/serving-lease.js +3 -3
  194. package/dist/fleet-client.js +3 -3
  195. package/dist/fleet-lease.d.ts +0 -1
  196. package/dist/fleet-lease.js +4 -5
  197. package/dist/history-anchor.d.ts +23 -3
  198. package/dist/history-anchor.js +24 -4
  199. package/dist/hitl-delivery.d.ts +90 -0
  200. package/dist/hitl-delivery.js +98 -0
  201. package/dist/hooks/classic-stations.d.ts +8 -11
  202. package/dist/hooks/classic-stations.js +0 -7
  203. package/dist/hooks/command-spawn.d.ts +7 -2
  204. package/dist/hooks/command-spawn.js +13 -6
  205. package/dist/hooks/hook-llm.d.ts +5 -1
  206. package/dist/hooks/hook-llm.js +24 -15
  207. package/dist/hooks/hook-runner.d.ts +72 -57
  208. package/dist/hooks/hook-runner.js +271 -193
  209. package/dist/host-lsp-manager.d.ts +22 -8
  210. package/dist/host-lsp-manager.js +4 -1
  211. package/dist/http/active-run-conflict.d.ts +2 -43
  212. package/dist/http/active-run-conflict.js +3 -7
  213. package/dist/http/admission.d.ts +4 -18
  214. package/dist/http/admission.js +76 -79
  215. package/dist/http/approval-sweeps.d.ts +3 -3
  216. package/dist/http/approval-sweeps.js +56 -31
  217. package/dist/http/caller-trust.d.ts +8 -10
  218. package/dist/http/caller-trust.js +1 -2
  219. package/dist/http/claim-heartbeat.d.ts +49 -0
  220. package/dist/http/claim-heartbeat.js +46 -0
  221. package/dist/http/claimed-run.d.ts +16 -8
  222. package/dist/http/claimed-run.js +8 -0
  223. package/dist/http/dispatch.d.ts +8 -1
  224. package/dist/http/dispatch.js +78 -30
  225. package/dist/http/durable-run-leg.d.ts +11 -4
  226. package/dist/http/durable-run-leg.js +45 -21
  227. package/dist/http/execution-context.d.ts +122 -47
  228. package/dist/http/execution-context.js +135 -43
  229. package/dist/http/health-reader.d.ts +36 -0
  230. package/dist/http/health-reader.js +21 -0
  231. package/dist/http/health-self-report.d.ts +9 -9
  232. package/dist/http/health-self-report.js +4 -4
  233. package/dist/http/idempotency.d.ts +9 -5
  234. package/dist/http/idempotency.js +4 -4
  235. package/dist/http/memory-compliance-failure-reply.d.ts +15 -16
  236. package/dist/http/memory-compliance-failure-reply.js +4 -2
  237. package/dist/http/memory-face-fault-reply.d.ts +67 -0
  238. package/dist/http/memory-face-fault-reply.js +71 -0
  239. package/dist/http/memory-store-refusal-reply.d.ts +1 -1
  240. package/dist/http/memory-store-refusal-reply.js +3 -0
  241. package/dist/http/owner-access.d.ts +392 -67
  242. package/dist/http/owner-access.js +370 -35
  243. package/dist/http/principal-gate.d.ts +39 -89
  244. package/dist/http/principal-gate.js +26 -68
  245. package/dist/http/refusal-body.d.ts +35 -2
  246. package/dist/http/refusal-body.js +34 -0
  247. package/dist/http/request-guards.d.ts +9 -13
  248. package/dist/http/request-guards.js +34 -68
  249. package/dist/http/resume-composition.d.ts +37 -0
  250. package/dist/http/resume-composition.js +18 -0
  251. package/dist/http/resume-ctx-read.d.ts +46 -12
  252. package/dist/http/resume-ctx-read.js +31 -6
  253. package/dist/http/resume-legs.d.ts +54 -19
  254. package/dist/http/resume-legs.js +408 -196
  255. package/dist/http/retired-skill-manifest.d.ts +1 -1
  256. package/dist/http/route-ctx.d.ts +31 -32
  257. package/dist/http/routes/a2a-serve.d.ts +43 -5
  258. package/dist/http/routes/a2a-serve.js +60 -37
  259. package/dist/http/routes/admin-config-refresh.js +2 -2
  260. package/dist/http/routes/admin-drain.js +2 -2
  261. package/dist/http/routes/admin-memory-optout.js +4 -3
  262. package/dist/http/routes/adoption.d.ts +3 -0
  263. package/dist/http/routes/adoption.js +17 -10
  264. package/dist/http/routes/agents-roster.js +13 -7
  265. package/dist/http/routes/approvals-assistant.js +73 -67
  266. package/dist/http/routes/attachments.js +2 -2
  267. package/dist/http/routes/background.d.ts +3 -3
  268. package/dist/http/routes/background.js +9 -17
  269. package/dist/http/routes/capabilities.js +16 -19
  270. package/dist/http/routes/config-catalog.js +2 -2
  271. package/dist/http/routes/devices.d.ts +3 -3
  272. package/dist/http/routes/devices.js +4 -4
  273. package/dist/http/routes/diagnostics.d.ts +29 -3
  274. package/dist/http/routes/diagnostics.js +49 -18
  275. package/dist/http/routes/engine.js +2 -2
  276. package/dist/http/routes/fleet.js +5 -3
  277. package/dist/http/routes/images.js +10 -6
  278. package/dist/http/routes/leader.d.ts +7 -2
  279. package/dist/http/routes/leader.js +12 -3
  280. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  281. package/dist/http/routes/mcp-reconnect.js +7 -15
  282. package/dist/http/routes/memory-bundle.js +4 -7
  283. package/dist/http/routes/memory-compliance.js +4 -4
  284. package/dist/http/routes/memory-consolidation.js +6 -9
  285. package/dist/http/routes/memory-origin.d.ts +2 -0
  286. package/dist/http/routes/memory-origin.js +7 -8
  287. package/dist/http/routes/memory-policy.js +17 -12
  288. package/dist/http/routes/notify-wake.js +10 -19
  289. package/dist/http/routes/observability.js +3 -3
  290. package/dist/http/routes/principal-inbox.d.ts +4 -2
  291. package/dist/http/routes/principal-inbox.js +5 -4
  292. package/dist/http/routes/projects.d.ts +1 -1
  293. package/dist/http/routes/projects.js +3 -2
  294. package/dist/http/routes/retention-ops.js +6 -9
  295. package/dist/http/routes/rules.js +20 -5
  296. package/dist/http/routes/run-memory-capture.d.ts +2 -2
  297. package/dist/http/routes/run-memory-capture.js +6 -12
  298. package/dist/http/routes/run-permission-mode.d.ts +2 -2
  299. package/dist/http/routes/run-permission-mode.js +10 -17
  300. package/dist/http/routes/runs.js +155 -237
  301. package/dist/http/routes/session-memory-sync.d.ts +2 -2
  302. package/dist/http/routes/session-memory-sync.js +7 -13
  303. package/dist/http/routes/session-sync.d.ts +28 -7
  304. package/dist/http/routes/session-sync.js +63 -50
  305. package/dist/http/routes/sessions-list.d.ts +3 -3
  306. package/dist/http/routes/sessions-list.js +9 -9
  307. package/dist/http/routes/sessions.js +87 -124
  308. package/dist/http/routes/shared-memory.js +6 -6
  309. package/dist/http/routes/side-query.js +2 -2
  310. package/dist/http/routes/tasks.js +237 -187
  311. package/dist/http/routes/trace-usage.d.ts +0 -12
  312. package/dist/http/routes/trace-usage.js +40 -46
  313. package/dist/http/routes/workflows.d.ts +39 -4
  314. package/dist/http/routes/workflows.js +42 -14
  315. package/dist/http/run-concurrency-cap.d.ts +20 -12
  316. package/dist/http/run-concurrency-cap.js +39 -26
  317. package/dist/http/run-read-face.d.ts +3 -5
  318. package/dist/http/run-read-face.js +8 -13
  319. package/dist/http/send.d.ts +12 -3
  320. package/dist/http/send.js +42 -6
  321. package/dist/http/server.d.ts +43 -45
  322. package/dist/http/server.js +61 -11
  323. package/dist/http/sse-log.d.ts +17 -10
  324. package/dist/http/sse-log.js +7 -7
  325. package/dist/http/stored-body-replay.d.ts +12 -0
  326. package/dist/http/stored-body-replay.js +2 -2
  327. package/dist/http/submit-ctx.d.ts +17 -8
  328. package/dist/http/submit-ctx.js +8 -5
  329. package/dist/http/submit-replay.d.ts +19 -6
  330. package/dist/http/submit-replay.js +18 -6
  331. package/dist/http/sync-submit-body.d.ts +3 -4
  332. package/dist/http/sync-submit-body.js +4 -5
  333. package/dist/http/wire-types.d.ts +4 -3
  334. package/dist/identity-source.d.ts +36 -5
  335. package/dist/identity-source.js +27 -0
  336. package/dist/index.d.ts +4 -1
  337. package/dist/index.js +2 -0
  338. package/dist/key-resolver.d.ts +32 -0
  339. package/dist/key-resolver.js +23 -9
  340. package/dist/leader/diffup.js +2 -1
  341. package/dist/leader/endpoint.d.ts +26 -5
  342. package/dist/leader/endpoint.js +154 -14
  343. package/dist/leader/fanout.d.ts +3 -0
  344. package/dist/leader/fanout.js +78 -63
  345. package/dist/leader/leader.d.ts +16 -0
  346. package/dist/leader/leader.js +43 -3
  347. package/dist/leader/merge.d.ts +9 -1
  348. package/dist/leader/merge.js +16 -1
  349. package/dist/leader/repair-wire.js +1 -1
  350. package/dist/leader/wire.d.ts +36 -3
  351. package/dist/leader/wire.js +59 -18
  352. package/dist/leg-facts.d.ts +7 -2
  353. package/dist/leg-facts.js +1 -0
  354. package/dist/local-store-declaration.d.ts +54 -0
  355. package/dist/local-store-declaration.js +59 -0
  356. package/dist/lsp-evict.d.ts +6 -4
  357. package/dist/lsp-evict.js +2 -3
  358. package/dist/mcp-assertion-header.d.ts +1 -1
  359. package/dist/mcp-assertion-header.js +1 -1
  360. package/dist/memory-operator-faces.d.ts +5 -4
  361. package/dist/memory-operator-faces.js +1 -1
  362. package/dist/memory-project-layer.js +1 -1
  363. package/dist/memory-scope.d.ts +33 -6
  364. package/dist/memory-scope.js +68 -19
  365. package/dist/memory-store-refusal.d.ts +5 -2
  366. package/dist/memory-sync-client.d.ts +3 -2
  367. package/dist/memory-sync-client.js +8 -5
  368. package/dist/model-compat.d.ts +17 -8
  369. package/dist/model-compat.js +6 -2
  370. package/dist/model-context-window.d.ts +57 -0
  371. package/dist/model-context-window.js +21 -0
  372. package/dist/model-entry-headers.d.ts +46 -4
  373. package/dist/model-entry-headers.js +2 -2
  374. package/dist/model-entry-refusal.d.ts +40 -20
  375. package/dist/model-entry-refusal.js +57 -30
  376. package/dist/model-plane-face.d.ts +19 -11
  377. package/dist/model-plane-face.js +9 -1
  378. package/dist/model-plane-probe.d.ts +2 -0
  379. package/dist/model-plane-probe.js +17 -0
  380. package/dist/model-provider.d.ts +3 -3
  381. package/dist/model-reach-scope.d.ts +2 -1
  382. package/dist/model-route-endpoint.d.ts +9 -5
  383. package/dist/model-route-endpoint.js +29 -7
  384. package/dist/model-select.d.ts +16 -0
  385. package/dist/model-select.js +4 -0
  386. package/dist/mountinfo.d.ts +37 -0
  387. package/dist/mountinfo.js +47 -0
  388. package/dist/namespaced-rule-name.d.ts +23 -14
  389. package/dist/namespaced-rule-name.js +8 -11
  390. package/dist/net-address.d.ts +1 -1
  391. package/dist/observability/corrupt-read-seat.d.ts +4 -4
  392. package/dist/observability/corrupt-read-seat.js +5 -3
  393. package/dist/observability/fail-open.d.ts +72 -40
  394. package/dist/observability/fail-open.js +74 -40
  395. package/dist/observability/logger.d.ts +22 -1
  396. package/dist/observability/logger.js +89 -12
  397. package/dist/observability/metrics.js +4 -5
  398. package/dist/observability/otel-exporter.js +2 -1
  399. package/dist/observability/principal-context.d.ts +14 -7
  400. package/dist/observability/principal-context.js +8 -3
  401. package/dist/observability/run-terminal.d.ts +7 -1
  402. package/dist/observability/run-terminal.js +6 -2
  403. package/dist/observability/secret-env-scrub.d.ts +1 -1
  404. package/dist/observability/secret-env-scrub.js +1 -1
  405. package/dist/orchestration/hardened-vm-runner.d.ts +1 -0
  406. package/dist/orchestration/hardened-vm-runner.js +11 -5
  407. package/dist/orchestration/hardened-vm-worker-runner.d.ts +0 -14
  408. package/dist/orchestration/hardened-vm-worker-runner.js +5 -0
  409. package/dist/orchestration/hardened-vm-worker.js +2 -1
  410. package/dist/orchestration/workflow-completion-inbox.d.ts +3 -3
  411. package/dist/orchestration/workflow-completion-inbox.js +3 -2
  412. package/dist/org-delivery-gate.d.ts +36 -10
  413. package/dist/org-delivery-gate.js +12 -8
  414. package/dist/outbound-dispatcher.d.ts +1 -1
  415. package/dist/outbound-dispatcher.js +6 -12
  416. package/dist/owner-brands.d.ts +81 -0
  417. package/dist/owner-brands.js +42 -0
  418. package/dist/owner-faces.d.ts +532 -0
  419. package/dist/owner-faces.js +126 -0
  420. package/dist/park-row-commit.d.ts +67 -0
  421. package/dist/park-row-commit.js +76 -0
  422. package/dist/parked-decide.d.ts +76 -12
  423. package/dist/parked-decide.js +152 -11
  424. package/dist/parked-revive-surface.d.ts +14 -4
  425. package/dist/parked-revive-surface.js +5 -4
  426. package/dist/peer-directory.d.ts +7 -9
  427. package/dist/peer-directory.js +3 -2
  428. package/dist/permission-rule-vocab.d.ts +53 -8
  429. package/dist/permission-rule-vocab.js +30 -2
  430. package/dist/plugins/adoption-log-sql.d.ts +3 -25
  431. package/dist/plugins/adoption-log-sql.js +23 -21
  432. package/dist/plugins/approval-ask-retired-delete-by-task-m50.d.ts +7 -0
  433. package/dist/plugins/approval-ask-retired-delete-by-task-m50.js +17 -0
  434. package/dist/plugins/approval-ask-store-file.d.ts +18 -7
  435. package/dist/plugins/approval-ask-store-file.js +37 -14
  436. package/dist/plugins/approval-ask-store-memory.d.ts +12 -4
  437. package/dist/plugins/approval-ask-store-memory.js +24 -10
  438. package/dist/plugins/approval-ask-store-sql.d.ts +40 -21
  439. package/dist/plugins/approval-ask-store-sql.js +44 -15
  440. package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
  441. package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
  442. package/dist/plugins/approval-exemption-skill-m46.d.ts +14 -0
  443. package/dist/plugins/approval-exemption-skill-m46.js +21 -0
  444. package/dist/plugins/approval-exemption-store.d.ts +32 -2
  445. package/dist/plugins/approval-exemption-store.js +42 -19
  446. package/dist/plugins/approval-nonce-store.d.ts +39 -12
  447. package/dist/plugins/approval-nonce-store.js +72 -23
  448. package/dist/plugins/blob-backend.d.ts +2 -0
  449. package/dist/plugins/blob-backend.js +9 -6
  450. package/dist/plugins/caching-session-store.d.ts +13 -1
  451. package/dist/plugins/caching-session-store.js +43 -4
  452. package/dist/plugins/checkpoint-index-columns.d.ts +32 -5
  453. package/dist/plugins/checkpoint-index-columns.js +36 -1
  454. package/dist/plugins/checkpoint-store-face.d.ts +83 -10
  455. package/dist/plugins/checkpoint-store-face.js +18 -1
  456. package/dist/plugins/device-store-sql.js +1 -0
  457. package/dist/plugins/ensure-index.d.ts +13 -1
  458. package/dist/plugins/ensure-index.js +154 -21
  459. package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -18
  460. package/dist/plugins/ensure-schema-lock-policy.js +76 -9
  461. package/dist/plugins/file-run-store.d.ts +85 -32
  462. package/dist/plugins/file-run-store.js +177 -94
  463. package/dist/plugins/host-platform.d.ts +24 -3
  464. package/dist/plugins/host-platform.js +15 -1
  465. package/dist/plugins/image-bake-store-sql.js +2 -0
  466. package/dist/plugins/imported-layer-root-retirement.d.ts +2 -2
  467. package/dist/plugins/k8s-pod-reaper.d.ts +1 -3
  468. package/dist/plugins/k8s-pod-reaper.js +0 -1
  469. package/dist/plugins/leader-run-store-sql.d.ts +22 -0
  470. package/dist/plugins/leader-run-store-sql.js +34 -4
  471. package/dist/plugins/local-checkpoint-store.d.ts +62 -23
  472. package/dist/plugins/local-checkpoint-store.js +197 -77
  473. package/dist/plugins/local-data-dir-modes-m39.js +2 -1
  474. package/dist/plugins/local-data-root-admission.d.ts +52 -0
  475. package/dist/plugins/local-data-root-admission.js +100 -0
  476. package/dist/plugins/local-docker-capacity.d.ts +93 -0
  477. package/dist/plugins/local-docker-capacity.js +194 -0
  478. package/dist/plugins/local-docker-reaper.d.ts +92 -0
  479. package/dist/plugins/local-docker-reaper.js +102 -0
  480. package/dist/plugins/local-engine-high-water.d.ts +29 -6
  481. package/dist/plugins/local-engine-high-water.js +27 -19
  482. package/dist/plugins/local-session-store.d.ts +458 -140
  483. package/dist/plugins/local-session-store.js +906 -292
  484. package/dist/plugins/local-session-window.d.ts +3 -2
  485. package/dist/plugins/local-session-window.js +3 -2
  486. package/dist/plugins/local-sidecar-quarantine.js +3 -2
  487. package/dist/plugins/local-task-attachment-store.d.ts +18 -1
  488. package/dist/plugins/local-task-attachment-store.js +22 -1
  489. package/dist/plugins/memory-embedder.js +9 -7
  490. package/dist/plugins/memory-engine-pg.d.ts +3 -2
  491. package/dist/plugins/memory-engine-pg.js +14 -5
  492. package/dist/plugins/memory-engine-sql-apply.d.ts +8 -4
  493. package/dist/plugins/memory-engine-sql-apply.js +6 -8
  494. package/dist/plugins/memory-engine-tidb.d.ts +4 -2
  495. package/dist/plugins/memory-engine-tidb.js +11 -2
  496. package/dist/plugins/memory-optout-grant-store-sql.d.ts +1 -1
  497. package/dist/plugins/memory-optout-grant-store-sql.js +3 -3
  498. package/dist/plugins/memory-run-store.d.ts +53 -36
  499. package/dist/plugins/memory-run-store.js +116 -88
  500. package/dist/plugins/one-time-migration-marker.d.ts +26 -0
  501. package/dist/plugins/one-time-migration-marker.js +13 -0
  502. package/dist/plugins/one-time-migrations.d.ts +214 -47
  503. package/dist/plugins/one-time-migrations.js +481 -135
  504. package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
  505. package/dist/plugins/org-delivery-quota-store.js +31 -15
  506. package/dist/plugins/permission-rule-store-file.d.ts +3 -3
  507. package/dist/plugins/permission-rule-store-sql.d.ts +5 -64
  508. package/dist/plugins/permission-rule-store-sql.js +11 -95
  509. package/dist/plugins/pg-pool.d.ts +2 -32
  510. package/dist/plugins/pg-pool.js +24 -17
  511. package/dist/plugins/remote-env-device.d.ts +3 -2
  512. package/dist/plugins/remote-env-e2b.d.ts +8 -32
  513. package/dist/plugins/remote-env-e2b.js +44 -32
  514. package/dist/plugins/remote-env-host.d.ts +51 -17
  515. package/dist/plugins/remote-env-host.js +111 -42
  516. package/dist/plugins/remote-env-k8s.d.ts +40 -45
  517. package/dist/plugins/remote-env-k8s.js +111 -60
  518. package/dist/plugins/remote-env-local-docker.d.ts +152 -15
  519. package/dist/plugins/remote-env-local-docker.js +352 -72
  520. package/dist/plugins/remote-scratchpad.js +4 -0
  521. package/dist/plugins/retention-deployment.d.ts +49 -17
  522. package/dist/plugins/retention-deployment.js +39 -8
  523. package/dist/plugins/run-preview-m45.d.ts +11 -0
  524. package/dist/plugins/run-preview-m45.js +19 -0
  525. package/dist/plugins/run-store-sql.d.ts +82 -75
  526. package/dist/plugins/run-store-sql.js +164 -125
  527. package/dist/plugins/s3-answer.d.ts +2 -1
  528. package/dist/plugins/sandbox-reaper.d.ts +26 -0
  529. package/dist/plugins/sandbox-reaper.js +2 -0
  530. package/dist/plugins/scenario-prefix-switch-m42.d.ts +56 -0
  531. package/dist/plugins/scenario-prefix-switch-m42.js +56 -0
  532. package/dist/plugins/scheduler-support.d.ts +16 -1
  533. package/dist/plugins/scheduler-support.js +22 -2
  534. package/dist/plugins/schema-consistency.d.ts +131 -14
  535. package/dist/plugins/schema-consistency.js +388 -18
  536. package/dist/plugins/schema-drift-sentence.d.ts +10 -6
  537. package/dist/plugins/schema-drift-sentence.js +15 -7
  538. package/dist/plugins/schema-ensure-legs.d.ts +9 -0
  539. package/dist/plugins/schema-ensure-legs.js +1 -1
  540. package/dist/plugins/schema-indexes.js +3 -0
  541. package/dist/plugins/schema-live-columns.d.ts +14 -5
  542. package/dist/plugins/schema-live-columns.js +10 -10
  543. package/dist/plugins/send-user-file.js +2 -1
  544. package/dist/plugins/session-birth.d.ts +37 -0
  545. package/dist/plugins/session-birth.js +38 -0
  546. package/dist/plugins/session-epoch-anchor.d.ts +40 -12
  547. package/dist/plugins/session-epoch-anchor.js +33 -11
  548. package/dist/plugins/session-ext-table.d.ts +27 -3
  549. package/dist/plugins/session-ext-table.js +19 -6
  550. package/dist/plugins/session-fork.d.ts +15 -1
  551. package/dist/plugins/session-fork.js +3 -0
  552. package/dist/plugins/session-ownership.d.ts +1 -1
  553. package/dist/plugins/session-placement.d.ts +27 -20
  554. package/dist/plugins/session-placement.js +15 -12
  555. package/dist/plugins/session-row-sql.d.ts +12 -0
  556. package/dist/plugins/session-row-sql.js +3 -3
  557. package/dist/plugins/session-run-rollup.d.ts +29 -0
  558. package/dist/plugins/session-run-rollup.js +40 -0
  559. package/dist/plugins/session-store-sql.d.ts +38 -12
  560. package/dist/plugins/session-store-sql.js +130 -30
  561. package/dist/plugins/session-withdraw-sql.d.ts +36 -0
  562. package/dist/plugins/session-withdraw-sql.js +42 -0
  563. package/dist/plugins/shared-memory-store-sql.d.ts +0 -69
  564. package/dist/plugins/shared-memory-store-sql.js +2 -1
  565. package/dist/plugins/shell-sentinel-owner-m48.d.ts +42 -0
  566. package/dist/plugins/shell-sentinel-owner-m48.js +9 -0
  567. package/dist/plugins/snapshot-bucket-presence.d.ts +2 -1
  568. package/dist/plugins/sql-driver.d.ts +1 -1
  569. package/dist/plugins/sql-driver.js +2 -1
  570. package/dist/plugins/sql-errors.d.ts +32 -5
  571. package/dist/plugins/sql-errors.js +55 -7
  572. package/dist/plugins/sql-json-column.d.ts +8 -7
  573. package/dist/plugins/sql-json-column.js +10 -6
  574. package/dist/plugins/stop-then-start-sentence.d.ts +16 -0
  575. package/dist/plugins/stop-then-start-sentence.js +7 -0
  576. package/dist/plugins/store-backend.d.ts +99 -16
  577. package/dist/plugins/store-backend.js +230 -65
  578. package/dist/plugins/store-contracts.d.ts +123 -33
  579. package/dist/plugins/store-contracts.js +38 -1
  580. package/dist/plugins/store-fault.d.ts +28 -2
  581. package/dist/plugins/store-fault.js +20 -2
  582. package/dist/plugins/task-attachment-store.d.ts +15 -3
  583. package/dist/plugins/task-attachment-store.js +22 -9
  584. package/dist/plugins/tidb-pool.d.ts +11 -6
  585. package/dist/plugins/tidb-pool.js +39 -18
  586. package/dist/plugins/web-search.js +5 -3
  587. package/dist/plugins/workflow-run-store-sql.d.ts +6 -1
  588. package/dist/plugins/workflow-run-store-sql.js +11 -5
  589. package/dist/plugins/workspace-custody.d.ts +44 -0
  590. package/dist/plugins/workspace-custody.js +47 -0
  591. package/dist/principal-jwt.d.ts +4 -4
  592. package/dist/principal-jwt.js +20 -5
  593. package/dist/principal-shape.d.ts +41 -0
  594. package/dist/principal-shape.js +19 -0
  595. package/dist/project-identity.d.ts +8 -7
  596. package/dist/project-identity.js +40 -17
  597. package/dist/project-layer-key.d.ts +13 -2
  598. package/dist/project-layer-key.js +9 -1
  599. package/dist/question.d.ts +13 -23
  600. package/dist/question.js +21 -39
  601. package/dist/read-deny-floor-notice.d.ts +36 -0
  602. package/dist/read-deny-floor-notice.js +40 -0
  603. package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
  604. package/dist/request-declaration-disposition.js +39 -0
  605. package/dist/request-declaration-refusal.d.ts +35 -12
  606. package/dist/request-declaration-refusal.js +21 -9
  607. package/dist/request-form.d.ts +58 -0
  608. package/dist/request-form.js +72 -0
  609. package/dist/request-image-urls.d.ts +8 -2
  610. package/dist/request-image-urls.js +2 -1
  611. package/dist/request-images.d.ts +20 -0
  612. package/dist/request-images.js +59 -0
  613. package/dist/request-key-closure.d.ts +6 -7
  614. package/dist/request-key-closure.js +15 -2
  615. package/dist/resource-suspend.d.ts +7 -16
  616. package/dist/resource-suspend.js +1 -1
  617. package/dist/retired-name-host-notice.d.ts +21 -0
  618. package/dist/retired-name-host-notice.js +12 -0
  619. package/dist/rule-entry-list.d.ts +2 -2
  620. package/dist/rule-entry-list.js +3 -4
  621. package/dist/rule-issue-reading.d.ts +58 -0
  622. package/dist/rule-issue-reading.js +14 -0
  623. package/dist/rules-consent.d.ts +5 -3
  624. package/dist/rules-consent.js +1 -0
  625. package/dist/run-acceptance.d.ts +3 -1
  626. package/dist/run-acceptance.js +3 -0
  627. package/dist/run-cancel-card.d.ts +28 -0
  628. package/dist/run-cancel-card.js +19 -0
  629. package/dist/run-cancel-context.d.ts +10 -0
  630. package/dist/run-cancel-context.js +1 -0
  631. package/dist/run-local.d.ts +14 -6
  632. package/dist/run-local.js +117 -90
  633. package/dist/run-stale-default.d.ts +7 -0
  634. package/dist/run-stale-default.js +2 -0
  635. package/dist/runs.d.ts +56 -21
  636. package/dist/runs.js +73 -43
  637. package/dist/runtime-caps-resolver.d.ts +21 -6
  638. package/dist/runtime-caps-resolver.js +17 -4
  639. package/dist/runtime-governance.d.ts +2 -2
  640. package/dist/runtime-governance.js +5 -3
  641. package/dist/sealed-key-layout.d.ts +12 -5
  642. package/dist/sealed-key-layout.js +5 -0
  643. package/dist/sealed-key.d.ts +12 -2
  644. package/dist/sealed-key.js +115 -27
  645. package/dist/security.d.ts +128 -158
  646. package/dist/security.js +163 -59
  647. package/dist/sema-config-dir.d.ts +20 -0
  648. package/dist/sema-config-dir.js +25 -0
  649. package/dist/server-secret-env.d.ts +55 -25
  650. package/dist/server-secret-env.js +75 -22
  651. package/dist/session-agent.d.ts +3 -2
  652. package/dist/session-children-retire.d.ts +13 -8
  653. package/dist/session-children-retire.js +9 -7
  654. package/dist/session-deletion.d.ts +88 -0
  655. package/dist/session-deletion.js +8 -0
  656. package/dist/session-erase.d.ts +145 -0
  657. package/dist/session-erase.js +115 -0
  658. package/dist/session-error-wire.d.ts +5 -5
  659. package/dist/session-error-wire.js +1 -1
  660. package/dist/session-incarnation.d.ts +52 -5
  661. package/dist/session-incarnation.js +19 -2
  662. package/dist/session-policy-wire.d.ts +6 -3
  663. package/dist/session-policy-wire.js +11 -1
  664. package/dist/session-resident-background.d.ts +0 -71
  665. package/dist/session-resident-background.js +4 -3
  666. package/dist/session-row.d.ts +2 -1
  667. package/dist/session-rules-seat.d.ts +12 -0
  668. package/dist/session-rules-seat.js +19 -0
  669. package/dist/session-titler.d.ts +7 -15
  670. package/dist/session-titler.js +1 -1
  671. package/dist/session-workspace.d.ts +3 -3
  672. package/dist/spec-fields.d.ts +57 -3
  673. package/dist/spec-fields.js +72 -51
  674. package/dist/store-admission.d.ts +33 -0
  675. package/dist/store-admission.js +49 -0
  676. package/dist/store-posture.d.ts +141 -20
  677. package/dist/store-posture.js +205 -3
  678. package/dist/stored-request-hooks-m20.js +2 -2
  679. package/dist/stores-sql/background-agent-store-sql.d.ts +11 -2
  680. package/dist/stores-sql/background-agent-store-sql.js +73 -20
  681. package/dist/stores-sql/checkpoint-store-sql.d.ts +34 -29
  682. package/dist/stores-sql/checkpoint-store-sql.js +78 -49
  683. package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
  684. package/dist/stores-sql/file-history-store-sql.js +3 -5
  685. package/dist/stores-sql/mailbox-store-sql.d.ts +7 -4
  686. package/dist/stores-sql/mailbox-store-sql.js +31 -32
  687. package/dist/stores-sql/pg-session-storage.d.ts +7 -5
  688. package/dist/stores-sql/pg-session-storage.js +54 -46
  689. package/dist/stores-sql/retention-store-sql.d.ts +87 -19
  690. package/dist/stores-sql/retention-store-sql.js +92 -27
  691. package/dist/stores-sql/session-policy-store-sql.d.ts +32 -10
  692. package/dist/stores-sql/session-policy-store-sql.js +44 -36
  693. package/dist/stores-sql/session-write-hooks.d.ts +12 -6
  694. package/dist/stores-sql/tidb-session-storage.d.ts +4 -4
  695. package/dist/stores-sql/tidb-session-storage.js +13 -8
  696. package/dist/stores-sql/tidb-session-store.d.ts +36 -17
  697. package/dist/stores-sql/tidb-session-store.js +69 -39
  698. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  699. package/dist/stores-sql/tool-result-store-sql.js +4 -6
  700. package/dist/stores-sql/windowed-session-storage.d.ts +5 -0
  701. package/dist/stores-sql/windowed-session-storage.js +9 -0
  702. package/dist/submission-exit.d.ts +50 -0
  703. package/dist/submission-exit.js +108 -0
  704. package/dist/task-a2a.d.ts +3 -8
  705. package/dist/task-a2a.js +28 -30
  706. package/dist/task-cwd.d.ts +43 -7
  707. package/dist/task-cwd.js +11 -0
  708. package/dist/task-mcp.d.ts +3 -3
  709. package/dist/task-mcp.js +4 -4
  710. package/dist/task-settings.d.ts +14 -10
  711. package/dist/task-settings.js +19 -7
  712. package/dist/terminal.d.ts +27 -43
  713. package/dist/terminal.js +49 -14
  714. package/dist/tool-approval.d.ts +173 -163
  715. package/dist/tool-approval.js +247 -232
  716. package/dist/trace/core-keyset-guard.d.ts +13 -6
  717. package/dist/trace/core-vocab-wire.d.ts +95 -0
  718. package/dist/trace/core-vocab-wire.js +15 -0
  719. package/dist/trace/engine-notice-wire.d.ts +24 -21
  720. package/dist/trace/engine-notice-wire.js +7 -3
  721. package/dist/trace/exit-seat.d.ts +30 -4
  722. package/dist/trace/exit-seat.js +40 -36
  723. package/dist/trace/extension-call-face.d.ts +3 -2
  724. package/dist/trace/extension-call-face.js +3 -1
  725. package/dist/trace/ledger-events.d.ts +4 -7
  726. package/dist/trace/ledger-sink.d.ts +4 -31
  727. package/dist/trace/ledger-sink.js +0 -11
  728. package/dist/trace/model-segment.d.ts +5 -5
  729. package/dist/trace/model-segment.js +5 -5
  730. package/dist/trace/project.d.ts +59 -44
  731. package/dist/trace/project.js +60 -26
  732. package/dist/trace/redact.d.ts +135 -27
  733. package/dist/trace/redact.js +884 -260
  734. package/dist/trace/self-minted-wire.d.ts +567 -20
  735. package/dist/trace/self-minted-wire.js +205 -24
  736. package/dist/trace/wire-projection-faces.d.ts +5 -6
  737. package/dist/trace/wire-projection-faces.js +2 -2
  738. package/dist/upstream-body.d.ts +23 -0
  739. package/dist/upstream-body.js +16 -0
  740. package/dist/url-refusal.d.ts +3 -3
  741. package/dist/url-refusal.js +11 -4
  742. package/dist/user-authored-text.d.ts +1 -1
  743. package/dist/user-input-ledger.d.ts +7 -8
  744. package/dist/user-input-ledger.js +1 -1
  745. package/dist/web-admin-client/apply-effective.d.ts +6 -3
  746. package/dist/web-admin-client/apply-effective.js +33 -23
  747. package/dist/web-admin-client/apply-ledger.d.ts +16 -7
  748. package/dist/web-admin-client/apply-ledger.js +5 -2
  749. package/dist/web-admin-client/center-request.d.ts +2 -2
  750. package/dist/web-admin-client/center-request.js +15 -15
  751. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  752. package/dist/web-admin-client/effective-keys.js +1 -1
  753. package/dist/web-admin-client/entry-metadata.d.ts +8 -0
  754. package/dist/web-admin-client/entry-metadata.js +13 -0
  755. package/dist/web-admin-client/http-client.d.ts +1 -1
  756. package/dist/web-admin-client/http-client.js +23 -4
  757. package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
  758. package/dist/web-admin-client/mcp-revocation.js +2 -1
  759. package/dist/web-admin-client/read-warnings.d.ts +1 -0
  760. package/dist/web-admin-client/read-warnings.js +1 -0
  761. package/dist/web-admin-client/restart-signal.js +8 -4
  762. package/dist/web-admin-client/skills-mcp.d.ts +2 -2
  763. package/dist/web-admin-client/types.d.ts +1 -2
  764. package/dist/workspace-space.d.ts +3 -2
  765. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +4 -4
  766. package/docs/error-text-lexicon.json +317 -0
  767. package/package.json +8 -3
  768. package/scripts/drain-check-local.mjs +118 -147
  769. package/scripts/drain-check.mysql.sql +22 -2
  770. package/scripts/drain-check.pg.sql +22 -2
  771. package/scripts/embed-minimal.mjs +183 -0
  772. package/wire-changes/server@7.148.0.json +1517 -0
  773. package/wire-changes/server@7.149.0.json +372 -0
  774. package/dist/http/memory-control-plane-corrupt-reply.d.ts +0 -25
  775. package/dist/http/memory-control-plane-corrupt-reply.js +0 -19
  776. package/dist/http/memory-layer-reply.d.ts +0 -30
  777. package/dist/http/memory-layer-reply.js +0 -24
  778. package/dist/lsp/e2b-bridge.d.ts +0 -57
  779. package/dist/lsp/e2b-bridge.js +0 -139
  780. package/dist/lsp/e2b-manager.d.ts +0 -93
  781. package/dist/lsp/e2b-manager.js +0 -178
  782. package/dist/lsp/lsp-frames.d.ts +0 -14
  783. package/dist/lsp/lsp-frames.js +0 -25
  784. package/dist/lsp/manager.d.ts +0 -129
  785. package/dist/lsp/manager.js +0 -127
  786. package/dist/lsp/types.d.ts +0 -12
  787. package/dist/lsp/types.js +0 -2
  788. package/dist/lsp/ws-transport.d.ts +0 -40
  789. package/dist/lsp/ws-transport.js +0 -210
  790. package/dist/plain-string-record.js +0 -70
package/MIGRATION.md CHANGED
@@ -1,11 +1,1456 @@
1
1
  # 迁移指引(BREAKING 变更)
2
2
 
3
3
  > 版本策略:`@sema-agent/server` 1.x = 快速迭代期,行为破坏性变更可能落在 minor 版本
4
- > (内部多 AI 协作节奏,当日黑板通告+实解)。**生产部署请锁精确版本**;GA 后 2.0 起严格 semver
4
+ > (内部多 AI 协作节奏,当日通告+实解)。**生产部署请锁精确版本**;GA 后 2.0 起严格 semver
5
5
  > (BREAKING → major)。本文件只记录会影响存量部署行为的变更。
6
6
  >
7
7
  > ⚠️ 完整清单在仓库根 `CHANGELOG.md`——它**不随 npm tarball 出包**(本文件随包)。看完整迁移窗的
8
8
  > 权威姿势是源码 tag diff:`git diff v<旧>..v<新>`(每版都推 `v<版本>` tag);npm 包页也镜像 CHANGELOG。
9
+ > 文中的「契约 §N」「契约附录 X」指服务端 wire 契约的节号(内部记录,不随包),只作查证坐标。
10
+
11
+ ## 7.149.0 —— 1–40 条见下
12
+
13
+ **升级清单(本节唯一的一张;下面各条只讲为什么,不再各自重述升级步骤)** —— 一次读清本版对一只存量部署要做的全部动作。每版同形:① 手工 DDL(逐表逐句,两方言各一份)② 起服自建与一次性迁移 ③ 停-迁-起 ④ 顺序;后续每版的段头照此写,新增一句 `ALTER`、一条一次性迁移、一条停-迁-起时,先改这里,再写条目。
14
+ 已发各节(7.148.0 及以前)逐字只读,不在原处补汇总 —— 跨过它们的部署读下面「跨过 7.148.0」一块。起服拒句是同一张清单的运行期形:缺列拒、单表探针拒、一次性迁移的判活拒,每一句都带同一张升级清单:这只库此刻还差哪些 `ALTER`(按库实读,全库一次列全)、本构建带的**全部**停-迁-起迁移(M40 / M41 / M42 / M51,按登记表列,不判这只库欠不欠)、先后顺序;一次起服读全 `ALTER`,不必补一句再试一次。
15
+
16
+ - **从 7.148.x 升级到本版**:
17
+ - 手工 DDL(SQL 后端 `DB_BACKEND=mysql|pg`;一张表一句,**先升库、再升副本**;在跑的旧副本不受影响 —— 它的语句不提这一列;旧副本**重启**时按「库比构建新」拒启,多出的这一列是它的幽灵列)。语句逐字是起服列册对账拒句打印的那一句(由本构建的建表语句生成),不回填(第 21 条「停驻写只许这条 run 的持有腿落下」):
18
+ - MySQL 协议:
19
+ `ALTER TABLE task_run ADD COLUMN leg_id VARCHAR(36) NULL;`
20
+ - PostgreSQL:
21
+ `ALTER TABLE task_run ADD COLUMN leg_id VARCHAR(36) COLLATE "C";`
22
+ - 起服自建(运维零手工):无新表;一次性迁移标记表 `one_time_migration_marker` 改由中央建表语句建(`CREATE TABLE IF NOT EXISTS`,形不变,已有的不动)。
23
+ - 一次性迁移:本版**无新增**。停-迁-起:**无新增**。本版条目没有一条要求停光旧副本。漏了上面那一句 `ALTER` 的 7.148.x 库起服撞缺列拒,拒句升级清单的第 2 步仍照列本构建带的全部停-迁-起迁移,并说「先停光旧副本、不可滚动」—— 那一步不判这只库欠不欠:起过 7.148.x 的库四条都已走过(M42 / M51 读到标记、M41 读到部署格列已不在 `session_meta`、M40 读到零行旧词 ⇒ 各自不读心跳、零写放行),第 2 步对它是多余的保守句,照第 1 步加列,再按下一行的顺序滚动即可。
24
+ - 顺序:① 备份 ② 上面那一句 `ALTER`(先升库)③ 换版本(可滚动 —— 缺列拒句清单第 2 步的「不可滚动」对这一跨度不适用,见上一行;滚动窗里不要重启旧副本;新旧副本混跑的窗里「停驻写只许这条 run 的持有腿落下」一条的两项担保不成立,换完即成立)。
25
+ - **跨过 7.148.0(从 ≤ 7.147.x 直升本版)另加 7.148.0 节的全部动作**(库里还留着退役的 `snapshot_manifest` 表或 `checkpoint.pending_steer` 列的跳版库 —— 从没起过 7.74.0–7.125.x 的版本 —— 先撞退役 schema 拒:出路是先用一只 7.125.x 起服一次再升,那一跳不在这张清单里):
26
+ - 手工 DDL(SQL 后端 `DB_BACKEND=mysql|pg`;四张表十句,**先升库、再升副本**;旧副本不受影响,只在它重启时按「库比构建新」拒启)。语句逐字是起服列册对账拒句打印的那几句(由本构建的建表语句生成);表尚不存在的库(起服自建,建表语句已带新列)那一张零动作:
27
+ - MySQL 协议:
28
+ `ALTER TABLE leader_run ADD COLUMN error_code VARCHAR(64) NULL;` · `ALTER TABLE leader_run ADD COLUMN cancel_requested SMALLINT NOT NULL DEFAULT 0;` · `ALTER TABLE leader_run ADD COLUMN identity_source VARCHAR(32) NULL;` · `ALTER TABLE leader_run ADD COLUMN identity_scope VARCHAR(190) NULL;` · `ALTER TABLE leader_run ADD COLUMN identity_principal_inc VARCHAR(64) NULL;`
29
+ `ALTER TABLE session_ext ADD COLUMN client_writes BIGINT NOT NULL DEFAULT 0;` · `ALTER TABLE session_ext ADD COLUMN deleting_token VARCHAR(36) NULL;`
30
+ `ALTER TABLE session_meta ADD COLUMN forked_from VARCHAR(64) NULL;` · `ALTER TABLE session_meta ADD COLUMN forked_from_incarnation VARCHAR(64) NULL;`
31
+ `ALTER TABLE checkpoint ADD COLUMN host_session_id VARCHAR(190) NULL;`
32
+ - PostgreSQL:
33
+ `ALTER TABLE leader_run ADD COLUMN error_code VARCHAR(64) COLLATE "C" NULL;` · `ALTER TABLE leader_run ADD COLUMN cancel_requested SMALLINT NOT NULL DEFAULT 0;` · `ALTER TABLE leader_run ADD COLUMN identity_source VARCHAR(32) COLLATE "C";` · `ALTER TABLE leader_run ADD COLUMN identity_scope VARCHAR(190) COLLATE "C";` · `ALTER TABLE leader_run ADD COLUMN identity_principal_inc VARCHAR(64) COLLATE "C";`
34
+ `ALTER TABLE session_ext ADD COLUMN client_writes BIGINT NOT NULL DEFAULT 0;` · `ALTER TABLE session_ext ADD COLUMN deleting_token VARCHAR(36) COLLATE "C";`
35
+ `ALTER TABLE session_meta ADD COLUMN forked_from VARCHAR(64) COLLATE "C";` · `ALTER TABLE session_meta ADD COLUMN forked_from_incarnation VARCHAR(64) COLLATE "C";`
36
+ `ALTER TABLE checkpoint ADD COLUMN host_session_id VARCHAR(190) COLLATE "C";`
37
+ - 起服自建(运维零手工):`approval_nonce_floor`(7.148.0 节第 21 条)。
38
+ - 一次性迁移(起服时自跑,运维零手工):M42 场景前缀的切换检查 · M43 撤回出口的启用标记 · M44 run 的 `errorCode` 只读列 · M45 run 行预览列的旧形 · M46 引擎家 `Skill` 会话豁免行 · M47 / M50(`DB_BACKEND=local` 独有)· M48 cli 哨兵属主 · M49 检查点的归属会话回填(要先有 `checkpoint.host_session_id` 这一列,所以排在上面那句 `ALTER` 之后)· M51 会话在删态的切换。
39
+ - 停-迁-起(SQL 后端):**M42**(更早版本的副本不保留 `_scn:` 前缀)· **M51**(更早版本的副本不读会话的删除中状态);从 ≤ 7.146.x 直升的另有 **M40** · **M41**(7.147.0 节)。四条共用一个守卫谓词:判活窗(`REAP_RUN_STALE_SEC`)内库里还有 `running` run 在心跳 ⇒ 起服拒(`config.scenario_prefix_switch_refused` / `config.session_deleting_switch_refused` / `config.execution_lane_rename_refused` / `config.session_ext_move_refused`,拒句同一段动作),一个字节不写。守卫只看心跳:没有在跑 run 的空闲旧副本它看不见,**停全部旧副本是运维的动作**。
40
+ - 顺序:① 备份 ② 全部 `ALTER`(先升库)③ **停光**全部旧版本副本,等满判活窗(`REAP_RUN_STALE_SEC`,缺省 120 s,必须大于 30 s 的心跳周期,否则起服拒)④ 起**一只**本版副本(迁移在这次起服里自跑;拒句里的「可再起的时刻」= 最新心跳 + 判活窗)⑤ 再起其余副本。滚动升级在这一跨度上不成立。
41
+ - **数据根高水位(`DB_BACKEND=local`;每次起服的常设不变量)**:`<数据根>/engine-high-water.json` 记下打开过这只根的最高引擎版本。起服准入先判 —— 高于本构建 ⇒ 拒 `config.schema_mismatch`(`newer-engine`),数据根一个字节不动;判过之后、本构建的第一笔受保护写之前,把它抬到本构建的发布线(缺席或更低 ⇒ 写;相等 ⇒ 只证落盘)。所以成功起服之后 marker 恒不高于在跑的版本,带这一臂的更旧构建重开这只根会被拒(保护起点如实:只有旧的那一方带着这一臂才守得住,更早发出的版本改不了)。
42
+
43
+ 1. **没有身份边界(dev-open)的部署上,报了主体的调用方在每一口都是那位主体:会话读面与列表、存续面与键面、run 读面与 `/metrics` 族按主体头钉人,与提交挂接同读(安全收紧;行为变更;wire 零新键、零新码;部署零动作)**:
44
+ 「没有身份边界」= 没声明 `REQUIRE_PRINCIPAL`,且没配 `SERVICE_AUTH_TOKEN(S)`、鉴权桥 issuer(`AUTH_BRIDGE_ISSUER`;接了中心 ⇒ 回退中心基址,同算)、直连门、只读 `TRACE_TOKEN`(`/health.auth.kinds` 为空且后两者都没有)。
45
+ 旧形:这一形上主体头被读成「谁都能自报的标签」—— 每位调用方(带不带头)都持 fleet 资格:会话读面(视图 / head / 事件流 / 记忆状态 / 执行放置)、会话列表、改名置顶、fork、删除、同步族、记忆抹除、后台任务、MCP 重连、
46
+ 规则口、notify、审批豁免、run 的两只按 id 读口(`GET /v1/runs/:id` · `…/events`)、舰队流 / 名册 / trace 列表 / 用量 / 发件链接都不按头钉人,`/metrics*` 与 `GET /v1/tasks/source-summary` 不要凭据;
47
+ 而提交挂接(`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs` 带 `sessionId`)一向按头判属主 —— 同一位 `x-agent-principal: mallory` 往 alice 的会话提交答 `404 resume.session_not_found`,同时读得到那只会话的正文。
48
+ 新形:**报了主体的调用方恒是那位主体**(与带主体头的 service 凭据请求早已成立的那一句同读,部署形不改它);只有**不报主体**的调用方在这一形上代部署本人说话(fleet,读写照旧全开)——
49
+ 「不报」= 没有主体头,也没出示一枚这台部署验不过的 Bearer / token 凭据(带了它的请求没有可信身份:不代部署本人,只看得见普通无主行,列表 `401 auth.unauthorized`)。
50
+ 报了主体的调用方对别人的行:会话各口答各自「没有这一行」那一答 —— `404 not_found.session`,体与不存在的会话逐字节同(审批豁免 `404 not_found.session "not found"`;删除 `200 {deleted:false}`;
51
+ 同步推送族 plan / 导入 / blob 上传对别人的会话 404、对不存在的 id 照答它既有的新建那一答,与有身份边界的部署同形);
52
+ run 的两只按 id 读口 `404 not_found.run`;列表面(会话列表、舰队流 `meta.scoped:true`、名册、trace 列表、用量、发件链接)钉到这位主体,`?owner=` / `?scope=` 不生效;`/metrics*` 与 `GET /v1/tasks/source-summary` 答 `401 auth.unauthorized`(运维面句;配了 `METRICS_TOKEN` 时出示它照放,没带它的请求先答 401、不先读主体头)。
53
+ 无主的委派子代转录行(placed)对它与别人的行同答(只对不报主体的调用方 / 运维开放)。运维律不变:`OPERATOR_PRINCIPALS` 里的主体在运维可越的口(规则口 / notify / 执行放置 / 后台任务 / 审批豁免 / run 的监督口)照放,
54
+ 运维不越的读口(会话视图 / head / 事件流 / run 轮询)与别的主体同答。有身份边界的部署一字不变。
55
+ **谁受伤**:dev-open 部署上带主体头、靠「读面全开」去读或动别人会话 / run 的调用方与脚本;带主体头抓 `/metrics*` 的采集;带主体头当运维看全舰队的控制台;
56
+ 对没配 service 凭据的部署照样发一枚 Bearer 的客户端(那枚凭据这台部署验不过 —— 此前被静默忽略、照看全舰队,现在没有可信身份:列表 401,只看得见无主行)。
57
+ **出路**:要看全舰队 ⇒ 请求不带主体头、不带这台部署验不过的 Bearer(dev-open 上不报主体的调用方照旧代部署本人);或给部署配 `SERVICE_AUTH_TOKEN` 并以不带主体头的 service 凭据读(`SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT` 缺省即代部署本人);
58
+ 运维越属主照旧经 `OPERATOR_PRINCIPALS`。dev-open 上主体头仍是自报的,这一条给的是一致的「这次请求为谁」,不是隔离 —— 要按用户隔离照旧给部署接一个身份来源。
59
+ **升级前做**:无(零配置、零存储形变化)。**回滚**:回到 7.148.x 即回到旧形;无存储形变化。
60
+
61
+ 2. **判坏的停驻卡在三扇决断门上同拒,出路成一只机读词 `wayOut`;订正 7.138.0 节第 19 条 ②、7.146.0 节第 19 条、7.147.0 节第 29 条的出路句(wire 加性:一键;行为零变化;部署零动作)**:
62
+ 旧形:引擎判「本引擎续不了」的停驻卡(例:7.136.x 停驻、本版引擎读作 `requirements_damaged` 的工具门 / 计划门卡)在 `POST /v1/approvals/:id/decide`、`POST /v1/assistant/tasks/:id/plan_review`、
63
+ `POST /v1/assistant/tasks/:id/resume` 上批 / 拒 / 驳一律 `409`(`retriable: true` = 卡仍 pending),出路只在句子里。
64
+ 新形:码、句子、`retriable` 与各键不变,拒体多一键 `wayOut`(闭集;出路只看判决与这张卡本身,与门的哪一扇、决定词无关):
65
+ `cancel_run` —— 这张卡在本引擎上不收任何决定(批 / 拒 / 驳 / 改同拒);出路是 `POST /v1/runs/:id/cancel`:它把卡 expire、把 run 驱到取消终局、释放会话,之后另起任务;
66
+ `newer_worker` —— 更新引擎停驻的行,不低于停驻它那一版的 worker 续得了它,同一决定在那里落得下;卡留 pending(cancel 在这里是放弃它)。
67
+ 判坏而取消动词不会结算这张卡(卡停在已终局的 run 的纯 park 上、run 已终局而卡仍挂着、run 在跑、归属说不出的老行,或没有耐久 run 店)⇒ 键缺席:本服务说不出客户端出路,由运维处置那一行。
68
+ `/plan_review` · `/resume` 上引擎对这张卡的拒原样过境(行记下的配置词拒的 `field` / `blockedBy` 照在),卡仍 pending 时带 `wayOut`;`/decide` 的这一行自己的拒同。
69
+ 不带 `wayOut` 的拒:决定体那一格的拒(改那一格再决)、部署事实的拒、`POST /v1/sessions/:id/wake`。
70
+ 订正(已发节不改字节):7.138.0 节第 19 条 ② 的出路「拒掉」—— 引擎 7.63.0 起这类行连拒也在认领前被拒;7.146.0 节第 19 条 ①「升级前做」与 ④ 补偿句里的「expire」—— 客户端的那一个动词是 `POST /v1/runs/:id/cancel`;
71
+ 7.147.0 节第 29 条「补偿 / 升级前做」的「出路是作为新任务重提」—— 只重提不离队:卡仍在队里,同一会话上的 run 仍持会话锁(新任务 `409 conflict.session_active_run`),先 cancel。三处的出路一律读拒体 `wayOut`。
72
+ **谁受伤**:按拒体全键集逐字断言的消费方(多一键)。
73
+ **出路**:壳按 `wayOut` 渲出路(`cancel_run` ⇒ 只给「取消这条 run」,不给批准 / 拒绝按钮;缺席 ⇒ 提示找运维),不按 `retriable` 渲「再决」;部署零动作。
74
+
75
+ 3. **取消停驻 run 时,卡的属主读店里的属主格、不读行体:行体与店不一致或读不成检查点,取消照样结卡、驱 run 终局;判坏的卡的 `wayOut: cancel_run` 跟着取消动词走;另外四条作废卡的路同读店的属主格(行为修复;wire:取消口两面状态 `409` / `500` → `202`,`wayOut` 在场律放宽;零 DDL;部署零动作)**:
76
+ 旧形:`POST /v1/runs/:id/cancel` 对停在门上的 run,先读那张卡的行体、再拿行体里自带的属主格去 CAS 结卡 —— 而 CAS 的谓词吃的是店里的属主格(路由层的属主门也读它);两份说法一致时读哪份都一样,不一致时只有店里的那一格能让 CAS 命中这一行。
77
+ 两处不一致(被手改 / 外来写者写下的行)时 CAS 打空,取消答 `409 conflict.approval_settled`(「被并发决议了」,与事实不符;卡与 run 都没动);行体读不成检查点时取消答 `500 internal.error`。
78
+ 一条续跑腿被取消之后结算它续的那张卡,读法同(卡留 pending,留给收割)。7.149.0 新增的 `wayOut: cancel_run` 又按载入的行体判「取消落不落得下」,行体坏得越厉害越说不出出路 —— 恰是最需要被指出来的那些卡。
79
+ 新形:取消动词找卡、结算卡只读店的列(归属 run 的会话 × 活 run 的门型找卡,属主格读属主列);行体怎么坏(读不成检查点、属主格丢了或与店不一致、整格 `{}`)都不改变取消落不落得下:
80
+ 卡 expire、run 取消终局、会话锁放开,答 `202`(体与取消停驻 run 的 `202` 同形)。`wayOut` 问取消动词自己那一问:`cancel_run` 当且仅当取消动词会结算这一张卡(有耐久 run 店;卡归属的 run 会话上持着认领的 run 停着;取消动词在那条会话上找到的恰是它)——
81
+ 行体读不成检查点或属主格丢了的坏卡也给;卡是已终局的 run 的纯 park、run 已终局而卡仍挂着(取消口对终局的 run 是空操作)、run 在跑(取消口只挂旗)、归属说不出的老行(升级窗里旧副本写下、回填前的行)、没有耐久 run 店(取消口恒 `501`)⇒ 键缺席。`POST /v1/sessions/:id/wake` 的读行拒仍不带 `wayOut`。
82
+ 取消口一向不读请求体,没有字段被读或被删;这里的「体」指停驻卡存储行里的 JSON 快照。
83
+ 同一读法推广到另外四条「按令牌作废一张卡」的路 —— 全仓「把一张 pending 卡 CAS expire」从此只有一种读法(属主格读店的列、不读行体):① 审批 SLA 拒扫腿对「准入策略挡住」的续跑当场过期该卡;② 会话删除 / 显式结清口(`POST /v1/sessions/:id/children/retire`)带走停驻子代时作废它的卡;③ 停驻写没落定就以失败收场时作废手里那张卡;④ 复活不了的停驻子代被 `deny` 时作废它的卡。
84
+ 这四处此前也是先读行体、再拿行体里的属主格去配:行体与店不一致或读不成检查点时,拒扫腿把「没过期成」记成「输给了并发」而卡留 pending 到收割,结清口 / 删除作废不了那张卡(子代停不净,答未净或读抛),结算作废静默放过或记「卡对不上」/「店读错」(兑现不了的卡留在待决面),`/decide` 的 `deny` 答 `409 decide.gate_moved`。现在这四条路上走得到作废的卡被作废,上列失败随之消失;好卡的结局一字不变。共用读法的次序恒为「先读状态、(要求归属就)再核归属、最后按属主列 expire」,取消口与取消之后的续跑腿结算同此:卡已不在待决面(已结 / 已不在)不再写一次(店写口故障时也不因此失败;取消口此前会答 `500`,现按 run 此刻的真实状态答 `409` / `202`),那一问读行状态、不读行体里的属主格;行体读不成检查点时读不出状态,不当作「已结」,交给吃列的 CAS 判。
85
+ **已知边界**:① 拒扫腿要先从行体读出待批动作与世代号才去过期,整格 `{}` / 读不成检查点的行认不出这些,不走到过期那一步(修前同);`/decide` 的行形判官先于赎回腿,判坏的行答该行自己的拒 —— 这两处本版未动。② 行体读不成检查点(JSON `null` 字面)的停驻子代,卡被作废,但子代行翻终局要引擎对账读卡状态,而对账读的是行体、读不出就不动它 —— 结清口 / 删除对这一形仍答未净;要对账改读状态列,属引擎侧,本版未做。
86
+ **谁需要**:用 `POST /v1/runs/:id/cancel` 清停驻坏卡的部署与壳(被手改的行、存储损坏的行);卡行被手改 / 被外来写者写过的部署上的会话删除、结清口与 `/decide` 的 `deny`。**谁受伤**:无 —— 取消此前对这些卡答的 `409` / `500` 本来就是没有落下的取消,那四条路此前的失败同理;
87
+ 依赖「这类取消恒 `409`」的脚本在第一次调用就得 `202`。**出路 / 补偿**:无需动作;零存储形变化。
88
+
89
+ 4. **有身份边界的部署上,存量 cli 哨兵属主行不再零信号:起服时对留着没改的行只数不写,有就一行 warn 给出各面计数;并订正 7.148.0 节第 86 条漏写的约束 —— 判「有没有身份边界」读的是起服那一个进程自己的配置(文字订正 + 日志面加性;行为零变化;wire 零变化;部署零动作)**:
90
+ 旧形(7.148.0 节第 86 条):一次性迁移 M48 只在没有身份边界的部署上把哨兵属主 `anon:shell-live` 改写成无主;有身份边界的部署上零改写、读数 0 —— 起服日志里看不出库里还留着多少行,运维要自己 `SELECT COUNT(*)`。
91
+ 第 86 条没有写明的约束:判「有没有身份边界」读的是**起服的那一个进程**的配置,而改写落在整只库 / 数据根上、不可逆。同一只库 / 数据根被身份配置不同的进程打开
92
+ (`run-local` 不带服务凭据 / 鉴权桥;嵌入方的起服序列在装配验签器之前先打开店;临时进程连着共享 SQL 库)时,一样身份键都不带的那个进程先起,就会替有身份边界的服务进程把这些行改成无主(改写只在下面五样一样都没有时发生)——
93
+ **打开同一只库 / 数据根的每个进程,都至少要带一样身份键**(service 凭据、鉴权桥、`REQUIRE_PRINCIPAL`、直连门、只读 trace 凭据,任一即可)。改写之后的行是普通无主行(第 86 条「放给谁」一段照旧适用),不会因为后来起的有边界进程而回来。
94
+ 想刻意收成无主,等价于用没有身份边界的配置起一次(第 86 条的手工一步是同一件事的 SQL 写法)。
95
+ 新形(日志面,加性):有身份边界的部署起服时,M48 对同一批面(SQL:`session_meta` / `task_run` / `leader_run`;`DB_BACKEND=local`:会话元数据格与 run 行)用**与改写同一个逐字节比较**只数不写。
96
+ 留着的行数大于 0 ⇒ 一行 warn `shell_sentinel_rows_retained`:`backend`、`rows`(总数)、`surfaces`(逐面计数,只列非零的面;local 上 `session_meta` = 会话元数据格、`task_run` = run 行)与指向第 86 条手工一步的 `note`;
97
+ 起服迁移读数行多一键 `shellSentinelOwnerRowsRetained`(总行数),汇总行 `one_time_migrations_applied` 在这时是 warn。计数为 0 ⇒ 没有这一行。窗内每次起服都数、每次起服都报,直到有人处置。没有身份边界的部署改写行为不变,不数。
98
+ **谁需要**:多个进程共用一只库 / 数据根的部署(服务进程与 `run-local` 同根;嵌入方先于验签器装配;临时进程连着共享库)。**谁受伤**:无 —— 多三句(local 为内存里的一遍)只读计数与有行时的一行日志。
99
+ **已知边界**:这一行说的是「此刻库里属主为这个字面量的行有多少」,不区分存量与新写 —— 有身份边界的部署上主体恰为 `anon:shell-live` 的调用方新写下的行同属这个属主,同样被数进来;它不拦截不带任何身份键的进程:
100
+ 这样的进程先起并改写时,改写那一方的起服日志里是读数 `shellSentinelOwnersCleared`(warn),有边界的进程之后再起读到的是 0。
101
+
102
+ 5. **订正 7.148.0 节第 64 条 ⑦ 与第 115 条的用词:受限技能那一问(配置有没有接已验身份来源)在已发文字里被叫「身份边界」,订正为「已验身份来源」;起服拒句的措辞随之改(文字订正 + 拒句措辞;判据、拒启面、出路零变化;wire 零变化;部署零动作)**:
103
+ 7.148.0 节里「身份边界」一词有两个意思。第 86 条(一次性迁移 M48)与属主门的 dev-open 判据问的是「这台部署有没有身份边界」:声明了 `REQUIRE_PRINCIPAL`、或配置接了任一已验身份来源(服务凭据 / 鉴权桥 / 直连门)、或声明了只读 trace 凭据 ⇒ 有。
104
+ 第 64 条 ⑦ 的「名单的强度 = 部署的身份边界:没有身份边界的部署(没接任何已验身份来源:……;只设 trace 凭据或只开 `REQUIRE_PRINCIPAL` 不算)上写了 `audience` ⇒ 起服拒」与第 115 条旧形句里的「受限技能的身份边界座」问的是另一件事:配置里有没有接**已验身份来源**(只设 trace 凭据或只开 `REQUIRE_PRINCIPAL` 不算)。
105
+ 两问都对,只是不许共用一个词。订正:受限技能这一问只叫「已验身份来源」(括号里的判据本来就是它,事实不变);「身份边界」只答第 86 条那一问。
106
+ 起服拒句首句随之从 `…but this deployment has no identity boundary: it wires no verified identity source (…)` 改为 `…but this deployment has no verified identity source: no service credential, no SSO bridge and no direct-door principal JWT is wired (…)`,
107
+ 句尾的不变量名从 `a2a-audience-identity-boundary` 改为 `a2a-audience-verified-source`;判据(`A2A_SERVE_SKILLS` 写了 `audience` ∧ 配置没接任何已验身份来源 ⇒ 起服拒)、拒启面与两条出路(接一个已验身份来源 / 删掉 `audience`)一字不变。
108
+ 已发的 7.148.0 节不改字节,订正记在这里;USAGE 里的同一句已按新词改。**谁受伤**:无;只把拒句文字做硬匹配的脚本要改匹配串(拒句文字不属 wire 契约)。**出路**:无需动作。**回滚**:不适用(文字 + 拒句措辞)。
109
+
110
+ 6. **嵌入方:验签器席(`ServiceDeps.webAdminJwtVerifier`)多一只必填只读成员 `issuer`,`createHttpServer` 的验签器 × 配置成对座多一判 —— 验签器验的 issuer 必须就是配置读出来的桥 issuer,不一致构造期拒启(嵌入方类型面 + 装配面 BREAKING;服务入口零变化;wire 零变化;部署零动作)**:
111
+ 旧形:席的型是 `{ verify(bearer) }`,成对座只比「在不在」(上一版把两个方向钉在构造期);验签器验 X、配置里的桥写 Y 的嵌入起得来 —— `/health.center.issuer` 报 Y,门收 X 的令牌。
112
+ 新形:席的型多 `readonly issuer: string`(这只验签器验令牌的 issuer);成对座第三判:它与配置读出来的桥 issuer(显式 `authBridgeIssuer` 恒赢,缺席而接了中心 ⇒ 中心基址回退)两侧去尾斜杠后相等才起。
113
+ 不等,或(绕过类型的)验签器没有字符串 `issuer` ⇒ `createHttpServer` 抛,句子以 `createHttpServer: the injected webAdminJwtVerifier verifies issuer` 起头并点名两个值(过 display-safe 铸点,userinfo / query 值不进句子)。
114
+ **谁受伤**:自己注入验签器的嵌入方 —— 验签器对象没有 `issuer`(TypeScript 编译红;JavaScript 构造抛),或验的 issuer 与配置里写的不是同一个。服务入口(`sema-server` 进程 / 镜像 / chart)与不注入验签器的嵌入方无。
115
+ **补偿 / 做法**:在自己的验签器对象上加 `issuer: "<它验令牌的 issuer>"`,让配置里的桥(`authBridgeIssuer`;接了中心而没写它 ⇒ 中心基址)写同一个值;两侧只差尾斜杠不算不一致。
116
+ **升级前做**:嵌入方按上面对齐;服务入口无。**回滚**:无存储形变化。
117
+
118
+ 7. **嵌入方(运行期):`createHttpServer` 对 `peerDesk` 与 `scenarioGate` 两个必填席也在构造期判 —— 绕过类型省掉它们(或传形不对的值)当场拒启并点名席名(行为收紧;类型面、wire、部署零变化)**:
119
+ 旧形:这两席只有型必填。绕过类型(JS / `as` 硬转)省掉 `peerDesk` ⇒ 起得来、监听,每条提交在受理漏斗开宿主租约处读 `undefined.lease`,答 `500 internal.error`;省掉 `scenarioGate` ⇒ 起得来,不带场景头的提交不受影响(它读 `resolveSpec` 自铸的那一只门),`GET /v1/capabilities/mcp` 状态面等读口与带场景头的请求(分派层的在册判问这一席)答 `500 internal.error`。
120
+ 新形:`createHttpServer` 入口在 `runnerFor` / `authorize` / `deploymentMods` 三只拒之后多两只同形的拒:`peerDesk` 缺 `lease` / `declare` / `seat.answer` 任一 ⇒ 抛 `createHttpServer: the peerDesk seat is required — …`;`scenarioGate` 不是函数或没有 `known` ⇒ 抛 `createHttpServer: the scenarioGate seat is required — …`。`runner` / `sideQuery` / `resolveSpec` 仍只有型必填。
121
+ **谁受伤**:绕过类型省掉这两席(或传形不对的值)的嵌入方 —— 此前起得来,现在起不来;TypeScript 嵌入方此前就是 tsc 红,服务进程入口的部署不经此路,零影响。**出路**:传这两席 —— `createPeerDesk()`(包根,零 IO;它的 `.seat` 同时给每只 Runner 的 `peerSeat`)与 `createScenarioGate({ config, scenarios, principalCaps, logger }, "peek")`(包根);随包的 `scripts/embed-minimal.mjs` 是可运行的写法。
122
+
123
+ 8. **`DB_BACKEND=local`:比本构建新 / 本构建读不出 / 跳过了必经一次性迁移的数据根,拒启时数据根零写(行为修复;wire 零变化;部署零动作)**:
124
+ 旧形:引擎版本高水位与跳版拒启臂在「打开数据根」那一步判、严格边档在起服对账里判;判之前起服已落下保管店的两把新钥匙(`sealed-key/exec-*.json`)、`prompt-epoch/` 店目录、
125
+ 引擎内核取锁时的店目录与两只 0 B 账本,配置根与数据根合一时还有 `config.migration.SS-M11.json`;严格边档那一形连 marker 首写与本服务各店目录都在拒之前。
126
+ 新形:这几种判收进一只只读的数据根准入,HTTP 服务在起服第 1 段(配置根供给之前)、`run-local` 在同一位置、公开序列 `createStoreBackend()` 在打开时取;拒 ⇒ 数据根一个字节不动(不取锁)。
127
+ 拒的码(`config.schema_mismatch`)、读数种别与出路不变;起服形拒句末行改为「拒启没有动数据根」。准入之后、取锁之前另一只引擎碰了这只根(marker、会话元数据边档、存档目录或欠账标记任一变了)⇒ 打开那一步拒(专句,出路 = 重起再判)。准入按物理路径判(经符号链接 / `..` 的数据根路径判的是真目录)。
128
+ **谁受伤**:无;拒启进程的输出里不再先出现保管店 / 店目录的起服行。**升级前做**:无。**回滚**:回到 7.148.x 即回到「判之前先落钥匙 / 目录 / 空账本」;用 7.148.x 或更早被拒过的根上多出的新钥匙文件与空目录无害(旧构建按 `publicKeyId` 读不到就重铸自己的),可留可删。
129
+
130
+ 9. **跨主体投递口:额度拒的 429 多一键 `retryAfterSec` 与同值 `Retry-After` 头;配额状态文件读不出的拒有了专码 `internal.org_delivery_quota_unreadable`;嵌入方自建配额店的返回形换成判决(嵌入方类型面 BREAKING;wire 加性 + 一码;部署零动作)**:
131
+ 旧形:`POST /v1/principal-inbox/messages` 的额度拒答 `429 org_delivery.rate_limited`,体只有 `error` / `errorCode`、没有 `Retry-After` 头;`DB_BACKEND=local` 的配额状态文件读不出时,每次投递答 `500 internal.error "internal error"`;`OrgDeliveryQuotaStore` 的 `admitAttempt` / `take` 返回 `Promise<boolean>`;`ServiceDeps.orgDeliveryGate` 的型是引擎的 `OrgDeliveryGate`。
132
+ 新形:429 体多 `retryAfterSec`(整数秒,到当前挂钟整点桶结束,向上取整、≥ 1)、响应多同值 `Retry-After` 头,三种额度拒同口径、同一个数;配额文件读不出 ⇒ `500 internal.org_delivery_quota_unreadable` + 固定句(不点名宿主路径),无 `Retry-After`(运维修好或移走坏文件并重启本服务才恢复 —— 店只在起服时读这份文件;移走 = 当前桶计数清零);`OrgDeliveryQuotaStore` 的两个动词返回 `Promise<OrgDeliveryQuotaVerdict>`:放行 `{ granted: true }`,拒 `{ granted: false, retryAfterSec }`(包根导出该型);`ServiceDeps.orgDeliveryGate` 的型换成对引擎契约的子型 `ServerOrgDeliveryGate`(包根导出它与 `ServerOrgDeliveryOutcome`):`rate_limited` 一词的答案必带 `retryAfterSec`,另三词与引擎契约逐字相同。
133
+ **谁受伤**:自建配额店、或自建 `ServiceDeps.orgDeliveryGate` 的嵌入方(tsc 红即通告);只用 `internal.error` 字面识别「配额文件坏」那一形的消费方(此前它与一切未分类 500 同码)。**出路**:自建店把 `true` 换成 `{ granted: true }`、`false` 换成 `{ granted: false, retryAfterSec }`(秒数 = 店钟到当前窗结束,向上取整、≥ 1);自建门把 `rate_limited` 的答案补上 `retryAfterSec`;按 `internal.` 前缀读 500 的消费方零动作;服务进程部署零动作。
134
+
135
+ 10. **settings hook 的环境多一个来源:部署方 `HOOK_ENV_ALLOW` 点名放回的服务进程变量(新旋钮,缺省空;嵌入方类型面:`ServiceConfig` 多一只必填席 `hookEnvAllow`;`settings.env` 凭据拒的 message 多一句;wire 零新键、零新码;部署零动作)**:
136
+ 旧形:hook 环境(命令钩子的子进程环境与 http 钩子 header 的 `$NAME` 插值同读)= 十二名基础变量 + 请求 `settings.env`;`settings.env` 不收凭据 ⇒ http 钩子 header 里的秘密形 token 没有合法通道,恒为空串。
137
+ 新形:`HOOK_ENV_ALLOW=NAME,NAME` 点到、且服务进程环境里在的变量原样放回 hook 环境;能插哪些名仍是条目 `allowedEnvVars` ∩ `settings.httpHookAllowedEnvVars`(只收窄,请求层授予不了服务进程变量);点名本服务自有凭据 / 名单型旋钮 ⇒ 拒启;值是本服务某一枚凭据的另一个变量同样拒启(本节「本服务凭据换个变量名放着也不出任何出口」一条);`REQUIRE_PRINCIPAL=true` 下忽略并起服 warn。`400 request.env_credential_refused` 的 `message` 在「挪进引擎进程环境」之后多一句:settings hook 要读它,部署方还要在 `HOOK_ENV_ALLOW` 点名(`errorCode` / `field` / `entries` 不变)。
138
+ **谁受伤**:自建 `ServiceConfig` 的嵌入方(tsc 红即通告);按该拒句 `message` 全文匹配的脚本。**出路**:嵌入方补 `hookEnvAllow: []`(或按需点名);webhook token 放进引擎进程环境,部署方写 `HOOK_ENV_ALLOW=<名>`、钩子条目的 `allowedEnvVars` 列它;壳自起的本机引擎由壳写这只旋钮;读拒句按 `errorCode` 分支。
139
+
140
+ 11. **`REMOTE_EXEC=host` 车道:本服务铸的临时工作区归持有它的执行环境,最后一只放手的删它;同一身份的续跑腿拿回停驻腿的那一只环境(行为修复;wire 零变化;部署零动作)**:
141
+ 旧形:请求不带 `cwd` ⇒ 父 run 的一次性工作区 `<HOST_WORKSPACE_BASE>/sema-host-<id>-<rand>` 在父 run 终局、销毁执行环境时被删,不管落在里面的后台子代是不是还停驻在审批门上;
142
+ 被批准之后续跑腿另铸一只新目录,命令落在已删的那只上(引擎拒句 `the task root directory no longer exists`);同一身份每次调工厂都另铸一只新环境(续跑腿拿到空目录)。
143
+ 新形:同一身份(顶层 run = run 号,委派子代 = 它自己的会话号)还有一只没收场的执行环境 ⇒ 工厂交回它;一次性工作区由落在它里面的执行环境共同持有,最后一只放手的删它
144
+ (父收场时停驻的子代还持有它 ⇒ 不删;子代最后一条腿收场 ⇒ 删)。带 `cwd` 的形零变(调用方目录永不删)。
145
+ **谁受伤**:停驻中被取消 / 过期的后台子代持有的一次性工作区活到进程退出(退出兜底删),此前随父收场即删。**出路**:提交时带 `cwd`;进程重起之后才批准的不带 `cwd` 的停驻子代仍落在已删目录上(重起时临时目录已被退出兜底删),同样带 `cwd`。
146
+ 嵌入方类型面(包入口不出口,只影响直接 import 适配器源文件的嵌入方):`hostExecutionEnvFactory(config, legOf?)` 多一只逐腿参数、对同一身份交回同一只环境;`RemoteHostExecutionEnv.destroy()` 第二次调用等同一次收场。
147
+
148
+ 12. **请求体 `a2aPeers[i].headers` 里成员名 `constructor` / `prototype` 起拒:与 `mcpServers[i].transport.headers` / `.env` 同一张保留成员名表、同一个拒形;存盘续跑体里带这样 A2A 头名的停驻任务续跑被拒(行为收紧;wire 零新键、零新码;部署零动作)**:
149
+ 旧形(本版之前):A2A 对端 `headers` 只拒名叫 `__proto__` 的成员;名叫 `constructor` / `prototype` 的成员照收(200),作头名交给对端座、发送时按原字节发出。
150
+ 新形(自本版起):三个保留名(`__proto__` / `constructor` / `prototype`,与 MCP 传输记录同一张表、同一只读法)同拒 —— 新提交 `400 request.field_invalid`,`field` 点名成员级路径(如 `a2aPeers[0].headers.constructor`),原因句与 MCP 面逐字同一句,不回显值;名字大小写敏感(`Constructor`、`X-Prototype` 照收)。
151
+ 续跑重放:存盘的请求体里带这样 A2A 头名的对端,在本部署兑现请求 A2A 时读不出 ⇒ 按「请求成员读不出」那一只判据拒续跑(`409 resume_blocked_by_policy`,`blockedBy` = `request.field_invalid`,`field` = `a2aPeers[i].headers.<名>`),卡 / 任务仍待决、行不动(此前这样的对端照挂,这一名作头名发出)。
152
+ **谁受伤**:把 `constructor` / `prototype` 当 A2A 头名写进请求体的调用方(极罕见),与升级前停驻、存盘体里带着这样头名的任务。**出路**:改头名;停驻的任务续跑时带合形的 `a2aPeers` 整表(续跑时换表),或取消后按本版的形重提。
153
+
154
+ 13. **`GET /v1/models` 的行多一键 `contextWindowSource`(`declared` / `assumed`);窗口没人声明的模型起服 / 目录落地时各一行 warn `model_context_window_assumed`;`ServiceConfig` 多两只必填席;窗口没人声明时的假定窗由 262144 改为 131072(wire 加性;运维日志加一行;嵌入方类型面 BREAKING;已声明窗口的部署零动作)**:
155
+ 旧形:窗口没人声明(目录条目没写 `contextWindow`、部署没设 `MODEL_CONTEXT_WINDOW`)时本服务落假定值 262144,行上只给数,日志零行。
156
+ 新形:行上 `contextWindowSource` 与 `contextWindow` 同进退(`assumed` = 假定值);模型表定形之后(起服在目录应用之后;运行中每次模型面落地之后),此刻服务的表里窗口是假定的模型各一行 warn `model_context_window_assumed`(字段 `model` / `contextWindow` / `declareAt`;每个模型名每进程一次;在 boot 被目录顶替的 env 模型不说)。**假定值由 262144 改为 131072**(取栈内部署里有人亲手声明过的最小真窗;单点一处改,不按模型族分档):压缩触发点按更小的窗算,工具 schema 延迟阈值(窗的 10% × 每 token 3 字符)由 78 642 降到 39 321 字符;`MODEL_MAX_TOKENS` 缺省仍是 32000。
157
+ 自拼 `ServiceConfig` 的嵌入方:新增必填席 `envModelContextWindowSource`(`"declared" | "assumed"`)与 `contextWindowSources`(与 `models` 同键的目录名 → 来源表),均由 `loadConfig` 一次铸出、中心热应用与 `models` 一起换。
158
+ **谁受伤**:按 schema 严格校验 `/v1/models` 行的消费方(多一键);告警规则对「起服零 warn」有断言的部署(没声明窗口的部署多一行);自拼 `ServiceConfig` 的嵌入方(tsc 红即通告);真实窗口大于 131072 却没声明窗口的模型(`contextWindow` 读数由 262144 变 131072,压缩提前,工具 schema 延迟阈值降到约 39 000 字符;已声明窗口的部署不受影响)。**出路**:放行该键;声明真实窗口(目录条目 `contextWindow` / 部署 `MODEL_CONTEXT_WINDOW`,cheap 槽 `MODEL_CHEAP_CONTEXT_WINDOW`)即消掉那一行、也即回到真实的大窗(`GET /v1/models` 行 `contextWindowSource:"assumed"` 指出哪几行在吃假定值);嵌入方从 `loadConfig()` 的结果起拼,或按上面的形补两席。
159
+
160
+ 14. **settings 的 `PreToolUse` 钩子:`ask` 带 `updatedInput` 的改写现在生效(行为修复;类型面、wire、部署旋钮零变化)**:
161
+ 旧形:钩子回 `permissionDecision: "ask"` 并带 `updatedInput`(真改写,与它看见的输入不同)时,本服务只记「要问人」,**丢掉改写** —— 审批卡显示模型自己的参数,人批后执行的是模型自己的参数,叠加的 `deny` 规则(如 `Write(protected/**)`)判的也是模型自己的路径;同一份改写换成 `allow` 或不带 `permissionDecision` 则生效。
162
+ 新形:`allow` / `ask` / 不带决定词三形的改写同一条读法 —— 卡上读的、批后执行的、其后的组 / 相(含托管守卫,托管相条目改写则整相按新输入重判一遍)与 `deny` 规则判的,都是改写后的参数(同一组里的条目共用组开始时的那一份载荷,与 `allow` 的改写同)。判词不可信(拿到截断标记 / 超预算按选中)的条目,`ask` 照收、改写不作数,非托管条目此时多一行 warn `hook_verdict_not_honored` 与一帧 `hook_verdict_untrusted`(此前这一形无声)。「放行的是哪一份参数」仍只有 `allow` 才记。
163
+ **谁受伤**:写了 `updatedInput` 却没打算让它生效的 `ask` 钩子(此前被静默丢掉)现在会生效;只问不改写的钩子结果逐字不变。**出路**:不想改写就不要在 `ask` 里交回与输入不同的值(与看见的输入规范化后相同的值不算改写);运维不需要动任何旋钮。
164
+
165
+ 15. **🔴 本服务凭据换个变量名放着也不出任何出口;名单型旋钮点到这样的变量拒启(安全轴,fail-closed;行为收紧;wire 零新键、零新码;部署零动作,除非服务进程环境里有变量的值等于本服务**任何一枚**凭据而名不同 —— 目录 secret 行的整值、令牌表逐枚、模型 `apiKeyEnv` 指的值;名单型旋钮点到这样的同值别名即拒启)**:
166
+ 旧形:值臂把每个凭据变量的**整值**交给引擎按整串比 —— `SERVICE_AUTH_TOKENS` 表里**一枚**令牌、`APPROVAL_HMAC_KEYS` 里**一把**钥换个变量名放着(同值、另一个名)不扣:`inheritEnv:"all"` 的模型 shell、`LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 放回的子进程都拿到它;名单型旋钮只按**名**判自有凭据,沙箱名单点名这个副本照装进沙箱 env。
167
+ 新形:值臂按本服务读它的颗粒把**每一枚**凭据交给引擎(整值总在内,`SERVICE_AUTH_TOKENS` 另加每一枚令牌、`APPROVAL_HMAC_KEYS` 另加每一把钥),每一条宿主腿都扣别名变量(整串比:部分重叠 / 前后缀不同的值照交),被扣的名进既有披露面(`secret_env_scrubbed` 行的 `keys`、`inherit_env.names_withheld` 通告);名单型旋钮点到「名是本服务凭据,或值是本服务某一枚凭据」的变量 ⇒ 起服拒,拒句开头仍是 `env <旋钮>: entry #k of n is this deployment's own credential — `,副本那一形其后多 `a copy under another name …`;模型目录换代时新并进的凭据(名或值)正被某只名单交出去 ⇒ 候选整拒,拒句开头改为 `… a model entry's apiKeyEnv makes a variable a name-list env knob hands on one of this deployment's own credentials (by its name, or by its value under another name) — `;一张令牌表里某一枚不足 8 字符 ⇒ 这一枚不扣、同表其余照扣、该变量一行 `own_credential_value_not_withheld`、能力位 `inherit_env.own_credential_values_withheld` 答 false。
168
+ **谁受伤**:把服务令牌 / HMAC 钥换个变量名放在服务进程环境里另作他用的部署(那个变量从此不进模型 shell、语言服务器、配方脚本、hook、git / CLI 子进程);名单型旋钮点着一个变量、而它的值等于本服务**任何一枚**凭据的部署(起服拒)—— 不止服务令牌 / HMAC 钥的副本:目录 secret 行的整值(`GIT_API_TOKEN`、`MODEL_API_KEY` …)、令牌表的每一枚、模型 `apiKeyEnv` 指的值都算,7.148.x 的名单只按名判,这样的同值别名照交出去;按模型目录换代拒句开头全文匹配的告警规则;令牌表里有短令牌的部署(多一行 warn、值能力位 false)。**升级前自查**:逐只名单型旋钮(`LSP_ENV_ALLOW` / `HOOK_ENV_ALLOW` / 三只沙箱名单 / bake-runner 的 `BAKE_ENV_ALLOW`)看它点的每个变量的值是不是本服务某一枚凭据 —— 例:`E2B_SANDBOX_ENV=GIT_TOKEN`,而 `GIT_TOKEN` 与 `GIT_API_TOKEN` 同值(一枚 PAT 同时给 repo 工具与沙箱)⇒ 7.148.x 起服、本版拒启 `env E2B_SANDBOX_ENV: entry #1 of 1 is this deployment's own credential — a copy under another name …`。**出路**:要给子进程 / 沙箱一枚凭据 ⇒ 给它铸一把自己的(名与值都不同于本服务的任何凭据)再点那个名;按 `this deployment's own credential — ` 匹配拒句;短令牌换成真随机串。
169
+
170
+ 16. **订正 7.148.0 节漏写的一项行为变化:`cascade: true` 与 `requireExistingSession: true` 同体的提交自 7.148.0 起照跑 —— 7.147.x 上每一级都被引擎拒;本版把「必须已在」盖给谁收成一只按引擎入口的判据(文字订正 + 嵌入方装配器边角的行为变化;wire 零变化;部署零动作)**:
171
+ 旧形(≤ 7.147.x):这样的提交交到引擎,梯子派生每一级时只剥 `sessionId`,「必须已在」随 spec 展开到在引擎现铸的会话里冷跑的级上 ⇒ 每一级以 `resume.session_not_found` 被拒,会话在也拒,梯子以 `exhausted` 收场,一级都没跑。
172
+ 新形(7.148.0 起):梯子的每一级不在提交的会话上取会话,提交的会话只是梯子的宿主,「必须已在」不进梯子的 spec;调用方的要求由本服务判 ——
173
+ 会话不在 ⇒ 受理即 404 `resume.session_not_found`(`requireExistingSession: session does not exist (resume.session_not_found)`,不登记这只 id);带 run 店的部署上受理之后、执行之前被删 ⇒ 404 同码(`the session this run was to start on no longer exists …`),一级都没起;
174
+ 执行已认领 ⇒ 删除答 409 `conflict.session_active_run`,梯子照跑。单腿、验证门(`verify`)与续跑家族不变:引擎在提交的会话上取会话,「必须已在」照旧交给引擎(只接、不建)。
175
+ **谁需要**:用梯子在一只既有会话上提交、又要求它必须已在的调用方(7.147.x 上这一形一律失败)。**谁受伤**:把 7.147.x 的那一拒读成「会话不在」、或读成「梯子不能与 `requireExistingSession` 同用」的调用方 —— 现在会话在就照跑;
176
+ 嵌入方自带的装配器若在梯子提交的产物上自写 `requireExistingSession`(契约说装配器不写它):本版起这一位在梯子上被剥掉,梯子照跑(此前每一级被拒)。
177
+ **补偿**:要的若是「会话不在 ⇒ 拒」,在提交体上带 `requireExistingSession: true`,本服务在受理口与执行起点两处照判,同码同状态。**已知边界**:嵌入装配不带 run 店、或 run 店不带根行锁而会话店又不带执行席时,受理之后被删的梯子提交照跑(各级在自己的会话里,不碰提交的会话);三种出厂后端不在此列。
178
+ **出路**:无需动作(嵌入方:把「必须已在」交给提交体,不写在装配器产物上)。**回滚**:不适用(无存储形变化)。
179
+
180
+ 17. **单用户记忆的项目层按检出的 `.sema/project` 记号键控:带记号的检出键形 `userrepo:<属主段>/m.<24 hex>`,没有记号照旧 `r` / `p` 档(行为变更;持久数据:git 根档条目自动折进记号档,无需动手;开了记忆同步的部署先升中心)**:
181
+ 旧形:项目层只按 git 根键控 —— `r` 档 = `origin` 网络远端 URL 归一后的哈希,`p` 档 = 项目根路径的哈希;检出里的 `.sema/project` 记号不参与。同一项目的两只 fork(两个 origin)是两把键;同一 origin 的两只检出带不同记号是一把键。
182
+ 新形:检出带记号 ⇒ `m` 档 = 记号里项目 id 的 sha256 前 24(在任务根上读记号,与引擎判项目同一读法:linked worktree 读它自己检出里的那一份);没有记号 ⇒ `r` / `p` 逐字照旧;记号读不出(坏记号 / 嵌套在仓根之下 / 读不了)⇒ 这一任务没有项目层,写家落全局层,运维日志 `memory.project_scope_absent`(`reason: unreadable`)与一次 fail-open 留痕 `server.memory.project-marker-unreadable`(计数逐次、每进程一行 warn)。
183
+ 档序 `m > r > p`:检出取最高档,低档里的条目在该项目下一个任务开跑前自动折进当前档(info `memory_project_layer_folded`;常设,不随窗删)—— 已带记号的仓升级后第一个任务就把 `r` / `p` 档的条目折进 `m` 档,同一条记忆照读得到。没有记号的检出上请求体里的 `projectId` 不改项目层的键。
184
+ **谁受伤**:① 开了记忆同步(`MEMORY_SYNC_*`)、中心还是旧版:旧中心不认 `m` 档,该层每轮一行 warn `memory_sync_layer_failed`(条目在本机,不丢);② 同一远端下还有没带记号的检出(老分支、没拉到记号的机器):它此后写进 `r` 档的条目由下一个带记号检出的任务折走,拉到记号之后才读得到;③ 带坏记号 / 嵌套记号的检出:此前有项目层,现在没有(写全局层);④ 按键里档字母分支的脚本(键按契约不透明)。
185
+ **出路**:① 先升中心再升客户端;② 让各检出都拉到记号;③ 修好记号(引擎在每条腿上报同一个错:`config.memory_project_marker` / `config.memory_project_marker_nested`),修好后 git 根档自动折进记号档;④ 把键当不透明串读。回滚:回到上一版后带记号的检出回到 `r` / `p` 档,已折进 `m` 档的条目不在旧版的读列表里(盘上不删;再升级即重新可见)—— 要回滚又要保住这段时间的项目记忆,回滚前先别跑带记号检出的任务。
186
+
187
+ 18. **续跑认领之后提交执行放置撞店故障:停驻的 run 回到停驻、卡仍待决,答 `503 state.resume_context_unreadable`(此前 `500 internal.error`,run 落 `failed`)(行为修复;wire:一面 500 → 503,码沿用;零 DDL;部署零动作)**:
188
+ 旧形:决断(批准 / 拒绝)、`/resume`、`plan_review`、应答口的停驻赎回席与 SLA 拒扫在认领停驻的 run 之后、交给引擎之前,提交这条会话的执行放置那一次店往返失败(库断连 / 拒连 / 超时、缺表 / 权限拒、认不出的库错、本服务的程序错)
189
+ ⇒ run 终结成 `failed`、会话认领与提交幂等键放开,答 `500 internal.error`;卡仍待决,再发同一个决定 ⇒ `200` 不带 `taskId`,引擎照续,但不持会话认领、不落那条 run 的事件账,`GET /v1/runs/:id` 一直是 `failed`。
190
+ `/wake` 现建的行撞同一形 ⇒ `500`(行终结,卡仍待决)。
191
+ 新形:店故障不是答案 —— 续跑认领的停驻行回到认领之前的停驻词(`suspended`;`plan_review` 为 `needs_review`),会话认领与幂等键留着,卡仍待决,答 `503 state.resume_context_unreadable`(句子:`the stored state of this task could not be read or written just now (the store failed), …`;体只有 `error` / `errorCode`);认领那一笔本身(`markResuming`、`/wake` 现建行)撞店故障同答这一只 503(此前 `500 internal.error`);
192
+ 本服务的程序错 ⇒ `500 internal.error`,run 同样回到停驻。认领窗里已有人取消这条 run(耐久取消旗在)⇒ 不回停驻,按取消收场:卡按取消结算、run 取消终局,答 `200 { …, status: "failed", errorCode: "cancelled" }`。`/wake` 现建的行删掉(它在这次认领之前不存在;认领与幂等键随行去,撤回同下一条 ④),答同一只 `503`。店答出会话不在 / 住客换了 ⇒ `404 resume.session_not_found`,续跑认领的那条 run 照旧终结、`/wake` 现建的行同样删掉(写者在别处、已放在别的车道两形见下一条)。
193
+ **谁受伤**:依赖「续跑撞故障 ⇒ run 终结、会话放开」的部署 —— 这条 run 现在留在停驻态继续占着会话(同一会话的新提交答 `409 conflict.session_active_run`),直到再决、取消或停驻过期收割;按 `500` 告警的监控在这一形上看到 `503`。
194
+ **出路**:`503 state.resume_context_unreadable` 一臂 = 稍后原样重发同一请求(一直如此 ⇒ 报运维查库;`plan_review` 的一次性证明已在受理时用掉 ⇒ 换一份新证明再发);不想等它 ⇒ `POST /v1/runs/:id/cancel`。**回滚**:回到上一版即回到旧形;数据零改动。
195
+
196
+ 19. **认领之前到交给引擎之前那一段的店故障在每一面都不再是答案;撤回本请求铸的 run = 删掉它;认领之后读出「本处此刻不能执行」与认领之前同一个命运、同一只答(行为修复;wire:新码 `503 state.run_store_unavailable` + 几面 500 → 503 / 409 + 认领之后两只 409 改答 `resume_blocked_by_policy`;零 DDL;部署零动作)**:
197
+ 旧形:① 续跑腿(决断、`/resume`、`plan_review`、`/wake`、应答口的停驻赎回席与 SLA 拒扫)提交放行之后、把续跑交给引擎之前那一段(排空 workflow 完成、通告口落账)撞店故障 ⇒ 停驻的 run 终结成 `failed`,答 `500 internal.error`;
198
+ ② 新提交(`POST /v1/tasks` 同步 / 流式、`POST /v1/runs`、A2A)认领这一段(建行认领、执行放置、续跑输入的写、起跑之前的认领复核)、`/decide` 在宿主会话上起的新一跑(含落决定行那一笔)、停驻子代赎回认领之后的执行放置,
199
+ 以及每一面认领之前那一次执行席读撞店故障 ⇒ `500 internal.error`(流式腿的流断掉、没有终帧);落决定行那一笔店答「没落成」⇒ `500`;③ 续跑认领之后提交放置读出 `execution_lane.tree_bound` / `conflict.session_mirror` ⇒ 原码原样 409,
200
+ 停驻的 run 以 `failed` 收尾、卡留着谁也兑不了;宿主新一跑与停驻赎回认领之后同形 ⇒ 原码原样 409;④ 撤回本请求铸的 run 把它终结成 `failed` 留着 —— 自带 `taskId` 的同 id 重发读到它(`202` + `status: failed`,不跑)。
201
+ 新形:① 停驻的 run 回到停驻、卡仍待决,答 `503 state.resume_context_unreadable`(`/wake` 现建的行删掉,同答;认领窗里已挂取消旗 ⇒ 按取消收场,`200 { …, status: "failed", errorCode: "cancelled" }`);
202
+ ② 新提交答 `503 state.run_store_unavailable`(新码;认领之后的流式腿 = 流的终帧);续跑家族(含 `/wake`、宿主新一跑与它的落决定行)答 `503 state.resume_context_unreadable`;停驻子代赎回答 `503 decide.store_unreachable`(体带 `taskId`;认领那一笔撞店故障也换成这同一句,码与状态不变)
203
+ —— 认领之前那一读与认领之后同一面同一只答;落决定行答「没落成」⇒ 与起跑之前认领复核答「没持有」同一只三臂答复(`409 conflict.session_active_run` / `404 resume.session_not_found` / `409 conflict.claim_lost`);
204
+ ③ 停驻的 run 回到停驻(停驻赎回回滚)、卡仍待决,答 `409 resume_blocked_by_policy`(`blockedBy` = 原码,`forkPath` / `boundLane` 随体,`retriable: true`),与认领之前读出同一个事实那一形同一只体,三面同;
205
+ ④ 本请求铸的行删掉(认领、提交幂等键、事件随行去),同一个 `taskId` / 同一把 `Idempotency-Key` 的重发是新提交、真跑。本服务的程序错各面仍是 `500 internal.error`(认领同样已撤回)。
206
+ **谁受伤**:把 `500` 读成「已失败、换个法子重投」的调用方与按 `500` 告警的监控(这几面现在是 `503`,稍后原样重发);按 `execution_lane.tree_bound` / `conflict.session_mirror` 码分支的续跑调用方(认领之后那一形改读 `blockedBy`);
207
+ 依赖「认领之后读出别的车道 ⇒ run 终结、会话放开」的部署(run 现在留在停驻占着会话,同一会话的新提交答 `409 conflict.session_active_run` —— 与认领之前读出同一事实那一形同);
208
+ 提交被拒之后按 `taskId` 去读那条 `failed` run 找拒因的调用方(那一行不再有,`GET /v1/runs/:id` 答 `404`;拒因在这一次的答复体 / 终帧里);断连转后台(`x-detach-on-disconnect: true`)而恰在认领这一段断开的流式调用方(`x-task-id` 读到 `404`)。
209
+ 已绑设备的会话上认领之后那一次执行席读撞店故障由 `409 device.not_bound` 改答同一只 `503`(与认领之前那一读同);设备准入 / 首绑 / 再断言上本服务的程序错不再折成 `device.not_bound`,响亮 `500`。
210
+ **出路**:`503` 各臂 = 稍后原样重发(同 id / 同键重发真跑;撤回那一笔自己也没落、或撤回之前那一行已被收割时,行以 `failed` 留着,同键重发照样真跑、同 id 重发读到它 —— 换一个 id);`409 resume_blocked_by_policy` 读 `blockedBy`;
211
+ 不想等停驻的 run ⇒ `POST /v1/runs/:id/cancel`。**回滚**:回到上一版即回到旧形;数据零改动(删掉的只有从没起跑的行)。
212
+
213
+ 20. **卡已提交之后停驻的簿记撞店故障不再烧掉等审批的 run:店答出的拒是答案,店的故障不是(行为变更;wire 零新键、零新码;嵌入方类型面加宽一处;部署零动作)**:
214
+ 旧形:run 停在要批的门上(卡已在 checkpoint 店里)而记这次停驻的账本行(停驻帧 / 停驻前用量 / 结果到手之后的清单行与缓冲文本)写抛 ⇒ 后台 run 与续跑腿的再停把行收成 `failed`、卡作废(7.141.0 节第 14 条),续跑腿另答 500;
215
+ run 行的停驻写本身抛 ⇒ 行无心跳地留在 `running`,由失联收割收成 `failed`,卡悬到审批兜底收割;停驻写被店答出「这条行已不是本腿的」(失联收割 / 取消先落了判决)⇒ 无声,卡仍待决。
216
+ 新形:停驻只由 run 行的停驻写提交(后台 / 续跑 / 同步三条腿同一只提交点)。账本行写不下只留痕(`fail_open_total{tag="server.runs.terminal-ledger-write-failed"}`,`arm=park-*` / `resume-park-*`),行照常停驻、认领在、卡可决。
217
+ 行的停驻写抛 ⇒ 不收场(不落 `failed`、不作废卡):当拍再提交一次,仍没答出 ⇒ 每 30 s 再提交,店答出即收。再提交与第一笔同一个形(一笔抛了的写可能已落下):写;店答出「不」⇒ 读行、由行答
218
+ (怎么答见本节「停驻写只许这条 run 的持有腿落下」一条)。续跑腿的中止句柄认领一赢就登记 —— 此前在执行放置提交放行之后,
219
+ 这一窗里按下的取消现在落在续跑腿上、续跑按取消结算,此前只挂旗、续跑照跑完。上界 = 两个判活窗(`REAP_RUN_STALE_SEC`),到上界停手,交既有出路 —— 失联收割按判活窗把行收成 `failed` 并放认领,审批兜底收割按卡的截止 / 绝对兜底时刻作废卡。
220
+ 每一次失败计 `fail_open_total{tag="server.park.row-commit-deferred"}`(detail `leg=<bg|resume|sync> step=<first|again|retry|gave_up>`)。停驻写被店答出拒、读到 run 已收场 ⇒ 卡跟着作废(行先、卡后;没作废成照旧计 `server.park.held-card-void-failed`,detail 多 `at=park_commit_refused`;取消那一形 `at=park_commit_cancelled`)。
221
+ 取消落在结果到手之后的腿照旧先作废卡、再放认领(7.141.0 节第 14 条的这一半不变)。与续跑认领之后提交撞店故障同一条律(店的故障不收场、卡仍待决)。
222
+ **谁需要**:共享库偶有抖动的部署 —— 一次写失败不该烧掉等人批的 run、也不该留下「行终局、卡待决」。**谁受伤**:续写期间行停在 `running`,对那张卡的决定答 409 `conflict.not_resumable`,写落下之后再发即受理;
223
+ 只读账本尾帧判停驻的尾随方在那一形里看不到停驻帧(`GET /v1/runs/:id` 与待决列表照说停驻);店一直故障时这条 run 占着会话直到失联收割收走;再提交期间按下的取消答「取消中」,至多一个心跳节拍之后由下一次再提交落成取消终局。
224
+ **补偿**:决定答 409 时稍后原样重发;看 `step=gave_up` 计数定位交给既有出路的那次停驻;判活窗旋钮同时定续写上界。
225
+ **嵌入方**:三只 run 店的 `setSuspended` / `setNeedsReview` 返回型由 `Promise<void>` 加宽为 `Promise<boolean>`(`true` ⇔ 行停在这个词上),以 `Promise<void>` 覆写这两只的子类需改;`runInBackground` 多一个必填参(本腿的持有腿 + 判活窗,见本节「停驻写只许这条 run 的持有腿落下」一条)。
226
+ **回滚**:回到上一版即回到旧形(零数据面、零 DDL)。
227
+
228
+ 21. **停驻写只许这条 run 的持有腿落下、不落在挂着的取消请求上:`task_run` 加一列 `leg_id`(SQL 后端升级前先执行一句 `ALTER`;行为修复;wire 零新键、零新码,两面停驻答复改按收场的行作答;嵌入方类型面 BREAKING)**:
229
+ **升级前做**:见本节段头升级清单(SQL 后端一句 `ALTER`,先升库;不回填 —— 列之前的行读作「没有持有腿」)。不执行 ⇒ 本版起服列册探针拒启 `config.schema_mismatch`,拒句带同一张清单。
230
+ `DB_BACKEND=local` 与内存店零动作(`run.json` 缺这一键读作没有持有腿)。
231
+ 旧形:停驻写(`setSuspended` / `setNeedsReview`)的 CAS 只看行在跑(或已停在本词上);「行还是不是本腿的」读行的持有副本与本进程的在飞登记 ⇒ 一笔回执丢了的停驻写之后,续跑腿在同一副本上认领了这条行而还没登记时,
232
+ 旧腿的再提交把在跑的续跑腿的行停回 `suspended`;run 在跑时按下的取消(只置旗)落在第一笔停驻写之前 ⇒ 行照停、卡可决,下一次批准的认领清掉旗、被取消的活照跑。
233
+ 新形:持有腿 = `task_run.leg_id`,每次认领(建行 / 续跑认领)铸一只、交给认领者;停驻写的 CAS 多两件 —— 行的持有腿是本腿的、没挂取消请求;对一条在跑行,取消与停驻恰好一笔赢。
234
+ 店答出「不」⇒ 读行、由行答:已收场 / 不在 ⇒ 卡作废;归别的腿(含没有持有腿的行)⇒ 停驻成立过、卡不碰;归本腿、挂着取消 ⇒ 先作废卡、再落取消终局(码 `cancelled`);店拒而行读来该写 ⇒ 计 `fail_open_total{tag="server.park.row-commit-contradicted"}`,当店故障再提交。
235
+ 认领之后提交没放行时撤回本请求铸的行(删行)读同一只身份:行上的持有腿不是建行交回的那一只 ⇒ 一个字节不动。
236
+ 停驻提交答出 run 已收场时:同步提交 `POST /v1/tasks` 答 200 + 收场那一行的信封(与同键重放同一只:终局行的结果 —— 取消那一形 `terminal.code: "cancelled"`;行上没有结果 ⇒ 回执三键;此前答停驻回执、`status` 为停驻词);续跑腿再停 / 重开答收场那一行的 `status` / `errorCode` / `errorMessage`、不带 `retriable`;
237
+ 引擎在提交前拒、放回停驻答出收场 ⇒ 拒体 `retriable: false`、不带 `wayOut`。流式提交的 `done` 帧在停驻提交之前已上流(既有序),那一形帧上仍是停驻词,`GET /v1/runs/:id` 读收场的行。
238
+ **混版本窗**:两项担保(持有腿、取消旗)需全部写者在本版 —— 旧副本的停驻写不比持有腿也不看旗,旧副本的续跑认领不铸持有腿(行上留着前一条腿的那一只);本版副本读到没有持有腿、在跑的行(旧副本持有)⇒ 不写、卡不碰。
239
+ **谁需要**:用审批门(工具门 / 计划门)且共享库偶有抖动的部署,与在 run 停驻前后按取消的用户。**谁受伤**:SQL 后端的部署要先执行一句 `ALTER`;按同步提交 200 体带 `status` 停驻词判「已停驻」的调用方在取消先到的那一形读到终局结果(`terminal.code: "cancelled"`);
240
+ 自建 run 店 / 直调 `runInBackground` 的嵌入方(类型面)。**补偿**:拒句原样给出 `ALTER`;同步提交答终局结果即 run 已收场(卡已作废,不用再去决)。
241
+ **嵌入方**:`RunRecord` 多必填成员 `legId: string | null`;三只 run 店的 `createRun` 成功形多 `legId`,`markResuming` 返回型 `Promise<boolean>` → `Promise<string | undefined>`(赢 ⇒ 本次认领铸下的持有腿),
242
+ `setSuspended` / `setNeedsReview` 多必填末参 `legId`(停驻写只许它落下),`withdrawMintedRun` 多必填末参 `legId`(撤回只认它);`runInBackground` 第五位多一个必填参 `parkCommit: { legId, runStaleSec }`(原第五位起的各参后移一位;
243
+ 绕过类型交来的不是一只持有腿 ⇒ 引擎起跑之前按本腿失败收场:行 `failed`、句子点名持有腿);新导出 `mintRunLegId`(持有腿的唯一铸点)。
244
+ **回滚**:先停光全部本版副本 → `ALTER TABLE task_run DROP COLUMN leg_id;` → 再起上一版(上一版把多出的这一列读成幽灵列、按「库比构建新」拒启,所以这一句要先执行);删了再升本版 ⇒ 重新执行上面那一句。
245
+
246
+ 22. **带 `cwd` 提交的梯子(`cascade: true`)每一级与验证门(`verify: true`)的验证器腿落在提交的目录里,不再落本服务现铸的临时目录(行为修复;用户可见;wire 零变化;部署零动作)**:
247
+ 旧形:host 车道上这两种组合腿跑在引擎现铸的会话里,工厂读不到提交登记的 `cwd`,每一条落在 `HOST_WORKSPACE_BASE` 下一只 `sema-host-*`(那一级收场即删):梯子写的文件不在项目里,停驻续跑的那一级 `pwd` 是临时目录,验证器验的是一只空目录。
248
+ 新形:组合入口把提交的会话登记的 `cwd` 作为交活方的工作目录交给每一条腿(委派子代用的同一臂),每一条腿的工作目录 = 会话登记的 `cwd`(与同一会话上的普通 run 同读);会话从没登记过 `cwd` 的提交照旧落临时目录、收场即删。普通 run 与跑在提交会话上的腿(验证门的实现腿 / 修复腿)读数不变。
249
+ **谁需要**:在自己项目里用梯子 / 验证门的用户。**谁受伤**:依赖梯子的级落在隔离临时目录的调用方(靠缺陷跑的):失败那一级的改动现在留在提交的目录里,下一级冷跑时看得见。
250
+ **出路**:要每一级在隔离的目录里跑 ⇒ 用一只从没登记过 `cwd` 的会话提交、且不带 `cwd`(每一级各落一只临时目录、收场即删)—— 只是这次不带 `cwd` 不够:`cwd` 登记粘在会话上,同一会话上之前带过 `cwd` 的,
251
+ 之后不带 `cwd` 的提交照旧在那只目录里跑(普通 run 同读);梯子的级本来就逐级重做副作用,写操作请自带幂等或用结构化输出门在副作用之前判。部署零动作。**回滚**:不适用(无存储形变化)。
252
+
253
+ 23. **读拒规则不按字节守的 run 照跑时,run 事件流多一帧 `engine_notice` `config.read_deny_floor_unkept`、终局结果多一键 `readDenyFloor`;`READ_DENY_FLOOR_REQUIRED=true` 的 409 拒句改为本服务的句子(行为变更;wire 加性:一通告码、结果一键;部署零动作)**:
254
+ 旧形:缺省部署(`READ_DENY_FLOOR_REQUIRED` 未设)上读拒表有行、执行环境不守读拒字节地板(`REMOTE_EXEC` = `host` / `ssh` / `adb` / `device` 恒不守;沙箱三车道今天也不守)的 run 照跑,
255
+ 只有运维日志一行引擎句(点名引擎席名 `readDenyFloorRequired`);run 的流、事件账、run 行、同步 200 体一处都不说。设了 `=true` 的部署上,409 的 `error` 是引擎句。
256
+ 新形:照跑 ⇒ run 事件流一帧 `engine_notice`(`code: "config.read_deny_floor_unkept"`,`detail: { rowCount, sessionId, runId }`),终局结果 `readDenyFloor: { code, message }`(与那一帧逐字同句);
257
+ 句子点名执行环境 `REMOTE_EXEC=<车道>` 与出路 `READ_DENY_FLOOR_REQUIRED=true`,运维 `engine_notice` 日志行同一句。`=true` ⇒ 准备期拒照旧(409,码不变),`error` / run 行 `error` / `done.result.terminal.message` /
258
+ 起服 warn `read_deny_floor_required_unkept` 的 `note` 是同一只组句器的拒起句,零帧、无 `readDenyFloor`。读拒表空、执行环境守地板 ⇒ 都不出。
259
+ 帧投在这条 run 所在的那条 run 腿的流上:cascade 的每一级、verify 的验证器、子代各一帧,落在父 run 的事件流(`detail` 说的是那一条 run);verify / cascade 的续跑腿同样投;
260
+ 停驻中被取消的 run,取消终局带停驻行上那一格;`run-local --json` 的终局带这一格,文字模式 stderr 打同一句。
261
+ **谁需要**:写了读拒规则(或靠出厂读拒档)、跑在不守地板执行环境上的用户 —— 那些规则命令点名时照拒,但程序打开文件时不拦,字节可以进对话。
262
+ **谁受伤**:按 `engine_notice` 码闭集或结果全键集逐字断言的消费方;按 409 `error` 原文匹配引擎句的脚本(按 `errorCode` 判)。
263
+ **出路**:要拒起而不是照跑 ⇒ 设 `READ_DENY_FLOOR_REQUIRED=true`;不想看到这一帧 ⇒ 换守地板的执行环境。部署零动作。
264
+
265
+ 24. **一次性迁移 M46 窗关删码之后的跳版库:起服拒启并给出路,不再让存量 `Skill` 会话豁免行代答同名工具;订正 7.148.0 节第 74 条「窗」一段末句(本版对完好的库行为零变化;持久面:标记表改由中央建表语句建,形不变、零 ALTER;wire 零新键;部署零动作)**:
266
+ 旧形(7.148.0 节第 74 条):「窗关之后第一个 minor 删迁移步与读数键。跳过本版直接升上来的库,存量 `Skill` 行照旧代答「不绑授予」的同名调用」—— 删码之后,从 ≤ 7.147.x 直升的库(SQL 库或 `DB_BACKEND=local` 数据根)里
267
+ 更早版本为「激活某技能」落下的 `(会话, "Skill")` 豁免行一声不响地代答部署自挂的同名工具。
268
+ **勘误(第 74 条末句)**:删码之后这类库**起服拒启**,不再照旧代答 —— 常设的跳版拒启臂(无窗)在本次起服对这只库的任何写之前判:首次放行早于 `Skill` 豁免截点 T0(T0 缺席 ⇒ 任一)的 `Skill` 行在场 ⇒
269
+ 拒 `config.schema_mismatch`(SQL:`ensureSchema()` 建表之前,具名类 `LegacySkillExemptionsPresentError`,拒句点名行数与截点;`DB_BACKEND=local`:数据根准入,读数种别 `skipped-required-migration`,点名会话数、截点与出路版本),库 / 数据根一个字节不写。
270
+ 出路 =(1)先用一个仍带这条迁移、不低于 7.148.0(`DB_BACKEND=local` 还要不低于拒句里已记的引擎高水位)的版本(服务或 `run-local`)对这只库完整起一次 —— 它落 T0 并删掉那些行 —— 再升;
271
+ (2)SQL 另可手工 `DELETE FROM approval_exemption WHERE tool_name = 'Skill'`(那些会话的人下一次 `Skill` 调用被问一次)。第 74 条其余各句不变。
272
+ 新形(本版起,常设):T0 = 一只按今天的意思读会话豁免行的构建第一次接管这只库的时刻,每次起服**缺席才落**、先落的那一只赢 —— SQL 由 `ensureSchema()` 建表之后的种子行落进标记表 `one_time_migration_marker` 的 `M46` 行
273
+ (标记表改由中央建表语句建,两方言同形,与 7.148.0 由迁移自建的那一张逐列相同 ⇒ 零 ALTER;MySQL 协议上新建的那一张与中央各表同钉 `COLLATE utf8mb4_bin`,已建的那一张不动 —— 键是固定的迁移名,列册对账不看排序规则);`DB_BACKEND=local` 由数据根准入的锁内一步(抬引擎版本高水位之前)写 `one-time-migration-M46.marker`。
274
+ M46 在窗内照旧删 T0 之前的行(读同一个 T0);删码之后全新的库第一次起服就有 T0,其后写下的合法「本会话放行」`Skill` 行不会被判成截点之前的行。
275
+ **DDL(本版起由起服的中央建表语句发,`IF NOT EXISTS`,已有的表不动;运维零手工)**:MySQL 协议 `CREATE TABLE IF NOT EXISTS one_time_migration_marker (migration_id VARCHAR(16) NOT NULL PRIMARY KEY, marked_at_ms BIGINT NOT NULL) COLLATE utf8mb4_bin`;
276
+ PostgreSQL `CREATE TABLE IF NOT EXISTS one_time_migration_marker (migration_id VARCHAR(16) COLLATE "C" NOT NULL PRIMARY KEY, marked_at_ms BIGINT NOT NULL)`;建表之后的种子行 `INSERT INTO one_time_migration_marker (migration_id, marked_at_ms) VALUES ('M46', <此刻的毫秒>)`
277
+ 只在缺席时落(MySQL 协议 `ON DUPLICATE KEY UPDATE migration_id = migration_id`,PostgreSQL `ON CONFLICT (migration_id) DO NOTHING`)。这一行此后常设:每只库一行,是这只库的截点。
278
+ **fail-closed 律(截点的两只读数)**:截点或一行的首次放行时刻读不出时,读作「更早」或拒启,永不读作「此刻」或「没有」——
279
+ 截点行在而读不出时刻(手改成超出时刻范围的数、非数)⇒ 起服拒,在建表之前、带不带 M46 都判(7.148.0 上 M46 对超出范围的值一行不删、零信号),出路 = `DELETE FROM one_time_migration_marker WHERE migration_id = 'M46'` 再起;
280
+ `DB_BACKEND=local` 的截点文件读不出 ⇒ 数据根准入拒(读不出的那一形,数据根零写;7.148.0 是 M46 的腿在打开数据根之后拒)。
281
+ `DB_BACKEND=local`:豁免日志里读不出首次放行时刻的记录(缺 `ts` / `ts` 不是时刻;写口从来都写,只有手改或损坏的日志)读作最早 —— 按截点算在截点之前(M46 删它、删码之后的臂拒它);
282
+ `GET /v1/approvals/:sessionId/exemptions` 上这类行的 `createdAt` 由「本次起服的时刻」改为 `0`。
283
+ **谁需要**:窗关之后从 ≤ 7.147.x 直升的部署。**谁受伤**:那类直升的运维 —— 起不来,拒句给两条出路;本版里无人(M46 仍在,臂只判不拒)。**补偿**:拒句的出路;升级路径见下。
284
+ **升级前做**:无(本版零 DDL 要手工执行、零新旋钮)。从 ≤ 7.147.x 升级的部署,在 M46 的窗内(7.148.0 发布日 + 30 天,窗口见 `plugins/one-time-migrations.ts` 登记表)至少用一个带它的版本起一次服,就不会撞上这条拒启。
285
+ **回滚**:零 DDL、零手工。标记表里的 `M46` 行与数据根里的标记文件对 7.148.x / 7.147.x 无害(7.148.x 读同一个 T0,7.147.x 不读);多出来的标记表 7.147.x 不读。
286
+ 不要为回滚删表或删行:表里还有 M42 / M43 / M51 的标记(删了那几条下一次起服重判);删 `M46` 行 ⇒ 下一次起服以那一刻为新截点,其前写下的 `Skill` 行都算截点之前。
287
+
288
+ 25. **`DB_BACKEND=local` 的店落在易失介质上不再一律拒启:local 店对引擎的声明改由一只读者定 —— 店落在调用方自己的盘上(host 车道单主:壳自起的本机引擎)且数据根易失,或运维写了新旋钮 `LOCAL_STORE_DURABILITY=ephemeral`(闭集只有这一个词)⇒ 会话店与检查点店两半一起声明 `process-local`,照常起服、读面如实、起服 warn 一行;店落在调用方看不见的 worker 盘上而没写这一词 ⇒ 照旧拒 `config.store_not_durable`(行为变更;一只新旋钮;wire 零新键、零新码;引擎静态装配读数在这两形上变;部署零动作)**:
289
+ 旧形(7.148.0 节第 34 条):local 店对引擎的声明是常量 —— 会话店(连同委派分区)与检查点店恒声明 `durable`(活过进程重启);起服布线审计「引擎静态装配报会话店 `declared_durable` ∧ 会话店的介质(数据根)判 `ephemeral` ⇒ 拒启」
290
+ 因此对一切数据根落在容器可写层 / tmpfs / emptyDir 上的 local 部署成立,包括无卷容器(Docker / devcontainer / CI)里壳自起的单用户引擎;想在易失介质上跑 local 店的运维除了挂卷或换 `DB_BACKEND=memory`(店进内存、重启即丢)没有别的写法。
291
+ 新形:拒启判据一字不改,变的是声明从哪来 —— 只有一只读者,按序判:① 写了 `LOCAL_STORE_DURABILITY=ephemeral` ⇒ `process-local`(不论车道与介质);② 店落在**调用方自己的盘**上(`REMOTE_EXEC=host` ∧ 没开 `REQUIRE_PRINCIPAL`;local 上本就不许开)
292
+ 且数据根介质判 `ephemeral` ⇒ `process-local` —— 调用方的工作区、工具与会话史同在那块盘上,部署不替他声明他自己那块易失盘活过替换;③ 其余 ⇒ 店型的设计声明 `durable`(开发机、挂了卷的容器、非 Linux 判不出的介质 —— 壳的笔记本形零变化)。
293
+ 声明降为 `process-local` 时**两半一起降**:会话店顶层与检查点店读同一份(只降一半,引擎的 durable-park 自检会读出「检查点活过、会话不活」的缺口);委派分区(子代转录)的声明不降 —— 它决定后台子代转录档位 `full`,降了它要审批的后台子代就停不住⇒ 引擎静态装配读 `session.store = "process_local"`(接了检查点店〔`DURABLE_APPROVAL`〕时 `parkLane.checkpointDurability = "process_local"`;`fleet.subagentTranscripts` 照旧 `full`),
294
+ 审计「声明不是 `declared_durable` ⇒ 恒过」;起服一行 `wiring_static_warning`(句子写明依据、介质判定与挂卷出路;停驻审批不随替换保留这件事并在这一行里,park 那条告警不再另起)。`GET /v1/capabilities` 的 `store.durability` 与 `/health.store.durability` 照旧按介质如实报(与上一版同一只读数)。
295
+ 拒句的出路从两条变三条:挂持久卷 / `LOCAL_STORE_DURABILITY=ephemeral` / `DB_BACKEND=memory`。`DURABLE_APPROVAL` 的缺省不变(进程重启照旧活过:停驻审批在同一只容器里跨重启续得上)。
296
+ **新旋钮** `LOCAL_STORE_DURABILITY`(enum,闭集只有 `ephemeral`;缺席 = 店型的设计声明;别的任何词拒启 —— 没有第二个放宽词,也不收 `durable` 这样的反向写法):运维声明这台部署的 local 店易失。
297
+ **后果**:会话店与检查点店对引擎声明 `process-local`;店里的会话、停驻审批与记忆不随容器 / Pod 替换保留(进程重启照旧活过)。介质持久(挂了卷)时写了也只改声明:读面照旧报 `durable`,起服 warn 一行如实说介质。
298
+ SQL / memory 后端不读它。**这只旋钮由部署者自己设**:壳 / 编排器 / 安装器不替用户写(替用户写 = 替他放弃这份承诺);壳自起的本机引擎不需要它(②那一臂)。`REMOTE_EXEC=device` 的部署要 SQL 后端(既有不变量),本条与它无关。
299
+ **谁需要**:在无卷容器里跑壳 / 单用户引擎的人(会话随容器一起删是他们接受的,与参照实现在同一只容器里同形);CI / 预览环境里刻意不挂卷、但要 local 文件店行为的部署(写那一个词)。
300
+ **谁受伤**:① 把 host 车道单主的 local 部署放在易失介质上、却以为会话会活过替换的人 —— 上一版拒启,本版起服;② 误把生产 local 部署声明成易失的运维 —— 停驻审批与会话不再跨替换;③ 读引擎静态装配(`wiring_manifest` / 诊断面)`session.store` 的消费方:这两形上读到 `process_local`。
301
+ **补偿**:读面如实(`store.durability` = `ephemeral`)+ 起服 warn 一行(依据 + 挂卷出路);拒码不变;写了词的部署撤掉这一词即回到设计声明(介质易失则照旧拒启)。非 host 车道且没写词的 local 部署零变化。
302
+ **拒启在任何写之前**:local 店的拒启判挪到起服第 2 段车道合成之后、第一笔往数据根 / 封签钥匙目录的写之前(判据读车道,所以在车道合成之后;保管店铸钥匙、第 3 段开店都在它之后)。
303
+ 7.148.0 在第 9 段布线审计才拒 —— 拒之前已在易失数据根上铸出封签钥匙(日志还叫人把它备份)、建出几十个条目;本版拒的时候数据根上没有本服务的店、封签钥匙目录里没有钥匙。机器码不变(`config.store_not_durable`),
304
+ 拒句头换成「store durability admission failed — refusing to start before any store or sealed key is written」。配置根与数据根重合时(都取缺省 `AGENT_DATA_DIR` / `~/.ai-agent`,或写成同一目录)
305
+ 同样零写:配置根上的一次性迁移 SS-M11 与配置根供给(`SEMA_CONFIG_DIR`)都排在这一判之后(见本节「起服序」一条)。
306
+ `DB_BACKEND` 没写(缺省推导出 local)、数据根空、易失又建不出店的部署,7.148.0 开店失败会降级成 memory 起服,本版在开店之前就拒。第 9 段布线审计的同码一臂仍在(引擎读到的会话店声明 × 数据根介质的通用对表,也管没有后端的 env-only 形);local 部署走不到那里就已判过。
307
+ **三只根各管什么**:拒启看**数据根**(会话店与检查点店落在它上面)与**显式写了的**封签钥匙目录(`SEALED_KEY_DIR`,停驻审批耐久时;见本节「起服序」一条)。`/health.store.durability` 与 `GET /v1/capabilities` 的 `store.durability` 报**参与判定的根里最弱的那只**(数据根 / 封签钥匙目录 / file 记忆根 —— 记忆根只在 file 记忆引擎真接了线时参与;逐根明细在 `GET /v1/diagnostics/wiring` 的 `storeDurability.roots`);
308
+ 缺省的封签钥匙目录与 file 记忆根只进读数与起服 warn,不拒启。file 记忆根 = `MEMORY_ENGINE_DIR`,缺省 `AGENT_DATA_DIR`,再缺省 `~/.ai-agent` —— **跟 HOME 走,不跟 `LOCAL_DATA_ROOT`**:接了 file 记忆引擎、只给数据根挂卷而 HOME 在 emptyDir / 容器可写层上 ⇒ 起得来,
309
+ 但 `/health.store.durability` 报 `ephemeral`(记忆随替换而去);要读面报 `durable`,三只根都落到卷上(或把 `MEMORY_ENGINE_DIR` / `SEALED_KEY_DIR` 指到挂进来的卷上)。封签钥匙目录缺省在数据根下(`<数据根>/sealed-key`),只有单独写了 `SEALED_KEY_DIR` 才会与数据根分家 ——
310
+ 分家且落在易失介质上时,替换之后封签的模型钥匙与停驻行封签钥匙(`checkpoint-ctx-keys/`)都没了:停驻审批耐久 ⇒ 拒启(见本节「起服序」一条);停驻关着 ⇒ 读面报 `ephemeral`、起服 warn 一行,不拒。
311
+ 记忆根为什么不进拒启判据:拒启守的是引擎被告知「活过重启」的那两半店(会话与停驻审批 —— 丢了就有一笔已承诺的停驻悬空);记忆丢了是召回变差,不让任何承诺悬空。把它算进拒启 ⇒ 每一个只给数据根挂卷的部署(常见的单卷 Pod 形)升级即拒启,补偿只有再挂一只卷。
312
+ **订正**:7.148.0 节第 34 条「『运维显式声明 local 店易失』的部署形随后版」即本条;第 34 条本体不改。
313
+ **已知边界**:会话里给用户看的一行通告(「会话历史不随容器替换保留」)本版没有 —— 它要一枚新的通告码进引擎码册;本版只在读面与起服日志上说。没有起服取证的入口(`run-local`、嵌入方直调 `createStoreBackend`)按介质 `unknown` 读,只有写了词才降声明。
314
+
315
+ 26. **多副本同时起一只 TiDB 库:启动锁的非阻塞探针撞「悲观锁重试上限」读成「别人持着」,不再被当成坏连接(行为修复;运维可见;wire 零变化;零 DDL;部署零动作)**:
316
+ 旧形:SQL 部署(MySQL 协议腿 = TiDB)上 N 个副本同时起,`ensureSchema` 与一次性迁移段取同一把具名锁 `sema_ensure_schema` 的非阻塞探针(`GET_LOCK(name, 0)`)本身会抛 `pessimistic lock retry limit reached`(TiDB 把 `GET_LOCK` 做成内部行的悲观锁,并发探针撞行的重试上限);取锁器把它算进「连续 5 次探针抛错 ⇒ 连接不可用 ⇒ 上抛」,同起的副本约一半以上起服失败(拒句 `lock probe threw 5 times in a row … (last: pessimistic lock retry limit reached)`)。
317
+ 新形:这一句(整句相等)被读成「别人持着」,与 `got = 0` 同一条律:持锁方还在就一直等(按进展每 40 拍 warn 一行)、永不无锁跑,不计入连续 5 次上限、不另设一道钟。放弃的上界仍只有调用方外圈的窗:`ensureSchema` 在 `STORE_LOCK_WAIT_MS` 大于 0 时由外圈窗兜(窗内换池重试、到窗拒启);迁移段与 `STORE_LOCK_WAIT_MS=0` 的 `ensureSchema` 没有外圈,持锁方不放时等不到头(对「别人持着」本来如此,现在对撞上限同形)。其余任何探针错照旧计入连续 5 次上限。PG 腿读法不变。
318
+ **谁需要**:多副本(≥ 2)同时起、共用一只 TiDB 库的部署(一次性拉起 N 副本、扩容、滚动重启)。**谁受伤**:正常部署无;失去的是一种快速失败 —— 迁移段与 `STORE_LOCK_WAIT_MS=0` 的 `ensureSchema` 上,持锁方卡死(而不是慢)时,等待方此前在连续 5 次撞上限后失败退出,现在一直等并按进展 warn(与持锁方卡死而探针答干净 `0` 时的既有形一致);撞上限的探针不再各写一行 `probe attempt N threw`,等待期改由每 40 拍一行的 `still waiting for GET_LOCK(...)` 说明。要期限的部署用编排器的启动探针兜(`ensureSchema` 一段另可设 `STORE_LOCK_WAIT_MS` 大于 0)。
319
+ **出路**:不需要动作。仍在旧版本上的部署,多副本冷启建议首副本 ready 之后再起其余(升级序:先升库再升副本不变)。部署零动作。**回滚**:不适用(无存储形变化)。
320
+
321
+ 27. **按问读口 `GET /v1/tool-approvals/:id`:行读不出时本副本上的活卡也答 `404 not_found.ask`(与 7.148.0 节第 29 条同句同码),不再回落登记答 `200 pending`(安全轴,fail-closed;行为收紧;wire 零新键、零新码;部署零动作)**:
322
+ 旧形:有行的问,读口读行那一拍出错(店抛 / 超时)时,本副本自己铸的活卡按登记上记下的属主作答 —— 认调用方 ⇒ `200` `state:"pending"`,否则 `404`(7.136.0 起;7.133.0–7.135.x 的读口对活卡不读行,恒按登记作答)。起服接管的登记一直答 `404`。
323
+ 新形:行读不出 ⇒ 看不见 ⇒ `404 not_found.ask`,与查无 / 不是你的逐字节同,活卡与接管登记同答 —— 7.148.0 节第 29 条「看不见这只问(查无 / 不是你的 / 行读不出 / 本 worker 没有问账)」本来就是这一句,本版起实现与它一致。
324
+ `POST /v1/tool-approvals/:id/respond` 零变化(属主门那一读读不出 ⇒ 同一句 `404`;决议写失败之后读不回行 ⇒ `500`,第 40 条)。没有行的问(问账没上场 / 旧族腿)照旧按登记作答。
325
+ **谁受伤**:把店抖动期读口的 `200 pending` 当「问还在」的调用方 —— 现在收 `404 not_found.ask`,按第 29 条的出路会消卡。
326
+ **出路**:店恢复后重读即回 `pending`(行与在等的 run 都没被动);同一抖动期 `GET /v1/approvals` 的 `livePending` 与 `/v1/approvals/stream` 的 `live_pending` 与读口同隐、恢复同回(见本节「活卡的列表面」那一条)。一直 `404` ⇒ 报运维查库。**升级前做**:无。**回滚**:回到上一版即回到旧形(零数据面)。
327
+
328
+ 28. **缺列拒启的两只判官收成一只出口:单表探针(检查点 · 工具结果 · 文件历史 · 审批问账 · 规则审批记录 · 规则兑付票)的缺列拒启也带 `config.schema_mismatch`(`code` 字段 + 消息首词),与整库列册对账同一只类;订正 7.148.0 节第 84 条「检查点列册探针拒启 `config.schema_mismatch`」在 7.148.0 上不成立、自本版起成立(行为修复;拒句首词加码、其余逐字不变;运维日志面:起服 fatal 行的标题随类名变;部署零动作)**:
329
+ 旧形:存量库缺列时起服先撞见的是单表探针(检查点 · 工具结果 · 文件历史 · 规则审批记录 · 规则兑付票五个先于一次性迁移;审批问账那一个在第 6 段装配协调器之后才跑),它抛不带机读码的裸 `Error`,拒句形如 `checkpoint is missing the column host_session_id — refusing to start. …`;只有整库列册对账(靠后)的拒句首词是 `config.schema_mismatch:`。
330
+ 7.148.0 节第 84 条把检查点探针的拒启写成 `config.schema_mismatch`,在 7.148.0 及更早的构建上这一句对检查点探针不成立(码只出现在整库对账的拒句里)。
331
+ **勘误(第 84 条括注)**:自本版起成立 —— 缺 `checkpoint.host_session_id` 的库起服拒启 `config.schema_mismatch`,拒句点名 `checkpoint` 与缺的列、逐列打印生成的 `ALTER`、给闭集三条出路(第 84 条的升级动作与回填 M49 不变)。
332
+ 新形:缺列拒启只有一只出口(`SchemaMismatchRefusedError`,`StoreBootRefusalError` 族,`code` = `config.schema_mismatch`,消息码领头):整库对账的三条拒与六个单表探针判点(`checkpoint` 后加列册 · `tool_result` 出处两列与 `ref` 键宽 · `file_history_*` · `approval_ask` · `permission_rule_approval` · `permission_rule_ticket`)都经它抛。
333
+ 谁先判、各判官管哪些列、非缺列故障(连接 / 超时 / 权限 / 表不在)原样透出、拒句正文与闭集三条出路:逐字不变;不新增 DDL、不改任何表。包根导出不变(这只类在包内)。
334
+ **谁需要**:升级漏了一句 `ALTER` 的运维,以及按码 `config.schema_mismatch` 告警 / 脚本分派的部署。**谁受伤**:按第一个词或 `Error:` 标题逐字匹配探针拒句的脚本 —— 现在首词是 `config.schema_mismatch:`,fatal 行标题是 `SchemaMismatchRefusedError [config.schema_mismatch]: …`(与既有带码拒启同形)。**补偿**:不需要,按码匹配的读者不用改。
335
+ **升级前做**:无。**回滚**:零 DDL、零数据面;回到上一版,探针的拒句回到不带码的形,其余不变。
336
+
337
+ 29. **收编弧锁并入启动锁的同一只取锁器:多副本同拍收编同一个源主体时,TiDB 的「悲观锁重试上限」读成「别的副本正持着」,不再让收编请求上抛(行为修复;运维可见;wire 零变化;零 DDL;部署零动作)**:
338
+ 旧形:收编弧锁自带一只 `GET_LOCK(name, 0)` 探针(20 次 × 100 ms 的有界轮询);TiDB 上多个副本同拍探同一把锁时探针语句本身会抛 `pessimistic lock retry limit reached`,这只探针第一次抛就上抛 —— `POST /v1/adoption` 答 500,起服扫描把该弧记进 `failed`。
339
+ 新形:弧锁与启动锁(`ensureSchema` / 一次性迁移段)走同一只取锁器(同一套锁语句、同一个答案读法、同一条「撞上限 ≡ 别人持着」的律):撞上限继续轮询,用尽 20 次仍被持着 ⇒ 回「在飞」(与此前同);其余探针错连续 5 次才上抛(此前第一次就上抛);用尽 20 次时最近一次探针若是抛的也上抛(不读成「在飞」)。锁名限定、PG 键空间、`withLock` 签名与「在飞」窗的量级都不变(最后一次探针之后不再多睡一个间隔,约早 100 ms)。
340
+ **谁需要**:多副本同拍收编同一个源主体的 TiDB 部署。**谁受伤**:无(弧锁探针偶发一次坏答不再立刻失败,最坏多探几拍;预算最后一拍的坏答除外,照样上抛)。**出路**:不需要动作。**升级前做**:无。**回滚**:回到上一版即回到旧形(零数据面;锁不落库,随连接消失)。
341
+
342
+ 30. **起服拒句一次列全:缺列拒、单表探针拒、一次性迁移的判活拒都带同一张升级清单 —— 全库欠的 `ALTER`(逐表)+ 本构建的停-迁-起迁移 + 顺序(拒句措辞;码、判据、拒启面、出路集合零变化;wire 零新键、零新码;部署零动作)**:
343
+ 旧形:一台升级时漏了 DDL 的库,起服路上有三族拒各报各的一段 —— 单表探针(`checkpoint` 等六张表)只列它点名的那一张表的缺列;一次性迁移的判活守卫(M40 · M41 · M42 · M51)只说「停光旧副本再起」;整库列册对账(其余全部缺列)排在迁移段之后。
344
+ 运维按拒句补一句再起,撞上下一族 —— 7.148.0 的升级路径上曾要起四次才读全十句 `ALTER`(缺列拒 → 补列 → 判活拒 → 其余九句)。
345
+ 新形:三族的拒句尾是**同一张清单**(正文只有一份):`Upgrade checklist` 三步 ① 全库欠的 `ALTER` 一次执行(逐表段与语句行由本构建的建表语句生成,两方言各自的那一份)② 本构建带的停-迁-起迁移
346
+ (登记表里每一条带 `stopThenStart` 的行,一行一句缘由;已走过它们的库不被再问)与那一句动作(停光旧副本、等满 `REAP_RUN_STALE_SEC`、再起)③ 起服。第 ② 步按登记表列、不判这只库欠不欠,动作句的「不可滚动」照出:对已走过这几条迁移的库(如 7.148.x → 本版,见本节段头)它是多余的保守句。单表探针的拒因列的是**整库**的缺列(以前只列探针点名的表);
347
+ 判活守卫的拒句在库还欠列时句尾接同一段(列齐时句子一字不多)。清单只在有语句要执行时出现:库里只有多出的列(库比构建新)时没有语句可给,出路仍是持有那些列的构建;一次性迁移段之前读列册时,待跑迁移自己要删的旧列与自己要建的列(改名 / 加列 / 换表的目标列)不进清单(部署者照句子先加了,迁移的改名反而撞上已存在的目标列)—— 按迁移自己的条件读(与起服列册对账同一只投影,见本段「起服序」一条:改名的源列不在 ⇒ 迁移不会替它建 ⇒ 目标列照列);句尾读列册有期限,读不回来就如实说没读到,拒照出。
348
+ 与本节「缺列拒启的两只判官收成一只出口」一条叠加:那一条只给探针拒句加码(其余逐字不变指它自己的改动);探针拒因的逐表段本条改为整库口径、并加清单,以本条为准。
349
+ 四只守卫的「停光旧副本 → 等满判活窗 → 再起」一段并成一份(M42 的这一句措辞随之与另三条齐一;其余各自的缘由句不变)。
350
+ 不变:码(`config.schema_mismatch` / `config.scenario_prefix_switch_refused` / `config.session_deleting_switch_refused` / `config.execution_lane_rename_refused` / `config.session_ext_move_refused`)、哪些情形拒、一字节不写的保证、
351
+ 闭集三条出路(仍在句尾,逐字不变);起服各步的先后不在本条(本段「起服序」一条把列册对账排到了一次性迁移段之前:漏 DDL 的库第一次起服先撞对账的拒句,清单在那里列全;起服里判活守卫在对账之后,句尾只在库形与迁移登记的声明对不上时才非空;不经起服对账的嵌入方公开序列上守卫可能是第一只拒,句尾照列全)。没有进清单的拒:跳版库的退役 schema 拒、`Skill` 豁免截点拒、M32 的放置切换前提拒(它们的出路各自成句);M42 的 `stored_prefix` 拒仍点名行数,句尾同样接清单。
352
+ **谁需要**:升级运维 —— 一次读清本版对这只库要做的全部动作,不靠试探起服。**谁受伤**:按拒句全文做字面匹配的脚本(拒句措辞变了;按码判别的不受影响)。**补偿**:按码判别;全文匹配的改读清单标题 `Upgrade checklist`。
353
+ **升级前做**:无。**回滚**:回到 7.148.x 即回到旧拒句;无存储形变化。
354
+
355
+ 31. **勘误 7.148.0 节第 3 条:「相接 / 重叠的凭据合成一枚记号」只在本服务出口座投影的面成立;终局 `error` 文本与审批卡 `riskDescriptor.summary` 由引擎打码器逐段遮,相接 / 重叠形可留多枚记号与尾段(文字订正;零行为变化;wire 零变化;部署零动作)**:
356
+ 已发节(7.148.0)不改字节,本条即订正。
357
+ 订正对象:7.148.0 节第 3 条的标题与「新形」说每张面一枚段首记号,并把「run 的 `error`」「审批卡」列在合成的面里。实现里的合并律(相交或相接 ⇒ 一段一枚;本服务的脱敏器与出口座)只作用于本服务自己铸的 `«redacted:…»` 这一只记号族,
358
+ 所以成立的面是**本服务出口座投影出来的**那些:结果面(`result`)、账本行、事件重放、活流、审批卡的 `input`。
359
+ 不在其内的两处:**终局 `error` 文本**与**审批卡的 `riskDescriptor.summary`** 的字节,在到达本服务的出口座之前就由引擎的打码器逐段遮过(引擎自己的记号族:`[redacted]` / `[redacted-credentials]` / `[redacted-url]` / `[redacted-path]`);
360
+ 本服务不重写引擎已经打下的记号,所以这两处相接 / 重叠的两枚凭据可以留下多枚记号(例:终局 `error` 面上相接的两枚凭据读作 `[redacted][redacted]`),卡 `summary` 上可以看到两种记号串在一起,也可能留下尾段 —— 与 7.148.0 节第 3 条的「新形」不符。
361
+ 修法在引擎:引擎的打码器按相接 / 重叠合并之后,随提货到本服务,届时本服务再补一条 MIGRATION 更新这两处;在那之前这两处按旧形读。遮住的字节、`redactions_applied_total` 与其余各面(上面列的成立面)不受影响。
362
+ **谁需要**:按 7.148.0 节第 3 条的字面去断言「每张面恰一枚记号」的消费方与测试。**谁受伤**:在终局 `error` 或卡 `summary` 上按「一枚」解析或断言的消费方(这两处本来就没有合成)。
363
+ **出路**:把每一处记号(`«…»` 与 `[redacted…]`)当「这里遮了一段」读,不读个数、标签组合与相邻关系(契约原有规定:记号个数不是身份位)。**升级前做**:无。**回滚**:无存储形变化。
364
+
365
+ 32. **活卡的列表面与按问读口同一只店事实读法:`GET /v1/approvals` 的 `livePending[]` 与 `/v1/approvals/stream` 的 `live_pending` / `live_resolved` 列出的每一张卡,按问读口对同一调用方都答 `pending` —— 行读不出 / 行已离开待决的不再列,属主取行上当下的那一位(安全轴,fail-closed;行为收紧;wire 零新键、零新码;嵌入方类型面一处;部署零动作)**:
366
+ 旧形:列表面与推流只遍历本副本的进程内登记,按登记上记下的属主列、不读行。于是店抖动期(按问读口答 `404 not_found.ask`,本节「按问读口」那一条)列表照列这张卡 —— 按第 29 条的出路消卡的壳,下一次列表又会看到它回来;行被别处答掉 / 收走而本副本的登记还没闻讯时照列「待决」,直到这条登记自己结算(悬挂轮询或窗到期);收编在别的副本落定、本副本还没读到行时按前属主列。
367
+ 新形:对每只有行的候选(本副本此刻的登记,一只问一行)点读它的行,与读口、应答口同一只读行入口(读不出 ⇒ 看不见):行读不出 ⇒ 不列;行已离开待决 ⇒ 不列;行上当下的属主不在 scope 内 ⇒ 不列(scope 读法不变)。没有行的问(问账没上场 / 旧族腿)登记记下的属主是唯一可读的属主事实,照登记列。推流是同一只读函数:问账读不出这张卡的行而 checkpoint 队列这一拍读得出时,这张卡一帧 `live_resolved`,恢复后一帧 `live_pending`(队列读本身失败的拍只发错误帧、live 半场保持上一拍)。读行并发发起,一次列表至多等一个读期限(2 s),响应里的 `serverNowMs` 取在等完之后。列表的 scope 比读口窄(具名主体的列表不含无主的卡;运维列表含读口不放行的卡),本条不动:「列出的 ⇒ 读口答 `pending`」成立,反过来不成立。
368
+ **嵌入方类型面**:`ServiceDeps.toolApproval` 的 `listLivePending` 由同步返回改为返回 `Promise<LivePendingRow[]>`(包根不导出协调器类;自建 `toolApproval` 的嵌入方 tsc 红即通知,零别名)。
369
+ **谁需要**:读列表再逐卡读(或按卡应答)的壳 —— 抖动期不再「列表有、点开 404」,消卡后不再被列表带回。**谁受伤**:① 把 `livePending` 空数组读成「没有待批」的调用方 —— 空数组不区分「没有」与「此刻读不出」,没有机读位(唯一的运维信号是同一实例第一次读失败时的一行 warn `approval-ask store call failed` 与失败计数);② 按「列表是进程内投影、零 DB 成本」估算店读负载的运维 —— 现在每次列表 / 每个推流拍,本副本上每个有行的不同 ask 各多一次按 id 点读(重复登记共用一次,没有行的问不读;不按调用方 scope 先筛;上界是每个任务 / 每个属主各一个未决帽〔`STREAM_APPROVAL_ADMIT_MAX_PER_TASK` 默认 32、`STREAM_APPROVAL_ADMIT_MAX_PER_OWNER` 默认 256〕加起服接管至多 1000 张,总数没有全局帽;多租户单副本上登记数大时放大随之变大)。
370
+ **出路**:店恢复后下一次列表 / 下一拍推流即回(推流按「任一非 heartbeat 事件 ⇒ 重取权威 `list()`」姿势接则无需改动);读负载收小就收小那两个未决帽。多副本下候选集仍是本副本的登记(会话粘性要求不变)。**升级前做**:无。**回滚**:回到上一版即回到旧形(零数据面)。
371
+
372
+ 33. **自选会话 id 的创建面成文,且「被占着」只剩一种读法:别的主体的会话在删时,同步推送三口与对活行同答 404;推送族「别人 404 / 不存在新建」的两答与提交挂接、键控 fork 同形,先占者得,反枚举只靠 id 的熵(安全收紧;行为变更;wire:推送三口一面状态改答 404〔登记〕,零新键、零新码;部署零动作)**:
373
+ 旧形:同步推送三口(plan / 导入第一阶段 / blob 上传)的门把「在删的行」(删除围栏已立、尚未删净)读作不在,提交挂接的认领面把它读作仍占着这个 id —— 同一件事两种读法。别的主体的会话在删时,别的主体对它 plan 得 `200 {"relation":"fresh"}`(local 后端)/ 第一阶段 200 带 `stagingId` / blob 上传 204;SQL 后端的导出不看在删态,plan 还答 `200` 带 `stale` / `fork` 关系体(随来源条目与残留条目的包含关系),内含该会话残留的条目 id,第一阶段 `409` 带同一关系体。(既有,非回归。)
374
+ 新形:「这个 id 被占着吗」只有一种读法(活行 ∪ 在删行,三张面同读):别的主体对在删的会话与对活行同答 `404 not_found.session`(体与拉取口对不存在 id 的答复逐字节同);本人 / fleet 对自己在删的会话不变;拉取口仍只认活行。同时把三张让调用方**自选**会话 id 的创建面 —— 会话同步推送、提交挂接(带 `sessionId`)、键控 fork(`forkId`)—— 的同一条律成文:空闲的 id 就地建(落在调用方名下),别的主体占着的 id 答这一面自己的「没有这一行」(推送族 `404 not_found.session`、提交挂接 `404 resume.session_not_found`、键控 fork `404 not_found.session`),先占者得。三张面不保证「别人的 ≡ 不存在」:`session_id` 是全局主键、自选、空闲即建,「这个 id 被占了」对创建者固有可观察,反枚举只靠 id 的熵;server 的 id 门是形门(canonical uuid、任意版本),不是熵门,低熵的 canonical uuid 可被枚举。契约新增「自选会话 id 的创建面」一节。
375
+ **谁需要**:有身份边界的多主体部署上自选会话 id 的消费方,以及任何有会话正在被删的多主体部署。**谁受伤**:在删窗口里靠推送三口的「新建」答复去探别人会话状态的调用方(靠缺陷,现答 404;本人 / fleet 不受影响);用可预测 id(序号、名字的确定性 uuid、时间戳 uuid)的消费方 —— 别的主体能探出占用并抢先占掉。**出路**:自选 id 用随机 uuid(v4 / v7);要零信号就不自选 id(提交不带 `sessionId`、fork 不带 `forkId`、收编批量导入的云端 id 是 `(adoptionId, clientSessionId)` 的纯函数);会话镜像推送的零信号形得把 id 空间按主体分区(服务端派生 id,或 id 自带主体前缀、查表前先验前缀),是另立设计、本版不承诺。**升级前做**:无(已在用可预测 id 的消费方自行换成随机 uuid)。**回滚**:回到上一版即回到旧读法(零数据面)。
376
+
377
+ 34. **会话同步推送的导入租约按「落点属主格」分键:空闲 id 上各占各的(先提交者得),既有会话上共一把 —— 一个主体的在飞第一阶段不再挡住、也不再透给另一个主体;第一阶段 blob 在场预检核实为真、本版不收(安全收紧;行为变更;wire:导入第一阶段一面 409 改答 200〔登记〕,零新键、零新码;部署零动作)**:
378
+ 旧形:导入第一阶段占的实例级租约键只是会话 id。空闲 id(还没有会话行)上任一主体的在飞第一阶段,让别的主体对同一 id 的第一阶段答 `409 import_in_flight`(带 `retryAfterSec`)—— 既把首推挡到租约陈旧(缺省 600 s),也让「此 id 此刻有人在导」成为可观察位。别人的既有会话上没有这件事(属主门在租约之前,先答 `404 not_found.session`)。(既有,非回归。)
379
+ 新形:租约键 = 落点属主格 + 会话 id。会话行在 ⇒ 行的属主格,属主 / fleet / 存量无主互认共一把(同一份会话上第二份在飞导入,谁发起的都 `409 import_in_flight`);空闲 id ⇒ 这位调用方自己,各占各的,先提交者得,输的那一份在提交前复判答 `404 not_found.session`(与赢家的提交撞在同一刻时由店的属主 CAS 拒、答 `409 conflict`);删除中的会话上属主与 fleet 同样共一把。同一主体自己的两份在飞照旧互斥;只有走到开暂存臂的第一阶段碰租约(`identical` 不碰)。陈旧判成了一条读法:任何第一阶段路过都把闲置 ≥ `SYNC_IMPORT_LEASE_STALE_SEC` 的租约连同暂存登记清掉(`0` = 关,行为不变)。第一阶段的 blob 在场预检读的是全局内容地址表(别的主体传过的 blob 对你也算在场),重放取值口读同一张表 —— 不上传、只在信封里写 hash 的主体可在提交后读到别人传的字节;要让它只认本会话可见的 blob 需要 blob 来历这个持久事实,另裁,契约「自选会话 id 的创建面」一节如实写明(既有,非回归)。
380
+ **谁需要**:有身份边界的多主体部署上经会话同步推送的主体(镜像推送首推一个新 id 的客户端)。**谁受伤**:靠「同一空闲 id 上第二份 409」当互斥的不同主体 —— 现在各自受理,先提交者得;对 blob 内容有机密要求的多主体部署(blob 面见上,本版未收)。**出路**:自选 id 用随机 uuid(见上一条);同一主体重试遇 409 照 `retryAfterSec`;blob 面本版没有部署侧旋钮(文件历史半族由后端形态定:`capabilities.sessionSyncFileHistory`),在它另裁收口之前,多主体部署上互不信任的主体之间,文件历史内容并不互相保密(知道 hash 即可取)。**升级前做**:无。**回滚**:回到上一版即回到旧读法(租约是进程内存,零数据面)。
381
+
382
+ 35. **目录条目的名字就是一枚凭据形(`sk-…` / `ghp_…` / `AKIA…` / `xoxb-…` 一类,引擎的脱敏器对孤立标识符的读法认得出)⇒ 这条条目不可用:`config.model_entry_invalid`、坏字段 `name`,不进目录、不进 `GET /v1/models`(安全轴;行为收紧;wire 零新键、零新码;目录里没有这种名的部署零动作)**:
383
+ 旧形:条目名是 `@name` 选择把手,`GET /v1/models` 的 `models[].name` 原样回给任何调用方;同一个名字在启动日志里被日志出口接缝遮掉。把密钥误写进模型名的部署,密钥随目录读面对每个调用方公开,日志里却看不到 —— 同一个值两种读法。
384
+ 新形:模型面逐条判据在形判里多问一句 —— 名字是凭据形 ⇒ 这条条目不可用(码 `config.model_entry_invalid`,坏字段 `name`;拒因句点名字段与出路、不带名字的任何字节),与不合 `ModelEntry` 形的条目同律:不进目录、不进 `GET /v1/models`、不当缺省,`@name` 点它拿 400 `request.model_unavailable`,每条一句 warn `web_admin_model_entry_invalid`(`field: "name"`、`modelNameWithheld: true`,名字不进日志字段)。中心下发、`config.d/models.json`、盘上 last-known-good、`run-local` 同走这一只判据,起服与热发布同判。它是目录里仅有的启用条目 ⇒ 这份候选没有缺省模型,模型面整组被拒(`config.default_model_missing`):起服时 env 也没有 `MODEL_ID` 则拒启、有则 env 表继续服务,热发布则上一代继续服务。
385
+ 「凭据形」的读法:名字**就是**一枚凭据 —— 脱敏器对孤立标识符的读法(不是自由文本的读法:词法关键字臂出局,`tokenizer-model-2026-11-08` / `token-introspection-endpoint` 这类标识符不是凭据形),只认强证据,凭据形在串首。典型形:`sk-` / `sk-proj-` / `sk-ant-` + 长体(值 ≥ 20 位且含 ≥ 2 个大写或数字)、`ghp_` / `github_pat_`、全大写的 `AKIA…` / `ASIA…` + ≥ 16 位大写字母数字(AWS 访问钥 ID 的形)、`xoxb-…`、`npm_`、`glpat-`、`ya29.`、`sk_live_`、`hf_` + 够长的体;脱敏器自己的裸形启发式认不出的(`sk-` + 规范 UUID、`sk-proj-` + 全小写长体)不拒。名字里嵌着这些前缀、前面还有别的字的(`mask-rcnn-…`、`prod_<钥>`)不拒。现实模型名(厂商 id、端点 id、日期戳、十六进制串、点分前缀)逐个对照不被误判。
386
+ 同批收同类缺口:`/health.modelRefusals` 与 fleet 心跳的键、拒因 warn 的 `model` 字段、拒因句里的名字位,此前只问契约包的名筛,它读不出 `npm_` / `glpat-` / `ya29.` / `sk_live_` / `hf_` 五族 —— 因别的原因被拒(如无 anthropic 凭据的 `provider:"anthropic"` 条目)又叫这类名的条目,名字会出现在 `/health.modelRefusals` 的键里;现在这三个出口同问一个口(契约包名筛 ∧ 脱敏器),凭据形的名只写码、不上 wire。`request.model_unavailable` 的拒句在调用方只发了上游 id 时带的别名段 `(catalog entry "<名>")` 是配置里的名字,不可披露的名改写成 `(catalog entry (name withheld))`;续跑腿留声 `task_model_unavailable_fallback` 的 `name` 字段同走名字出口(不可披露的名换成 `nameNameWithheld: true`)。
387
+ **谁需要**:把密钥误写进模型名的部署(目录名字位当成密钥槽用 / 复制粘贴错位)—— 起服 / 发布时就被拒,而不是静默公开。**谁受伤**:目录里有凭据形名字的条目(此前照常服务并公开名字,现在不可用;`sk-Mistral-7B-Instruct-v0.3` 一类以 `sk-` 起头的长名也在内 —— 它就是那种钥的形);读 `/health.modelRefusals` 的消费方 —— 叫这五族名的被拒条目此前在键里、现在不在(不可披露的名既不进键也不计数,与此前其它不可披露的名同律);按「拒句里别名段是条目名」解析 `request.model_unavailable` 的调用方(仅凭据形名的那一条变成 `(name withheld)`)。**未覆盖(如实)**:`MODEL_ID` / `MODEL_CHEAP_ID` 铸的 env 表与条目的上游 `id` 字段不经这一判据(凭据形的 `MODEL_ID` 仍会原样出现在 `GET /v1/models`);被读腿丢掉的条目的 `droppedEntries[].identity` 仍按契约包名筛判;凭据形前面粘着别的字的名字不拒。
388
+ **出路**:给条目改名(纯标识符:字母 / 数字 / `.` `_` `-`);名字若是从一枚真凭据贴来的,那枚凭据按已泄露处理 —— 它写进过配置文档(与可能的版本库)。**升级前做**:`config.d/models.json` 与中心目录里的条目名过一遍,任何凭据形的名先改名再升级,否则升级后那条条目不可用;若它是目录里唯一的启用条目且 env 没有 `MODEL_ID`,升级后起服拒启。**回滚**:回到上一版即回到旧形(零数据面)。
389
+
390
+ 36. **勘误 7.148.0 节第 49 条:能力位 `sessionReadRedaction` 由布尔改叶名表不是「部署零动作」—— 升级本服务之前,先确认接入它的壳已能按数组形读这一位;旧壳会把 `--resume` 读成未脱敏,会话静默变成一只空白的新会话(文字订正;零行为变化;wire 零变化;部署有前置动作)**:
391
+ 已发节(7.148.0)不改字节,本条即订正。
392
+ 订正对象:第 49 条标题写「部署零动作」。本位的值由 `true` 改成叶名表 `string[]` 之后,按旧读法判本位的壳(`!== true` ⇒ 当作「历史读面没有过脱敏」)
393
+ 会把 `--resume` 读成未脱敏、不续这只会话 —— 用户那一侧看到的是会话静默变成一只空白的新会话,没有报错。
394
+ 改为前置动作:先确认接入的壳已能按数组形读本位(cli ≥ 1.0.164;client-core 的对位版本),再升本服务。
395
+ **谁需要**:运维(升级顺序)。**谁受伤**:壳还是旧版就先升了本服务的部署 —— 续跑静默落成新会话。**出路**:先升壳、再升本服务。
396
+ **升级前做**:上面那一条确认。**回滚**:无存储形变化。
397
+
398
+ 37. **进程内「本会话放行」绑会话的这一位住客:会话删了(删除路由 / 留存清理 / 别的副本)再用同一个 id 重登记之后,上一位住客点的放行不再落到下一位身上;读不出住客令牌的腿不记(安全收紧;行为变更;既有缺陷;wire 零新键、零新码;嵌入方类型面三处;部署零动作)**:
399
+ 旧形:活卡上对引擎的问点的「本会话放行」(`allow_session`)记在协调器的进程内表里,键 = (属主,会话 id,能力桶,绑定摘要)。会话 id 由调用方自选,删会话(`DELETE /v1/sessions/:id`)与留存直删清不到这张表(只清耐久豁免店),所以同属主在本进程用同一个 id 重登记之后,新一位住客的第一次调用被上一位点的放行代答、免问。别的副本删了再登记同形。
400
+ 新形:键加会话行上的住客令牌(化身):装配点把执行上下文那一读的住客交给审批席的身份,读写两点取同一格(取出处腿的住客,不取应答那一刻会话行上的)。会话删了再用同一个 id 登记 ⇒ 令牌换了 ⇒ 上一位的放行读不中,新一位的第一次调用出卡;同一位住客内「本会话放行」照旧生效。删除路径不新增任何清表动作(上一位的表项留到容量帽逐出或进程重启;新一位住客的腿算不出它的键,仍在跑的上一位住客的旧腿读自己名下的,不跨住客)。读不出住客令牌的腿(会话店不带执行席 —— 引擎缺省的内存会话店;SQL 两方言与 local 后端恒带)不读也不铸:点 `allow_session` 只放行这一次、回执 `rememberApplied:false`,日志一行 warn `session_grant_refused_occupant_unreadable`。
401
+ **嵌入方类型面**:`ToolApprovalRunContext`、`boundAsk` / `boundUnattendedAsk` 的身份、`approverSeatFor` 的身份各多可选键 `incarnation`;包根导出的 `runInBackground` 的 `approval` 参数里原来的 `executionLane` 键并进 `origin: { executionLane, incarnation? }`(自建调用的嵌入方 tsc 红即通知,零别名)。
402
+ **谁需要**:用「本会话放行」又会删会话 / 被留存清理清掉会话的运维与用户(含反复用固定会话 id 的脚本)。**谁受伤**:靠上一位住客的放行给下一位免问的调用方(靠缺陷);用引擎缺省内存会话店的嵌入方 —— 其腿读不出住客,「本会话放行」不再被记住(每次照问)。**出路**:要跨删除保留免问不是这张表的职责(耐久面的 `remember:"session"` 随会话树删除一起清,同样不跨住客);嵌入方要「本会话放行」生效就给会话店带执行席(`sessionStorage.executionPlacement`)。**升级前做**:无。**回滚**:回到上一版即回到旧形(零数据面;进程内表随进程重启清空)。
403
+
404
+ 38. **起服序:每一只拒启判都先于第一笔一次性迁移写与封签钥匙的铸造;显式写了 `SEALED_KEY_DIR` 的钥匙目录在停驻审批耐久时进拒启判据(行为修复;拒启码不变;wire 零新键;部署零动作 —— 只有 `SEALED_KEY_DIR` 指在易失介质上、停驻审批耐久的部署起服被拒)**:
405
+ 旧形:SQL 起服的列册对账(缺列 / 多列 / 可空列 ⇒ `config.schema_mismatch`)、记忆向量指纹门、SQL 引擎姿态(隔离级 / 事务模式复核)、device 审计探针、`REQUIRE_PRINCIPAL=true` × `DB_BACKEND=local` 与云形快照 blob 姿势两道配置判排在一次性迁移段之后:
406
+ 漏跑了升级前 DDL 的库被拒之前,迁移已改写存量(搬格、删列、清行),起服日志打过一行 `one_time_migrations_applied`;运维补完 DDL 再起,迁移读数是零,看上去像什么都没改,而数据已改。
407
+ 配置根与数据根合一(本地配置源)时,配置根上的一次性迁移 SS-M11 的运行记录与决定、配置根供给建出的 `SEMA_CONFIG_DIR` 先于店的持久性准入落盘。
408
+ `SEALED_KEY_DIR` 指在 tmpfs / 容器可写层上而停驻审批耐久(SQL 检查点店,或声明耐久的 local 店):起服、停驻;下一次替换之后停驻行还在、封它请求凭据的钥匙没了,之前停驻的每一条续跑都答 `key_not_held`。
409
+ 新形:一条律 —— 拒启判排成一段,全部早于第一笔一次性迁移写与钥匙铸造。
410
+ ① SQL:列册对账排在一次性迁移段之前,比的是「本构建带着的、待跑的迁移跑完之后」的形 —— 迁移要删 / 改名 / 补 / 重建的列不让起服拒(没改过库的正常升级照起),别的缺列 / 多列 / 可空列照拒
411
+ (改名之后的可空性按方言读:MySQL 协议的改名句带本构建的列定义,PG 的 `RENAME COLUMN` 保留旧列的可空性;重建的旧表缺搬运要读的列 ⇒ 迁移之前拒),
412
+ 拒的时候存量一笔没改、没有迁移读数行;补上拒句给的 DDL 再起,迁移在起得来的那一次跑、读数行如实。发车门 1.10 第三档读同一只投影,读数不变(`migration-pending` / `mismatch`);单表探针的拒因与判活守卫的句尾(本段「起服拒句一次列全」一条的升级清单)读同一只投影。
413
+ 迁移跑完之后同一只对账再跑一次(待跑集为空):只在本构建某条迁移的表形声明与它真落下的形不符时拒 —— 构建缺陷,不是部署状态;部署状态的不符都在迁移之前、零写拒过。
414
+ ② 配置根:店的持久性准入排在配置根供给、配置根上的一次性迁移 SS-M11、保管店铸钥匙之前 —— 配置根与数据根合一而介质易失、被拒的那一次起服,那只根上没有本服务写下的任何东西。
415
+ 准入之前唯一可能的写是 `config.d` 的一次性迁移(目录里还有 settings-schema 11 之前写法的文档时它改写这些文档:执行车道读的 `remote-exec.json` 是其中一份,准入判的是读它合成出的车道)。
416
+ `run-local` 同序(它没有店的持久性准入;配置根上的 SS-M11 挪到车道合成之后)。
417
+ ③ 封签钥匙目录:`SEALED_KEY_DIR` 写了 ∧ `DURABLE_APPROVAL` 在 ∧ 检查点店耐久(SQL 后端恒是;local 随店的声明)∧ 目录介质判 `ephemeral` ⇒ 起服拒 `config.store_not_durable`;数据根那一臂同时不过 ⇒ 一句拒、逐条列出。
418
+ 缺省的钥匙目录(`<数据根>/sealed-key`)不进判据:local 后端由数据根那一臂判;SQL 后端无卷的无状态副本是常形,没写 `SEALED_KEY_DIR` 的部署没有对钥匙目录作过承诺 —— 只进读数(`store.durability`)与起服 warn。
419
+ 判不出的介质(`unknown`)不拒。读面(`/health.store.durability`、caps `store.durability`、`GET /v1/diagnostics/wiring` 的逐根明细)不变。
420
+ **谁需要**:漏跑升级前 DDL 的 SQL 部署;配置根与数据根合一的本地部署;写了 `SEALED_KEY_DIR`、停驻审批耐久的部署(钥匙目录不活过替换就不起服,不再静默丢停驻)。
421
+ **谁受伤**:`SEALED_KEY_DIR` 指在易失介质上、停驻审批耐久的部署 —— 上一版起服(停驻的任务在下一次替换之后续不了),本版拒启。
422
+ `REQUIRE_PRINCIPAL=true` × `DB_BACKEND=local` 的拒挪到开店之前、按声明的后端词判(local 店的 `ensureSchema()` 自带几条 local 一次性迁移):没写 `DB_BACKEND`、缺省推导的 local 数据根空而开不了、
423
+ 上一版静默降级成内存起服的多租户部署,本版拒(出路:SQL 后端;要照旧跑内存就显式写 `DB_BACKEND=memory`)。其余只改顺序,无人受伤。
424
+ **补偿 / 出路**:拒句逐条给出路 —— 给钥匙目录挂持久卷(每个副本看见同一只目录);或关停驻审批(`DURABLE_APPROVAL=false`,要审批的任务只在活连接上等);local 部署还可声明易失(`LOCAL_STORE_DURABILITY=ephemeral`)。
425
+ **已知边界**(既有,本条未收):第 2 段铸钥匙(web-admin 运行时)之后,第 3 段开店里的 SQL 判(退役 schema、跳版截点、列册对账)拒启时保管店的钥匙已铸;起服第 6 段之后的拒启判(停驻凭据封签不可用、装配期配置不变量)
426
+ 晚于第 3 段的迁移段;记忆向量指纹门在运维确认重嵌(`MEMORY_EMBEDDER_REEMBED`)时的清列在判官段里。嵌入方的公开序列(`createStoreBackend()` → `ensureSchema()` → `runOneTimeMigrations()`)不跑列册对账。
427
+
428
+ 39. **勘误 7.148.0 节第 35 条:账本里的 `delete` 事件不是本服务写的 —— 本服务自身不写该事件,排空脚本读到的是引擎留存域 / 别的嵌入方写下的账本(文字订正;零行为变化;部署零动作)**:
429
+ 已发节(7.148.0)不改字节,本条即订正。
430
+ 订正对象:第 35 条说引擎自 7.56.0 起在删某个会话的检查点行时写 `delete` 事件,读起来像本服务删会话就会写。`DB_BACKEND=local` 删会话时检查点那一腿只把这只会话的停驻门作废、删掉它的续跑输入文件,账本与快照照样留着终局历史,不写 `delete`。
431
+ `scripts/drain-check-local.mjs` 认这个事件,是为了读引擎的留存域、或别的嵌入方在同一只数据根上写下的账本;本服务自己写的账本里不会有它。
432
+ **谁需要**:按第 35 条去本服务的数据根里找 `delete` 事件的运维。**谁受伤**:无。**出路**:无动作;脚本读法不变。**升级前做**:无。**回滚**:无存储形变化。
433
+
434
+ 40. **勘误 7.148.0 节第 78 条:会话记忆抹除口(`POST /v1/sessions/:id/memory/erase`)那一臂「层拒改答 400 `request.memory_layer`」在 wire 上不可达(文字订正;零行为变化;wire 零变化;部署零动作)**:
435
+ 已发节(7.148.0)不改字节,本条即订正。
436
+ 订正对象:第 78 条把会话记忆抹除口列进「层拒改答 400 `request.memory_layer`」。这只面的请求体不收 `scope` 也不收 `select`(两者都答 400 `request.body_shape`),选择子由路径铸成「这只会话」,抹的是部署里每一只店里这只会话的那一份 ——
437
+ 没有「点哪一层」可以点错,所以这一臂从 wire 上构造不出来;映射保留(引擎若对这只面抛层错,答的就是这一形)。同条「旧形:`500 internal.error`」对这只面指的也是引擎抛层错的那一形,同样不能从 wire 构造。其余四口的控制面损坏改答 `500 internal.memory_control_plane_corrupt` 不变。
438
+ **谁需要**:按第 78 条给会话记忆抹除口写「400 `request.memory_layer`」用例的消费方与测试。**谁受伤**:无。**出路**:这只面要测的拒是 `scope` / `select` ⇒ 400 `request.body_shape`。**升级前做**:无。**回滚**:无。
439
+
440
+ ## 7.148.0 —— 1–115 条见下
441
+
442
+ 1. **删净一只会话只有一个执行体:SQL 上在线删除与留存同一段事务;删后收尾两者同一只(行为统一;嵌入方类型面 BREAKING;wire 零变化;零 DDL;部署零动作)**:
443
+ 旧形:在线删除逐店调删除动词;SQL 会话店带 `deleteSession(id, owner)`;留存删除不写完成信箱围栏、不丢会话信箱盒、不释放附件字节;留存回执带 `endedSpaces`。
444
+ 新形:SQL 后端的在线删除由后端的 `sessionEraser(opts)`(与 `retention(opts)` 同一份选项)完成:`erase({ sessionId, owner, token })`(`token` = 本版会话三态一条里删除围栏写下的那一只)在会话行锁下一个事务里比属主、判令牌、删全部行(完成信箱围栏、会话盒都在里面),答 `superseded`(被接管 / 已删完,一行没删)或 `erased`;SQL 会话店不再有 `deleteSession`;
445
+ local 会话店的 `deleteSession` 改为 `deleteSession(id, owner, token, legs)`(删除锁节:比属主、判令牌,`legs(住客)` 在锁里跑各店的删除,答删掉的那一位或 `undefined`);执行器选项多两只必填 `mailboxTables`(收件箱四表在不在)/ `completionInbox`(完成信箱在不在用);
446
+ `TaskAttachmentStore` 多一只必填 `releaseBytes(shas)`(回 `{ failed }`,不抛);留存回执的 `endedSpaces` 换成 `erased`(删掉的会话 + 删前属主 + 住客、附件字节哈希、无出处卸载结果数),交同一只收尾。
447
+ **谁受伤**:自建会话店 / 附件店 / 留存执行器的嵌入方(tsc 红即通告)。**出路**:按新签名实装;服务进程部署零动作。
448
+
449
+ 2. **🔴 配了服务凭据的部署上,`GET /health` 对没出示凭据的调用方只给闭集 `status` / `auth` / `operator` / `center`(wire BREAKING:对匿名读者收窄;零新旋钮;部署零动作 —— 读匿名 `/health` 里身份 / 路径 / 后端字段的脚本改带凭据)**:
450
+ 旧形:不论部署配没配服务凭据,匿名调用方 `GET /health` 都拿整张体(含 `dataRoot` 数据根绝对路径、`pid`、`configHash`、`startedAt`、`sessionBackend`、`store`、`version`、`engineSignal`、排空 / 租约窗等)。
451
+ 新形:没配任何服务凭据(`SERVICE_AUTH_TOKEN` / `SERVICE_AUTH_TOKENS` 都没有)⇒ 匿名读全键,与旧形逐字节同;配了而请求**没出示读路谓词认的凭据**(service token / 只读 `TRACE_TOKEN` / 已验登录令牌;出示了验不过的串同算没出示)⇒ 状态仍 200、体只有 `status` / `auth` / `operator` / `center` 四键(其余一律不出,含 `instanceId` / `pid` / `dataRoot` / `configHash` / `startedAt` / `port` / `sessionBackend` / `version` / `engineSignal`);出示了 ⇒ 全键。`/readyz` 不变。
452
+ 谁要动:① 嵌入宿主(桌面 / cli 自起引擎)验引擎身份读 `instanceId` / `pid` / `dataRoot` / `configHash` / `startedAt`:配了服务凭据的引擎上改带起引擎用的那枚凭据(`Authorization: Bearer <token>`);没配服务凭据的嵌入形不用动。② 读匿名 `/health` 里 `sessionBackend` / `store.durability` / `version` / `draining` / `engineSignal` 的部署验收脚本与编排器:同样带部署的服务凭据。随包的 sema-up 三处验收已改。③ k8s `httpGet` / Docker `HEALTHCHECK` 只看状态码的探针:不用动。④ 壳在带凭据之前读 `auth` / `operator` / `center` 三键:不用动(三键在闭集里,值与带凭据读逐字同)。⑤ 壳与脚本经 SDK 读 `/health` 并按 `instanceId` / `pid` 判「这是不是我起的那只引擎」:在配了服务凭据的引擎上,读口必须带凭据 —— SDK 的 `probeHealth(url, { token })`(`@sema-agent/sdk` ≥ 37.0.0 才有 `token` 选项;更早的 SDK 只会匿名读,在这样的引擎上拿不到 `instanceId` / `pid`,身份判不出)。带不带凭据是调用方逐次的选择:只对自己起的、已信任的端点带,不向复用端口上的陌生进程出示。
453
+
454
+ 3. **同一个凭据值在每个出口面上是同一枚记号:相接 / 部分重叠的两枚凭据在结果面、审批面、终局错误、账本行、活流上合成一枚(行为变更;wire 零新键、零新码;部署零动作)**:
455
+ 旧形:`AKIA…sk-…` 一类零分隔相接、或 `xoxb-AAAsk-…_XYZ` 一类部分重叠的两枚凭据,trace 帧 / 完成帧 / 运维日志上一枚记号,`result` / 账本行 / 审批卡 / run 的 `error` / 活流上两枚(`«redacted:aws-key»«redacted:key»`)。
456
+ 新形:每张面一枚段首记号(`«redacted:aws-key»`);格式字符隔开、原文上不相接的两段仍两枚;遮住的字节不变;`redactions_applied_total` 不变。跨引擎块相接的两枚在活流与段末帧上两枚、结果面一枚。
457
+ **谁受伤**:按记号个数推断凭据枚数、或按第二枚记号的标签分支的消费方。**出路**:把每一处 `«…»` 当「这里遮了一段」读,不读个数与标签组合(契约原有规定)。
458
+
459
+ 4. **运维日志:上游应答「体不是 JSON」的报错句不再带体的片段;记忆同步对端非 2xx 只带码 + 体长(行为变更;wire 零变化;部署零动作)**:
460
+ 旧形:`config_source_unreachable_using_env` / `web_admin_refresh_failed` / `config_boot_arrival_repull_failed` 等行的 `err` 是 `SyntaxError: Unexpected token 'x', "<体前 10 字>"... is not valid JSON`;`memory_sync_layer_failed` 的 `err` 带对端错误体前 200 字原文。
461
+ 新形:`SyntaxError: the response body is not JSON (<n> characters; the body is not echoed)`;记忆同步 `HTTP <码> (<n> characters; the body is not echoed)`。
462
+ **谁受伤**:按 V8 原句匹配日志告警的规则;靠记忆同步行里对端拒因排障的运维。**出路**:改匹配 `the response body is not JSON`;拒因读对端(`MEMORY_SYNC_SERVE` 那一台)同一时刻的运维行。
463
+
464
+ 5. **run 终局里库驱动的原句不再上 wire:`internal.store_error` 的失败句改成固定对外句(行为变更;wire 零新键、零新码;部署零动作)**:
465
+ 旧形:持久层失败折成 `internal.store_error` 时,`GET /v1/runs/:id` 的 `error` 与 `result.terminal.message`(同一次失败的 `done.result` / 账本行 / 同步提交 200 体同)逐字带库驱动的原句(库账号、主机、表名、约束名都可能在里面)。
466
+ 新形:句 = 「<类别句> [original code: <码>]」,类别(连接类 / 部署错配类 / 其余)由整仓一只店故障判官按码说,与库写了什么无关(句子只断言码证明得了的事:只有缺表 / 权限拒两类库专有码才说「数据库」);原句只进 worker 日志里同一条 `outward_failure_code_folded … at=exit` 行的 `message=` 格。`terminal.code` 不变(仍 `internal.store_error`),`error` 与 `terminal.message` 是同一句;没有码、或码在本仓词法内的失败文本不变(码在词法之外的 —— 持久层的驱动错与少数系统错误码如 `ENOENT` —— 同样换句)。
467
+ **谁受伤**:按这句失败文本分支的调用方(它一向是自由文本,判别读 `terminal.code`),与靠 wire 上库原话排障的运维。**出路**:判别读 `terminal.code` 与句尾 `[original code: …]`;要库的原话读 worker 日志那一行。已落盘的旧行不改写。
468
+
469
+ 6. **workflow 完成的 `diagnostics`:live `task_notification` 帧不再带部署路径 / 内部 URL 原文,与 `workflow_complete` 补投帧同一读法(行为变更;wire 零新键、零新码;部署零动作)**:
470
+ 旧形:同一次 workflow 完成,补投帧 `diagnostics` 里的 journal 坐标是 `[redacted-path]`,live 帧上是部署路径原文(引擎在两条腿上递的不是同一份,本服务两条腿各接一行座、都不读「读者是人」的档)。
471
+ 新形:两张脸读座表的同一行,整条 URL / 绝对路径换 `[redacted-url]` / `[redacted-path]`,同一次完成逐字节相等(主机身份这一维);live 帧同补投帧界 4000 码元(此前不设界)。读取手柄句与续跑句不含路径、不变。顺带:所有有界座行的切点律认引擎的记号族,`[redacted-path]` 一类恰被界切到时切在记号前(此前留半枚)。
472
+ **谁受伤**:按 live 帧上 journal 路径文本分支的调用方(极罕见)。**出路**:读 `ReadToolResult (ref …)` 手柄句与 `resumeFromRunId` 续跑句,不读路径。
473
+
474
+ 7. **取消一次 wake 不再收掉它续的那张会话 park(行为变更;wire 零新键、零新码;部署零动作)**:
475
+ 旧形:wake 在入口屏 / 预检上被取消(`checkpoint.resume_aborted`)⇒ 合成行取消终局,会话的 `task_done` park 被 expire,再 wake 答 `404 not_found.parked_checkpoint`。
476
+ 新形:合成行照旧取消终局(`errorCode:"cancelled"`)、放认领;park 留 pending,再 wake 续它(与 wake 跑起来之后失败 / 取消时的结局同一个)。
477
+ **谁受伤**:把「取消 wake」当成「结束这条会话的 park」的调用方。**出路**:新提交一条任务(新 run 与 park 并存),或等审批窗到期收割。
478
+
479
+ 8. **local-docker 车道容器帽:新旋钮 `DOCKER_MAX_CONTAINERS`(缺省 `0` = 关);新提交可能拿到 429 `limit.rate_exceeded` 的第二个机读 `reason`:`"sandbox_capacity"`;`/health` 多一格 `sandboxCapacity`(行为加性,缺省关;wire 加性;部署零动作)**:
480
+ 旧形:`REMOTE_EXEC=local-docker` 下沙箱容器的总量服务侧不封顶(每条 run、每只委派子代各一只,停驻期不销毁;`DOCKER_MEMORY` 只封单只)。
481
+ 新形:`DOCKER_MAX_CONTAINERS` 是 `0` / 不设 ⇒ 不建闸、不读 daemon;帽关着也生效的只有三处 —— 每只 `docker run` 恒带本 worker 标签 `--label sema.local-docker=<worker>`(惰性元数据);连接还没完成时被取消的工具调用立刻答 `aborted`(此前等连接完成后答同一个码),
482
+ `docker` CLI 的 spawn 同步抛(argv 过长等)不再让适配器的 promise 拒掉、改答 `spawn_error`。开了之后:`DOCKER_MAX_CONTAINERS` = 本 worker 同时在跑的容器数上限(上限只有这一只旋钮;按内存定上限自己换算:
483
+ `floor(愿给容器的总内存 / DOCKER_MEMORY)`)。计数读 docker daemon:本 worker 起的每只容器都带标签 `sema.local-docker=<worker>`(标签恒在,上限随时可开 —— 上限关着时起的也计;停驻期的、委派子代的都计),加上 `docker run` 回执丢了而 daemon 仍列着的。
484
+ 射程 = 本 worker:worker 是本服务数据根绝对路径的摘要,同一数据根上重起不变 —— 上一次进程崩掉留下的容器照计;别的数据根是别的 worker,不计;多只 worker 共用一只 daemon 时整机合计不在本旋钮。
485
+ 只有本版之前起的容器不带标签、不计。
486
+ 起容器没空位 ⇒ 每只执行环境等一份预算(缺省 60 s),到期这一次工具调用拿到带 `limit.rate_exceeded` · `sandbox_capacity` 的拒句(run 不被终结;句里给本 worker 的标签过滤式)。
487
+ 闸里有起动在等空位时,新提交的四个口(`POST /v1/runs` · A2A `message/send` · `POST /v1/tasks` · `POST /v1/tasks/stream`,幂等重放之后)答 429 `limit.rate_exceeded` + 体 `reason: "sandbox_capacity"` + `retryAfterSec: 5`,头 `Retry-After: 5`;续跑 / 唤醒 / 作答不判。
488
+ `GET /health` 多 `sandboxCapacity: { lane, limit, inUse, readAt, waiting }`(帽开着才在场;`inUse` 是最近一次读 daemon 的数,还没读过 / 读不出 ⇒ `null`)。
489
+ **谁需要**:local-docker 车道上有内存预算的多租 / 家用常驻部署。**谁受伤**:没空位时的工具调用(等满预算后拒)与有人在等时的新提交(429);停驻的 run 占格(续跑腿接着用它,不另要一格;停驻期间被停掉的那只不占格,续跑时重新经准入);
490
+ **开了上限的部署里,本版之前起的容器占位**(旧名带随机尾,本服务不认;停驻中取消 / 停驻过期的 run 留下的、上一次进程崩掉留下的都在内)—— 看 `/health.sandboxCapacity.inUse` 与拒句里的过滤式,手删残留即放;
491
+ 本版起,停驻中取消 / 停驻过期 / 重起之后才结清的 run 的容器由维护 tick 上的回收腿按 run 行终局删掉(见下一条的「谁受伤」),不再占位。
492
+ **部署方**:一个数据根只跑一只服务进程(准入的互斥只在进程里:同一数据根上同时跑的两只进程看得见对方在跑的容器,看不见对方正在起的,同时起动时合计可超过上限);按内存换算上限时,改小 `DOCKER_MEMORY` 之前先清掉残留(旧容器按起动时的限额占内存);升级后第一次开帽之前先清掉旧版留下的无标签残留(`docker ps -a --filter name=sema-docker-`)。**消费方**(按 `limit.rate_exceeded` 分支的 sdk / cli / 控制台 / 编排):`reason` 闭集多一词 `sandbox_capacity`,
493
+ 按 `Retry-After` 退避即可;按 `reason` 穷举分支的读者补这一词(未知词按「稍后再来」处理)。
494
+ **补偿**:缺省关;`Retry-After: 5`。**升级前做**:无。**回滚**:去掉这根 env 即关;回到上一版时它被忽略,`sandboxCapacity` 格与 `sandbox_capacity` 词消失。
495
+
496
+ 9. **local-docker 停驻 → 续跑:续跑腿接着用停驻时那只容器,续跑腿收场时删它;容器名改由 run 的身份确定(行为修复;运维面容器名形变;wire 零变化;部署零动作)**:
497
+ 旧形:每只执行环境一只新容器,名 `sema-docker-<身份>-<8 位随机>`;续跑腿另起一只空容器(看不到停驻前的文件),停驻时那只一直跑(开了上限时占格)。
498
+ 新形:名 `sema-docker-<身份>-<12 位摘要>`(身份 = 顶层 run 的 run 号 / 委派子代自己的会话号;摘要含本 worker 标签),同一身份恒同名;续跑腿用停驻那只(同一进程:同一只执行环境;
499
+ 服务重起之后:`docker inspect` 见它在跑且带本 worker 标签 ⇒ 附着),收场时删恰一次。每次起容器前多一次 `docker inspect`;本 worker 的同名容器停着(`exited`)⇒ 经容器帽准入后 `docker start` 再附着;
500
+ 建了没跑过(`created`)⇒ 删掉再起;`paused` / `restarting` / `removing` / `dead`、不带本 worker 标签的同名容器、读不出的答 ⇒ 这一次连接拒(`connect_failed`,不起、不删)。
501
+ 执行环境只碰它负责的那只容器实例(`docker exec` / `docker rm -f` 按容器 id);删除证实不了的那只永不再附着,先删它再起新的。
502
+ 重起之后那只容器已经不在 ⇒ 续跑腿起一只新的空容器(工厂分不出续跑腿)。
503
+ **谁受伤**:停驻期间 daemon 重起 / 宿主重启的 run —— 续跑时那只容器被 `docker start`(文件在,停之前在跑的进程不在);停在 `paused` / `dead` 一类状态的 ⇒ 续跑的工具调用拒,
504
+ 运维用 docker 处置后重试;停驻中取消 / 停驻过期的 run 的容器由维护 tick 的回收腿按 run 行终局删(下一条)。
505
+ **部署方**:按名前缀找容器的脚本照旧(`sema-docker-`);升级前已停驻的 run 续跑时仍另起新容器、旧的留下 —— 升级后清一次:`docker ps -a --filter name=sema-docker- --format '{{.Names}} {{.Label "sema.local-docker"}}'`
506
+ 列出的容器里只删第二列为空的(不带标签 = 上一版起的,同第 8 条);带 `sema.local-docker` 标签的是本版起的(含在跑与停驻的),不碰。
507
+ **升级前做**:无。**回滚**:回到上一版即回到随机尾;本版起的容器上一版不认(按标签清)。
508
+
509
+ 10. **local-docker 无主容器回收:停驻中取消 / 停驻过期 / 重起之后才结清的 run,它的容器在 run 终局后由维护 tick 的回收腿删掉(行为修复;新运维读数;wire 零变化;部署零动作)**:
510
+ 旧形:停驻中被取消 / 过期的 run,停驻时那只容器没有销毁者(引擎只在自己结清停驻时销毁;本服务的取消与过期扫描在店层结清),一直在跑,开了 `DOCKER_MAX_CONTAINERS` 的部署里一直占一格。
511
+ 新形:维护 tick 上的沙箱回收腿(k8s 车道 pod 回收的同一只座,起服后第一个维护 tick 跑一轮、此后每 5 分钟一轮;没有旋钮)对 local-docker 车道多回收一类:本 worker 标签下、名字读得回 run 号、且那条 run 的行已终局并过了 5 分钟保持窗的容器(引擎在 `done` 帧之后还要用环境收尾,窗内不动)——
512
+ 按容器 id 删(证实才清;证实不了的仍欠着,下一轮先删它)。run 行是活的(跑着 / 停驻着)⇒ 不动;读不回身份 / 没有 run 行 / 读 run 账本抛 / 状态词不在词表 / 终局时刻读不出 / 没有存储后端 ⇒ 都不动。
513
+ 每轮一行 `local_docker_reap_round`、每删一只一行 `local_docker_reaped`、计数 `local_docker_containers_reaped_total{reason}`、退化口 `server.local-docker-reaper.degraded`;
514
+ 维护 tick 的沙箱回收腿连败告警(`reaper_leg_repeated_failure`)的 `reaper` 字段由 `sandbox_pod_reap` 改为 `sandbox_reap`(两条车道共一只座)。
515
+ **谁受伤**:被取消 / 过期的 run 的容器此前能留着供事后进去看,现在终局 5 分钟后的下一轮被删(与一条 run 正常收场时被删同一件事);**不覆盖**:本版之前起的容器(名带随机尾)、委派子代的容器(身份是会话号、不在 run 账本里)
516
+ ⇒ 仍要手删:本版之前起的容器不带标签,按第 9 条的命令找(名前缀列出、只删标签列为空的);委派子代的容器带本 worker 标签,按标签过滤式找。**升级前做**:无。**回滚**:回到上一版即回到「无主容器无人收」。
517
+
518
+ 11. **🔴 leader run 的取消口 `POST /v1/leader/:id/cancel` 与取消终局;SQL 后端 `leader_run` 表加五列(升级前先加列;持久数据,不能删表重建;新口 + wire 加性;嵌入方类型面 BREAKING)**:
519
+ 旧形:leader run 没有停止口;`leader_run` 行不记受理时验过的凭据来源;`GET /v1/leader/:id` 体 = `{ id, status, result?, error? }`。
520
+ 新形:`POST /v1/leader/:id/cancel` —— 行还在跑 ⇒ 翻耐久取消旗,`202 { leaderRunId, status: "cancelling", cancelRequested: true }`,驱动副本当场(同副本)或下一个存活心跳拍(别的副本)中止;行已终局 ⇒ 幂等 `202`(带终局词与 `note`),同时过期这条 run 留下的待决 worker 停驻(并发结算抢先的那几张 ⇒ `409 conflict.approval_settled`)。
521
+ run 停在中止核点 ⇒ 终局 `failed` + `errorCode: "cancelled"`、零 push;取消晚到、push 已发出 ⇒ 终局照实。读面多两键 `cancelRequested`(恒在)/ `errorCode`(只在取消终局),结果多一键 `stopped`(只在停在中止核点时在场,恒 `true`)。
522
+ **升级前做(SQL 后端:`DB_BACKEND=mysql|pg`;开了 leader 端点的部署)**:本服务不发 `ALTER`,存量库缺列 ⇒ 起服列册对账拒启(`config.schema_mismatch`,拒句带同样的语句)。先在库上执行(先升库再升副本):
523
+ MySQL 协议:
524
+ `ALTER TABLE leader_run ADD COLUMN error_code VARCHAR(64) NULL;`
525
+ `ALTER TABLE leader_run ADD COLUMN cancel_requested SMALLINT NOT NULL DEFAULT 0;`
526
+ `ALTER TABLE leader_run ADD COLUMN identity_source VARCHAR(32) NULL;`
527
+ `ALTER TABLE leader_run ADD COLUMN identity_scope VARCHAR(190) NULL;`
528
+ `ALTER TABLE leader_run ADD COLUMN identity_principal_inc VARCHAR(64) NULL;`
529
+ PostgreSQL:
530
+ `ALTER TABLE leader_run ADD COLUMN error_code VARCHAR(64) COLLATE "C" NULL;`
531
+ `ALTER TABLE leader_run ADD COLUMN cancel_requested SMALLINT NOT NULL DEFAULT 0;`
532
+ `ALTER TABLE leader_run ADD COLUMN identity_source VARCHAR(32) COLLATE "C";`
533
+ `ALTER TABLE leader_run ADD COLUMN identity_scope VARCHAR(190) COLLATE "C";`
534
+ `ALTER TABLE leader_run ADD COLUMN identity_principal_inc VARCHAR(64) COLLATE "C";`
535
+ 存量行:`cancel_requested` 由列缺省填 0,其余四列为空 —— 身份元组为空 = 不合格(没有事实可回填,不回填)。表还没建过的库(从没开过 leader 端点)零动作,起服照常建全列。
536
+ **回滚到上一版:只回退二进制不可行**(两方言皆然)—— 加过列的库上,上一版的起服列册对账把多出的五列读成幽灵列、起服拒。回滚 = ① 先停光全部本版副本;② 手工 `ALTER TABLE leader_run DROP COLUMN error_code;`、`… DROP COLUMN cancel_requested;`、`… DROP COLUMN identity_source;`、`… DROP COLUMN identity_scope;`、`… DROP COLUMN identity_principal_inc;`(分五句,两方言同);③ 再起上一版。
537
+ **嵌入方**:`createLeaderEndpoint` 的 `runLeader` 收第二参 `signal: AbortSignal`(必须把它交给 `runLeaderTask` 的 `deps.signal`,否则取消停不下 run);`createLeaderRunner` 的返回函数多一个可选第二参 `signal`(端点交给它;直接调它而不交 = 这次调用停不下,与上一版同);自带 `LeaderRunStore` 实现的要补 `requestCancel(id)`,`LeaderRunRecord` 多 `cancelRequested` / `identity`(必填)与 `errorCode?`;`NewLeaderRun` 多必填 `identity`。
538
+ **行为变更(只涉调低过 `LEADER_RUN_STALE_MS` 的部署)**:驱动副本每个存活心跳拍读一次自己的行,行已被陈旧清算判了终局 ⇒ 停下;它的终局写因此打空,落定时过期它的残留停驻(旧形:照跑,可能在一条写着 `failed` 的行背后照 push)。缺省 26 h 大于 run 上限,零动作;调低过的把它调回大于真实 run 时长。
539
+ **谁受伤**:拿取消晚于 push 的 run 当「已取消」读的消费者(看 `errorCode`,不看 `cancelRequested`);事后想对一条已取消 run 的 worker 停驻 `/decide` 续跑的运维(取消就是把它们过期)。**出路**:要续跑就别取消;按 `errorCode === "cancelled"` 判「停下了、没推」。
540
+
541
+ 12. **只改条目备注 `notes` / 名册标签 `rosters` 的配置编辑不再签重启、不换装模型面;已撤的 MCP 服务器改了这两键再加回照常恢复(行为修复;wire 零变化;部署零动作)**:
542
+ 旧形:中心(或本地 `config.d`)上一条模型 / 技能 / MCP / 场景条目只改了 `notes`(技能 / MCP 另有 `rosters`)⇒ `/health.restart` 签 `skills` / `mcp` / `scenarios` 片、模型面换装一次;已撤的 MCP 名带着改过的备注加回仍被撤。
543
+ 新形:这两键不进三处指纹(只减条目顶层键);MCP 条目的分组标签 `source` 按挂载口的判据进指纹(坏形与缺席同值);改任何运行期字段(含合法分组标签)照旧签 / 换装 / 保持撤销。本地配置源交给消费方的视图与配置中心的 `/effective` 同形(消费方读数不变)。
544
+ **谁受伤**:靠「改备注触发滚动重启」的手动流程。**出路**:要重启就显式重启。
545
+
546
+ 13. **dry-run 行 `web_admin_dry_run` 的 `wouldOverrideModels` 改报「这份候选管不管模型面」:只有被读腿丢掉的启用条目(或载体形不对)的候选报 `true`,与 `wouldRefuseModelPlane` 同在(日志面读数变;wire 零变化;部署零动作)**:
547
+ 旧形:只数幸存的启用条目 —— 条目全被读腿丢掉的候选报 `false`,而同一行带 `wouldRefuseModelPlane`(真 apply 照常判它、组拒)。
548
+ 新形:与真 apply 同一只判决位;`true` + `wouldRefuseModelPlane` = 「管,但会被组拒,模型面不动」。只有停用条目的候选照旧 `false`。
549
+ **谁受伤**:只读 `wouldOverrideModels` 判「会不会动模型面」的上线前核验脚本。**出路**:两格并读 —— 动模型面 ⇔ `wouldOverrideModels` 且没有 `wouldRefuseModelPlane`。
550
+
551
+ 14. **`MODEL_PROVIDER=anthropic` 而没有 anthropic 钥匙、又要服务 env 模型表 ⇒ 起服拒,网关在场也拒(行为收紧;wire 零新键、零新码)**:
552
+ 旧形:env 写了 `MODEL_PROVIDER=anthropic`、`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 都没设、`MODEL_GATEWAY_BASEURL` 设着 ⇒ 起得来,env 模型的请求由网关腿服务(OpenAI 兼容线路、网关钥匙),
553
+ 模型行上的 `api` / 缓存族仍按 anthropic 写;只有网关也没有时才拒(`config.model_route_endpoint_missing`,缺口 `lane_credential_missing`)。
554
+ 新形:同一个码、同一个缺口词,网关在不在都拒;目录在服(env 模型表不服务)时不判 env 表,照常起。
555
+ **谁受伤**:env 模型表在服、靠这一形走网关的部署。**出路**:三选一 —— 补 `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN`;把 `MODEL_PROVIDER` 改成 `gateway`(或 `vllm`)—— 就是此前实际在走的线路;不设 `MODEL_ID`,让目录的缺省条目服务。
556
+ 15. **中心配置的盘上 LKG 与调度共享店过本地配置根的同一只目录信任判官:别人改得动 ⇒ LKG 不读回、调度店读写整条拒(安全轴,fail-closed;零新旋钮;日志面多一事件;部署零动作 —— 两只文件落在组 / 他人可写处的部署除外)**:
557
+ 旧形:LKG(`<SEMA_CONFIG_DIR>/config-lkg-*.json` 或 `CONFIG_LKG_PATH`)读回只判 JSON / 信封 / 身份,不判属主与模式;调度共享店(`SCHEDULER_STORE_PATH`,缺省 `<SEMA_CONFIG_DIR>/scheduled_tasks.json`)读写不判。
558
+ 新形:两者读之前过本地配置根的同一只判官(从 `/` 起逐级判;属主 ∈ {本服务用户, root, `CONFIG_LOCAL_OWNER_UID`};非链接组件不得组 / 他人可写;常规文件 ≤ 16 MiB)。
559
+ LKG 有发现 ⇒ 不读回,`config_lkg_unusable` 的 `reason` = 同族拒句(`config.dir_untrusted: refusing to read the last-known-good config …`),env 兜底;
560
+ 调度店有发现 ⇒ 这一次读写整条拒(`io`),日志 `scheduler_store_untrusted`(`path` / `refusal`)。`CONFIG_LOCAL_OWNER_UID` 对三只读者同一格。
561
+ 判的是读者真正打开的路径(不做词法归一:`链接/..` 按链接目标的物理父目录解);调度店目录还不在 ⇒ 本服务首写前建成 `0700`(与 umask 无关)。
562
+ **谁受伤**:`SEMA_CONFIG_DIR` / `CONFIG_LKG_PATH` / `SCHEDULER_STORE_PATH` 落在组 / 他人可写目录(或属主是别的 uid)的部署。
563
+ **升级前做**:按拒句改 —— `chmod go-w <路径>` / `chown` / 声明 `CONFIG_LOCAL_OWNER_UID=<uid>` / 把文件挪到只有本服务用户或 root 写得动的目录;本服务自己首建的配置根是 `0700`,零动作。
564
+
565
+ 16. **🔴 单用户声明要有一道身份边界:`OPERATOR_SINGLE_USER=true` ∧ 没配服务凭据 ∧ 监听地址不只在本机回环 ⇒ 服务进程起服拒(安全轴;行为 BREAKING:起服拒启面;零新旋钮;符合这一形的部署升级前补一行)**:
566
+ 旧形:声明之后,没配 `SERVICE_AUTH_TOKEN` / `SERVICE_AUTH_TOKENS` 的部署照常起服、监听全接口 —— 能连上端口的任何人都是运维(只写在 USAGE 里)。
567
+ 新形:起服第 1 段(声明必填之后)判 —— 声明 ∧ 无凭据 ∧ 监听地址不只在本机回环(缺省全接口 / `0.0.0.0` / 局域网地址 / 主机名;`ALLOW_UNAUTHED_WRITES=true` 且无凭据时自收窄到 127.0.0.1,算回环)⇒ 非零退出,
568
+ stderr 一行拒句(不变量 `operator-single-user-boundary`)点名监听在哪与三条出路。热路径上删光凭据的候选同判拒。`run-local` 不判。
569
+ **谁受伤**:本地单机 dev 监听全接口、没配凭据、写了声明的部署;`docker-compose.yml` 写了声明而没填 `SERVICE_AUTH_TOKEN` 的部署。
570
+ **升级前做**(三选一):配 `SERVICE_AUTH_TOKEN`(或 `SERVICE_AUTH_TOKENS`);或 `BIND_HOST=127.0.0.1` 只听本机回环(容器端口要发布给别的主机时这一条不适用,改配凭据);
571
+ 或撤掉 `OPERATOR_SINGLE_USER`、在 `OPERATOR_PRINCIPALS` 里具名运维。`sema-up` / chart 部署恒带凭据,零动作。
572
+
573
+ 17. **🔴 单用户部署上不带主体的 run 读本机属主的规则桶:桶里持久的 deny / ask / allow 行开始约束不带 `x-agent-principal` 的 run(安全轴;行为变更;零新旋钮;零 DDL;部署零动作 —— 本机属主桶里存着旧行的部署先看一眼)**:
574
+ 旧形:不带主体的 run(裸 HTTP / 没设主体的 SDK / 本机控制台)读零条持久规则 —— 规则店里本机属主那只桶(file 后端 `<数据根>/permission-rules/local-owner.json`;SQL 后端 `permission_rule` 表 `owner_kind='local-owner'` 的行)对它不生效。
575
+ 新形:单用户部署(`REQUIRE_PRINCIPAL` 未开)∧ 规则店装配了(`PERMISSION_RULES_ENABLED` 开着且后端有规则店)⇒ 不带主体的 run 读这只桶;运维手动整理阀门(`POST /v1/admin/memory/consolidation/run`)不带主体的调用方同读它。
576
+ 带主体的 run(含 cli —— 它恒带主体)读自己的桶,不变;多租形(`REQUIRE_PRINCIPAL=true`)零变化。不带主体的问卡照旧不给「不再询问」。
577
+ **谁受伤**:本机属主桶里存着旧行的单用户部署 —— 那些行(包括 allow 行)从本版起对不带主体的 run 生效。
578
+ **升级前做**:看一眼那只桶(file 后端读上面那只文件;SQL 后端查 `permission_rule` 表 `owner_kind='local-owner'` 的行),不要的行在存储层删(本版没有它的 HTTP 自助口);要整条关掉 ⇒ `PERMISSION_RULES_ENABLED=false`。
579
+
580
+ 18. **🔴 单用户部署上不带主体的 run 要有一道身份边界:单用户 ∧ `ALLOW_UNAUTHED_WRITES=true` ∧ 没配服务凭据 ∧ 显式 `BIND_HOST` 不只在本机回环 ⇒ 服务进程起服拒(安全轴;行为 BREAKING:起服拒启面;零新旋钮)**:
581
+ 旧形:显式 `BIND_HOST=0.0.0.0`(或局域网地址 / 主机名)把无鉴权写面暴露出去照起 —— 网络上任何人都能不带主体提交 run,而单用户部署上这样的 run 就是那个用户(读本机属主的规则桶,上一条)。
582
+ 新形:起服第 1 段(排在 `operator-single-user-boundary` 之前;两条同时成立时先报本条,本条两条出路照做那一条也随之不成立)判这一形 ⇒ 非零退出,stderr 一行拒句(不变量 `single-user-anonymous-boundary`)点名监听在哪与两条出路。
583
+ 没设 `BIND_HOST` 时无鉴权写面本来就只听 127.0.0.1,照起;写面要凭据而没配凭据的部署没人能提交 run,不归本条。热路径上删光凭据的候选同判拒。`run-local` 不判;多租形不归本条。
584
+ **谁受伤**:单用户部署里显式暴露无鉴权写面的 —— 含容器里 `BIND_HOST=0.0.0.0`、宿主只把端口发布到回环(`-p 127.0.0.1:…`)的那一形(进程看不见宿主怎么发布端口)。
585
+ **升级前做**(二选一):配 `SERVICE_AUTH_TOKEN`(或 `SERVICE_AUTH_TOKENS`);或只听本机回环(删掉 `BIND_HOST`,或 `BIND_HOST=127.0.0.1`;容器端口要经 `-p` 访问时改配凭据)。
586
+
587
+ 19. **运维手动整理阀门 `POST /v1/admin/memory/consolidation/run` 的写判官读人:发起者的规则桶(不带主体 ⇒ 本机属主桶)里点名记忆库的 deny / ask 行拦得住这一轮折叠(安全轴,行为收紧;wire 零新码;部署零动作)**:
588
+ 旧形:阀门只读匿名地板 —— 人的持久行拦不住手动整理(自动整理腿一直照判)。
589
+ 新形:按发起这一轮的调用方读人的桶(并入正在跑的那一轮的调用方用起跑者的判官);拒 ⇒ 既有的 `409 memory.consolidation_refused` 与引擎通告。
590
+ 部署的调用方策略(审批名单 `APPROVAL_DENY` / `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO`、敏感路径守卫 `SENSITIVE_WRITE_PATTERNS`)仍不参与手动阀门(自动腿照判)。
591
+ **谁受伤**:有人的 deny 行点名记忆库、又靠手动阀门整理记忆的部署 —— 现在与自动整理腿同答(拒)。**出路**:删掉或收窄那条行,或接受与自动腿同样的结局。
592
+
593
+ 20. **勘误(7.114.0 节「运维面」一条;已发节不改字节):`server.session-policy.corrupt-read-fail-open` 不再是债,改 R 类(有界放行,计数长期保留);三条读路的「仍按无规则」收窄到只剩无从归属的坏行(文书 + 遥测分类;本版行为零变;部署零动作)**:
594
+ 那一条写「另三条路仍把坏规则行当作『无规则』」。7.116.0 起有归属的坏行(行里的 `__sid`,否则同名高水位标记的 `__sid`)在枚举 / 别的会话抹除 / 数据根重绑三条路上也拒(或不动 / 带走);
595
+ 只剩无从归属的坏行(行里读不出 `__sid`,标记也不在、坏了或不带 `__sid`)照旧按无规则 —— 这一形按 core 已知限制接受(无从归属 ≠ 本会话),是这一臂的终形。计数、探针行、告警不变,告警 / 看板照留。
596
+
597
+ 21. **🔴 审批证明店的持久时间地板:店钟被往回拨之后,已清扫的 plan_review 证明不再能被再受理;SQL 后端一张新表 `approval_nonce_floor`(起服自建);local 消费账多一种行(安全轴,行为修复;零 ALTER;新 warn 事件;部署零动作)**:
598
+ 旧形:消费记录按店钟到期、按店钟清扫;店钟往回拨 Δ 之后,刚清掉的证明在回拨后的钟下重新过验签,同一 nonce 可再消费一次。
599
+ 新形:店钟 = max(原始钟, 地板),地板 = 清扫用过的删除线(先落地板再删);原始钟低于地板 ⇒ 店钟答地板 + 一行 warn `approval_nonce_clock_rollback`(`rolledBackMs` / `floorMs` / `clockMs` / `store`)。
600
+ SQL 后端:新表 `approval_nonce_floor(singleton CHAR(1) PK DEFAULT 'x', floor_ms BIGINT NOT NULL)` 由起服 DDL `CREATE TABLE IF NOT EXISTS` 自建(零 ALTER、零一次性迁移;没有那一行 = 从没清扫过)。
601
+ local 后端:`<数据根>/approval-nonces/consumed.jsonl` 每次压实把一行地板 `{"f":<ms>}` 与幸存记录一起写下(老账零迁移)。
602
+ **谁受伤**:local 数据根降级到上一版 —— 上一版把地板行读成坏记录、整本消费账拒用(直连门 plan_review 5xx);多 tidb-server 部署的钟差会在清扫后表现为 warn 行。
603
+ **出路**:降级前等在途证明的 TTL(约 150 秒)过去后移开 `approval-nonces/consumed.jsonl`(上一版拒句给的同一出路);warn 行按句中出路核时间同步。DDL 账号要能建表(与起服其余表同)。
604
+
605
+ 22. **随包排空检查多一条回滚判据 `prompt-lean-rollback`(随包工具加一条;行为零变;零 DDL;部署零动作 —— 从 7.137.0 及以后回滚到 7.136.x 之前多跑这一段)**:
606
+ 7.137.0 节第 4 条说「回滚到 7.136.x:被改写过的停驻任务在 7.136.x 上续跑回到缺省形(长形丢,零通告)—— 回滚前先决完或取消停驻的任务」;本版起随包 `scripts/drain-check.{mysql,pg}.sql` 与 `scripts/drain-check-local.mjs` 有一条同名判据数出这些行:
607
+ 续跑上下文的提交体里 `promptLean` 为 `false` 的停驻行(一次性迁移改写出的、与 7.137.0 起新提交时就带 `false` 的都在;7.136.x 不认这个键,续跑时回到缺省形、不报错)。读到 0 再回滚;非 0 ⇒ 逐条决完或取消。
608
+ 还跑着 7.137.0–7.147.x 的部署:SQL 后端取本版的包(`npm pack @sema-agent/server@<本版>`,解开 `package/scripts/drain-check.<mysql|pg>.sql`)来跑这一段 —— 只读,对旧版的库同样成立;`DB_BACKEND=local` 的脚本读隔壁的 `dist/` 与引擎依赖,只解开 `scripts/` 跑不起来(答 rc 2 `criterion-unavailable`):把本版装进一个临时目录(`npm install @sema-agent/server@<本版>`),再 `node node_modules/@sema-agent/server/scripts/drain-check-local.mjs <数据根>`。
609
+ **谁受伤**:按行数 / 按位置读整只文件输出的脚本(SQL 多一行;local 末行多一行 `PROMPT-LEAN-ROLLBACK`,在 `RETIRED-MODE-SEED` 之前)。**出路**:按判据名读。
610
+
611
+ 23. **读续跑上下文失败答 `503 state.resume_context_unreadable`,不再落 `409 conflict.resume_context_unavailable`(行为修复;wire 多一码;零 DDL;部署零动作)**:
612
+ 旧形:库断连 / 拒连 / 超时、缺表 / 权限拒、认不出的库错发生在读续跑上下文那一读上 ⇒ 决断、续跑、唤醒、`plan_review`、workflow 决定的宿主新一跑、终态 run 的 steer、`permission-mode` 一律答 `409 conflict.resume_context_unavailable`(「上下文没了」);本服务自己的程序错同落那一码。
613
+ 新形:这些读失败 ⇒ `503 state.resume_context_unreadable`(`error` / `errorCode` 两键;这一请求没有执行:续跑入口上卡仍待决、行字节不动;终态 steer 没入队,铸卡之后复核那一读失败则撤回铸出的卡,撤回自己失败 ⇒ 运维 warn `steer_wake_card_withdraw_failed`、卡留在待决里),程序错 ⇒ `500 internal.error`;行真的不在仍是 `409 conflict.resume_context_unavailable`,坏行仍是 `500 corrupt`。
614
+ **谁受伤**:按 `409 conflict.resume_context_unavailable` 自动重提新任务的客户端(读失败那一形不再是它);错误码的穷举 `switch`(多一个成员)。**出路**:`state.resume_context_unreadable` 一臂 = 稍后原样重发同一请求(一直如此 ⇒ 报运维查库);`conflict.resume_context_unavailable` 一臂不变。
615
+
616
+ 24. **起服前的模型面读数:新入口 `dist/model-plane-probe.js`(子路径 `@sema-agent/server/model-plane-probe`)在引擎起来之前答 `GET /v1/models` 的 `modelPlane` 同一格,stdout 一行(新入口,加性;部署零动作)**:
617
+ env 与工作目录 = 将要起的那只引擎的;跑起服前两段到模型表定形即停,不开店、不监听;日志在 stderr。退出码 `0` = 答案在 stdout,非 `0` = 起服会在这两段拒(stderr 是同一条 `fatal` 行)。
618
+ 同一份配置下与起服第 2 段末的那一格字节同;起服拉取超过 `CONFIG_BOOT_FETCH_BUDGET_MS`(或预算写 0)时答的是那次拉取落地之前的回落读数(stderr 有 `config_boot_fetch_deferred`),探针不等迟到的那一份。
619
+ 动作与起服前两段相同(配置根上的一次性迁移、`SEMA_CONFIG_DIR` 不在就建、封签钥匙保管店与提示词店的目录;远端配置源另有中心拉取、LKG 落盘、执行公钥上报、文件形凭证的续签 —— 已发出的续签落盘之后才退)
620
+ ⇒ 在本会起服的地方调;引擎已在服就读它的 `GET /v1/models`。
621
+ 订正 7.133.0 节「没有起服前的预判口」一句(已发节不改字节,本条即订正)。
622
+
623
+ 25. **运维审批队列上后台委派子代的停驻行 `taskId` = 子代自己的 `a…` 句柄(此前恒 `null`)(行为修复;wire 零新键;零 DDL;部署零动作)**:
624
+ 旧形:停驻行的 `taskId` 只读行的会话上的 run 认领;后台委派子代的会话不进 run 账本 ⇒ 它的停驻行 `taskId` 恒 `null`(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)。
625
+ 新形:`taskId` = 停在这道门上的那条腿以哪个 task 在跑 —— 引擎在停驻行上记下的登记行(后台子代的 `a…` 句柄,与 `/decide` 复活它的回执 `taskId`、placed 子代的 `agent.id` 同一个串)⇒ 否则会话认领的 run(与旧形同)⇒ 否则 `null`。
626
+ 引擎 7.61.0 起停驻的后台子代行升级后即带(零迁移);订阅流在升级后那一拍对这些行各补一帧 `pending`(投影变了;按键覆盖即可)。
627
+ **谁受伤**:拿「`taskId === null`」判子代行的消费者;拿行上 `taskId` 拼 `/v1/runs/:id` 的消费者(后台子代行上答 404 —— 它是代理句柄,不是 run 资源 id)。
628
+ **出路**:判子代与发起会话读 `agent`;子代本身按句柄寻址(`TaskStop` / `SendMessage` 用的同一个串),宿主 run 按 `agent.rootSessionId` / `parentSessionId` 的会话找。
629
+
630
+ 26. **勘误(7.139.0 节第 23 条 ④;已发节不改字节):host 车道上名字逼近 255 字节上限的文件写得进,那条「已知缺口」不再成立(文书;本版行为零变;部署零动作)**:
631
+ 那一条写「名字超过约 230 字节的文件写不进(引擎的暂存名超出 255 字节上限 ⇒ `unknown` / `ENAMETOOLONG`)」。引擎 7.61.0 起暂存名逼近上限时截短到上限之内,本服务 7.143.0 起所钉的引擎都含这一修(7.139.0 – 7.142.x 有这一缺口),
632
+ host 车道的整文件替换(新建与覆盖)对 255 字节以内的名字照常写成,与远端五车道同。按那一条绕开长文件名的做法可以撤掉。
633
+
634
+ 27. **领养 `POST /v1/adoption` 在没有可选存储面的部署上走完(此前裸 500),回执 `legs[]` 只列真跑的腿;接线了的面缺表答新码 `409 adoption.table_missing`(行为修复;wire:多一码、这类部署的 `legs[]` 少七条腿;零 DDL;部署零动作)**:
635
+ 旧形:缺省 file 记忆引擎、没配对象存储的 SQL 部署上 `POST /v1/adoption` 答 `500 internal.error`(`agent_memory_engine_*` 六张表与 `task_attachment` 在这类部署上不存在,收编的探针 / 迁移腿 / 残留计数逐腿发 SQL 打在它们上);回执 `legs[]` 恒是计划表全集(那七条腿也在)。
636
+ 新形:腿集由库上在场的表定 —— 核心腿恒跑,这七张可选表的腿其表在库上才跑,回执 `legs[]`(`agent_memory_engine_{entry,cursor,sync_cursor,sync_partition,push_queue,history}#scope`、`task_attachment#owner`)只列真跑的;
637
+ **没接线但表在**(曾配过对象存储后撤掉配置)腿照跑;**接线了(记忆引擎 DB 后端 / 附件店构造过)而库上缺表** ⇒ `409 adoption.table_missing`,体 `{ adoptionId, tables[] }` 点名缺的表,弧不落终态(零 UPDATE),重启一个副本建好缺的表后重发同一请求即续。
638
+ **谁受伤**:按腿名逐条对账收编回执的下游围栏(缺省 file 记忆引擎 / 没配对象存储的部署上 `legs[]` 少七条 —— 那七条在这类部署上从未跑成过);`adoption` 错误码的穷举 `switch`(多了一个成员)。**出路**:按「真跑的腿」对账(`legs[]` 里有的腿逐条核,不要求七条可选腿在场);错误码穷举补 `adoption.table_missing` 一臂(重试语义:修表后重发同一请求);有记忆 DB 后端 / 对象存储的部署回执与上一版逐字同,无动作。
639
+
640
+ 28. **`POST /v1/approvals/:id/decide` 对载入的停驻行先问一次行形判官,坏行一律答这一行自己的带码拒:缺 `pendingAction` 的行不再 `500 internal.error`,坏行也不再先答 `approval_stale` / `400 decide_requires_binding` / `conflict.resume_context_unavailable`;`request_error` 运维行多一格 `at`(栈顶帧)(行为修复;wire 零新码;日志面加一格;部署零动作)**:
641
+ 旧形:判官只在门型守卫里对「非工具审批门」的行问;工具审批门上的坏行越过它 —— 缺 `pendingAction` ⇒ 读 `cp.pendingAction.kind` 抛 ⇒ `500 internal.error`;判官判坏的其它形(缺 `state` 等)按调用方交了什么先答 `409 approval_stale`(旧 `boundCallId`)/
642
+ `400 decide_requires_binding`(没回显绑定)/ `409 conflict.resume_context_unavailable`(续跑上下文缺),续跑第一级才被引擎拒。
643
+ 新形:行级属主复核之后、门型守卫 / 绑定判 / stale 臂 / 续跑上下文之前问一次判官(与运维队列行 `rowVerdict` 同一只);判非 `ok` ⇒ 答判官的判决:`409` + `errorCode: "checkpoint.invalid_outcome"` + `reason: "requirements_damaged"`(更新引擎停驻的行 ⇒ `checkpoint.unsupported_version`,同续跑腿),
644
+ `retriable: true`,卡仍 pending。工具审批行的拒句是判官的固定句,不再带引擎续跑第一级附的 `Diagnostic:` 尾。`request_error` 运维行多一格 `at`(`<src | dist | node_modules 起的尾段路径>:<行>`,抛出物栈顶第一条读得出位置的帧;读不出则无此键)。
645
+ **谁受伤**:按「坏行决断先答 `approval_stale` / `400`」写分支的壳(这些坏卡此前得到的是会把壳带去重拉坐标的答案,重拉不会让坏行变好);按「决断口 500 = 存储故障」重试的壳(缺 `pendingAction` 的行此前就是不会好的 500)。
646
+ **出路**:读 `errorCode` / `reason`,按 `GET /v1/approvals` 里同一行的 `rowVerdict` 定位这张卡;`request_error` 行的 `at` 是出处。
647
+ 29. **🔴 live 应答口 `POST /v1/tool-approvals/:id/respond` 与按问读口 `GET /v1/tool-approvals/:id`:看不见这只问(查无 / 不是你的 / 行读不出 / 本 worker 没有问账)⇒ `404 not_found.ask`(与耐久决断口同码),不再答 `tool_approval.not_pending`(wire BREAKING;部署零动作;消费方有动作)**:
648
+ 旧形:这几形答 `404 tool_approval.not_pending`,有问账时带 `cause: "unknown_or_other_replica"`,没有问账的 worker 上不带 `cause`(包括窗到期 / 已答 / 转耐久停驻之后再答同一张卡)。
649
+ 新形:`404` `{ errorCode: "not_found.ask", error: "no such approval ask (never existed, no longer kept, or not yours)" }`,不带任何状态位。`tool_approval.not_pending` 只对属主出:
650
+ 行 `VOID` / `DENIED`(`cause` = 行上的成因词)、行仍待决而本副本没有在等它的登记(`cause: "unknown_or_other_replica"`)、坏行 / 赎回席缺席(无 `cause`),这些形逐字不变。耐久决断口零变。
651
+ **谁受伤**:只认 `tool_approval.not_pending` 才消卡的壳 / SDK 映射;断言非属主拿 `unknown_or_other_replica` 的契约套。**出路**:live 应答口与按问读口上 `not_found.ask` 同样消卡(与耐久决断口同处置);
652
+ 没有问账的 worker 上按 `404` 改走 `/v1/approvals` 读面 + `/decide` 的出路不变。
653
+
654
+ 30. **委派 / 后台子代那条腿的停车行已提交时,它的问收成 `PARKED`,不再在宿主 run 终局时收成 `DENIED` / `routing_failure_fail_closed`(local 起服收敛不再收 `VOID`)(行为修复;wire 零新键、零新码;零 DDL;部署零动作;嵌入方店接口一处改名 BREAKING)**:
655
+ 旧形:子代卡转耐久停驻后,收敛器按问行上的投递会话(根会话)找停车行,而子代的停车行落在子代自己的会话上 ⇒ 找不到;宿主 run 终局时问被收成 `DENIED`,按问读口读 `void` + `cause: "routing_failure_fail_closed"`,决断口 `410 gone.ask`,live 应答口 `404 tool_approval.not_pending`。
656
+ 新形:按问的发起会话找(与停车行同一个会话)⇒ 问 `PARKED`:按问读口读 `parked`,决断口 `410 gone.ask_parked`,live 应答口照答即走停驻赎回。根腿的卡零变。
657
+ 「去哪决它」三处同读停车行自己的会话(= 问的发起会话):决断口 `410 gone.ask_parked` 回显的 `sessionId`、按问读口 `parked` 与迟到回决口 `202` 的 `decidePath` 对子代卡都指子代会话的耐久回决口(此前 410 回显根会话;
658
+ 更正 7.122.0 节第 5 条「`decidePath` 对委派子代腿缺席、句子指父会话」—— 现在只有发起会话是 taskId 替身的问缺席、句子照旧);根腿零变。照 410 回显 / `decidePath` 去 `/decide` 即决得到那张卡。
659
+ **谁受伤**:把子代卡的 `routing_failure_fail_closed` 当作「这张卡没地方答了」消卡的壳。**出路**:按停驻卡处置(`parked` 态 / `gone.ask_parked`),经耐久审批门决。
660
+ **嵌入方(类型面 BREAKING)**:经包根导出型 `StoreBackend` 的 `approvalAsk()` 可达的问答账本店,停车行提交那一拍的找行读口 `listParkingBySession(sessionId)` 改名
661
+ **`listParkingBySourceSession(sourceSessionId)`**,按行的**发起会话**(`sourceSessionId`,SQL 列 `source_task_id`)筛仍 `PARKING` 的行(此前按投递会话 `sessionId` 筛);tsc 红即是提示,零别名。
662
+ **升级时做**:自实现该店的嵌入方改名并把谓词换成发起会话(序仍 `created_at_ms ASC, ask_id ASC`);本服务自带三店(SQL 两方言、local、内存)已是这个读法,用它们的部署零动作。
663
+
664
+ 31. **`/decide` 赎回的后台子代按停驻时的代理定义续上:内建 / 部署定义的子代(Explore / Plan …)工具面与停驻前相同,不再按 general-purpose 形复活;逐请求 `agents` 定义的子代赎回 fail-closed —— `409 decide.agent_definition_unavailable`、不复活、卡仍待决(安全轴,行为修复 + 新拒;wire 加性:新码;部署零动作)**:
665
+ 此前每一只带定义的子代被批准之后都拿回定义拒掉的工具(Explore 拿回 `Agent`);逐请求 `agents` 定义的子代同样按通用形续上。现在在册的(内建 / 部署)定义照定义赎回;
666
+ 名册外的(逐请求定义 —— 不随耐久卡保存;停驻之后部署撤了的定义;名叫 `fork` 的定义)approve 与 deny 都答 409,委派工具零调用、认领回滚、卡留待决(体带 `taskId` + `rollback`:`rolled_back` = 卡仍待决)。
667
+ **谁受伤**:依赖「批准之后子代变通用」的用法;用请求里的 `agents` 定义派后台子代、又靠 `/decide` 批准它复活的调用方。
668
+ **出路**:要通用子代就派 general-purpose;要「批准后按定义续」就用内建 / 部署定义派;已停驻的逐请求定义子代,它的卡随过期收场,或 `POST /v1/sessions/:id/children/retire` 结清会话的后台子代(停驻卡作废);
669
+ 逐请求定义的子代按定义赎回,待存下的任务注册重铸逐请求定义表(引擎侧的契约)到货。**升级前做**:无。**回滚**:无(没有委派调用、没有子代被复活;认领已回滚,卡仍待决)。
670
+
671
+ 32. **`GET /v1/agents/roster` 缺省读调用方自己那一格(与引擎写后台行同一只读法):dev-open 上带主体头 ⇒ 那位主体的行;带场景头的主体 ⇒ 人那一格的行(行为修复;wire 形不变;部署零动作)**:
672
+ 此前 dev-open 上带主体头的名册缺省读 `default`,带场景头的主体按带场景前缀的分区键读,两形都答 `agents: []`。**谁受伤**:dev-open 上带主体头、靠缺省看 `default` 那一格的脚本。
673
+ **出路**:带 `?scope=default`(fleet-wide 调用方照旧可指定任何格)。
674
+
675
+ 33. **委派子代改的文件进根会话的 rewind 历史:子代的首次触碰与父会话同一条「记不下就拒」规则(行为修复;部署零动作)**:
676
+ 此前子代跑的那只 Runner 没有历史店,子代的编辑不记,父会话 rewind 撤不回它们;现在记。**谁受伤**:历史店写失败的部署 —— 子代那次编辑被拒(此前照做不记)。
677
+ **出路**:修好历史店;或 `FILE_HISTORY_CAPTURE=false` 关掉首次触碰捕获(已存历史照常还原)/ 请求带 `fileHistory: "disabled"`。
678
+
679
+ 34. **🔴 「持久」一个读数:能力位 `store.durable` 删、换三态 `store.durability`;`/health.durable` 删、`/health.store.durability` 加;`/health.sessionBackend` 只写后端种类;引擎声明会话店持久而会话店落在易失介质上 ⇒ 起服拒 `config.store_not_durable`(wire BREAKING;起服拒启面;local 店落在容器可写层 / emptyDir 上的部署有升级动作;消费方有动作)**:
680
+ 旧形:`GET /v1/capabilities.store.durable: boolean`(= 后端不是 memory,local 店不论落在什么文件系统上恒 `true`);`/health.sessionBackend` = `durable(pg)` / `durable(mysql)` / `durable(local)` / `memory`;降级时 `/health` 带 `durable: false` + `storeDegraded: true`;起服布线审计按后端种类认 local 为持久介质,恒过。
681
+ 新形:`store.durable` 整删(不留别名 —— 老读者 `if (store.durable)` 对三个串值全真),`store.durability: "durable" | "ephemeral" | "unknown"`(数据活不活得过容器 / Pod 替换;数据根 · 封签钥匙目录 · 接线时的 file 记忆根三根取最弱;SQL 后端的数据根委托给库恒 `durable`,local 读数据根所在挂载,判不出 ⇒ `unknown`);`/health.store = { durability }` 恒在场、与 caps 同一只读数;`/health.sessionBackend` = `pg` / `mysql` / `local` / `memory`;降级时 `/health` 只带 `storeDegraded: true`。新拒码:引擎声明会话店 `declared_durable` ∧ 会话店的介质(数据根那一行)判 `ephemeral` ⇒ 起服拒,fatal 标题 `[config.store_not_durable]`,拒句逐根列判定(路径 / fs 类型 / 挂载源 / 挂载点 / 依据词)。 起服拒只看数据根(会话店的介质)判 `ephemeral`;封签钥匙目录 / file 记忆根非持久(`ephemeral` / `unknown`)只 warn、不拒。
682
+ **谁受伤**:按 `store.durable` 布尔读的壳;按 `sessionBackend` 字面 `durable(...)` 读 `/health` 的脚本;按 `/health.durable` 判降级的告警;`DB_BACKEND=local`(含缺省推导)而数据根落在容器可写层 / emptyDir 上的部署(本版起服拒)。**出路**:读 `store.durability`(`/health.store.durability` 同值;缺席 = 老 server,按「≤7.147.x」读),后端种类读 `sessionBackend`,降级读 `storeDegraded`;无卷容器里的 local 部署(数据根在容器可写层 / tmpfs / emptyDir 上)升级后拒启,**留在 local 店的出路只有挂卷**(PV / 整块盘 / 网络盘;或把 `LOCAL_DATA_ROOT` 指到一只持久卷上)—— 「运维显式声明 local 店易失」的部署形随后版;`DB_BACKEND=memory` 是换后端(店在进程内存里、重启即丢),不是 local 店的易失形。跑本仓测试的 Linux 开发机 / 容器车道同理:/tmp 是 tmpfs 或容器可写层时,起真服的钉在 local 店上被拒 —— `npm test` 前把 `TMPDIR` 设到一只仓外的磁盘目录。判不出的介质(非 Linux、挂载表读不到、hostPath / docker 卷这类绑定一只子目录的挂载)答 `unknown`、起服 warn 一行、不拒;逐根明细读 `GET /v1/diagnostics/wiring` 的 `storeDurability.roots`。
683
+ 35. **local 排空脚本 `scripts/drain-check-local.mjs` 的账本读法换成引擎包根的 `readCheckpointLedger`:账本里有 `delete` 事件的 `DB_BACKEND=local` 数据根不再 rc 2「无结论」;每条判据末行的 `unknownEvents` 键退役(随包脚本的读数面变更;部署零动作)**:
684
+ 旧形:脚本自抄六个事件词并自己折叠账本;引擎自 7.56.0 起写 `delete` 事件(引擎删某个会话的检查点行时写),脚本把它记成 `unknownEvents` ⇒ rc 2、九行末行都是 `unknownEvents=1`、不给结论 —— 账本里带 `delete` 事件的 local 数据根读不出结论。
685
+ 新形:账本经引擎包根的 `readCheckpointLedger` 读(引擎自己的折叠 + 快照换新时的有界重读),`delete` 事件折掉对应的行,有结论(rc 0 / 1)。读期间服务在追加账本不再逼出 rc 2:读口只比快照的身份(压实才换快照),账本只追加,读到的是读那一刻的一致前缀(旧脚本连账本的身份也比);rc 0 / 1 仍只是那一刻的视图,换钉 / 回滚前先停写、排空。末行少一个键:`… total=<n> unknownEvents=<n> corrupt=<n> root=…` 变 `… total=<n> corrupt=<n> root=…`;
686
+ 账本里有引擎不认的事件词(新版 worker 写下的,或引擎已退役的词)⇒ rc 2,九行末行是 `rows=- pending=- total=- corrupt=- reason=ledger-event-unknown`,stderr 一句列出「引擎认得的词」;崩在半行的尾行(无换行结尾)与店的重放同判,不再计 `corrupt`。
687
+ **谁受伤**:按键解析末行、读了 `unknownEvents=` 的运维脚本(键没了;`rows=` / `pending=` / `total=` / `corrupt=` / `root=` / `reason=` 不变)。**出路**:删掉对 `unknownEvents` 的读取;不认的事件词改读 `reason=ledger-event-unknown`。
688
+ **升级前做**:无。**回滚**:无(只读脚本,不改数据根)。
689
+
690
+ 36. **治理命令规则的命令名在配置应用期由契约包判:超过 128 字符的 `commandPolicy[].command` 被拒(`web_admin_commandpolicy_invalid`,保留上一份规则)(行为收紧;部署零动作)**:
691
+ 中心发布与本地 `config.d` 两条读腿本来就按契约判这一格;只有绕过读腿的输入(手改的盘上 LKG、直塞的配置)此前能带进超长名(那条规则照样生效)。**出路**:命令名写在契约的 128 字符以内;被拒时上一份规则保留。
692
+
693
+ 37. **记忆整理席所用条目的凭据身份随座冻结:重贴 `sealedApiKey` / 换 `apiKeyEnv` 变量名之后要重启才进座,`/health` 报 `restartRequired`(`memory-consolidation`)(安全轴;行为变更;部署零动作)**:
694
+ 此前整理席的模型在启动时定,凭据却跟着热应用 —— 同名条目把端点与凭据一起换掉时,重启前整理请求带新凭据打旧端点。现在两者同一代:重启前打旧端点、带旧凭据;
695
+ 凭据身份变了与端点变了一样签重启。**谁受伤**:靠重贴托管密钥即刻轮换整理条目 key 的运维。**出路**:按 `restartRequired` 重启;或改用 `apiKeyEnv` 引用做同名轮换(值热、不用重启)。
696
+
697
+ 38. **默认路径上 7.98.0 及以前的 LKG 旧文件(`config-lkg-<worker>.json`,formatVersion 1):本身份的箱缺席时起服一行 `config_lkg_unusable` 点名它(日志面加一行;读回结局不变;部署零动作)**:
698
+ 此前这只旧文件不被读、也零日志(只有 `CONFIG_LKG_PATH` 指到旧文件时才有这一行)。现在两形同一行、同一句 `reason`(`pre-identity LKG (formatVersion 1) — not read back: …`),
699
+ `path` 是那只旧文件,`note` 写出路。**谁受伤**:按「这一行只在覆写时出现」写的告警规则 —— 按 `path` 区分。**出路**:删掉那只旧文件(缓存,不是数据);中心可达时第一份干净候选写出本身份的箱。
700
+
701
+ 39. **审批登记的属主跟行走:收编(`POST /v1/adoption`)之后本副本的活卡按新属主列(`livePending` / `live_pending`),店抖动那一支不再按前属主放行(行为修复;安全轴收紧;wire 零新键;部署零动作)**:
702
+ 旧形:收编改写问行属主之后,本副本上有引擎腿在等的活卡在列表面仍只给前属主列;决议写与确认读都因店抖动失败时,按前属主的决定放行一次。
703
+ 新形:有行的问,登记上那一位是行上属主的读缓存:每读到仍待决的行就对齐,收编落成回执之前本副本全部重读一遍。别的副本在它下一次读到这一行之前仍按旧属主列。
704
+ **谁受伤**:收编之后还按旧账号看审批列表的前属主(店正常时本来就答不了)。**出路**:用新账号看与答;卡在别的副本上时按问读一次即跟上。
705
+
706
+ 40. **live 应答口的决议写失败之后,确认读与 CAS 同答:读不回行 ⇒ `500 internal.error`(与耐久决断口对店不可用同答),不再按本副本登记上的属主放行;读得出「没有这一行」⇒ `404`;读到别处已落的终局 ⇒ 按行答(安全轴,fail-closed;行为变更;wire 零新键、零新码;部署零动作)**:
707
+ 旧形:决议 CAS 抛错且确认读也读不出时,活卡按本副本登记上记下的属主答 `200`、把这一答交给在等的 run(收编在别的副本落定时那一位是前属主);接管登记同一形答 `404`。
708
+ 确认读读到别处已落的终局(反向决议 / 作废 / 停驻)或读得出行不在时,活卡同样答 `200` 并按这次的决定结算在等的 run。
709
+ 新形:确认读读不出 ⇒ `500 internal.error`,这一次请求不按自己的决定结算卡(那次写可能已落 ⇒ 随后按行收、重答回放首决;属主门那一读就读不出 ⇒ 照旧 `404`);读得出没有这一行 ⇒ `404`;读到别处已落的终局 ⇒ 按行答(已决 ⇒ `200` 回放首决、run 按行上的决议结算)。
710
+ CAS 抛而确认读读到仍待决的行(属主在域)时照旧交给在等的 run。
711
+ **谁受伤**:店整个不可用期间答卡的人(上一版 `200`、run 续上)。**出路**:店恢复后原样重答 —— 落了 ⇒ 回放首决;没落 ⇒ 这一次写成。按 `404` 消卡的壳对 `500` 不要消卡。
712
+
713
+ 41. **审批队列读失败:本服务自己的程序错答 `500 internal.error`(订阅流发 `internal.error` 帧后收流),不再落可重试的 `503 approvals.read_unavailable`(行为修复;wire 零新码;部署零动作)**:
714
+ 旧形:读审批队列的四个面把程序错(代码缺陷 / 读腿漂移)与店此刻读不出同答 `503 approvals.read_unavailable`;订阅流发可重试帧、流不收、每拍重读。
715
+ 新形:程序错 ⇒ `500 internal.error` + 运维行 `request_error`;流面一帧 `internal.error` 后收流。坏行 `500 approvals.read_corrupt`、店此刻读不出 `503 approvals.read_unavailable` 照旧。
716
+ **谁受伤**:靠 `503` 自动重试等程序错「自己好」的客户端。**出路**:`503 approvals.read_unavailable` 照旧重试;`500 internal.error` 不重试、报运维(看 `request_error`)。
717
+
718
+ 42. **停驻卡的门被引擎重开之后,live 应答口按原决议再答即续跑(受理回执的键带门世代;行为修复;wire 零新键、零新码;部署零动作)**:
719
+ 旧形:同一副本上受理过的停驻卡被重开之后 1 小时内再答,`POST /v1/tool-approvals/:id/respond` 回放首次受理(`idempotent:true`)、不续跑,出路只有 `decidePath`。
720
+ 新形:门站开在比受理所决更新的一代 ⇒ 照常进赎回腿、真续跑;门还站在受理的那一代 / 已不在待决 / 此刻读不出 ⇒ 照旧回放。
721
+ **谁受伤**:无(那一形此前不续跑)。**出路**:按原决议在原卡上再答即可;`decidePath` 照旧可用。
722
+
723
+ 43. **SLA 拒扫按页轮转走全部到期审批(每拍从上一拍取到的最后一行之后取一页,一页取不满回到队首);取行序回到「到期时刻、行键」两键,「卡列为空的排后」那一键退役(行为修复;SQL 店与 local 文件后端同律;零 wire 变化;零 DDL;部署零动作)**:
724
+ 旧形:每拍只取到期最早的 100 张;拒扫拿它没办法、留在停驻且到期时刻不变的行(引擎认领前拒、停驻子代、本版不重放的存量体)积满 100 张,后面的到期审批就一直不被拒扫,等终局兜底(缺省 30 天)收割。SQL 店另把卡列为空的行排在后面。
725
+ 新形:拒扫在过期集上记一个进程内的位置,每拍从它之后取一页,一页取不满回到队首;一圈 ⌊N/100⌋ + 1 拍,每张到期审批每圈被试一次;一行的存体读法抛出只让这一行这一拍不续(`deny_sweep_row_failed`)。重启从队首起;位置不落盘、不上 wire。
726
+ **谁受伤**:到期审批多于 100 张时,原本每拍都会被试到的最早那一批要等轮到它那一页;按「卡词已知的行先取」排查拒扫顺序的运维。**出路**:缩短 `REAP_INTERVAL_SEC` 即缩短一圈的墙钟时长;拒不掉的行照旧由 `APPROVAL_TERMINAL_BACKSTOP_MS` 兜底收。
727
+
728
+ 44. **勘误(7.136.0 节第 6 条「起服之后桶才没的」一句):拒的是这条 run 的沙箱,不是 run 本身(文书;行为零变;部署零动作)**:
729
+ 读 `latest` 得 `404 NoSuchBucket` ⇒ 一行 `workspace_snapshot_bucket_missing`、一只 pod 不建、这只执行环境此后每次连接都答同一个 `connect_failed`(句子带 `snapshot_bucket_missing` 与出路);
730
+ 要动工作区的工具调用逐个以它失败,run 的终态照常由引擎定(模型收尾 ⇒ `completed`)。那一条写的「该 run 以 `connect_failed` 拒」应读作「该 run 的沙箱以 `connect_failed` 拒」。
731
+ 7.140.0 之前工具结果是「任务根目录不在了」那句(文件面把拒报成未知);7.140.0 起是带 `snapshot_bucket_missing` 的拒句。
732
+
733
+ 45. **勘误(7.136.0 节漏写一条:入站 MCP elicitation 没人应答的释放词由 `decline` 改 `cancel`;已发节不改字节,本条即订正;wire 词改,零新键、零新码;按 action 分两支的已 opt-in MCP server 升级时改一处)**:
734
+ 旧形(7.135.x 及以前):入站 elicitation 的答题窗(`MCP_ELICITATION_TTL_MS`)到期、与开帧没送达(表单没到任何人面前)时,回给 MCP server 的结果与 `elicitation_complete.action` 的词都是 `decline`。
735
+ 新形(自 7.136.0 起):这两种「没人应答」的释放都回 `cancel`(run 中止、腿退出时仍挂着的原本就是 `cancel`);本服务自己放出的 `decline` 只留给有判据的拒 —— 没有 run 上下文、url 形、节流越界(并发帽 / 总量帽 / 同一 server 的最小间隔);用户经应答口答的词原样落地(含 `decline`)。
736
+ 词表仍是 MCP 的 `accept` / `decline` / `cancel` 三词,帧形不变;词律是 `src/elicitation.ts` 里 `RELEASE_ACTION` 一张表,回给 MCP server 的与 `elicitation_complete.action` 是同一个词。
737
+ **谁受伤**:开了入站 elicitation(`MCP_ELICITATION_ENABLED=true` 且该 MCP server 自己 opt-in `elicitation: true`)、并把 `decline` 与 `cancel` 走两支的 MCP server —— 答题窗到期与表单没送达现在落到它的 `cancel` 支,不再是 `decline` 支(此前被读成「用户明确拒绝」);
738
+ 按 `elicitation_complete.action` 渲染终局的壳,到期那一帧的词随之由 `decline` 变 `cancel`。没开入站 elicitation 的部署(缺省)零影响。
739
+ **升级前做**:按 action 分两支的 MCP server 把到期分支改读 `cancel`;不分两支的(任何非 `accept` 都当没授予、且不把到期缓存成会话级拒绝)两个词读法没有差别,零动作。窗长仍由 `MCP_ELICITATION_TTL_MS` 调,没有词义开关。
740
+
741
+ 46. **补记(7.147.0 节漏写一条:7.147.0 起写下的会话行在 ≤7.146.x 版本上续跑不保证;文书;行为零变;部署零动作 —— 回退的部署先读专条)**:
742
+ USAGE 的「已知限制」里有专条「混版回退」:把部署回退到 ≤7.146.x 再续跑 7.147.0 起写下的会话(SQL 后端的 `session_ext` 旁表与精简后的 `session_meta`,local 数据根的引擎版本高水位 marker),一次续跑可能照常跑到终答,也可能被拒,两种都不保证。
743
+ 出路:回退前先排空(让待续跑的停驻 run 先收完;随包的排空检查 `scripts/drain-check-local.mjs` / `scripts/drain-check.mysql.sql` / `scripts/drain-check.pg.sql` 只读),或不跨版回退;唯一支持形仍是恢复升级前的数据根 / 库备份。已发的 7.147.0 节不改字节,本条即补记。
744
+
745
+ 47. **补记(7.147.0 节漏写一条:请求体 `mcpServers[i].transport.headers` / `.env` 里成员名 `constructor` / `prototype` 起拒;已发节不改字节,本条即订正;行为收紧;wire 零新键、零新码)**:
746
+ 旧形(7.146.x):这两处记录里只有名叫 `__proto__` 的成员被拒;名叫 `constructor` / `prototype` 的成员照收(200)。
747
+ 新形(自 7.147.0 起,契约包的保留成员名只有一张表):`__proto__` / `constructor` / `prototype` 三个名字同拒,同一个 `400 request.field_invalid`,`field` 点名成员级路径(如 `mcpServers[0].transport.headers.constructor`),不回显值;名字大小写敏感(`Constructor`、`X-Prototype` 照收)。
748
+ 范围如实:`a2aPeers[i].headers` 这一座**没有**收进这张表,仍只拒 `__proto__`(本服务自己的 A2A 头读法只认这一个名字),`constructor` / `prototype` 作 A2A 头名照收。存盘的续跑体里带这样 MCP 成员的条目,续跑时同样读不出 ⇒ 按「请求成员读不出」那一只判据拒续跑(`409 resume_blocked_by_policy`,`blockedBy` = `request.field_invalid`)。
749
+ **谁受伤**:把 `constructor` / `prototype` 当 MCP 头名或环境变量名写进请求体的调用方(极罕见)。**出路**:改名。
750
+
751
+ 48. **sema-up 三条交付路径同形挂钥匙卷:cluster 静态清单(`cluster-up.sh` 缺省 `STACK_ENGINE=render`)与单机 compose 的 server 也把钥匙保管目录挂成持久卷,三条路径都显式设 `SEALED_KEY_DIR=/root/.ai-agent/sealed-key`(部署形变更;零 DDL;部署有动作)**:
752
+ 静态清单新增 PVC `sema-server-sealed-key`(与图表同名;`ReadWriteMany`、存储类 `longhorn`、64Mi);compose 新增具名卷 `<项目>_sealedkey`(`--data-root` 时 bind 到 `<数据根>/sealedkey`,sema-up 落定时建目录)。
753
+ 图表持久开时两只 worker 多一条 `SEALED_KEY_DIR`(值 = 原挂载位,存量 PVC 里的钥匙原位可读)。`kube-up.sh` 的 `STORAGE_CLASS` 同样用于钥匙卷(此前它走集群缺省类)。
754
+ **动作(静态清单路径)**:重跑 `cluster-up.sh` **之前**给每个节点装 NFS 客户端(Debian / Ubuntu `nfs-common`,RHEL 系 `nfs-utils`)—— Longhorn 的 RWX 卷由它挂载;缺了 ⇒ server 新 Pod 挂不上卷、
755
+ 第 7 步等不到就绪而失败(旧 Pod 照常服务)。空卷上多副本并发首启只出一把钥匙(本版的首把钥匙创建口;NFS 的独占创建按协议原子),升级后不必重启。
756
+ **动作(compose)**:无;下次 `sema-up.sh` 重跑建卷。`--teardown-volumes` 起连钥匙卷对象一起删:docker 管的卷钥匙随之没了(之前停驻的任务续跑 409 `key_not_held`,web-admin 贴的 `sealedApiKey` 要对着新公钥重封);
757
+ `--data-root` 时卷是 bind,盘上 `<数据根>/sealedkey` 留着,落回同一条数据根重装即读回原钥匙。
758
+ **动作(kube-up 显式 `STORAGE_CLASS` 的存量部署)**:无;钥匙卷已在时 kube-up 沿用它建好时的存储类(PVC 的存储类建好后不可改,7.134.0–7.147.x 建的钥匙卷走的是集群缺省类),`STORAGE_CLASS` 只用于新建的钥匙卷。
759
+ **谁受伤**:升级之前停驻、带请求凭据的任务照旧续不了 —— 那时的钥匙从没持久过,本版之后的停驻行才跨得过重启。节点装不了 NFS 客户端的集群改走图表路径(`STACK_ENGINE=helm`,可单副本 / RWO / 关持久)。
760
+
761
+ 49. **🔴 能力位 `sessionReadRedaction` 的值由 `true` 改成历史读面过脱敏的叶名表 `string[]`(`<形>.<键>`,今天十一员;键名不变,布尔形整删)(wire BREAKING;部署零动作;消费方有动作)**:
762
+ 旧形:`sessionReadRedaction: true`(7.120.0 起恒真;7.120.0–7.122.x 报真而 `assistant` 的 `errorMessage` / `diagnostics` / `repetition` 叶仍是存档原形)。
763
+ 新形:`sessionReadRedaction: ["assistant.content", "assistant.errorMessage", "assistant.diagnostics", "assistant.repetition", "toolResult.content", "toolResult.details", "bashExecution.command", "bashExecution.output", "compactionSummary.summary", "compactionSummary.details", "attachmentFrame.content"]` —— 名单里的叶在 `GET /v1/sessions/:id` 的 `messages[]` 里过与 live 帧同一只脱敏;不在名单里的已知叶逐字(人写输入、标识、闭集词)。`attachmentFrame` = 带引擎送达记录 `attachment` 的 `user` 行。
764
+ **谁受伤**:按布尔读本位的壳(`=== true` 转 `false`;真值读法不再分叶)。**出路**:先判形再按叶判 —— `Array.isArray(caps.sessionReadRedaction) && caps.sessionReadRedaction.includes("<形>.<键>")`(老 server 上本位是布尔,直接 `.includes` 会抛);位缺席照旧按「≤7.119.x 老 server」读;遇到布尔 `true` 按「7.120.0–7.147.x」读(`assistant` 的三叶 7.123.0 起才脱)。
765
+
766
+ 50. **配置拉取失败行多一个闭集键 `cause`:起服 `config_source_unreachable_using_env`、刷新拍与迟到起服 `web_admin_refresh_failed`、迟到起服重拉 `config_boot_arrival_repull_failed`、run-local 同名行;门控域读拒 / 本地目录不被信任 = `rejected`(日志面加性;事件名不变;部署零动作)**:
767
+ 旧形:中心连不上、中心发了门控域判形失败的配置(或载荷不是有效视图),起服都记 `config_source_unreachable_using_env { source, err }`;刷新拍上这两形与本地配置目录不被信任都记 `web_admin_refresh_failed { err }`,分不出因(起服遇目录不被信任一向是拒启,不变)。
768
+ 新形:四行带 `cause` —— `unreachable`(没拿到候选:传输 / HTTP 非 2xx / 凭证 / 重定向 / 超时 / 本地腿读目录撞文件系统错)、`rejected`(配置源答了,本引擎拒收:读腿整包抛或本地目录不被信任)、`superseded`(应答属于在飞期间被换掉的中心凭证);刷新失败行另有 `apply_refused`(拉取已成、应用段抛)。拉取失败三行另带一句 `note`。`err` 逐字不变。
769
+ **谁受伤**:按 `config_source_unreachable_using_env` 一律认「中心连不上」的告警(读拒此前也在里面,本版不更糟);按整行字段集比对的解析器。**出路**:按 `cause` 分流;`rejected` 的 `err` 带读腿那一句与字段路径(不单列域名)。
770
+
771
+ 51. **run-local 执行本地目录的 `models.atMention`:objective 内联 `@name` 点了名单外的模型 ⇒ exit 2、零模型请求,拒句与 HTTP 400 `request.model_not_allowed` 同一句;`@<档位词>` 按本地目录的档位绑定解析(行为变更;wire 零变化;部署零动作)**:
772
+ 旧形:run-local 判 `@name` 取契约缺省 `{mode:"all"}`,本地目录里的 `atMention` 在这条腿上不生效;解析用的目录不含档位词 / CC 别名,`@pro` 落缺省模型。
773
+ 新形:run-local 与 HTTP 提交腿调同一只入口(同一张可选目录、本代 `atMention`)。名单外 ⇒ stderr `cannot run: @-mention "<名>" is not @-mentionable on this deployment (it resolves to catalog model "<目录名>") — …`,退出码 2。
774
+ **谁受伤**:靠 run-local 点名单外模型的脚本。**出路**:把那只模型写进 `config.d/models.json` 的 `atMention.models`(或改 `{mode:"all"}`),或不带 `@name`。
775
+ 52. **补登(引擎 7.61.0 起,7.143.0 已到货):停驻行可带挂起行 `heldRows` 与要求词 `held_rows` —— 7.142.x 及更早的副本不认这个词,对带它的行在认领前拒、行留 pending(7.142.x 答 `checkpoint.unsupported_version`、`reason: "version_newer"`)(文字补全;零行为变化;零 DDL;部署零动作)**:
776
+ 事实:停驻那一刻端口里若有挂起的会话行(扩展在一轮进行中经 `$.session.append` 记下、还没写进会话的行),引擎把它们按序带进这一行(`heldRows`),并给行的要求表加 `held_rows`;续跑腿在恢复的会话里把它们写一次。没有挂起行的停驻行不带这一员、不带这个词 —— 7.143.0 之前停驻的行形不变。
777
+ 存法:SQL 后端把整只检查点存在 `checkpoint` JSON 列,这一员随整行落列、随整行读回(零 DDL、零回填);`DB_BACKEND=local` 整只文档存回。收件箱 / 调度视图 / 运维队列的行不投这一员。
778
+ 混跑窗:7.142.x 的副本(引擎 7.60.x)读到带 `held_rows` 的行,认领前拒(`checkpoint.unsupported_version`,`version_newer`),行留 pending、不认领,落到 7.143.0 及以后的副本上可再决;更早的副本同样拒认领、行留 pending,拒码按它那一版自己的读法(读不懂带要求表的行形的老副本答的是它那一版的不可读码,不是这一个)。
779
+ **升级前做**:多副本滚动升级时先把会续跑 / 决卡的副本都升到 7.143.0 及以后,再放新的停驻。**回滚到 7.142.x 及更早**:先把带挂起行的停驻决完或取消,否则它们在旧副本上一直 pending。
780
+
781
+ 53. **目录条目只有一种读法:绕过读腿的条目(盘上被手改的 LKG、手写 effective)与两条读腿交来的条目同读,schema 补的缺省(`api` / `tier` / `provider` / `quotaWeight`)随之进 Model(行为修复;只有绕过读腿的输入可感;wire 零新键;部署零动作)**:
782
+ 旧形:两条读腿(中心 `/effective`、本地 `config.d`)交来的条目带 schema 补的缺省;绕过读腿的条目判按缺省、铸按原值 —— 缺 `api` 的条目让整只候选应用失败,同一候选里的好条目一并不落(boot 腿回落:拉到的候选落 `config_apply_refused`、盘上 LKG 落 `config_lkg_apply_failed`;热腿 `web_admin_refresh_failed`);缺 `tier` 的条目铸出无 `params.tier` 的 Model,缺省角色按档位选(`roles.default: { select: { tier } }`)选不中 ⇒ 模型面整组拒、上一代继续。
783
+ 新形:判与铸读同一份 schema 读数:缺 `api` 的 gateway 条目按 `openai-completions` 服务;缺 `api` 的 anthropic 条目由 provider ↔ api 配对拒(`config.model_entry_invalid`、字段 `api`);缺 `tier` 的条目 `params.tier` 为 `"standard"`;缺 `quotaWeight` 的条目以 1 进配额表(计量不变)。读腿交来的条目不变。
784
+ **谁受伤**:无(这些条目此前要么服务不了、要么让整面被拒)。**升级前做**:无;想让某条目走别的线路或档位,在条目上写明 `api` / `tier`。
785
+
786
+ 54. **🔴 `POST /v1/runs/:id/interrupt` 不再收 `text`:体带任何键 ⇒ `400 request.body_shape`(键在 `unknownKeys`,判在查 run 之前);「切断并说话」改发 `POST /v1/runs/:id/steer { text, priority:"now" }`(wire BREAKING;零 DDL、零数据迁移;部署零动作,调用方有动作)**:
787
+ 旧形:`/interrupt {text}` = 切断在飞 turn 并带这句话继续,run 在本副本在飞 ⇒ `202 delivery:"queued-immediate"`;run 不在本副本跑(停驻 / 他副本 / 终局)⇒ 一律 409、什么都不写。
788
+ 新形:`/interrupt` 只收空体(不发体 / `{}` / `null`)= halt(切 + 停),回执与非 live 码不变。带话改发 steer `priority:"now"`(≥7.116.0 的 server 上都生效,见 `capabilities.fleet.steerPriority === "engine"`;壳可以先改、server 后升)。回执按 `delivery` 分支:`applied` = 本副本在飞(真切与否看 `task.turn_interrupted`,`detail.inputId` = 回执 `messageId`);`queued` = run 停在待决上,这句话随续跑首轮到达(不会切断什么);`parked_for_wake` = run 已结束,要 `POST /v1/sessions/:id/wake` 才送。
789
+ **与旧口的差别(谁受伤)**:新形在停驻 / 终局 run 上**写一笔停放**(停放条目 / 候唤醒卡),旧口在这两态零写。旧口那条「在飞才收、否则零写」的原子保证**本版起没有替代**:先读 run 状态再发有竞态(读到在飞,发出那一拍流刚落定,steer 照样停放);事后见 `delivery !== "applied"` 时那笔停放已经落盘、撤不回。7.116.0 节「想要不停放的切断用 `/interrupt`」那句补偿自本版失效(已发节不改,本条即勘误)。
790
+ **另两处读法**:`interrupt.nothing_in_flight` 的句子改说「答那个待决,或 `POST /v1/runs/:id/cancel`」(码不变;按句子匹配 `/steer` 的消费方改按码读);服务端自铸的崩溃告知 `task.user_steer_undrained{cause:"crashed"}` / `task.user_followup_undrained{cause:"crashed"}` 的 `message` 去掉了点名回执形的括注(此前「each answered 200 applied or 202 queued-immediate」;按句子匹配回执形的消费方改读 `detail`)。
791
+
792
+ 55. **SQL 库的唯一键归起服补建、且不只按名判:八条此前只随建表到货的唯一键,存量表缺了就在起服时补建;唯一索引同名在场时再判形(列集 / 唯一性 / 整表);存量有重复行或同名形不对 ⇒ 起服拒启并点名(起服拒启面变更;SQL 开库的等待窗不重试;wire 零新键;新库与已齐的库零 DDL)**:
793
+ 旧形:`uq_file_history_boundary_seq` · `uq_wfinbox_seq` · `uq_device_pubkey` · `uq_image_bake_idem` · `uq_image_bake_event_line` · `uq_approval_ask_idem` · `uq_leader_run_idem` · `uq_adoption_log_from` 这八条唯一键只随 `CREATE TABLE IF NOT EXISTS` 到货:存量表缺了它们永远补不上,库不再对「不许重复行」执法而起服是绿的;索引原语只按名字判在不在,同名而形不对的旧索引(普通索引 / 列集不同 / 局部或前缀索引)也被当作已有。
794
+ 新形:八条进索引声明,存量表缺了就在起服时补建(PG `CREATE UNIQUE INDEX CONCURRENTLY`,不阻塞写;TiDB / MySQL 在线 `ADD UNIQUE INDEX`)。`unique: true` 的索引同名在场时(含既有的 `uq_task_run_idem` · `uq_session_event_entry` · `uq_repo_digest` · `uq_agent_memory_engine_entry_scope_slug` · `uq_att_seed`)再读一次库里的真形,与声明比表、列集(按集合,列序不论)、唯一性、是否整表,任一不符 ⇒ 起服拒启。MySQL 协议的目录读法 = `SHOW INDEX`(TiDB 7.5.1 的 `information_schema.statistics` 不报前缀长度,前缀唯一索引在那里会被读成整表;MySQL 8 / 9 与 TiDB 两引擎同读这一种)。建唯一索引撞存量重复行 ⇒ 起服拒启。两类拒启都点名索引与表并给出路,都是确定的拒启表态:开库等待窗(`STORE_LOCK_WAIT_MS`)不重试它、拒句不被改写成「库打不开」;出路执行完之前每次起服都拒。新库(唯一键随建表到货)零 DDL。
795
+ **重复行的出路**:拒句里是去重查询 `SELECT <列>, COUNT(*) FROM <表> WHERE <各列> IS NOT NULL GROUP BY <列> HAVING COUNT(*) > 1`(任一列为 NULL 的行不冲突,已排除),删除或合并多余的行 —— 留哪一行是你的决定,本构建不替你选 —— 再起服。PG 上失败的构建会留下一个 INVALID 的同名索引,下一次起服自己摘了重建,不必手摘。
796
+ **同名错形的出路**:停掉该表的写入,执行拒句里的那一条摘除语句(MySQL 协议 `ALTER TABLE <表> DROP INDEX <索引>;`,PG 独立索引 `DROP INDEX CONCURRENTLY IF EXISTS <schema>.<索引>;`,PG 约束底座 `ALTER TABLE <schema>.<表> DROP CONSTRAINT <约束>;`,PG 上语句里的 schema 是索引所在的那个),再起服 —— 下一次起服按声明的形建;摘除到重建完成之间库不执法唯一性。重复行仍在,则那一次起服转为「重复行」拒启。
797
+ **谁需要**:带存量表的 SQL 部署(升过多版的库:这八张表上的唯一键可能从没存在过)。**谁受伤**:存量表里已有重复行(唯一键缺席期间写进去的)或留着同名错形索引的库 —— 升级后起服拒,直到按拒句出路处理;表较大时首次起服多一次建唯一索引。**补偿**:拒句逐处点名并带可执行的出路;新库零 DDL;不加旋钮。
798
+ **没做的(如实)**:普通索引不判形;PG 协议面不认 `CONCURRENTLY` 时的回退臂不读目录、不判形。
799
+ **升级前做(可选,省一次拒启)**:对每对 (表, 列) 跑一遍去重查询,无行即零动作 —— `file_history_boundary (scope, publish_seq)` · `workflow_completion_inbox (seq)` · `device (owner_tenant, pubkey)` · `image_bake (idem_key)` · `image_bake_event (bake_id, line_ord)` · `approval_ask (task_id, idempotency_key)` · `leader_run (idem_key)` · `adoption_log (from_principal)`;表不在或为空也无需动作。
800
+ **回滚**:回到上一版无需动作 —— 本版补建的唯一索引留在库里,旧版不读它,它继续在库里执法;多个副本滚动升级无先后要求(旧版副本不读索引,只比列集)。
801
+
802
+ 56. **`DB_BACKEND=local`:会话删除先落持久的「删除中」标记(会话元数据边档 `session-incarnations.json` 里那一格多一位 `"dropping": true`);回滚到 7.147.x 及更早之前先用本版起一次(持久面;行为修复;升级零动作)**:
803
+ 旧形:那一格只有化身 / 属主 / 建档时刻 / 执行位 / fork 键;删除逐只删四只行边档、存档、格,中途失败或进程被杀留下半删的会话(旧标题挂到同 id 的下一位住客、fork 中间态 409、补铸出的无主会话)。
804
+ 新形:删除第一步把那一格写上 `"dropping": true`(文件与目录 fsync),收尾完成时连格一起删;带这一位的格对一切读者是「不在」,同属主重发删除、下一次碰这只 id、或下一次起服把它收完(起服扫收不完 ⇒ warn `session_drop_unfinished`,照常服务)。
805
+ 正常收完的删除不在盘上留这一位;只有删除中途失败 / 进程被杀之后、还没收完时它才在。local 上 run 认领先锁根会话:受理之后会话被删 ⇒ 404 `resume.session_not_found`;删除 / 委派子代转录的收尾撞上活 run ⇒ 拒(删除答 409 `conflict.session_active_run`)。
806
+ **谁受伤**:回滚到 7.147.x 及更早时数据根里还留着标记格 —— 旧版的严格边档读不认识这一位,起服整只拒。依赖「换装半失败后同键 fork 从源补回内容」的调用方:存档保持空,由换装重试补齐。
807
+ **补偿 / 回滚**:回滚之前先用本版起一次(起服扫收完全部标记格;起服日志里没有 `session_drop_unfinished` 即收完),再换旧版。收不完的(warn 点名 id 与故障)先按故障修(权限 / 盘满),再起一次本版。
808
+ **升级前做**:无。SQL 后端零动作(删除本来就是一个事务)。
809
+ **与本版「会话删除是一只三态」一条合读**:会话删除先在那一格写下令牌 `"deleting"`,删行那一刀才带 `"dropping"`;带令牌的格由删除协议收完(同属主重发 = 接管;起服之后删除协调器的收尾,收不完 ⇒ warn `session_delete_recovery_unfinished`),
810
+ 不由「下一次碰这只 id」的写或店的起服扫收;上面「同属主重发、下一次碰这只 id、或下一次起服」这一句在会话删除上读作「同属主重发、或下一次起服」。只带 `"dropping"` 的格(placed release / 提交出口撤回)照旧。回滚前用本版起一次,日志里两种 warn 都没有再换旧版。
811
+
812
+ 57. **起服列集对账多问一件事:本构建声明非空(`NOT NULL` 或主键成员)的列在库里仍允许 NULL ⇒ 拒启,拒句逐列给配方;缺列的拒句按列的声明分类 —— 自填列一句 ADD COLUMN(与历史同)、要值列三步、主键列不出语句(行为收紧 + 文字订正;wire 零新键;SQL 部署有升级动作)**
813
+ 旧形:对账只问「列在不在」;缺列的拒句对每一列打印 `ALTER TABLE … ADD COLUMN <原文>;`。要值列(声明 `NOT NULL`、无缺省)的那一句原文在已有行的 PostgreSQL 表上被引擎拒,部署者常把列加成可空 —— 此后起服转绿,而这一列在已有行上是 NULL(`file_history_boundary.publish_seq` 是这一形)。
814
+ 新形:同一次对账(列册只有一个读者,一次读回「列在不在 + 可不可空」)再问「本构建声明非空的列在库里是否也非空」,否 ⇒ 拒启(同一个拒启码 `config.schema_mismatch`),拒句点名表与列;打印的语句全部生效之前每次起服都照拒。配方按列的声明分类:要值列(无缺省)缺列 ⇒ `ALTER TABLE <表> ADD COLUMN <去掉 NOT NULL 的原文>;` → 一行 `-- ` 注释(`UPDATE <表> SET <列> = … WHERE <列> IS NULL;`,值归你填,注释行不会被误执行)→ PostgreSQL `ALTER TABLE <表> ALTER COLUMN <列> SET NOT NULL;` / MySQL 协议 `SET SESSION sql_mode = CONCAT_WS(',', @@SESSION.sql_mode, 'STRICT_ALL_TABLES');` 加 `ALTER TABLE <表> MODIFY COLUMN <原文>;`;要值列已在而可空 ⇒ 只后两步;自填列(可空 / 有缺省 / 自增 / 生成列)缺列 ⇒ 一句 `ADD COLUMN <原文>;`,已在而可空 ⇒ 有缺省的先一句真 `UPDATE <表> SET <列> = <声明的缺省> WHERE <列> IS NULL;`(缺省是本构建声明的)再收紧,自增 / 生成列只收紧;主键成员 ⇒ 不出语句,一句话(出路是部署与库匹配的构建)。
815
+ **哪类库升级后会拒启**:某张表里有「本构建声明非空」而库里可空的列 —— 含带 `DEFAULT` 的列;典型是以前照拒句把某列手工加成可空、从没补值收紧的存量 PostgreSQL / TiDB 库,以及曾被手工放宽过 `NOT NULL` 的列。**不拒**:本就声明可空的列在库里可空;构建可空、库里非空的反方向不判。
816
+ **升级前做**:不确定自己的库属不属于上面那一类时,先在测试库按拒句演练:拒句逐表逐列给配方,要值列的回填值(注释行里的 `…`)由你按自己的数据填,有缺省的列配方里的 `UPDATE` 已是声明的缺省;执行完毕后再起服。空表上打印的语句逐字全部可执行。
817
+ **回滚**:回到上一版即回到只问列名的对账;数据零改动(已收紧的列在上一版照常工作)。
818
+ 58. **引擎 7.65.0 → 7.66.0(`@sema-agent/core` 精确钉;`@sema-agent/primitives` 随 core 的同版精确依赖到 7.66.0):① 🔴 mods 契约号 8 → 9 —— 部署 mod 包按 9 重建;② 🔴 `MODEL_DEFAULT_THINKING=off` 由「等于不设」改为真档「缺省不思考」;③ `GET /v1/models` 行加 `defaultThinking`;④ 人类输入帧带 `author` / `extension`、附件行带 `declinedBy`;⑤ 外源清标账行带 `custodyErased`;⑥ capture 记录三名退出引擎包根;⑦ 退役且没有后继的工具名在选择器 / 技能清单与 `neverAuto` 上也不再拒;⑧ 店形拒族第四码;⑨ 🔴 `PRINCIPAL_INBOX_ASSISTANT` 必须是 agent handle 形;⑩ URL 主机读法换成引擎的唯一读法(行为变更 + 硬破坏;wire 加性;零 DDL、零一次性迁移)**
819
+ 换钉:`@sema-agent/core` 7.65.0 → 7.66.0 精确(`package.json` 只钉 core),`@sema-agent/primitives` 随 core 的精确依赖到 7.66.0。下列各项按「谁看得见」排。
820
+ ① **mods 契约号 9(硬破坏)**:旧形:部署 mod 包写 `"contract": 8`。新形:引擎的 mods kernel 契约号是 9,写 8 的包起服拒 `config.mods_invalid`(拒句点名两个号)。9 = 扩展可经 `$.prompt.submit({ text })` 给自己的腿交一条提示,扩展帧多 `handler.event`。
821
+ **升级前做**:把包的 `contract` 改成 9 并按新契约重建。没声明 `MODS_PACKAGES` 的部署零动作。
822
+ ② **`MODEL_DEFAULT_THINKING=off`(行为变更)**:旧形:`off` 是哨兵词,与不设同义(不铸模型级缺省,提供方自己的缺省说了算;缺省开思考的网关照样思考)。
823
+ 新形:`off` 是七档之一,铸进引擎 `Model.defaultThinking: "off"` —— 没点档的请求带显式「关」;配置目录行的 `effectiveValue` 回 `"off"`(此前 `null`);中心有效配置回填同一读法。七档以外的值照旧起服拒;端点梯子 `MODEL_REASONING_EFFORT_LEVELS` 仍只收六档。
824
+ **谁需要**:要「这只模型缺省不思考」的部署(缺省开思考的网关,便宜步不要思考)。**谁受伤**:已写 `MODEL_DEFAULT_THINKING=off` 而靠「等于不设」让网关缺省思考的部署 —— 升级后缺省关。
825
+ **补偿**:想要「不设」的把这一行删掉或留空。**回滚**:回到 7.147.x 时 `off` 照旧读成不设。
826
+ ③ **`GET /v1/models` 行加 `defaultThinking`(wire 加性,present-iff)**:这一行的模型缺省档原样(七档含 `off`);缺席 = 没有模型级缺省。读「缺省是不是关」读本键,读「关不关得掉」读 `supportsThinkingOff`。
827
+ ④ **人类输入帧(wire 加性)**:`human_input.author` / `human_input.extension`(不是本人时才在场:`extension` = 扩展交的提示,`observer` = 观察者的报告;`extension` 键是交提示的扩展注册名)与附件行 `declinedBy`(拒了这只附件的扩展)。缺席 = 操作者本人。把每条 `human_input` 都当成本人输入渲染的消费方:按 `author` 区分。
828
+ ⑤ **外源清标账(引擎型面硬破坏;本服务零动作)**:清标账列表的读法改为异步(嵌入方直接调运维面 `listClearances` 的,改 await)。抹除连同清标托管一起抹 ⇒ `GET /v1/memory/origin/clearances` 的行带 `custodyErased: true`(在场才发)、`custodyBytes: 0`;对这一行的 resume 拒 `memory.origin_clear_unknown`;抹除收执的载体类多 `clearanceCustody`(原样转发)。
829
+ ⑥ **capture 记录三名退出引擎包根(引擎导出面硬破坏;本服务零动作)**:`listSessionCaptureOptOut` / `markSessionCaptureOptOut` / `readSessionCaptureOptOut` 没了,读法是 `fileSessionCaptureRecordStore(<控制面目录>)` 的 `list` / `mark` / `read`(异步)。直接 import 这三名的嵌入方换读法。
830
+ ⑦ **退役且没有后继的工具名,剩下两道门也放行(行为变更)**:旧形:请求的选择器清单(`excludeTools` → `400 config.tool_face_control` / 子代 `denyTools` → `400 config.agent.unknown_tool` / 技能 `disallowedTools` → `400 request.field_invalid`)与请求体 `settings.permissions.neverAuto`(`422`)上这种名被拒。
831
+ 新形:照收;选择器 / 技能清单由引擎保留这一行并在准备期说一句(会话流通告 `config.legacy_tool_name`,`layer` = `task_selector` / `skill_table`);`neverAuto` 只有本服务读 ⇒ 本服务按引擎的退役名账铸那一句一次(`layer` = `host_table`,条目带 `source`)。改名了的旧名(有后继)照旧拒。
832
+ **谁需要**:写着这种名字的清单(壳从 CC 用户 settings 转投的常带)—— 不再因一行死项整份被拒。**谁受伤**:按 `400` / `422` 找这种名字的调用方 —— 改读通告。**补偿**:按通告点名的条目把它从清单里删掉。
833
+ ⑧ **店形拒族第四码 `memory.control_plane_strays`(本服务的部署形零动作)**:后端自带治理店而引擎控制面里还留着旧治理记录 ⇒ 引擎构造期拒、一个字节不写;引擎不自动搬旧记录。本服务三种记忆后端都构造不出这一形(File 后端的治理店就是它控制面上那只;`pg` / `mysql` 不带治理店)。
834
+ 码按族入族:两受众同答 409 + 原码(会话所有者面固定句)。自己接带治理店后端的嵌入方:**升级前一步** = `adoptReplicaControlPlane(<控制面目录>, <那只治理店>)`。
835
+ ⑨ **`PRINCIPAL_INBOX_ASSISTANT` 的值形(收窄)**:旧形:任何非空白串照收(`asst-1` 也收),收件箱等一只永远不会来的读者。新形:必须是 agent handle(`a` + 6–32 位小写十六进制);不是 ⇒ 起服拒,拒句是引擎原句(引用值至多 96 字符)。
836
+ **谁需要**:跨主体投递要真能被一条助理腿读到的部署。**谁受伤**:值不是 handle 形的部署 —— 起服拒。**补偿**:换成那只助理的 handle,或删掉这一键。引擎这一版有读信的助理腿(以这只 handle 作任务 id 跑),本服务今天没有起它的入口,信照旧留在箱里。
837
+ ⑩ **URL 主机读法(行为变更)**:插件克隆 URL 对 `PLUGINS_ALLOW_HOSTS` 的判与 `GIT_API_BASEURL` 的主机族判改读引擎 `hostOfUrl`。旧形:插件 `new URL(url).hostname.toLowerCase()`(尾点主机被拒、带凭据的照放);`GIT_API_BASEURL` 去一只尾点 + 小写(不是 http(s) / 带凭据照过起服)。
838
+ 新形:小写、IDN 取 ASCII 形、尾点全读掉(`PLUGINS_ALLOW_HOSTS` 的名单项经同一只读法读,只认裸主机项);带凭据 / 不是 http(s) / 读不回一只主机 ⇒ 读不出:插件那一条不装(拒因是引擎那一句)、`GIT_API_BASEURL` 起服拒(这种值此前每次仓请求都失败)。
839
+ **谁受伤**:URL 里带凭据的这两种声明。**补偿**:凭据移到 `GIT_API_TOKEN` / 部署的 git 凭据,URL 只留主机与路径。
840
+ **引擎只读面的收窄,本服务零改(如实)**:个人挂载上坏掉的作用域登记簿与坏根锚同答(不带层座的状态面 `optOutSource: "fault"`、不带层座的记忆口 500 `internal.memory_control_plane_corrupt`);清标账更新删不掉已抹条目的托管对象 ⇒ 那一次清标操作失败关闭(500);
841
+ Runner 任务里委派工具的任务登记表不是这一跑的那只 ⇒ spawn 拒(本服务恒传这一跑的那只,不可达);模型缺省档在 `off` 以上的部署,记忆整理的蒸馏与 mod 的 `$.model.complete` 也按这一档请求(成本面)。
842
+ **升级前做**:① mod 包 `contract` 改 9;② 核 `MODEL_DEFAULT_THINKING=off` 是不是要「缺省关」;③ 核 `PRINCIPAL_INBOX_ASSISTANT` 是 handle 形;④ 把凭据从 `GIT_API_BASEURL` / 插件克隆 URL 里移走。**回滚**:本条各项无持久面(零 DDL、零一次性迁移),回到 7.147.x 时 mod 包要改回 `contract: 8`;`DB_BACKEND=local` 的数据根被本版打开过就记下了本版的引擎高水位(见本版「`DB_BACKEND=local`:数据根记引擎版本高水位」一条),换回 7.147.x 前先恢复升级前的数据根备份(回滚的唯一支持形)。SQL 后端不受这一条影响。
843
+
844
+ 59. **停驻行读者上存储体读不成检查点答这一行自己的拒:`/v1/assistant/tasks/:id/resume` · `/v1/sessions/:id/wake` · `plan_review` · 应答口 `POST /v1/tool-approvals/:id/respond` 的停驻赎回席不再借 `409 conflict.checkpoint_unreadable`,与决断口同答 `checkpoint.invalid_outcome`(wire 码变;按码分支的客户端改读法;部署零动作)**:
845
+ 旧形:这四个入口上停驻行的存储体读不成检查点(JSON 字面 `null` / 数组 / 标量 / 非 JSON)答 `409 conflict.checkpoint_unreadable` + 店的原句(不带 `reason` / `retriable`);决断口与运维队列 / 收件箱行上的 `rowVerdict.code` 已是 `checkpoint.invalid_outcome`(MIGRATION 7.147.0 节第 29 条)—— 同一张坏卡一行两码。
846
+ 新形:五个停驻行读者(决断口 · `/resume` · `/wake` · `plan_review` · 应答口的停驻赎回席)同答这一行自己的拒:`409 checkpoint.invalid_outcome`,体顶层 `reason`(判官对这一格原样字节的判决)与 `retriable: true`,`error` 以行上 `rowVerdict.sentence` 开头、后接 ` Diagnostic: ` 与店的诊断;卡仍 pending、字节不动。
847
+ 店的别的失败(连接 / 读腿漂)仍 `409 conflict.checkpoint_unreadable` + 店的原话 —— 这是该码今天唯一的产生处。
848
+ **谁受伤**:对这四个入口的 `409 conflict.checkpoint_unreadable` 做专门分支(当「存储体坏了」处置)的客户端:坏行上拿到 `checkpoint.invalid_outcome`。
849
+ **补偿 / 升级前做**:`conflict.checkpoint_unreadable` 今后只表示店的别的失败;「这一行续不了」读 `checkpoint.invalid_outcome` + `reason`(`error` 句即出路,卡仍待决);按前缀 `checkpoint.*` / `conflict.*` 兜底的客户端零改。**回滚**:回到上一版即回到四口借码;数据零改动。
850
+
851
+ 60. **本服务自己发出的出站请求一律不跟重定向:出口只有一只,搜索后端 · 记忆同步 · repo 工具 · OTLP 出口 · bake-runner · 对象存储 · `http` hook 都在内;对端回 3xx(304 除外)⇒ 拒,不跟、不重试,拒句点名出路(行为收紧,安全轴 fail-closed;wire 零新键、零新码;端点原先靠重定向转发的部署要把最终地址写进配置)**:
852
+ 旧形:出站 `fetch` 各写各的。hook 直连模型腿、记忆 embedder、对 web-admin 中心的请求早已以 `redirect: "manual"` 发出并拒 3xx;其余面交给传输层(undici)默认跟随 —— Brave 搜索(`X-Subscription-Token`)· Tavily(Bearer)· SearXNG 实例 · 记忆同步中心(Bearer + 同步体)· repo 工具(Git host 的 `token` / Bearer)· OTLP 出口(`OTEL_EXPORTER_OTLP_HEADERS` 里的鉴权头 + 指标体)·
853
+ bake-runner(runner bearer + 单 bake 摄取密钥)· 对象存储(预签名 URL:blob 后端、SendUserFile、leader 的 diff 回读、k8s 工作区快照的 worker 侧指针 / 列举 / 删除请求)· 沙箱桥探活(桥令牌在 query)。传输层跟随 POST 307 / 308 时把请求体连同未被剥掉的自定义凭据头(跨 origin 只剥 `authorization`)带去 `Location`,同 origin 的跟随连 `Authorization` 一起带走。`http` hook 自带 `redirect: "error"`:同样不跟,拒句却是传输层的 `fetch failed`,不点名出路。
854
+ 新形:全局 `fetch` 在整个 `src/` 里只被读一次(`src/egress-redirect.ts` 的出口工厂);每个出站面各造一只带「出路句」的出口,请求只经它发出,注入的 `fetchImpl`(测试座 / 嵌入方)同样被它包住。出口强制 `redirect: "manual"`,对端回重定向(`opaqueredirect` 或除 304 外的任何 3xx)⇒ 抛类型化拒,
855
+ 拒句 `endpoint answered with a redirect (HTTP <n>); it was not followed and no credential was sent anywhere else — <出路>`(与引擎一方 brain 的请求同一句;不回显 `Location` / 凭据 / 体)。各面既有的失败臂收这条拒、留话:搜索后端 = 搜索调用抛出该句(boot 探活留 `web_search_probe_failed`) · 记忆同步 = 运维行 `memory_sync_layer_failed`(这一层本轮零本地副作用)·
856
+ repo 工具 = 工具调用抛出该句 · OTLP 出口 = `server.otel.export-failed` 的 fail-open 计数 + warn `otel_export_failed` · bake-runner = `bake_claim_error` / `bake_ingest_error` / `bake_heartbeat_error` · 对象存储 = 各站既有的失败句(blob 的 `put` / `get` / `delete` 抛、SendUserFile 抛、leader 的 `diff fetch failed: …`、k8s 快照指针读 `connect_failed`)·
857
+ `http` hook = 日志 `hook_http_request_failed` + 故障帧 `spawn_failed`(拒句替换了 `fetch failed`)。(沙箱桥探活那一面随沙箱 LSP 桥在本版一并删除,见本节 LSP 一条。)出路句点名各面的那一席:`WEB_SEARCH_ENDPOINT` · `MEMORY_SYNC_URL` · `GIT_API_BASEURL` · `OTEL_EXPORTER_OTLP_ENDPOINT` · `IMAGE_API_BASE` · `MINIO_ENDPOINT` / `S3_ENDPOINT` · hook 条目的 `url`。
858
+ **谁需要**:把上述端点放在会回 3xx 的前面的部署 —— 负载均衡的 http → https 跳转、缺尾斜杠的 301、改名 / 迁移后的仓 API(托管方对改名或转移的仓常回 301 指向新位置)、代理网关的 307 转发。这一类部署此前由传输层静默跟随,体与自定义凭据头被送去另一处。
859
+ **谁受伤**:端点原先靠重定向转发的部署 —— 升级后那一面的请求在第一跳就失败(拒句在上面各条失败臂里),不再静默成功:搜索工具报错、记忆同步那一层本轮失败、仓工具报错、指标出口断供(`server.otel.export-failed` 计数涨)、bake-runner 认领失败、对象存储读写失败。自家 http → https 跳转的部署:把配置里的 `http://` 改成 `https://`。
860
+ **补偿**:把最终地址写进上面点名的那一席(无新旋钮;不提供「跟随重定向」开关 —— 凭据只去被判过的那个根是这条律的全部意义);改名 / 转移后的仓,`GIT_API_BASEURL` 不动,工具里改用新的 owner / repo。
861
+ **升级前做**:逐个确认配置的端点在**该面实际用的方法**上不回 301 / 302 / 303 / 307 / 308 —— 前面的路由可能按方法、路径、鉴权各回各的,GET 不回不等于 POST 不回。只读面(搜索后端 · repo API · 对象存储的读)可跑 `curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' <端点>`;POST 面(记忆同步 · bake 认领 / 摄取 · OTLP)不要对生产口发带体的真请求,在预发起一次本版、看日志里有没有拒句。`redirect_url` 只是下一跳,可能仍不是最终地址:顺着再探一次,直到 2xx / 4xx,把那一个写回配置。没有重定向的部署零动作。
862
+ **回滚**:回到上一版即回到「传输层默认跟随」(上述面);无持久面变更。
863
+ **304 的读法变了(如实)**:304 没有 `Location`、传输层也不跟,它不是重定向 —— 判据把它放过(中心请求原来单列的例外并进了判据)。hook 直连腿与记忆 embedder 此前把 304 当重定向拒;现在 304 是普通的非 2xx:hook 直连腿答 `bad_response`(句 `hook llm HTTP 304`),embedder 抛 `HTTP 304`。这两面从不发条件请求,304 本就不是合法答复;结果同样是失败,只是失败句与码变了。
864
+ **没做的(如实)**:`ws` / `node:http(s)` 客户端口(k8s API、exec 的 WebSocket、本进程回环探针)不经这只出口 —— 它们的传输层本就不跟重定向;源码门把这几处与出口一并登记成闭集,新加一条出站腿必须登册。
865
+
866
+ 61. **🔴 属主判一张面表:提交挂接对「不是你的 / 委派子代的」会话答「没有这只会话」;直连门计划审阅对别人的 task 答证明拒;策略口对委派子代行答 404;只持部署 service 凭据的调用方在 run / 会话读面看得见各用户的行(安全轴;行为变更;wire 零新键、零新码;部署零动作)**:
867
+ 旧形 → 新形(逐格;其余各口的码与句逐字不变):
868
+ ① 提交挂接(`POST /v1/tasks` · `POST /v1/tasks/stream` · `POST /v1/runs`,带 `sessionId`,认领形与 `requireExistingSession` 形)× 别人的有主会话:具名调用方 403 `auth.forbidden`「session does not belong to this principal」、不报主体 401 `auth.unauthorized`「session is principal-owned; missing principal header '<头名>'」→ 404 `resume.session_not_found`「requireExistingSession: session does not exist (resume.session_not_found)」,与这个 id 不存在逐字同体。多租部署上会话店记不了属主时的 403(「cannot claim a caller-supplied sessionId …」)不变。
869
+ ② 同三口 × 委派子代的无主 placed 会话(具名调用方、只持 service 凭据的调用方都算):修前执行席答 404 `resume.session_not_found`「the session this run was to start on no longer exists …」,不带执行席的嵌入装配上 `requireExistingSession` 形放行 → 属主门答 ① 那一体,嵌入装配同拒。那只会话的存档读不出时属主门不判这一格(执行席照判,存档的故障照旧按腿的形答 `corrupt_session`)。
870
+ ③ 直连门 worker × `POST /v1/assistant/tasks/:id/plan_review` × 证明有效、task 属于别人:404 `not_found.run` "task not found" → 401 `principal_unverified` "principal proof required",与查无此行同体。属主按这一次决定的证明推出的主体判;BFF 部署不变。
871
+ ④ `GET|PUT /v1/sessions/:id/policy` × 委派子代的无主 placed 会话 × 非 fleet、非运维调用方:409 `conflict.session_ownerless` → 404 `not_found.session`「session not found」。运维与普通无主会话仍 409。
872
+ ⑤ 放宽:只持部署 service 凭据、不报主体的调用方(部署未声明 `SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT=false`)× 各用户的行 × `GET /v1/runs/:id` · `GET /v1/runs/:id/events` · `GET /v1/sessions/:id` · `…/head` · `…/events` · `…/memory-status` · `…/execution-placement`:404(要求主体的部署上 401 `auth.principal_required`)→ 200(按幂等键读的口 `GET /v1/runs?idempotencyKey=` 键空间按调用方身份分区,它在那里读到的只是自己那把键建的行;要求主体的部署上那一口从 401 变成按自己的键作答)。没有身份边界的部署(dev-open)上 run 的两只按 id 读口不再按主体头钉人,与会话读面同读;驱动面照旧按属主。
873
+ 另两处同读的收口(码不变):a* / wa* 形的 id 在 compact / detach / 子代动词口的 404 句换成带指路的那一句(与 poll / cancel / steer / interrupt 同句),各 run 口非属主臂与缺行臂同句;会话存档读不出的无主会话上(本机文件后端),门只在两种假设(普通无主行 / 委派子代行)都放行时不读「是不是委派子代行」那一格:fleet / 运维调用方在 `…/background` · `…/background/stop` · `…/notify` · `…/mcp/reconnect` · `…/execution-placement` · 审批豁免的列表与撤销上照常作答(修前 500 `corrupt_session`);其余调用方照读,答法与上一版同(策略口 409、挂接放给执行席、店连接故障按店故障的码族);run 行缺属主格(盘上少 `owner` 键)× 没有 fleet / 运维资格的调用方:各 run 口答「没有这一行」(修前不报主体的调用方在续跑等口碰巧放行)。
874
+ **谁需要**:多租部署(「不是你的 ≡ 没有这一行」由构造保证);运维(拒因一行);代部署读舰队的中继(trace 与会话 / run 读面同答)。
875
+ **谁受伤**:按 ① – ④ 旧答分支的客户端 —— 按 403 / 401 判「挂接被拒、请带主体头」的前端改按 404 `resume.session_not_found` 读(指路句只在运维日志);直连门上持有效证明对别人的 task 下决定的调用方读到「principal proof required」;读策略口 409 判「无主」的管理面对 placed 行读到 404;dev-open 部署上靠主体头把别人的 run 藏起来的用法(那里主体头是谁都能自报的标签,不是身份)。
876
+ **补偿**:运维日志 `owner_gate_refused { policyFace, reason, principalPresent }` 一行(`policyFace` = 策略面)(`reason` = `missing` / `not_visible`;不记身份值)区分「缺行」与「看不见」;要「部署凭据看不见任何用户行」的部署声明 `SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT=false`(⑤ 不生效,其余各口按「过了凭据门、没有主体」那一臂答,与上一版同)。
877
+ **升级前做**:按 ① 的 403 / 401 或 ③ 的 404 分支的客户端改读新答;依赖 ⑤ 之前「部署凭据读不到用户行」的部署写一行 `SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT=false`。其余零动作。
878
+ **回滚**:无持久面;换回上一版即回到旧答。
879
+
880
+ 62. **🔴 拒体的机读位只有一种版式:`{ error, errorCode, ...机读事实 }`,根上不再有 `detail`;八条码路径的对象形 `detail` 摊到体根上(容器 `problems` / `fields` / `conflicts` 整只挂在根上),十一处串形 `detail` 并进 `error` 句尾;`settings.hooks` 面的拒体 `field` 改为精确坐标,`detail.path` 退役(wire BREAKING;码 · 状态不变;零持久化迁移;部署零动作,按 `detail` 读拒体的客户端要改)**:
881
+ 旧形 → 新形(逐码;「根上」= 与 `error` / `errorCode` 同层):
882
+ ① `400 request.field_invalid` · `settings.hooks` 面(全部拒):`field: "settings.hooks"` + `detail: { reason, path: [段…], event?, alias?, canonical?, groupIndex?, budgetMs?, totalMs?, type?, key?, count?, cap? }` → 根上 `field` = 判决所在处的坐标(方括号形,如 `settings.hooks.PreToolUse[0].matcher`)+ `reason` + 判决键原名;`path` 退役(坐标就是 `field`);`dead_alias` 补 `groupIndex`(四只 matcher 臂同一组定位键)。按 `field === "settings.hooks"` 认这一族的读法改为按 `reason` 认(本服务在这一面的自铸词与契约分类器的码),或按 `field` 是 `settings.hooks` 本身 / 以 `settings.hooks.` · `settings.hooks[` 起头认。
883
+ ② `400 / 409 / 422 request.field_conflict`:`detail: { kind, fields, count?, cap? }` → 根上 `reason`(原 `kind` 的词,逐字同)+ `fields` + `count?` + `cap?`。`kind` 改名 `reason`,词表不变。
884
+ ③ 条目问题(`400 request.field_invalid` · `400 config.agent.unknown_tool` · `400 config.tool_face_control` · `422 request.unprocessable` · `409 resume_blocked_by_policy`):`field` + `detail: { problems, total }` → 根上 `field` + `problems` + `total`;多租部署信任档的拒另带 `callerTrust`,同样从 `detail` 挪到根上。
885
+ ④ `409 conflict.session_placed`:`detail: { placement_kind }` → 根上 `placement_kind`。
886
+ ⑤ `503 state.scenario_assignment_unknown`(以及 `GET /v1/sessions/:id/mcp` 200 体里的 `scenarioRefusal`):`detail: { scenario, source }` → 根上(`scenarioRefusal` 里)`scenario` + `source`。
887
+ ⑥ `409 steering.duplicate_input_id`:`detail: { differs }` → 根上 `differs`。
888
+ ⑦ `400 config.user_attachment_invalid`(同步提交腿):`detail: { path, index? }`(引擎因由原样)→ 根上 `field`(引擎的 `path`,非空串才带)+ `index?`(非负整数才带);引擎在因由里多给的键不再进体。流式 `done.result` 与 run 记录上的 `terminal.detail.detail` 不变。
889
+ ⑧ `400 rules.invalid_shape` / `400 rules.inert_entry`:形不变(引擎的读数本来就在根上),改为按码逐键取:`invalid_shape` ⇒ `field` · `got`;`inert_entry` ⇒ `field` · `entry` · `reason` · `verdict` · `guidance` · `currentName` · `ambiguous` · `valueType`;表外的键不上 wire。
890
+ ⑨ 串形 `detail` 并进句尾(`error` = `<原句>: <原串>`,其余体键不变):`400 request.field_invalid`(领养 principals 的两句)· `409 adoption.destination_conflict` / `adoption.destination_unrepresentable`(`adoptionId` / `conflicts` 照旧)· `400 request.query_invalid`(三只分页口的 `before` 游标)· `503 memory.shared_unavailable`(`retryAfterSec` 照旧)· 留存口 `400 request.field_invalid` 的两只长度拒(另多 `field` · `reason: "too_long"` · `count` · `cap`,与请求体其余各处的帽同一组键)·
891
+ `POST /v1/rules` 的 `400 request.field_invalid` + `reason`(句子不再说「`detail` says why」,原因接在句尾;规范拼写那一臂另带 `canonical` = 店会存的规范串,原样重发即收 —— 此前它写在串形 `detail` 的句子里)。
892
+ ⑩ `settings.hooks` 面 `400 request.body_shape` 的 `unknownKeys` 与该面拒句里的坐标:点分数字段(`settings.hooks.Stop.0.hooks.0.onFailure`)→ 方括号形(`settings.hooks.Stop[0].hooks[0].onFailure`),与拒体 `field` 同一种写法。
893
+ ⑪ 保留键:`error` · `errorCode` · `detail` · `toJSON` 不作机读事实的键;本服务自己的组体撞上它们 ⇒ 那一拒答 `500 internal.error`(内部故障,不是调用方能修的拒)。
894
+ **谁需要**:按拒体机读位分支的消费方 —— 同一类事实此前有两种版式(摊在根上,或嵌在 `detail` 里),每加一个读点就要先问「这个码是哪一种」。
895
+ **谁受伤**:按 `detail.*` 读这些码的客户端读空(壳的 hooks 拒提示、坏附件「第几件」、条目问题清单、场景拒、按 `detail.problems[].field` 认字段的读口;SDK 的 `differs`);按 `field === "settings.hooks"` 认 hooks 族的读口认不出;按 `kind` 读字段冲突的读口读空;按点分数字段解析 `unknownKeys` 的读口。
896
+ **混版窗(新 server + 旧客户端,逐码)**:①:旧壳的 hooks 专门提示消失,改为通用的提交失败句(句子本身照旧点名坐标与原因);旧壳在提交失败后重扫已发 hooks 的那条提示路径可能给出与真拒因不同的别名 / 坏正则提示。②:旧读口拿不到冲突类别,只剩码与句子。③:按条提示消失,只剩句子(前 5 条 + `; and K more`)。④⑤⑥⑦:对应的机读位读空,退回到码与句子(⑥:旧 SDK 的 `differs` 为 `undefined`,「换不换 key」只能读句子)。⑨:旧读口读 `detail` 读空,原串仍在 `error` 句尾。⑩:按点分数字段切 `unknownKeys` 的读口切错。旧 server + 新客户端:新读点在 < 7.148.0 的服务端上读空(该位在那里不在根上)。
897
+ **补偿**:码 · 状态 · 句子骨架不变(串形 `detail` 的内容仍在句尾);消费方二选一,**不要双读**:(a) 把支持的服务端地板抬到 7.148.0;或 (b) 读点只读新形,并在说明里逐读点写明「低于 7.148.0 的服务端上该位缺席」(与该位上线之前的服务端同形)。
898
+ **持久化**:零迁移 —— 存量行(领养日志的拒因、存体)不改,只改 HTTP 投影;≤ 7.147.0 写下的存体续跑时按新形答。
899
+ **升级前做**:按上表把读 `detail.*` / `kind` / `field === "settings.hooks"` / 点分数字段 `unknownKeys` 的分支改到新位。部署零动作。
900
+ **回滚**:无持久面;换回上一版即回到旧形(新形的读点在旧版上读空,见混版窗)。
901
+
902
+
903
+ 63. **🔴 场景子命名空间 —— 请求头 `x-agent-scenario`,保留前缀 `_scn:`,起服切换检查,直连门证明的 sub 完整形判**
904
+ **是什么**:`x-agent-scenario: <场景名>` 在验过的人之内选一格分区:run / 会话 / 问行属主、停驻行 scope、附件、提交幂等身份、列表视域、会话规则按「人 + 场景」分;成本配额、租约、用量窗、并发帽、运维名册、持久规则、组织成员、出站身份、device 域、记忆仍按人。没带头的请求逐字节同上一版。判序、错误码与人面 / 分区面全表见契约 §0.12。
905
+ **新码**:`400 request.scenario_without_principal`(头在而没有验过的人)· `400 scenario_unknown`(头里的名字不合文法或不在册;此前只来自提交体)· `400 scenario_conflict`(提交体 `scenario` 与头不同)。`principal_too_long` 对带头请求判「人 + 场景」编码后的宽度。
906
+ **保留前缀**:主体头 · SSO 令牌 sub · 直连门 JWT sub 三处以 `_scn:` 开头的人一律 `400 principal_reserved`。直连门证明的 sub 此前只判长度,本版起与主体头同一只判官(名形 / 保留 / 长度):sub 带控制字符 → `400 principal_not_a_name`,sub 是保留标识 → `400 principal_reserved`。
907
+ **起服切换检查(一次性迁移,只读)**:库里没有本条的标记 ⇒ 扫存量身份(SQL:本构建建表语句里名字以 owner / scope / principal / subject 结尾、库里在的每一列;`DB_BACKEND=local`:run / 会话 / 问 / 附件的属主),任何一行以 `_scn:` 开头 ⇒ 拒启 `config.scenario_prefix_switch_refused`,拒句点名表 · 列 · 行数,一个字节不改;SQL 后端上零命中而判活窗内仍有 run 在心跳(更早版本的副本可能还在服务)⇒ 同码拒启、标记不写(停-迁-起);零命中 ⇒ 写一行标记(SQL:标记表 `one_time_migration_marker`,本条自己建;local:数据根里 `one-time-migration-M42.json`),之后起服不再扫。恢复到没有标记的旧备份 = 再扫一次。窗口见 `plugins/one-time-migrations.ts` 登记表。
908
+ **谁需要**:同一个人在不同场景(例:健康 / 财务)里各用一套会话与历史、互不看见的部署。
909
+ **谁受伤**:① 以 `_scn:` 开头的既有主体:边界 400,存量行让起服拒;② 直连门部署里 sub 带控制字符或是保留标识的证明:由放行改 400;③ 回显属主的读面(trace 列表、`?owner=` 收件箱)对带头写下的行显示 `_scn:<场景>:<人>`;④ 混版:更早版本的副本不读这只头,带头请求落到它上面写进人自己的分区;⑤ 引擎自己键控的面(工具登记轴、子代树域、恢复 rung、MCP 连接池、workflow scope、后台代理登记、peer 目录)与记忆本版仍按人,同一个人的不同场景在这些面上互见。
910
+ **补偿**:拒句点名每一处来源,运维改名或删除那些身份后重启;停-迁-起即无混版窗(SQL 起服守卫兜底:判活窗内有 run 在心跳就不写标记);不带头的调用方零改。
911
+ **嵌入方类型面(BREAKING,零别名)**:`RequestAuth` / `AuthContext` 的身份格 `principal` → `subject`(分区键);`withPrincipal` / `currentPrincipal` → `withSubject` / `currentSubject`(另有 `currentPerson`);`verifiedPrincipal` → `verifiedPerson`;`gatedPrincipal` → `gatedSubject` / `gatedPerson`;`ScenarioGate` 多一个成员 `known()`(在册名单);品牌型 `Principal` 拆成 `Person` / `Subject`(`DurableOwnerKey` 不变)。
912
+ **持久化**:零 DDL 进中央建表语句、零行改写;起服只读扫一次 + 一行标记(本条自己建的标记表)。
913
+ **升级前做**:① 停光全部旧副本、等判活窗(`REAP_RUN_STALE_SEC`)过去,再起本版(停-迁-起,不可滚动 —— 旧副本不保留 `_scn:` 前缀);② 自查主体 / 证明里以 `_scn:` 开头的身份(拒句会点名);③ 嵌入方按上面的改名改调用点。
914
+ **回滚**:回滚前把带场景写下的行处置掉(它们的属主是 `_scn:<场景>:<人>` 复合串,上一版把它当一个独立主体读);标记行 / 标记文件留着无害(上一版不读它)。
915
+
916
+ 64. **🔴 server-as-peer 的技能声明 `A2A_SERVE_SKILLS` 只认版本化外壳 `{"version":2,"skills":[…]}`;条目可带 `audience`(这条技能发布给谁);公开卡多一位 `supportsAuthenticatedExtendedCard`,新方法 `agent/getAuthenticatedExtendedCard` 回按人过滤的扩展卡;技能选择的拒句不再回显 id(行为变更 + wire 加性;设了 `A2A_SERVE_SKILLS` 的部署升级前改值形,镜像与 env 同一次滚动)**:
917
+ 旧形:`A2A_SERVE_SKILLS` 是裸 JSON 数组 `[{id, name?, description?, scenario}, …]`;条目里写了别的键被静默丢掉;卡上的每条技能对所有调用方公开;`message/send` 点名未知 skill id 的拒句回显那个 id,选中之后被场景门等拒的拒句点名 skill id;按调用方给的方法名查方法表会命中原型链成员(`toString` 等)。
918
+ 新形:值形只有外壳 `{"version":2,"skills":[{id, name?, description?, scenario, audience?}, …]}` —— 外壳键闭集(`version` / `skills`),`version` 必须是数字 `2`;条目键闭集(写了别的键,含拼错的 `audience`,拒启);裸数组拒启,拒句给迁移句。`audience` 写了就必须是 1–64 项的验过的主体名(保留的内部标识 / 不是名字 / 超宽 ⇒ 拒启,拒句点名下标与规则、不回显值),没写 = 公开。公开卡只列公开技能;名单里的人经 `POST /v1/a2a` 的 `agent/getAuthenticatedExtendedCard` 拿到自己那份卡;点名一条没发布给自己的技能,得到与「没有这条技能」逐字节相同的 `-32602`(常量句,零 id)。公开卡与扩展卡顶层多一位 `supportsAuthenticatedExtendedCard: true`(派生自方法表,与配不配名单无关)。`toString` / `__proto__` / `constructor` 这类方法名答 `-32601`。
919
+ **迁移(运维动作,零持久化迁移)**:`A2A_SERVE_SKILLS` 的旧值(裸数组)整只放进 `{"version":2,"skills":<旧值>}`,内容不变;`audience` 只能写在外壳内。旧值的条目里若带着旧解析器容忍、被静默丢掉的多余键,新版会拒启并点名它 —— 删掉那一键。
920
+ **滚动与回滚**:镜像与 env 同在 pod 模板里一次滚动。外壳 env 遇上不认外壳的旧版:旋钮开 ⇒ 旧版整只拒启(根是对象);旋钮关 ⇒ 旧版不读这个值。回滚到不认外壳的版本时 env 一并退回裸数组,并先删掉受限条目 —— **不要**把 `audience` 写进裸数组:旧版对裸数组条目只取具名键,那条技能在旧版上是公开技能。
921
+ **发布 ≠ 授权**:`audience` 只管谁看得见、谁能按 id 点名,不管谁能跑背后的场景 —— 不带 `sema.skillId` 的消息、映射到同一场景的公开技能、原生提交族(`POST /v1/runs` / `POST /v1/tasks` / `POST /v1/tasks/stream` 体里的 `scenario`)都不经过它;受限技能不要映射到部署缺省场景,也不要与公开技能共用场景。
922
+ **谁需要**:同一台 worker 上有只该给部分调用方看见的技能(如家庭部署里的健康 / 理财技能)的部署。
923
+ **谁受伤**:① 每个设了 `A2A_SERVE_SKILLS` 的部署升级时都要改值形,不改就拒启(响亮);② 带外壳 env 回滚到旧版(旋钮开)⇒ 拒启;③ 条目带多余键 ⇒ 拒启;④ 不发主体的单用户部署:受限技能对所有 A2A 调用方都不可见;⑤ 按 v0.3 类型严格解析的第三方客户端:本卡是 sema 方言(缺 `version` / `capabilities` / `defaultInputModes` / `defaultOutputModes` / 技能 `tags` / `securitySchemes`);1.0 方言客户端调 `GetExtendedAgentCard` 得 `-32601`;⑥ 被移出 `audience` 并重启之后,重发一条已受理的消息得 `-32602` 而不是那条任务 —— 丢了首个响应的调用方拿不回句柄;⑦ 名单的强度 = 部署的身份边界:没有身份边界的部署(没接任何已验身份来源:没配服务凭据、没装鉴权桥、没开直连门;只设 trace 凭据或只开 `REQUIRE_PRINCIPAL` 不算)上写了 `audience` ⇒ 起服拒(拒句一行给两条出路:接一个已验身份来源 / 删掉 `audience`),故不存在该形;卡与技能选择只认验过的身份来源(出示服务凭据之后的主体头 / SSO 凭据 / 直连门 JWT),不出示凭据、只自报主体头的调用方读成匿名(只看公开技能);BFF 形上取决于持共享 service 凭据的调用方够不够得着 worker;⑧ 拼错技能 id 的调用方拿不到回显。
924
+ **补偿**:①② 本条迁移句同滚 / 同回滚;③ 拒句点名下标与键;④ BFF 带主体头;⑥ 已拿到 taskId 的调用方 `tasks/get` 照常;⑦ 直连门(JWT)或 SSO 凭据;⑧ 它能看的技能名单就在它拉得到的卡上。
925
+ **升级前做**:设了 `A2A_SERVE_SKILLS` 的部署按上面的迁移句改值形,与镜像同一次滚动。没设这一键或没开 `A2A_SERVE_ENABLED` 的部署零动作。
926
+ **回滚**:无持久面;env 退回裸数组(先删受限条目)再换回旧版。
927
+ 65. **🔴 受理之前被拒的提交不再留下空会话(行为变更;持久面:SQL 加一列 + 一次性迁移 M43;wire 加性:新码一只 `409 conflict.claim_lost`)**:
928
+ 一次提交铸下的会话(不带 `sessionId` 的现铸、或带一个此前不存在的 `sessionId`)只在两件事之一发生之后才活过这次提交:引擎受理了它,或这次提交把结果交给了它自己的耐久 run
929
+ (`POST /v1/runs` 的 `202`;`POST /v1/tasks/stream` 带 `x-detach-on-disconnect: true` 且 run 行已建)。否则在**终局应答发出之前**条件撤回 —— 同步腿的应答体、流的 `done` 帧到达时,
930
+ `GET /v1/sessions/:id` 与 `/head` 已答 `404`、列表里没有它。被拒提交的码与状态不变;新增一码:三条提交腿起跑之前的认领复核发现本条 run 已被死亡判决结清(收割器、观察面或认领冲突落下;认领不在别的 run 上、会话还在)⇒ `409 conflict.claim_lost`,什么都没跑(此前这一形照样起跑;会话已被删 ⇒ `404 resume.session_not_found`,认领在别的 run 上 ⇒ `409 conflict.session_active_run`;契约附录 A.1)。
931
+ **保留条件**(任一在 ⇒ 留,与 7.147.0 同):已有消息 / 会进上下文的条目;客户端写过它(标题 / 置顶、会话规则、**已成功绑定**附件;无效附件 / 空数组 / 绑定之前的拒不算);本次之外的 run;
932
+ 认领还在;执行环境已为它留下按会话键的持久物(k8s 工作区空间 / 构建缓存卷);挂接已有会话。
933
+ **持久面(SQL)**:`session_ext` 加一列 `client_writes BIGINT NOT NULL DEFAULT 0`(客户端写的次数;四个写者在锁住根行之后同一事务 +1)。存量库缺这一列 ⇒ 起服列册对账拒启 `config.schema_mismatch`,拒句给
934
+ `ALTER TABLE session_ext ADD COLUMN client_writes BIGINT NOT NULL DEFAULT 0`(PostgreSQL 同句);执行后再起服。
935
+ **混版窗(SQL)**:7.147.x 副本的写者不计数 ⇒ 撤回只在本库的启用标记落下之后才生效(一次性迁移 M43;标记表 `one_time_migration_marker` 与 M42 同一张,由迁移自建)。标记在某一次起服落下:
936
+ 标记不在 ∧ 判活窗(`REAP_RUN_STALE_SEC`)内没有 `running` run 更新过;有 ⇒ 不落、**不拒启**,下一次起服再判。所以 **全部副本换成本版之后再起一次**(或在没有 run 在跑时起本版),
937
+ 标记落下、撤回生效;在那之前幽灵会话照旧(fail-closed:留)。看不见的边如实:空闲的旧副本(零 `running` run)没有心跳 —— 标记落下之后它对一只刚铸的会话做的客户端写不计数。
938
+ **local**:会话元数据格多一位 `clientWrites`(本版铸的格都带);数据根独占、没有混跑窗,撤回升级即生效。7.147.x 及更早的严格边档读认不得这一位 ⇒ 回滚的支持形 = 恢复升级前的数据根备份。
939
+ **谁需要**:每一只会话选择器(cli `/resume`、web-admin 会话区、sdk 列表)—— 配错 `allowTools` / 图片的客户端循环重试,此前每次一条无标题零消息的会话。
940
+ **谁受伤**:① 拿到了 `meta` 帧 / `x-task-id` 的交互流(没带断连转后台)被拒后读它们答 404;② 撤回候选的 `done` 晚到「引擎收尾 + 一笔事务」—— 那笔事务要等这只会话的根行锁,别的事务长持着它时一起等(与同一会话上的 `PATCH` 同),上界是库的锁等待超时与 `DB_QUERY_TIMEOUT_MS`(PG 池级 `statement_timeout`;不设则 PG 上不封顶),不另设期限;③ 同一只自选 id 上恰落在撤回窗里的并发提交者偶得
941
+ `404 resume.session_not_found`(可重试、零起);④ 运维失去「空行 = 有人被拒过」的痕迹。
942
+ **补偿**:新指标 `submission_exit_total{end, verdict}`(`verdict` = `withdrawn` | `kept_<词>`,`kept_upgrade_pending` = 标记还没落)+ 既有拒因日志;撤回抛 ⇒ 留 + fail-open 标签 `server.submission-exit.withdraw-failed`。无旋钮。
943
+ **升级前做**:SQL 部署执行上面那一句 `ALTER`(或先起一次本版读拒句);滚动升级完成后再起一次任一副本让标记落下。local / memory 零动作。
944
+ **删码点**:M43 的窗(`plugins/one-time-migrations.ts` 登记表)关闭之后的第一个 minor 删 M43 那一步与撤回判据里读标记的那一句(撤回无条件启用);标记行不再被读(标记表与 M42 同一张,留着无害)。删码之后跳版直升的库从第一次起服就启用撤回。
945
+ **回滚**:SQL:7.147.x 的起服列册对账见到多出的 `client_writes` 列按「库比本构建新」拒启 —— 出路是持有这一列的树;真要回到 7.147.x,先 `ALTER TABLE session_ext DROP COLUMN client_writes`(两方言同句)。多出的标记表 7.147.x 不读。local:见上。
946
+ 66. **请求形的拒先于授权器与执行上下文答,不再先铸会话(拒序变化;码 · 句 · 状态 · 机读位零变化;零 DDL;部署零动作)**:
947
+ 旧形:MCP / A2A 条目判官、`images`、工具名清单读成空、`inheritEnv:"all"` 的车道与射程、场景头 × 体冲突、`attachmentIds` 形、写容纳面 422、`settings.permissions` 三桶与 `neverAuto` 里不靠任务根的规则拒 422、体点名的 `sandboxImageProfile` × 非 k8s 车道 501、`/v1/tasks/stream` 的 verify / cascade 与 `x-detach-on-disconnect` 缺耐久账本、`/v1/runs` 无键提交的坏 `taskId` —— 在授权器登记会话、执行上下文解析之后才答,铸下的会话由上一条的条件撤回删掉。
948
+ 新形:这一批在授权器之前答(会话店零写)。一条请求同时撞上它们与留在铸点之后的拒(授权器 401 / 404、执行上下文、装配器的运维锁 `config.locked_key` / 场景门 / 模型名单 / 附件店 / 要任务根的规则条目 / 镜像索引、并发帽 429)时,答请求形那一只;`/v1/runs` 无键提交的坏 `taskId` 在体的其余值形门之前(与带键提交同位)。请求形之间的先后不变。运维锁 `mcp` / `a2a`、模型名单 / 不可用条目照旧在铸点之后。
949
+ **谁受伤**:按「同时坏两处时先得到哪一只码」写判定的客户端。**出路**:按码分别处置的客户端零改;要先拿到授权器的判(401 / 404)就先修请求形。
950
+
951
+ 67. **🔴 409 `conflict.session_active_run` 体与 `POST /v1/tasks/stream` 冲突 `done` 帧删 `stale` 键;心跳过期的 run 在第一次被读到 / 被新提交撞上时当场判死;run 的 `errorCode` 只读码列(BREAKING:删 wire 键;行为变更;wire 加性:死亡终帧带 `errorCode`、中止成因一词 `stall_verdict`;持久面:一次性迁移 M44,零 DDL)**:
952
+ **删了什么(BREAKING,零别名)**:409 `conflict.session_active_run` 体与 `POST /v1/tasks/stream` 冲突 `done` 帧 `result` 上的 `stale`(7.37.0 起的加性位:持有者心跳过期时为 `true`)。
953
+ **改读什么**:409 体此后只点名活着的持有者 —— 新提交撞上心跳过期(`updated_at` 早于 `REAP_RUN_STALE_SEC`)的持有者时,server 先把它判死、放掉认领、再认领一次,这次提交照常受理;
954
+ 所以 409 体上的 `activeTaskStatus:"running"` 就是行上存着的状态。要判「那条 run 死了没」读 `GET /v1/runs/{activeTaskId}` 的 `status` + `errorCode`(`run.stalled` / `run.orphaned` = 持有者死亡判决)+ `heldBy`。
955
+ 类型面按键删(消费方编译红即通知)。残窗(如实):持有者恰在认领冲突与组 409 体之间到期 ⇒ 体答 `running`;读一眼持有者或重发即成功。
956
+ **「死了没」只看 run 行(行为变更)**:死亡判决(`failed` + `errorCode:"run.stalled"` + `error:"run stalled (instance lost?)"` + 放认领,与收割器同一句)落在三处:收割器;
957
+ 观察面(过了属主门、把 run 的状态答给调用方的读口:`GET /v1/runs/:id`、`GET /v1/runs?idempotencyKey=`、`GET /v1/runs/:id/events`、`GET /v1/tasks/:id/stream`、四只句柄读腿、A2A `tasks/get` 与 `message/send` 的等待、两种同键重放);认领冲突。
958
+ ⇒ ① 死 run 上 `heldBy: null`(此前收割之前给失联副本的 id);② 判死之后不再翻回 `running`;③ 同键异步重放(`POST /v1/runs` 202)答 `status:"failed"`(此前 `running`);
959
+ ④ 句柄读腿答 `not_found.task_owner_settled`(此前 `task_owner_elsewhere`);⑤ 认领门(会话删除、会话同步导入、放置 / 设备门……)不判存活:持有者心跳过期而还没被观察、也还没被收割时仍 409 —— 读一眼持有者(`GET /v1/runs/{activeTaskId}`)即放开,再重发。
960
+ 判决写失败(库一时不通 / 锁超时)⇒ 这一次按行原样答(仍是 `running`)、计 F 类 fail-open `server.run-store.stall-verdict-unlanded`,收割器下一拍补;`runs_reaped_total{kind:"stale"}` 计三处落下的全部判决。
961
+ **死亡终帧带 `errorCode`(wire 加性)**:`GET /v1/runs/:id/events` 的死亡帧 `event: failed` `{type:"failed", errorMessage, errorCode}`(码 = 行上的码);trace 流 `event: error` `{type:"error", errorCode:"WORKER_DOWN", message:<行的 error>}`。
962
+ 两帧都从行合成,本连接投过账本终帧(`done` / `failed`)就不合成;收割之后才连上的流也收到它。消费端为「流断了没终帧」自己合成 `failed` 的兜底可以保留(断线 / 超时仍要它)。
963
+ **中止成因新词 `stall_verdict`(wire 加性)**:被判死的 run,原执行者的下一次心跳读到「行已不在跑」⇒ 中止自己的腿;那条腿自己铸的取消终局带 `result.abortCause: "stall_verdict"`(`errorCode` 仍是 `cancelled`)。
964
+ run 行上是那份死亡判决(`run.stalled`),`GET /v1/runs/:id` 读不到这个词。按闭集 `switch` 读 `abortCause` 的消费方加一臂;认不得的词按「server 中止,成因不认识」读。
965
+ **一次性迁移 M44(run 的 `errorCode` 只读码列;零 DDL)**:`errorCode` 的唯一读法是码列(SQL `task_run.error_code`;local:run 行的 `errorCode`)。写结果的三个写口同写这一列(`needs_review` 停驻写 `review.pending` —— 此前只在结果里),
966
+ 续跑认领清列。起服时(任何读者之前)改写存量行一次:带结果的非 `running` 行,码列改成结果投影的码(两代结果形同读、折码;结果无码则留原值);`running` 行带码的置空。
967
+ SQL 按 `task_id` 键集分批读,不等才写,按行版本(`status` + `updated_at` + 列原值)CAS,打空跳过、下一次起服再判;结果读不出的行跳过。窗内每次起服都跑,第二次起零命中。
968
+ 读数键 `runErrorCodeColumnRewritten`(起服迁移读数行;非零 = 真改写了存量行)。**窗** = 本版发布日 + 30 天(与停驻行终局兜底 `APPROVAL_TERMINAL_BACKSTOP_MS` 的缺省同长;窗口见 `plugins/one-time-migrations.ts` 登记表)。
969
+ 窗内 SQL 的读侧只对停驻行补读:列空的 `suspended` / `needs_review` 行读结果投影的码,`running` 行只答空 —— 滚动升级中更早版本的副本写下的不带列的停驻也读得对。窗关之后第一个 minor 删改写、读侧与读数键。
970
+ **改写之后变了的(如实)**:`GET /v1/runs/:id` 的 `errorCode` 前后不变;码列的其它读者对旧行随之改口、与 `GET` 对齐 —— 例:结果码 `cancelled`、列空的旧行,A2A 由 `failed` 改答 `canceled`,审批对账走取消分支(此前按非取消处理)。
971
+ **更长的停驻兜底(如实)**:调长了 `APPROVAL_TERMINAL_BACKSTOP_MS`(> 30 天)的部署,窗关时还可能有更早版本写下、没结清的停驻:删码之后那些行的 `errorCode` 缺席(`review.pending` 仍在结果里)。
972
+ 跳过本版直接升上来的库同此(旧行按列答:缺席或没折过的原码;`result.terminal.code` 仍在结果里)。出路 = 升级时先过一次本版并起服。
973
+ **`DB_BACKEND=local` 的认领接管(行为变更)**:接管一条「停驻无可续」的 `needs_review` 行之后答 `failed`、无码、`result: null`(此前 `failed` + `review.pending` + 停驻结果)。
974
+ **谁需要**:异步提交的调用方(sdk 轮询、壳断线重连)在副本崩掉之后要一个稳定终局;在同一只会话上重新提交的人;A2A 对端;看 `heldBy` 的运维。
975
+ **谁受伤**:① 读 409 `stale` 的客户端(键没了);② 活着而心跳停了一个判活窗的 run:此前只有收割器某一拍恰好落在那段时间里才判死,现在那段时间里任何一次观察都会判死它,判死后回不来,执行者随之停下;
976
+ ③ 读口会写(一次读碰到到期行写一笔 CAS);④ 升级时整表扫一遍带结果的 run 行。
977
+ **补偿**:旋钮 `REAP_RUN_STALE_SEC`(已有;起服与热发布都拒不大于心跳周期的值);CAS 条件里带心跳,先落下的心跳赢;被判死的执行者自停,不与新提交同写一只会话;只有过了属主门的观察才判;写失败按行原样答 + 收割器补。
978
+ **升级前做**:读 409 `stale` 的客户端改读 `GET /v1/runs/{activeTaskId}`;按闭集读 `abortCause` 的客户端加 `stall_verdict` 一臂。部署零动作(零 DDL、零新旋钮;起服多一次整表扫)。
979
+ **回滚**:零 DDL。改写过的码列与本版写下的停驻列对 7.147.x 无害(它先读结果里的码)—— 例外:7.147.x 续跑认领不清列,它续跑本版写下的 `needs_review` 停驻之后,在跑期间 `GET` 答 `errorCode:"review.pending"`,到终局被覆盖。
980
+ 68. **会话列表预览两后端同读 run 行的预览列 —— `GET /v1/sessions` 行的 `objectivePreview` 是这只会话最近一条预览非空的 run 的那一句;`?q=` 两后端都搜任一 run 的这一列;一次性迁移 M45 剥净以注入块起头的旧预览(行为变更;wire 键 / 型不变、读数变;持久面:一次性迁移 M45,零 DDL;部署零动作)**:
981
+ 旧形:一个问题两个读者。SQL 后端读最近一条 run 行的预览列(那条 run 的提示里没有用户正文 ⇒ 列是空串 ⇒ 行答 `null`);`DB_BACKEND=local` 从会话条目现算 —— 往回找最近一条用户消息,截 200 字,
982
+ 引擎包好的 steer 说明句(`The user sent a new message while you were working:` 起头)与 prompt 屏改写之后的文本也算,零 run 的会话(fork / 导入 / 同步来的)也有预览;`?q=` 在 SQL 上搜任一 run 的列,在 local 上只搜合成的那一句。
983
+ 新形:一条律 —— 预览 = 这只会话的 run 行里按建行序(`created_at` 降序、同刻按 `task_id` 降序)最近一条「预览列按字符长度非空」的那一列;没有 ⇒ `null`(含零 run 的会话)。
984
+ `?q=`(trim 之后非空)命中 ⟺ 这只会话有一条 run 的预览列含 q(大小写不敏感、按字面)。两后端读同一列、同一条谓词;`lastRunId` / `lastStatus` 仍取最新一条 run(与预览解耦)。
985
+ 列由提交建行时写下(剥注入块 → 脱敏 → 截约 120 字;装 prompt 屏的腿在引擎交付目标之后补写),与 `GET /v1/tasks` 等面读的是同一列。
986
+ **变了的(如实)**:SQL —— 最近一条 run 的提示只有注入块 / 回显块的会话,预览从 `null` 变成更早一条 run 的那一句。`DB_BACKEND=local` —— 零 run 的会话 `null`(此前是转录里的最近一句);预览截 120 字(此前 200);
987
+ steer 包装句与屏后文本不再进预览与搜索;`?q=` 能搜到更早 run 的词,搜不到零 run 会话的转录;存档头读不出的会话行(带 `unreadable`)照出 run 行的预览(此前 `null`)。只有空格的旧值算有预览(两后端同)。
988
+ **一次性迁移 M45(以注入块起头的旧预览;零 DDL)**:较早版本写下的 run 预览没有剥注入块,引擎前置的块(`<system-reminder …>…`)原样落在列的开头 —— SQL 的各读列面今天就显示它们,local 的会话列表改读列之后也会。
989
+ 起服时(任何读者之前)两后端各扫一遍:列值以闭集注入块的开标签起头的行,新值 = 对列值反复取今天的预览写法(剥块 → 脱敏 → 截 120)到不动点;不动点仍以开标签起头(开标签本身被 120 字截断)⇒ 空串。
990
+ SQL 按十四个标签前缀 `LIKE '<tag%'` 粗筛、进程内精判,按 `task_id` 键集分批(每页 500 行),按列原值 CAS,打空跳过、下一次起服再判;`DB_BACKEND=local` 内存里逐行算、改的行落盘。窗内每次起服都跑,第二次起零命中。
991
+ 读数键 `runObjectivePreviewRewritten`(起服迁移读数行;非零 = 真改写了存量行)。**窗** = 本版发布日 + 30 天(窗口见 `plugins/one-time-migrations.ts` 登记表);窗关之后第一个 minor 删改写与读数键。
992
+ **改写之后变了的(如实)**:块在 120 字之内闭合 ⇒ 剩用户正文;块被截断(多数旧值是这一形:引擎前置的块通常比 120 字长)⇒ 列变空串 ⇒ 会话列表回落到更早一条 run 的那一句(没有就 `null`),
993
+ `GET /v1/tasks` 等读列面上那一行的预览键缺席。用户自己在提示开头写了闭集开标签字面的行同样被剥(与正文里写开标签字面的那一段被剥同向)。
994
+ **认不出、不迁(披露)**:较早版本在装 prompt 屏的腿上建的 run,列里是屏判之前的原文 —— 行上没有「当时有屏」的记号,迁移认不出;此后 local 的会话列表也显示它(属主本人写的那句;列表的属主门不变)。
995
+ 跳过本版直接升上来的库,以注入块起头的旧预览照旧显示;出路 = 升级时先过一次本版并起服。
996
+ **谁需要**:同一只会话在 SQL 与 local 上该看到同一句预览、同一组搜索结果的壳与控制台(会话选择器、最近会话面);升级到 local 的单机用户。
997
+ **谁受伤**:① local 上靠预览认 fork / 导入会话的人(零 run ⇒ `null`;标题与会话视图照旧);② 想按 steer 文本或屏后文本搜会话的人;③ 7.124.0 之前那批旧会话的预览多数变空、回落到更早一句或 `null`;④ 起服多一遍粗筛扫。
998
+ **补偿**:会话标题(`title`)与会话视图不受影响;迁移窗关即删。不提供「回到旧读法」的旋钮(那就是第二个读者)。
999
+ **升级前做**:无(零 DDL、零新旋钮)。按 `objectivePreview` 渲染会话列表的壳不需要改码 —— 键与型不变,`null` 本来就是合法值。
1000
+ **回滚**:零 DDL。改写过的预览列对 7.147.x 无害(各读列面读到剥净后的那一句或缺席;7.147.x 的 local 会话列表不读列);回到 7.147.x 即回到两种读法。
1001
+
1002
+ 69. **🔴 嵌入方:只交 run 店的 `createHttpServer` 嵌入,`GET /v1/sessions` 改答 501;三只 run 店的 `listSessions` 删(嵌入方类型面 BREAKING;服务进程部署零动作)**:
1003
+ 删了什么(零别名):run 店(SQL / 内存 / 文件三只)身上的 `listSessions` 会话聚合,以及会话列表路由与能力事实「会话店不能列就读 run 店」的兜底。「有哪些会话」只有一只 lister —— 会话店的 `listSessions`。
1004
+ **改读什么**:自建 `createHttpServer`、只交 `runStore`、`sessionStorage` 缺席或没有 `listSessions` 的嵌入,`GET /v1/sessions` 答 501 `capability.session_store_required`(与「会话店缺席」的既有形同),
1005
+ `GET /v1/capabilities` 的 `sessionList` / `sessionSearch` 为假。类型面:`RunStore` 上不再有 `listSessions`(调它的嵌入方编译红即通知)。
1006
+ **出路**:交一只带 `listSessions` 的会话店(`sessionStorage`);本服务自己的三种后端都交,服务进程部署零动作。
1007
+ **谁需要**:无 —— 本条是删第二个读者(run 店的聚合按旧律出预览)。**谁受伤**:只交 run 店的自建嵌入(本服务没有这种部署形;会话店是起服必需)。**补偿**:见出路。
1008
+ **升级前做**:自建嵌入核一遍交给 `createHttpServer` 的依赖里有没有带 `listSessions` 的会话店。**回滚**:回到上一版,run 店的聚合回来;零持久面变更。
1009
+
1010
+ 70. **调度者出身词 `runOrigin`(引擎 7.58.0 起的归因位)四面同投:`GET /v1/assistant/inbox` 行、`human_input` 帧、`wiring_manifest.leg`、会话读面的 `user` 消息都把引擎记下的这个词逐字带过去;本服务自己不铸它;部署里另有铸词方时有升级序(行为修复 + wire 加性:三个面各多一个可选键、`differs` 词集多一词;零新码;部署零动作)**:
1011
+ 旧形:会话读面按「用户行每个键逐字」带着它;帧登记表、清单 `leg` 段、inbox 白名单三处各自记成「不投」。引擎一旦记下这个词(嵌入方自带的 `resolveSpec` 铸词;导入进来的会话里引擎的导入门保留的 `UserMessage.runOrigin`),读帧 / 清单 / inbox 的客户端把调度者交来的输入读成人敲的。
1012
+ 新形:一条规则 —— 引擎铸的、只作归因的闭集词,引擎报它的每一面本服务逐字带过去(成员判用引擎的 `isRunOrigin`;集外词在帧与清单上丢这一位并计一次;缺席 ⇒ 缺席,从不补一个词,也从不读成「人发的」)。`human_input.runOrigin` · `wiring_manifest.leg.runOrigin`(租户帧与 operator 帧同投)· inbox 行 `runOrigin` 三个可选键;
1013
+ 409 `steering.duplicate_input_id` 体的 `differs` 词集随引擎多一词 `runOrigin`(本服务读引擎活常量,原本就认;契约句同步)。
1014
+ **本服务不铸词**:铸词点只能是部署自己的调度器触发路径(引擎的信任契约:不从请求体直通);本服务只有调度店的写侧,到点触发的 daemon 在仓外,没有「调度器触发出一个 spec」的路径可盖词。所以:请求体带 `runOrigin`(提交口与三个送话口)⇒ 400 `request.body_shape`(与任何词表外键同一只门,上一版同);
1015
+ 装配出的 spec(fresh / resume)与续跑配置不带它(引擎:续跑配置带词即拒 `config.run_origin_invalid`,本服务的续跑配置触不到这一拒)。要在本服务上盖词,得先有一条可信的触发路径(设计件),不在本版。
1016
+ **谁需要**:渲染 `human_input` 帧 / inbox / 会话的壳(cli · client-core · web-client)—— 把调度者的输入渲成调度者的;读审计面的运维。**谁受伤**:严格按键白名单解析这三个面的消费方(多一个可选键,只在引擎记了词时在场);按 `differs` 全集穷举分支的客户端(多一词)。**补偿**:无旋钮;键缺席是常态,读成「宿主没说话」;未知键忽略。
1017
+ **升级前做**:无。
1018
+ **混版升级序(只在有人铸词时才有)**:只跑本服务的部署上没有带词的停驻行 / 带词的 steer / 带词的唤醒,混版窗零影响;本版读旧副本写下的行 / 帧 / 清单 = 没有词 ⇒ 四面缺席,与上一版逐字同。部署里另有铸词方(嵌入方自带 `resolveSpec`;与本服务共用检查点库的仓外调度 daemon)时,引擎 7.58.0 给的序是 —— **先把全部 worker 与店适配器升到引擎 ≥ 7.58.0(本版引擎 7.66.0),再让铸词方开始铸词**。引擎的话:引擎 < 7.58.0 的 worker 把带词的停驻行读成「格式比本引擎新」
1019
+ (本服务把它答成 409 `checkpoint.unsupported_version`、`retriable: true`、行留 pending,体带 `writerVersion` / `readerVersion`,换成新 worker 再决),对带词的唤醒消息或 `setPendingSteer` 在认领之前拒(未知的转向字段);旧 worker 认领新宿主停驻的带词 steer、又在投递前重停它时,旧 worker 自己的写口会拒这条目 —— **那条指令丢**。
1020
+ **回滚**:回到上一版:三个面少一个可选键;无持久面变更(本服务没有写下任何带这个词的字节)。
1021
+
1022
+ 71. **🔴 `LSP_ENABLED` 退役:设了它(任一值)的部署起服拒 `config.env_key_retired`;沙箱车道的 LSP 桥与它的四族指标删除(BREAKING,部署;每条车道的挂载与上一版逐格同;wire 行为零变化;部署动作:撤掉 `LSP_ENABLED`)**:
1023
+ 旧形:e2b / k8s 设 `LSP_ENABLED=true` 照常起服并打一行 `lsp_not_mounted`(7.127.0 起这两条车道本来就不挂 LSP:引擎只读执行环境绑定持有的对象,沙箱两车道不实现绑定读);
1024
+ `LSP_ENABLED=false` 拒启,但拒句是本服务另铸的一句、不带墓碑码;`/metrics` 恒出 `lsp_bridge_start_total` / `lsp_bridge_dead_total` / `lsp_session_open_total` / `lsp_session_heal_total` 四族(只有 HELP / TYPE,零样本)。
1025
+ 新形:`LSP_ENABLED` 是 settings-schema 墓碑表的一行(族 `removed`):在场即拒启,`true` / `false` 同码同句,拒句点名 host 车道的开关 `LSP_HOST_ENABLED`;空串 = 未设,照常起服。
1026
+ 配置目录 `GET /v1/config/catalog` 的 `retired[]` 多一条 `{ name: "LSP_ENABLED", kind: "removed", reason }`、`rows[]` 少这一行;起服行 `lsp_not_mounted` 没了;`/metrics` 少上面四族。
1027
+ **挂载律不变,只是收成一处**:本机语言服务器只在 host 车道、未设 `REQUIRE_PRINCIPAL=true` 时按 `LSP_HOST_ENABLED`(缺省开)挂,其余车道一律不挂 —— 与上一版逐格同;服务入口与 `run-local` 读同一只铸点。`wiring_manifest.lsp` 的形与在场律不变。
1028
+ **做法**:撤掉 `LSP_ENABLED`(e2b / k8s 上本来就没有 LSP,撤掉之后行为零变化);要关 host 车道的语言服务器用 `LSP_HOST_ENABLED=false`。抓 `/metrics` 的面板删掉那四族(它们自 7.127.0 起恒零)。
1029
+ 运维面:e2b 模板月度重烤的缺省名单去掉 `ai-agent-code-lsp`(不再维护,用 `dev-base`);三只模板的 verify 只证语言服务器在场(`command -v` + 版本读数),不再跑桥。
1030
+ **谁需要**:读配置的人 —— 一个开了也什么都不挂的旋钮被换成一句真话(这两条车道没有 LSP);维护者 —— 挂载判据只剩一处。
1031
+ **谁受伤**:① 设了 `LSP_ENABLED`(任一值)的部署升级后起服拒(此前 `true` 只换来一行告警);② 想在沙箱车道上要代码导航的人 —— 桥只在版本史里,回来要先有沙箱车道的绑定读,再另做设计;③ 抓那四族指标的面板。
1032
+ **补偿**:拒句由墓碑表铸、点名旋钮与出路;本条;没有过渡窗。
1033
+ **回滚**:回到上一版:`LSP_ENABLED` 重新被读(`true` 起服带一行告警、`false` 拒启);无持久面变更。
1034
+
1035
+ 72. **场景技能范围:内建 `code` 场景按自己的名字过滤部署技能 —— 只标了 `scenarios: code` 的技能开始进 `code` 的 run 与卡,只写 `scenarios: default` 的技能不再漏进 `code`(行为修复;wire 键 / 型 / 码零变化、读数变;零 DDL、零新旋钮;部署动作:靠 `code` 场景拿到 `default` 技能的部署,升级前在那些技能的原标签之外追加 `code`)**:
1036
+ 旧形:技能范围从一张表读,`code` 一行是 `default`(`code` 与 `default` 共用一只场景工厂,技能范围跟着借走)—— 只标了 `scenarios: code` 的技能,`code` 与 `default` 的 run 与卡上都没有(标签里另有别的场景名的,只进那些场景);只写 `scenarios: default` 的技能同时进 `default` 与 `code`。
1037
+ 新形:每个内建场景的技能范围就是它自己的名字:只标 `code` 的技能进 `code`(出厂缺省场景:`DEFAULT_SCENARIO` 缺省 `code`、无中心指派时,不带 `scenario` 的请求落在这里)、不进 `default`;只写 `default` 的技能进 `default`、不进 `code`;无标签的全局技能与 `scenarios: code, default` 两边都进。
1038
+ 进 run 的技能、场景卡 `GET /v1/capabilities/scenarios/<name>` 的 `skills`、提交体 `userInvokedSkills` 的点名门读同一个范围,三处同步变。三条来路(`SKILLS_DIR` / 配置源 `config.d/skills.json` 或中心 skills 域 / 插件)同一条律。随包出厂技能不受影响(只有 `code-review` 打了场景标签,标的是 `code-review`)。
1039
+ **谁需要**:想让技能只在编码场景出现、只标了 `scenarios: code` 的人;按场景分流技能的部署。
1040
+ **谁受伤**:靠「只写 `default` 的技能漏进 `code`」拿到技能的部署 —— 升级后落在 `code` 的请求(不带 `scenario` 且无中心指派、`DEFAULT_SCENARIO` 缺省,或显式 `scenario:"code"`)不再装这些技能,点名它们 400 `config.user_invoked_skill_unknown`;只标了 `code` 的技能开始出现在 `code` 的 run 里(占技能清单与上下文)。
1041
+ **补偿**:不提供「回到旧读法」旋钮(那就是第二个读者);技能自己的 `scenarios` 标签就是出路(下条)。
1042
+ **升级前做**:列出部署里所有 `scenarios` 含 `default` 的技能(出厂目录的 `scenarios:` 行、`config.d/skills.json` 或中心 skills 域条目的 `scenarios`、插件技能的 frontmatter),逐条判断它要不要继续出现在 `code` 的 run 里:要 ⇒ 在**原标签之外追加** `code`(`default` → `default, code`;`default, scan` → `default, scan, code` —— 不要覆盖原有场景名,否则它会离开那些场景),或去掉 `scenarios` 变全局技能(那就进所有场景);不要 ⇒ 不动。
1043
+ 同时列出含 `code` 的技能:升级后它们开始进 `code` 的 run(此前只标了 `code` 的哪个内建场景都没进;标了 `code, cowork` 这类多标签的此前已进 `cowork`),确认这正是你写它时的意图。配置源 / 插件的改动按各自的「重启生效」走(`/health` 的 `restart.reasons` 含 `skills`)。
1044
+ **回滚**:回到上一版即回到旧读法;零持久面变更。
1045
+ 73. **`DB_BACKEND=local`:`run-local` 与 HTTP 服务共用一个数据根时,同一只会话在两条入口上是同一位住客;一次性迁移 M47(无格会话收进行、沿用存档里的令牌);跳过 M47 的数据根拒启(行为修复;持久面一次性迁移,零 DDL;部署零动作)**
1046
+ 旧形:一个数据根两只会话行店。HTTP 服务的 local 臂读会话元数据边档(`session-incarnations.json`)那一格的化身;`run-local` 经引擎的裸会话店读会话存档头上引擎另铸的那只令牌(两只恒不等,HTTP 每整段换装一次存档头还换代)。
1047
+ 同一只会话在两条入口上是两位住客:一条入口上落下的记忆记录(`memory.capture:"off"` 的采集 opt-out、外部内容带来的污染标记)在另一条入口上不绑;`run-local` 新建的会话没有元数据格,不过引擎版本高水位与起服对账。
1048
+ 新形:`run-local` 与 HTTP 服务的 local 臂经同一只打开函数打开数据根(取锁 → 引擎版本高水位的判与抬 → 本服务的店 → 起服对账 → 一次性迁移 → 才读会话);住客只有一处存放(那一格)。
1049
+ **一次性迁移 M47(只 `DB_BACKEND=local`;零 DDL)**:升级后第一次起动(HTTP 服务或 `run-local`)给「存档在、会话元数据格缺」的会话建一格 —— 化身 = 存档头上的令牌(较早 `run-local` 的记忆记录绑的那一位;头里没有令牌 ⇒ 新铸),
1050
+ 建档时刻 / fork 谱系取自存档头,属主不写(从没被记下)。已有格的会话一个字节不动。在起服对账段里跑、先于其余一次性迁移;一次边档提交;第二次起零命中。读数键 `localArchiveTokensAdopted` / `localArchiveTokensMinted`(起服迁移读数行;非零 = 真写了存量行)。
1051
+ **窗** = 本版发布日 + 30 天(窗口见 `plugins/one-time-migrations.ts` 登记表);窗关之后第一个 minor 删迁移体与读数键。SQL 两后端没有存档头,读数恒 0。
1052
+ **第一次起动被打断(收令牌欠账)**:引擎版本高水位在打开数据根那一刻就抬(先于 M47)。所以带 M47 的版本打开这只根时(高水位之前早于 7.148.0 或缺席、会话存档目录里有存档),
1053
+ 在抬之前先在数据根顶层写一只 `archive-token-adoption.pending`(本服务内部的欠账记录,不是契约,宿主不读);M47 收齐、并按跳版拒启臂同一读法证明没有漏收之后才删它。
1054
+ 第一次 7.148.x 起动被打断(进程被杀、M47 的写失败、嵌入方不调 `ensureSchema()`、会话目录列不出 ……)⇒ 它留着,下一次窗内起服重来;**收完之前,不带 M47 的版本拒开这只根**。
1055
+ 标记在而根里已没有「存档在、格缺」的会话(收齐之后、删之前停了)⇒ 无事可收:打开它的任何版本在抬高水位之前删掉它、照起。
1056
+ 起动时会话存档目录读不出 ⇒ 带 M47 的版本打开即拒(不抬高水位)。
1057
+ M47 收不了的两类不挡销账:委派子代的转录(placed)、存档头读不出的会话(每只一行 warn `archive_token_adoption_skipped` 点名)—— 后者若到窗关之后才读得出,第一次读新铸令牌,那只会话的旧 `run-local` 记忆记录失绑(只响一行引擎事件)。
1058
+ 窗内按 id 打开、登记一只还没格的旧会话(不调 `ensureSchema()` 的嵌入方也一样)同样沿用存档头令牌 —— 长第一格只有这一条规则。
1059
+ **跳版拒启(常设,不随 M47 删)**:起动的版本已不带 M47,数据根里有「存档在、格缺」的会话,而打开之前的引擎高水位早于 7.148.0 或缺席,或 `archive-token-adoption.pending` 还在 ⇒ 起服拒 `config.schema_mismatch`
1060
+ (`findings` 一段 `problem: "skipped-required-migration"`,带 `skippedMigration: { highWater, requiredSince, sessions }`;拒句点名会话数与版本;标记还在的那一种说「没收完」并点名标记文件)。拒在高水位抬之前、本服务零写(引擎内核取锁时自己的收拢除外,见 USAGE 高水位一节的「残余」):
1061
+ 出路 = 先用一个仍带 M47、不低于 7.148.0 且不低于拒句里已记高水位的版本(HTTP 服务或 `run-local`)对这只根**完整**起一次(起服迁移读数行出现、`archive-token-adoption.pending` 不在),再起新版。
1062
+ 带 M47 的版本不判这一道。拒句的闭集出路多一条(四条)。
1063
+ **变了的(如实)**:① 已有元数据格、升级前 `run-local` 在存档令牌下落过记忆记录的会话(含 7.141.0 起 HTTP 服务起服时给 `run-local` 建的会话补过格的那些)——
1064
+ 那些记录升级后在 `run-local` 上也不再生效(它们在 HTTP 上从来不生效):引擎每只实例每会话只响一行 `memory.session_incarnation_mismatch`(不分记录类别,第一条被判作另一位住客的记录响;`run-local` 每跑一次即一只实例;令牌只留前 8 位);
1065
+ 其余静默,但那时 HTTP 上的同类记录照旧生效。需要时在那只会话上重提一次 `memory.capture:"off"`;污染标记没有可重提的用户动词。
1066
+ ② `run-local` 起动多跑一遍起服对账与一次性迁移(升级后第一次慢一截);HTTP 服务拒启的数据根(会话元数据读不出、残留迁移快照、引擎高水位高于本构建、跳版)现在也挡住 `run-local`(一行 + 退 2)。
1067
+ ③ `run-local` 写引擎版本高水位:此后比它旧的 HTTP 服务拒开这只根(与升级 HTTP 服务同一事实)。④ 会话同步导入落在「不在」的会话上时,不再读存档头当期望行:读间被抢建的存档答 `conflict`、零写。
1068
+ **谁需要**:同一数据根上既起 HTTP 服务又用 `run-local` 的单机用户。**谁受伤**:见「变了的」①②。**补偿**:重提一次 opt-out;拒句自带出路。不设旋钮(住客只有一种读法)。
1069
+ **升级前做**:备份数据根(回滚的唯一支持形)。部署零动作(零 DDL、零新旋钮)。
1070
+ **回滚**:比本版旧的 HTTP 服务本来就拒开升级过的根(引擎版本高水位)。较早的 `run-local` 不读高水位、仍开得了它,但它读存档头令牌 —— 升级后新写的记忆记录它读不全,
1071
+ 升级前那类旧会话与今天同病;**升级后不要再用较早的 `run-local` 打开这只根**,要回滚就恢复升级前的数据根备份。
1072
+
1073
+ 74. **`run_workflow` 问句门读会话豁免店改走与部署名单门同一只读口;一次性迁移 M46 删存量的引擎家 `Skill` 会话豁免行(行为收紧;wire 零新键、零新码;持久面:一次性迁移 M46,零 DDL;部署零动作,按旧事件名告警的运维有动作)**:
1074
+ 旧形:会话豁免店有两种读法。部署名单门与审批席读它是 2 s 有界、答 `true` 才算命中、读失败照问,命中的审计行是 `approval_exempted`;`run_workflow` 问句门在装配点自包一只读口 —— 无期限、真值判、审计事件名 `workflow_gate_exempted`。
1075
+ 店读黑洞化的那一次(连接被吞、池饿死)`Workflow` 调用永久悬挂;店答非布尔真值照样放行。另有一类存量行:更早版本(7.116.0 之前)为带摘要的 `Skill` 卡与点名 `Skill` 的名单问落下的 `(会话, "Skill")` 豁免行,
1076
+ 今天它代答「不绑授予」的同名调用 —— 引擎说无技能时不挂自己的 `Skill`,同名调用是部署自挂的**另一只工具**,当年批的是「激活某技能」,代答的却是这只工具的调用(扩权,不是子集)。
1077
+ 新形:读口一只铸点。名单门与 `run_workflow` 问句门经同一只读口:期限 2 s、判 `=== true`、读失败 / 超时 ⇒ 照问并 warn `session_grant_read_failed`(字段 `seat`:`deployment_list` / `workflow_gate`)、命中 ⇒ 一行 info `approval_exempted`(字段 `seat`)。
1078
+ 事件 `workflow_gate_exempted` 退役。存量 `Skill` 行由一次性迁移 M46 删;读者一字不改,没有新列、没有按时间分流的读侧臂。
1079
+ **一次性迁移 M46(存量的引擎家 `Skill` 豁免行;零 DDL)**:起服时(任何读者之前)删 `tool_name` = 引擎 `Skill` 工具名、首次放行(`created_at`)早于 T0 的行;**T0 = 本库第一次跑本步的时刻,先于删除落进标记**
1080
+ (SQL:标记表 `one_time_migration_marker` 的 `M46` 行,与 M42 / M43 同一张;`DB_BACKEND=local`:数据根里的 `one-time-migration-M46.marker`(正文 = T0 的 ISO 时刻)),不按日历截(各部署升级日不同,日历截点会漏掉跳版直升的库里升级前几天写下的行)。
1081
+ 第一次删升级前就在的全部 `Skill` 行 —— 不管哪一版写的:7.138.0–7.147.x 写下的合法行(部署自挂 `Skill`、无技能、「本会话放行」)一并删,方向 = 那些会话的人下一次 `Skill` 调用被问一次;之后各跑零命中、不碰本版自己写下的新行。
1082
+ SQL:`session_id` 键集分批(每页 500 个会话),一页一句 `DELETE … IN`(删句自带 T0 谓词,读与删之间被撤销又重新放行的行不删);被打断 ⇒ 下一次起服读同一个 T0 接着删。`DB_BACKEND=local`:对命中行逐会话追加墓碑(与按名撤销同形),日志已判坏的会话不碰;标记文件在而读不出(手改坏了)⇒ 起服拒并点名文件,删掉它再起(本步取新的 T0)。
1083
+ 读数键 `legacySkillExemptionsDropped`(起服迁移读数行;非零 ⇒ 另有一行 warn `legacy_skill_exemptions_dropped`)。无停-迁-起守卫(更早版本的副本窗内写下的 `Skill` 行是它们当时合法的行,T0 前后两个方向都是重问)。
1084
+ **窗** = 本版发布日 + 30 天(窗口见 `plugins/one-time-migrations.ts` 登记表);窗关之后第一个 minor 删迁移步与读数键。跳过本版直接升上来的库,存量 `Skill` 行照旧代答「不绑授予」的同名调用;出路 = 升级时先过一次本版并起服(或手工 `DELETE FROM approval_exemption WHERE tool_name = 'Skill'` / 删会话)。
1085
+ **文书改真(行为不变)**:豁免店的行 = 停驻行的 `remember:"session"` / 应答口 `allow_session` 与活卡上**名单自己的问**点的 `allow_session`;活卡上对**引擎的问**点的「本会话放行」记在审批席的进程内表(按副本、随进程),**不在**
1086
+ `GET /v1/approvals/:sessionId/exemptions` 的列表里、`DELETE …/exemptions/:toolName` 撤不到(回 `revoked:true` 只说耐久那一行没了)、删会话与留存清理清不掉、换副本 / 重启即失。这是 7.106.0 起的形,本版只把文书写真;收口另有后续。
1087
+ **谁需要**:读豁免列表决定「要不要撤」的人(会话面板、sdk 调用方、运维排障);开了 Workflow 自编排的部署(店慢 / 店坏时照问、不挂死)。
1088
+ **谁受伤**:① 店读超 2 s 的 `Workflow` 调用(多问一次),店答非布尔真值的部署;② 升级前就在的 `Skill` 豁免行所在会话的人(下一次 `Skill` 调用多问一次);③ 按 `workflow_gate_exempted` 检索 / 告警的运维;
1089
+ ④ 活卡上对引擎的问点过「本会话放行」的人 —— 列表仍空、无处可撤(未变,本版写真)。
1090
+ **补偿**:前两项方向都是多问一次、没有新旋钮;事件改读 `approval_exempted` 且 `seat:"workflow_gate"`;④ 今天只有等副本重启 / 进程内表逐出(结束会话不算)。
1091
+ **升级前做**:读 `workflow_gate_exempted` 的告警 / 检索改成 `approval_exempted` + `seat:"workflow_gate"`。部署零动作(策略构造函数的形变是内部接口,包根不导出)。
1092
+ **回滚**:零 DDL。被 M46 删掉的行不会回来(回到 7.147.x 即那些会话的人下一次 `Skill` 调用被问一次,没有数据要还原);标记表里的 `M46` 行与数据根里的标记文件对 7.147.x 无害、无人读。回到 7.147.x 即回到两种读法。
1093
+
1094
+ 75. **人在环三族一条投递律:经腿投出的问题 / 表单 / 审批帧先落本 run 账本、再写 live,账本落不下 ⇒ 这一帧不上 live;sync 流腿的撤卡帧与旧族审批帧随账本回放;detach 断连之后才发起的问题不再当场放掉,卡在回放里等窗(行为变更;wire 帧型 / 键 / 码零变化;零 DDL;部署零动作)**:
1095
+ 旧形:sync 流腿(`POST /v1/tasks/stream`)上,呈卡族审批卡账本与 live 并行写、任一接下即送到;撤卡帧 `approval_revoke` 与旧族 `tool_approval` / `tool_approval_complete` 只写 live,
1096
+ 回放(`GET /v1/runs/:id/events`)里没有;问题卡在直写面已断(detach 断连之后才发起、或开帧落账那一刻面断)时当场按 `unavailable` 放掉,账本落下了也一样。
1097
+ 新形:三族同一条律 —— 有 durable run 行的 sync 流腿先落本 run 账本、再写 live;账本落不下 ⇒ 这一帧不上 live。审批卡在 run 店写失败 / 挂住时这条连接不再 live 呈卡
1098
+ (它若是唯一投递目标 ⇒ 按无人值守政策收场:缺省停驻,`UNATTENDED_APPROVAL_POLICY=deny` 时部署政策拒);收帧 / 撤卡帧账本写失败时同连接 live 也不收。
1099
+ 回放里新增 sync 流腿的撤卡行与旧族 worker 的审批行。detach 断连之后才发起的问题(判决面已放行)卡落账本、等窗或被重连者答 —— 最多多等一个无人应答窗
1100
+ (`QUESTION_TTL_MS`,出厂 5 分钟)。无 durable run 行的部署:表单开帧写向已断的流当场 `cancel`(此前满窗才 `cancel`)。后台 / 续跑腿逐字不变。
1101
+ 运维面:三只 fail-open 计数退役 —— `server.hitl.frame-undelivered-stream-closed`(无账本部署上表单开帧写向已断的流)改由既有的 `server.elicitation.open-frame-undelivered` 计
1102
+ (这一形自此当场 `cancel`);`server.question.complete-breadcrumb-dropped` / `server.elicitation.complete-breadcrumb-dropped`(收帧丢失)并进新的 `server.hitl.close-frame-dropped`
1103
+ (问题 / 表单 / 审批三族的收帧与撤卡帧同一只,探针行带 `frame=`)。
1104
+ **谁需要**:重载 / 重连后要从回放取回审批卡、撤卡与问题卡的壳;detach 断连后想回来答问题的人。
1105
+ **谁受伤**:run 店写挂住时仍想在 live 上先答审批的人(尤其同会话别的 run 投来的问,此前照样呈出);detach 断连后的问题多等一个窗;按旧 tag 读 fail-open 计数的面板。
1106
+ **补偿**:停驻的卡经 `GET /v1/approvals` 取回、`POST /v1/approvals/:sessionId/decide` 补批;账本写失败照旧有响亮计数;窗长由 `QUESTION_TTL_MS` 调。
1107
+ **升级前做**:无;按 tag 读 fail-open 计数的面板:开帧那一只换读 `server.elicitation.open-frame-undelivered`,两只收帧计数换读 `server.hitl.close-frame-dropped`。
1108
+ **回滚**:回到上一版即回到三种投法;零持久面变更(新增的账本行都是既有事件型,上一版读得动)。
1109
+
1110
+ 76. **`settings.hooks` 的 `Stop` 条目不再在委派子代结束时跑;`wiring_manifest.mods[].events` 不再列 `classic.SubagentStop`(行为变更;wire 值变化:注册的事件列表少一站;部署零动作)**:
1111
+ 旧形:请求钩子的车道注册把 `Stop` 挂在两站 —— 主任务的停车点 `classic.Stop` 与委派子代的停车点 `classic.SubagentStop`;子代(同步 / 后台,含续跑的子代)结束时同一批 `Stop` 条目再跑一次,
1112
+ 载荷写 `hook_event_name: "Stop"`,条目的推回作用在子代上;`once` 的 `Stop` 条目可能被子代那一次用掉。`SubagentStop` 条目服务端不跑(契约判给壳)。
1113
+ 新形:`Stop` 只挂 `classic.Stop`(一事件一站,与参照实现同读:停车点按子代身份二选一);子代结束时服务端不跑任何 `Stop` / `SubagentStop` 条目。主任务结束时逐字不变。
1114
+ `wiring_manifest.mods[]` 里 `settings.hooks` / `settings.hooks.managed` 的 `events` 不再含 `classic.SubagentStop`。
1115
+ **谁需要**:照参照实现写 `Stop` 条件钩子的用户 —— 子代不再按主任务的条件被推回,同一守卫不再在子代上多跑一次。
1116
+ **谁受伤**:靠 `Stop` 条目兼管子代结束的配置(子代结束不再有服务端请求钩子);按字面断言 `events` 含 `classic.SubagentStop` 的面板 / 脚本。
1117
+ **补偿**:子代结束的守卫写成 `SubagentStop` 条目(壳属主,壳跑);运维要在服务端判子代结束,在部署座声明挂 `classic.SubagentStop` 的链成员。
1118
+ **升级前做**:把兼管子代结束的 `Stop` 条目改写成 `SubagentStop` 条目;按 `events` 字面读的面板去掉 `classic.SubagentStop`。
1119
+ **回滚**:回到上一版即恢复两站挂法(零持久面)。
1120
+
1121
+ 77. **hook 条目的 `once` 按结局消耗:一次请求里只在它成功之后算用掉,失败 / 拦下 / 没执行的那一次不算(行为变更;wire 零新键、零新码;部署零动作)**:
1122
+ 旧形:同步的 `once` 条目(command 非 async / http / prompt / agent)在起跑之前就记成已用 —— 起不来、超时、退出非 0 非 2、输出读不成判词、闭集外判词、退出 2、`decision:"block"`、
1123
+ `permissionDecision:"deny"` 的那一次之后,这次请求里它都不再跑;`async` / `asyncRewake` 条目交出即用掉。
1124
+ 新形:判决只读一处 —— 这次事件的钩子翻译交出的判决(拒 / 拦 / 继续)同时决定拦停与 `once` 消耗。判决不是拒 / 拦 ⇒ 跑完且给出了裁决的 `once` 条目用掉
1125
+ (`allow` / `ask` / 只给上下文 / 无输出;`PostToolUse` / `PostToolUseFailure` / `PostToolBatch` 的退出 2 与 `decision:"block"` 是反馈、也算;`Stop` × prompt 判词 `ok:false` 带 `impossible:true` 不拦停、也算);
1126
+ 判决是拒 / 拦(`PreToolUse` 拒调用:退出 2 / `decision:"block"` / `permissionDecision:"deny"` / `continue:false`;`UserPromptSubmit` / `PreCompact` 交拦;`Stop` 本车道推回)⇒ 这次事件里跑过的 `once` 条目都不用掉;
1127
+ 失败(没给出可采信的裁决,含观察站 `StopFailure` / `PostCompact` 上的退出 2、`PreToolUse` 上判在截断标记上的判词)与没执行(`if` 不匹配、matcher 不选、前面的组已经否决、墙钟耗尽、引擎叫停)都不用掉,
1128
+ 下一次事件照跑;`async` / `asyncRewake` 照旧交出即用掉;托管相改写输入而整相重判时,作废的第一遍不决定消耗(只结算重判那一遍)。作用域不变:一次请求、每条车道一份去重账;
1129
+ 账上记的是条目本身(不再按位置号:`Stop` 上 prompt 条目因证据不足被滤掉时,后面的条目不再用掉它那一格)。
1130
+ **谁需要**:写 `once` 守卫的壳与嵌入方 —— 守卫失败一次不再在这次请求里永久失效,拦下一次不再放行下一次同类调用。
1131
+ **谁受伤**:靠「`once` = 只试一次」做有副作用的初始化、而它会失败或拦下的配置(现在每次事件都重试,直到成功一次);同一请求里并发的两次事件上,成功之前的 `once` 条目可能各跑一次。
1132
+ **补偿**:要「只试一次」的条目在命令里自己记标记文件(第二次直接退出 0)。
1133
+ **升级前做**:无;依赖旧语义(失败即用掉)的 `once` 条目按上一条改写。
1134
+ **回滚**:回到上一版即恢复起跑前用掉(零持久面)。
1135
+
1136
+ 78. **记忆面「定店 / 控制面说不清」一种答法:整理状态 · 中心记忆导出 · 中心记忆同步 · 会话记忆状态四口的控制面损坏改答 `500 internal.memory_control_plane_corrupt`,会话记忆抹除口的层拒改答 `400 request.memory_layer`(wire BREAKING:五口错误码值变;零持久面;部署零动作)**:
1137
+ 旧形:这五形答通用 `500 internal.error`(四口控制面损坏的句子只有「… failed」,会话记忆抹除口把「请求可以改对」说成服务器坏了)。
1138
+ 新形:九只记忆面对这一个故障源同答两形 —— 层拒 `400 request.memory_layer`、控制面损坏 `500 internal.memory_control_plane_corrupt`;operator 带引擎原句,
1139
+ 中心记忆导出 / 同步的非 operator 层属主与会话所有者两口拿固定句(会话记忆状态一句只说「控制面读不清,运维修好后再读」),原句落运维行
1140
+ (`memory_export_refused` / `memory_sync_refused` / `session_memory_status_refused` / `session_memory_erase_refused`);这两形不再落 `memory_export_failed` / `memory_sync_failed` / `request_error` 行。
1141
+ 同批另一形(自由文本,不是码):SQL 记忆腿(`MEMORY_ENGINE_BACKEND=pg|mysql`)上目标名被别的条目占着的 update,冲突句由 `io error: <驱动原文>` 改为一句两方言同字的判者句,
1142
+ 记忆同步口 `conflicts[].reason` 上可见。
1143
+ **谁受伤**:按 `errorCode === "internal.error"` 判「记忆面坏了」的读者;按 `io error` 前缀给这一形报 I/O 故障的读者。
1144
+ **补偿**:两个码都是错误码目录里既有的码,消费端按码分支;不加旋钮。**升级前做**:无。**回滚**:回到上一版即恢复旧答(零持久面变更)。
1145
+ 79. **`DB_BACKEND=local`:运维队列行的身份格只读引擎对这一行的摘要 —— 引擎读不动的行不再从存储体回填任何一格、`createdAt` 读不成有限数 ⇒ 缺席;到期两扫按引擎的截止读法,截止或建行时刻读不成有限数的待决行升级后下一拍过期;嵌入方类型面 `PendingCheckpoint.createdAt` 变可选(嵌入方类型面 BREAKING;wire:local 坏行上的键可缺席 / 为 `null`;行为修复;零 DDL;部署零动作)**:
1146
+ 旧形:local 运维队列(`GET /v1/approvals` · `/v1/approvals/stream` 的 `pending`)行的身份格与卡格取存储体原值 —— 引擎判坏的行照样带 `createdAt`(可以不是数)、`deadline`、`checkpointId`、
1147
+ 绑定、描述符、卡位与 park 事实;同一行在收件箱上只带引擎读得出的身份。到期两扫自算截止(`deadline <= cutoff`):截止不是数的行永不过期;建行时刻不是数的行终局兜底永不触发,行永挂 pending。
1148
+ 新形:身份格(`sessionId` / `scope` / `gateKind` / `createdAt` / `deadline` / `checkpointId`)读引擎对这一行投的摘要,好行与坏行同一读法、与收件箱同一读法;
1149
+ 摘要读不动的行只带身份 + `rowVerdict` + `taskId`,`toolName` / `toolCallId` / `input` / `riskDescriptor` 为 `null`,`createdAt` 读不出 ⇒ 缺席、`deadline` 读不出 ⇒ `null`,其余可选键缺席
1150
+ (路由层照常补的 `kind` / `rememberRefused` / `agent` 照带);
1151
+ 好行门上的描述符在场却不是对象 ⇒ `riskDescriptor: null` + 计 `server.approvals.risk-descriptor-cell-unreadable`(与 SQL 后端同一只形读者、同一个计数)。
1152
+ 到期两扫的截止判是引擎的 `checkpointDeadlinePassed`(在场而非有限数 ⇒ 已过);终局兜底公式的两格(建行时刻、截止)任一读不成有限数 ⇒ 兜底已过,下一拍过期 ——
1153
+ 拒扫认领的门也一样(这种行引擎判坏,拒扫拒不成,不再每拍占一格拒扫窗)。
1154
+ 队列与收件箱同一只分诊序(严重度降序、`createdAt` 升序;缺席或读不成有限数计 0 = 档内最老)。嵌入方导出型 `PendingCheckpoint.createdAt: number` 改为 `createdAt?: number`(零别名;SQL 后端恒在场)。
1155
+ **谁需要**:local 上读审批队列的壳(同一坏行在收件箱与队列上同答);运维(坏行不再永挂 pending)。
1156
+ **谁受伤**:按 `createdAt` 必在解析队列行的消费方(local 坏行上缺席);直接把 `PendingCheckpoint.createdAt` 当数用的嵌入方(TypeScript 编译红即通知);
1157
+ local 上截止 / 建行时刻不是数的待决行在升级后第一拍被过期(这种行引擎判坏、本就续不了)。
1158
+ **补偿**:按 `rowVerdict` 渲坏行;`createdAt` 缺席按档内最老排(与收件箱同读);被过期的行重跑任务。
1159
+ **升级前做**:无;嵌入方把 `createdAt` 的读点改成可缺席。
1160
+ **回滚**:回到上一版即回到存储体回填与自算截止;零持久面变更。
1161
+ 80. **🔴 能力位 `rewindFiles` 删除:「这台部署能不能还原文件」只有 `restoreFiles` 一只位(wire BREAKING,读侧;零别名;零新码、零 DDL;部署零动作)**:
1162
+ 旧形:`GET /v1/capabilities` 同时铸 `rewindFiles` 与 `restoreFiles`,两位同谓词(文件历史店在场)、恒同值。
1163
+ 新形:`rewindFiles` 不再铸;`restoreFiles` 是唯一的还原位(值与旧 `rewindFiles` 逐字相同)。`rewindFilesTo` = `restoreFiles` ∧ `resumeAt`(谓词不变,只是文书改读唯一的那一位)。
1164
+ **谁需要**:读能力位决定 `/rewind` 档位的客户端(一个事实一只位)。
1165
+ **谁受伤**:仍按 `rewindFiles` 判「对话 + 代码」档的客户端 —— 在没有文件历史店的部署上该档从「不可用」退成「判不出」(照常给档,还原那一半由服务端如实拒)。
1166
+ **补偿**:改读 `restoreFiles`。它自 7.52.0 起就与旧位同谓词同值,改读之后在任何受支持的 server 上读数不变,不需要按版本分流。
1167
+ **升级前做**:客户端把 `capabilities.rewindFiles` 的读点换成 `capabilities.restoreFiles`(sdk 型面删这只键,tsc 红即通知)。部署零动作。
1168
+ **回滚**:回到上一版即两位同铸;零持久面变更。
1169
+
1170
+ 81. **钥匙保管目录的首把钥匙只有一个创建口:多个副本在同一个空目录上同时首启只出一把(目录里没有可装载的钥匙时,先以 `wx` 独占创建 `<保管目录>/.keygen.lock` 分先后;模型钥匙与停驻行封签两个域同一律;行为修复;盘上多一只瞬时文件;零 DDL、wire 零变;部署零动作)**:
1171
+ 旧形:保管店装载是「读目录 → 一把可装载的都没有 ⇒ 生成一把写文件」,读写之间没有互斥,钥匙文件按自己的指纹命名(两个副本生成的钥匙名字不同,独占创建挡不住):共享卷上多个副本在空目录上同时首启可能各建一把、各持自己那一把、互相答 `stale_ciphertext` / `key_not_held`,直到各自重启;所以首装要「先起一个副本再起其余」或首装后 `rollout restart` 一次。
1172
+ 新形:创建口只有一个。目录里没有可装载的钥匙时,副本以 `wx`(`O_CREAT | O_EXCL`)独占创建互斥文件 `<保管目录>/.keygen.lock`;拿到的那一个再读一次目录、仍空才生成,经原子写(tmp 独占新建 + `rename`,模式 0600)发布后撤互斥;没拿到的重读目录,有钥匙就用它,最多等 15 秒,仍没有 ⇒ 建店失败(句子点名互斥文件的路径与出路),不越过别人的互斥自己生成。互斥只在目录里没有钥匙时才被问到,已有钥匙的目录起服零等待。
1173
+ **谁需要**:共享保管卷的多副本部署(sema-up 图表多副本 RWX 首装、自备共享卷):首装并发起服不再需要「先起一个再起其余」与事后重启。
1174
+ **谁受伤**:无新增拒绝面,除「目录里没有钥匙、互斥被别人占着超过 15 秒」(拿着互斥的进程崩在生成中途遗留 ⇒ 之后每次起服等 15 秒后建店失败,声明了 `SEALED_KEY_DIR` 或耐久审批在场 ⇒ 起服拒,否则告警);把保管目录里每个条目都当钥匙文件处理的外部脚本会看到一只瞬时的 `.keygen.lock`(不以 `.json` 结尾)。
1175
+ **补偿**:崩溃遗留 ⇒ 没有副本正在起服时删掉拒句点名的互斥文件再起;外部脚本认 `*.json`。
1176
+ **已知限制**:互斥的原子性取决于共享卷的 `O_EXCL` 独占创建(本地盘与 NFSv3 及以上按协议满足,别的网络文件系统请向存储方确认),且拿到互斥之后那一次读目录要读到别的客户端刚发布的文件(按网络文件系统客户端语义的推断,未在真实 RWX 存储类上验过);7.147.x 及更早的副本不取互斥,新旧版本混跑在同一个空目录上同时首启时旧副本仍可能另建一把;已经分叉的目录(多把钥匙)不会被合并,照旧重启一次让每个副本读到全部钥匙。
1177
+ **升级前做**:无。**回滚**:回到上一版即回到「先读后写、没有互斥」(目录里留着的钥匙文件照常被读;互斥文件若恰在崩溃时遗留,上一版不认它,留着无害,可删)。
1178
+
1179
+ 82. **提 settings-schema 24.0.0(含 22.0.0 的条目好坏一条判据、23.0.0 / 24.0.0 的收紧域):配置条目体内带契约不认识的键(前瞻键、拼错的键)的条目整条丢、点名,不再剥键照装、也不再整份拒候选 —— 只对「条目缺席只会收窄可达面」的域;条目缺席会放宽可达面的 `scenarios` / `plugins` / `skills` 不逐条丢,任何条目问题 ⇒ 整份拒 / 读被拒、落回上一份好配置;一张值名单里坏一个元素 ⇒ 持有它的那一条整条判不过、不逐元素截短;线上 skills 清单与域文档同一只判官;`GET /v1/models` 的 `droppedEntries[].reasonCode` 闭集多一词 `entry-unknown-key`(行为变更;wire 加性:闭集加词;零 DDL;盘上 LKG 的被丢条目载体行可带新词 —— 回滚见本条回滚句;部署零动作)**:
1180
+ 旧形:逐条丢弃域(`models` `skills` `mcp` `plugins` `scenarios` `systems` `collab` `hosts` `projects` `a2a`)的条目体内带契约不认识的键 —— 契约读腿把键剥掉、报 `unknown-keys-dropped`,
1181
+ 本服务把它折成域级错误:候选判官整份拒(起服 / 刷新 / 迟到起服同一只判官;起服一行 `config_candidate_rejected`,`domains` 含该域,回落盘上 LKG 或 env)。带未知键的条目若经别的读口放行,以剥过键的形装上。
1182
+ `scenarios` / `plugins` / `skills` 里一条**坏形**条目(不是未知键,是形错)—— 只丢那一条、兄弟照装:被丢的覆盖条目让同名内建场景 / 同名出厂技能复活(带回它们自己更宽的工具面),被丢的引用让引用承运的 hooks 守卫缺席;
1183
+ 线上的 skills 清单(`/effective` 的 `skills`)另走自己的一条读法 —— 恒逐条抢救、恒默认化:`skills: null` 读成空清单(零告警),同名两条都装。
1184
+ 一张**值名单**(工具名单 / 范围名单 / 提示行)里坏一个元素 —— 只剔那个元素、条目带着更短的名单存活:被截短的拒绝名单(`skills[].disallowedTools`)比作者所写更松(少拒了作者要拒的),被截短的 `allowTools` 则少放了作者要放的(更窄,但同样不是作者写的那一张)。
1185
+ 新形(条目缺席只会收窄可达面的七个域:`models` `mcp` `systems` `collab` `hosts` `projects` `a2a`):带未知键的条目整条丢 —— 逐条丢弃面一条 `entry-dropped`(日志行 `config_entry_dropped`,坐标 = 原文档下标,`reasonCode: "entry-unknown-key"`;诊断句点名那个未知键),
1186
+ 目录条目同时进 `GET /v1/models.droppedEntries`(`{ index, reasonCode: "entry-unknown-key", identity? }`),其余条目照常服务、候选照收、零 `config_candidate_rejected`。
1187
+ 新形(值名单,同七个域):**条目是对象,一张值名单是一个值** —— 名单里坏一个元素 ⇒ 持有它的那一条整条 `entry-dropped`(`reasonCode: "entry-schema-invalid"`,坐标到那一条、诊断句点到元素),不逐元素截短;涉及 mcp 服务器的 `allowTools` / `scenarios` / `rosters`、a2a 对端的 `allowSkills` / `scenarios`、systems 的 `callsWorkers`、collab 槽位的 `tools`、hosts 的 `labels`、projects 登记的 `gitRemotes` / `defaultScopes`、模型的 `promptGuidance`;mcp 服务器 / a2a 对端被丢 ⇒ 那一台不挂载,模型被丢 ⇒ 进 `GET /v1/models.droppedEntries`。
1188
+ 新形(收紧域 `scenarios` / `plugins` / `skills`):不逐条丢。条目体内的未知键 ⇒ 剥键装上 + `unknown-keys-dropped`(本服务折成域级错误 ⇒ 候选判官整份拒:一行 `config_candidate_rejected`,`domains` 含 `scenarios` / `plugins` / `skills`;内建场景、守卫、出厂技能都不复活;拼错的 `disallowedtools` 不会以「没有拒绝名单」装上);
1189
+ **坏形条目 ⇒ 整域读不进、读档 throw**:本地读腿(`config.d`)与中心读腿都整包抛,调用方整包回落 —— 起服:盘上 LKG,首启无 LKG 落回 env,起服行 `config_source_unreachable_using_env` 带 `cause: "rejected"`;
1190
+ 刷新拍:`refreshNow()` 答 `failed`(运维刷新口 502)、`web_admin_refresh_failed` 带 `cause: "rejected"`,上一代继续服务。整份中心配置不收,而不是只丢那一条。
1191
+ `skills` 的坏形条目 / 同名两条 / `skills: null`、`skills[].disallowedTools` / `allowedTools` 里的坏元素同走这一条(整域读不进,读档 throw;`null` 是坏形,缺席只有「键不在」一种);**线上清单与域文档同一只判官**(同两张表、同一只读法,只换判它的那张 schema:清单条目带 `contentHash`、域形条目带 `content`),中心发来的清单里任一条坏 ⇒ 整份候选不收。
1192
+ 不变:域顶层的未知键(持键层不在任何条目体内)仍 `unknown-keys-dropped` ⇒ 整份拒;`tierGroups.<n>.tiers` 里五个档位词之外的键属条目体内未知键(见下);本来就不逐条丢的七个域(`rosters` `workers` `governance` `entitlement` `execution` `prompts` `limits`)不变;契约包的文档面不变。
1193
+ 边界(如实,都是契约包的读法):丢这一条会让引用悬空 —— `roles` / `atMention` 点名的模型、活跃的 `tierGroups` 档位组带未知键 ⇒ 整个 `models` 域退缺省(候选门域错误、整份拒);
1194
+ 一个顶层集合里的条目全带未知键(零幸存者;例:唯一一个档位组的 `tiers` 带 `budget`)⇒ 整域读不进、同走域错误;嵌套集合(collab 的槽位 / 成员、projects 的上下文条目)里全带未知键 ⇒ 拥有它的父条目整条丢、兄弟照留;
1195
+ `projects` 域唯一一条登记带未知键 ⇒ 整份读取抛。有好兄弟、且不被引用的带未知键条目只丢它自己。`tierGroups.<n>` 这类非目录行的丢弃只进日志,不上 `droppedEntries`(它只收 `models[i]` 目录行)。
1196
+ **谁需要**:在条目里加前瞻键的用户与跨版本写配置的管理面(一个键不再让整份候选被拒);拼错收紧键的运维(不再静默放宽成不设限);用 `scenarios` 覆盖内建场景名收窄工具面、用 `plugins` 引用承运守卫 hooks 的部署(拼错 / 前瞻键不再静默撤掉覆盖 / 守卫);用中心技能按名覆盖出厂技能(收窄工具面 / 加拒绝名单)的部署(一条坏技能不再静默让出厂技能回位、一个坏元素不再静默截短拒绝名单);在 mcp / a2a 条目上写 allow / 范围名单的部署(名单不再被静默改成作者没写过的那一张)。
1197
+ **谁受伤**:依赖「条目有未知键 ⇒ 整份拒」保护的逐条丢弃域部署 —— 写错一个收紧键的条目现在被丢而不是整份拒(丢了比错装安全,但那层保护没有了;条目缺席会放宽的域仍整份拒);
1198
+ 存量文档里条目带契约外键、此前剥键照装的部署 —— 升级后那一条不装;`scenarios` / `plugins` / `skills` 里有坏形条目(含 `skills` 同名两条、`skills: null`)的部署 —— 整份中心配置不再收(此前只丢那一条),落回上一份好配置 / 首启落回 env,直到那一条被改对或删掉;`CONFIG_PROVIDER=local` 的 `config.d/skills.json` 同(读档 throw,起服落回 env;整份内容是 `null` 的文件走文件层被拒文档、候选判官整拒,同样落回 env);
1199
+ 值名单里有一个坏元素的 mcp 服务器 / a2a 对端 / 项目登记 / 主机 / 模型 —— 由「带着更短的名单装上」变「这一条不装」。
1200
+ **已知限制**:契约包的写口(写入席 / 读改写)对带未知键的条目仍剥键后落盘(写错的收紧键经那条写路径落盘后,下次读不再带未知键、照常装上);写侧同判由契约包另立,本服务不改。
1201
+ 收紧域条目体内的未知键是「剥键装上 + 告警」(契约包的读法):没有候选门的读方(把告警当日志的读口 —— 引擎本地车道、嵌入方)装上的是剥过键的条目,拼错的 `disallowedTools` 会以「没有拒绝名单」装上;本服务的两条读腿都过候选判官,同一告警是整份候选失败,所以在本服务上不成立。
1202
+ `mcp` / `a2a` 的名字占位(契约包披露,本服务未另验):条目被丢后名字不再被部署占位,请求侧可补同名 —— 成立条件是读方放开请求侧注入的部署,即单用户 ∧ 未锁(`mcp` / `a2a` 锁)∧ 合规档位允许;值名单律让这类条目被丢的情形多了一种(名单里坏一个元素)。
1203
+ `models`:一个模型的 `promptGuidance` 坏一个元素 ⇒ 整个模型被丢(此前少一行提示装上),`roles` 里一个角色覆盖被丢后该角色回落到缺省模型 —— 可用性收紧,方向是 fail-closed。
1204
+ 盘上 LKG 读回的载荷不经契约读腿(本服务既有的读法,`projects` 同):由本版之前的服务落盘的 LKG 里若带着同名两条技能(此前的清单读法两条都收),读回起服仍按「同名后者赢」装并记一行 `web_admin_skill_duplicate_name`;之后每一份被采纳的候选落盘都会重写 LKG。
1205
+ **补偿**:`droppedEntries` / `config_entry_dropped` 点名;`scenarios` / `plugins` 的拒收由 `config_candidate_rejected` / `config_source_unreachable_using_env` / `web_admin_refresh_failed`(成因 `rejected`)点名坏条目的坐标与问题;**删掉那个键或那一条、改对拼写即回**,不需要迁移。
1206
+ **升级前做**:对存量配置文档跑契约包的 `parseDomainLoud(域, 文档, onWarning)`:逐条丢弃域里 `unknown-keys-dropped` 第一段是集合字段、第二段是下标 / Record 键坐标的,就是升级后会被丢的条目 —— 删键或改对拼写;
1207
+ `scenarios` / `plugins` / `skills` 跑它抛了、或带 `unknown-keys-dropped`,就是升级后整份不收的文档 —— 先改对;对逐条丢弃域的存量文档跑契约包的 `salvageEntries(DOMAIN_SCHEMAS[域], 文档, 域)`,`dropped` 里坐标落在条目上、`error` 的 issue 落在名单元素上的,就是此前被截短、升级后整条丢的那几条;
1208
+ 按 `reasonCode` 闭集三词分诊的消费方补第四词(sdk `DroppedEntryReasonCode` 随 sdk 同版锁步;认不出的词按「被丢,原因未知」渲)。
1209
+ **回滚**:回到上一版即回到剥键 + 整份拒的读法(`skills` 回到逐条丢 / 清单恒抢救;值名单回到逐元素剔);配置文档原样、已丢弃的条目没有被改写。**持久面一处**:接配置中心的部署上,盘上 LKG(`config-lkg-*.json`)里被丢目录条目的载体行在本版可带词 `entry-unknown-key`,
1210
+ 上一版的载体判形不认这个词 ⇒ 回滚后若中心不可达、从这份 LKG 起服,载体形不对 ⇒ 模型面整组拒(fail-closed:该组不落地,模型面停在 env 表;拒因码 `config.model_refused_name_minted`,日志行 `web_admin_model_plane_refused`,拒因句含 `malformed`);中心可达则第一拍拉取即覆盖。
1211
+ 回滚前:确认中心可达,或删掉该 worker 的 LKG 文件让它从中心 / env 重起(`CONFIG_PROVIDER=local` 不读 LKG,不受影响)。
1212
+
1213
+ 83. **SQL 后端:`session_meta` 加两列 `forked_from` / `forked_from_incarnation`(fork 谱系;两句 ALTER,缺列拒启并给句;存量 fork 不回填);`DB_BACKEND=local` 的会话元数据那一格多一位 `forkedFromIncarnation`;会话列表行多一个加性键 `forkedFrom`(持久面加列;wire 加性;SQL 部署有升级动作)**:
1214
+ 旧形:SQL 两方言的 fork 不记来源 —— 交出的会话元数据没有 `forkedFrom` / `forkedFromIncarnation`;`DB_BACKEND=local` 记 `forkedFrom`、来源住客读作未知;列表行不带来源。
1215
+ 新形:fork 的建行那一笔记下来源会话 id 与来源那一刻的住客令牌(SQL:两列,与行同一句 INSERT;local:那一格的 `forkedFrom` / `forkedFromIncarnation`,同一笔写);
1216
+ 交出的会话元数据带这两格,`GET /v1/sessions` 的行(与 `PATCH` 的 200 行同一只投影)带 `forkedFrom`(omit-when-absent)。
1217
+ SQL 后端本版起新建的 fork 随之与 `DB_BACKEND=local` 同读引擎按来源走的几路(文件历史从源会话带过来;已有对话的 fork 上声明 `workspace` 按 fork 首腿分配,不再拒;记忆捕获按来源读退出记录)。
1218
+ **升级前做(SQL 后端)**:MySQL 协议 `ALTER TABLE session_meta ADD COLUMN forked_from VARCHAR(64) NULL;` 与 `ALTER TABLE session_meta ADD COLUMN forked_from_incarnation VARCHAR(64) NULL;`;
1219
+ PostgreSQL `ALTER TABLE session_meta ADD COLUMN forked_from VARCHAR(64) COLLATE "C";` 与 `ALTER TABLE session_meta ADD COLUMN forked_from_incarnation VARCHAR(64) COLLATE "C";`。
1220
+ 不执行 ⇒ 起服列册对账拒启 `config.schema_mismatch`,拒句给同两句。两列可空,存量行不需要回填:本版之前建的 fork 两格保持 NULL = 来源未知(源已不可知,不做一次性迁移)。
1221
+ **谁受伤**:没加两列就起本版的 SQL 部署(拒启);对列表行做封闭形校验的消费方。**回滚**:7.147.x 的起服列册对账见到这两列按「库比本构建新」拒启 ⇒ 回滚前先 `ALTER TABLE session_meta DROP COLUMN forked_from, DROP COLUMN forked_from_incarnation;`(两方言同句;丢的是本版记下的 fork 来源);`DB_BACKEND=local` 的那一格多一位,7.147.x 及更早的严格读认不得 ⇒ 回滚 = 恢复升级前的数据根备份(与本版的「删除中」位同一形)。
1222
+
1223
+ 84. **🔴 SQL 后端:`checkpoint` 加一列 `host_session_id`(一张卡归在哪只会话上;**一句 ALTER**,缺列拒启并给句;存量行由一次性迁移 M49 自 `session_id` 回填);`DB_BACKEND=local` 数据根多一份归属索引 `checkpoint-host-sessions.json`;cascade 任务的级上停驻从此是这条 run 的停驻(行为修复;持久面;SQL 部署有升级动作)**:
1224
+ 旧形:一张卡只按它自己的会话连回 run。cascade 的每一级在引擎现铸的会话里跑,级上停下的卡因此连不回 run:run 行 `failed` + `unexpected.suspended`、认领释放;
1225
+ 那张卡在待决列表里看得见,对它决定答 409 `conflict.resume_context_unavailable`,到期自动收回;`RESOURCE_SUSPEND` 对 cascade 任务整只不开(撞限照旧 `failed`)。
1226
+ 新形:卡的行上多记一个事实 —— 它归在哪只会话上(兑现它的那条 run 的会话:cascade 的级上卡 = 提交的会话,其余每一张卡 = 卡自己的会话;停驻那一刻记一次)。
1227
+ 从 run 一侧找卡的读法(取消、steer 停放、活跃 run 409 的门材料、两条停驻收割、续跑输入回收、运维队列行的 `taskId`、收件箱行的目标预览、助手任务视图的门、
1228
+ 托管留存过期 pending 卡时的「run 仍持认领」保护、SLA 拒扫的存体预检、按 task 续跑的 `/resume` 与 `/plan_review`)只读它;
1229
+ 按卡的对话找卡的读法(`/v1/approvals/:sessionId/decide` 的 URL 会话、运维队列行与收件箱行的 `sessionId`)不变 —— cascade 级上卡的 `sessionId` 仍是级自己的会话,决定照旧对它发。
1230
+ 于是 cascade 的级上停驻:`POST /v1/runs` 的行停在 `suspended` / `needs_review`、会话认领保留;`POST /v1/tasks` 答停驻回执;决定那张卡 ⇒ 200 带 `taskId`,同一条 run 行接着跑 ——
1231
+ 续上停下的那一级、再按门判往上爬(引擎的梯子续跑入口);`POST /v1/runs/:id/cancel` 作废那张卡再终局;`RESOURCE_SUSPEND` 对 cascade 任务同样生效,撞限停驻、`POST /v1/assistant/tasks/:id/resume` 续梯子。
1232
+ **升级前做(SQL 后端)**:MySQL 协议 `ALTER TABLE checkpoint ADD COLUMN host_session_id VARCHAR(190) NULL;`,PostgreSQL `ALTER TABLE checkpoint ADD COLUMN host_session_id VARCHAR(190) COLLATE "C";`
1233
+ (不执行 ⇒ 起服的检查点列册探针拒启 `config.schema_mismatch`,拒句给同一句;索引 `idx_checkpoint_host_session_status` 由起服幂等补建,零动作)。
1234
+ **起服一次回填(M49)**:任何读者之前,空归属的行按 token 分页自 `session_id` 回填(本版之前停下的卡一律按卡自己的会话连 —— 它们停下时就是这么连的;那时的 cascade 级上卡,它们的 run 早已终局)。
1235
+ 窗内(本版发布日 + 30 天)每次起服都跑,第二次起零命中。`DB_BACKEND=local`:同一步自会话索引与此刻的待决行重建归属索引。
1236
+ **滚动升级窗**:先升库再升副本;仍在跑的旧副本这段时间新停下的卡归属为空 —— 本版副本从 run 一侧找不到它们(取消不作废那张卡、收割把那条 run 当成卡已不在),直到下一次起服的 M49 补上。
1237
+ ⇒ **全部副本换成本版之后,再起一次任一副本**(与 M43 同一个动作)。
1238
+ **谁受伤**:没加列就起本版的 SQL 部署(拒启);把「cascade + 审批 ⇒ 立刻 `failed`」当信号的调用方(现在停驻等人:同会话再提交、删会话、换绑设备、会话同步都答 409,先取消再做 —— 与普通停驻同形);
1239
+ 一张 `checkpoint-host-sessions.json` 读不出的 local 数据根(拒启;修好或移走这份文件再起,移走 ⇒ 下一次起服的 M49 重建)。
1240
+ cascade 停驻续跑时,梯子在续上那一级之后的各级是同一任务的冷重跑,这一次续跑的预算 / 升级次数 / 墙钟只算续跑这一段;续上的那一级不再收提交时挂在目标上的
1241
+ `userAttachments` / `images`(耐久续跑不收附件,与 verify 的续跑同一条重建规则),之后冷重跑的各级照原任务收到它们。
1242
+ **回滚**:7.147.x 的起服列册对账见到这一列按「库比本构建新」拒启 ⇒ 回滚前先 `ALTER TABLE checkpoint DROP COLUMN host_session_id;`(两方言同句;丢的只是归属 —— 回滚后的副本照旧按卡自己的会话连,cascade 级上卡回到连不上的旧形);
1243
+ `DB_BACKEND=local`:多出的 `checkpoint-host-sessions.json` 对 7.147.x 无害(不读它)。
1244
+
1245
+ 85. **SQL 后端:地板之下的 prompt epoch 锚沿会话当前分支读,不再按行序取最近一条 —— 回绕(resumeAt)之后留在废弃分支上的记录不再被当成锚(行为修复;零 DDL;wire 零变化;部署零动作)**:
1246
+ 旧形:有界唤醒的窗里没有 epoch 载体时(回绕切掉了最近一次压缩;或压缩写于引擎复述 epoch 之前),SQL 两方言按行序取地板之下最近的载体 —— 更早一次回绕跨过过提示词版本变更的会话,run 与 `GET /v1/sessions/:id` 读到废弃分支上那条更新的记录。
1247
+ 新形:沿地板那一条的父链往下找第一条载体(与 `DB_BACKEND=local` 同一只读法);受影响的会话下一次 run 按它当前分支的提示词版本组装,视图的 `promptEpoch` 随之。
1248
+ **成本**:只在窗里没有载体时才问;那时一页翻地板之下的每一行(主键区间,每页 100 行),而不只是载体行。**没做的**:SQL 窗的地板仍按行序取最近一条压缩。
1249
+
1250
+ 86. **cli 哨兵属主改写成无主,属主读法里不再有字面量互认;dev-open 部署上规则口与 notify 与会话列表、详情同读(持久面一次性迁移 M48,零 DDL;行为变更;wire 零变化;部署零动作)**:
1251
+ 旧形:cli ≤ 1.0.70 本地单用户自发的主体头 `anon:shell-live` 记成了那段时间会话 / run / leader run 的属主,属主面表按字面量让无身份调用方读到它们;规则口与 `…/notify` 不放这一格、也不放 dev-open。
1252
+ 新形:起服时(任何读者之前)一次性迁移 M48 把这些行的属主改写成 `NULL`(SQL:`session_meta` / `task_run` / `leader_run` 各一句 `UPDATE … SET owner = NULL WHERE owner = 'anon:shell-live'`,值逐字节比 —— MySQL 协议写作 `CAST(owner AS BINARY) = CAST('anon:shell-live' AS BINARY)`,只差尾空格的另一位属主不动;
1253
+ `DB_BACKEND=local`:会话元数据格与 run 行),之后它们与任何无主行同读;规则口与 `…/notify` 在 dev-open 部署上不钉人。读数 `shellSentinelOwnersCleared`;窗内每次起服都跑,第二次起零命中。
1254
+ 改写只在**没有身份边界**的部署上发生 —— 「哨兵 ≡ 不带主体的本地单用户」只在那里成立。判据只读配置,三种形:
1255
+ · **没有身份边界**(dev-open:`REQUIRE_PRINCIPAL` 未开,且没配 `SERVICE_AUTH_TOKEN` / `SERVICE_AUTH_TOKENS`、没配鉴权桥 issuer —— `AUTH_BRIDGE_ISSUER`,或接了中心(`SEMA_WEB_ADMIN_URL`)⇒ 回退中心基址 —— 、没开直连门、没配只读 trace 凭据):改写,读数 = 改写的行数;
1256
+ · **有身份边界、`REQUIRE_PRINCIPAL` 未开**(配了上面任一样,如带 service 凭据的单用户部署):零改写、读数 0,本条照样记完成。哨兵在这里是一位普通的具名属主,这些行成了孤儿:只有主体恰为 `anon:shell-live` 的请求按属主读写它们(与任何具名属主同);
1257
+ 出示 service 凭据而不报主体的 fleet 调用方(`SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT` 没声明成 `false` 时)照旧读得到、删得掉,但不能驱动、挂接;续跑等运维动词另按运维身份放
1258
+ (`OPERATOR_SINGLE_USER=true` 下每一位过了凭据门的调用方都是运维;具名 `OPERATOR_PRINCIPALS` 下只名单里的人);其余调用方 404。
1259
+ 上一版不带主体的调用方经那一格按属主读写它们 —— **这是本版对这一形的收紧**(那一格退役、本迁移又不在这里改写);
1260
+ · **`REQUIRE_PRINCIPAL=true`**:同上,零改写、读数 0 —— 这些行照旧按有主行读(与上一版同答:那一格本来就只在不要求主体的部署上放)。
1261
+ **耐久面**:改写的是存量行的属主列 / 属主位(从哨兵字面量到无主);规则行、收件箱条目、问账行、检查点 scope 不动(哨兵键下的规则此前也不对无主体任务生效 —— 改键 = 放宽)。
1262
+ **谁受伤**:仍用 cli ≤ 1.0.70 的客户端与新客户端混用的部署(新写下的哨兵行只有带那个头的请求读得到);dev-open 部署上原先靠规则口 / notify 404 当隔离的人(那从来不是隔离);
1263
+ 有身份边界、`REQUIRE_PRINCIPAL` 未开的部署上,不带主体地续用 cli ≤ 1.0.70 时代会话的人(上面第二形:驱动 / 挂接 404,续跑看运维身份)—— **补偿** = 下面的手工一步。
1264
+ 有身份边界的部署上的孤儿行(上面第二、三形)想收成无主,运维手工做(可核):SQL 后端对三张表各执行一句 —— MySQL 协议 `UPDATE session_meta SET owner = NULL WHERE CAST(owner AS BINARY) = CAST('anon:shell-live' AS BINARY)`
1265
+ (`task_run` / `leader_run` 同句;逐字节比,只差尾空格的另一位属主不动),PostgreSQL `UPDATE session_meta SET owner = NULL WHERE owner = 'anon:shell-live'`(另两张表同句);核法 = 同条件的 `SELECT COUNT(*)` 读 0。
1266
+ `DB_BACKEND=local` 没有手工口:窗内(本版发布日 + 30 天)以没有身份边界的形起服一次(上面第一形的配置,只听 loopback),起服读数 `shellSentinelOwnersCleared` = 改写行数,然后改回原配置;窗关后本条随删码退场,local 再没有这一步。
1267
+ **放给谁**(如实):改写后的行是普通无主行 —— 过了凭据门的任何调用方都能读、驱动、挂接它们。配了 service 凭据的部署 = 每一位持凭据者与它代为报出的每一位主体;
1268
+ **没配 service 凭据的部署(如只配了鉴权桥)全局凭据门不武装 ⇒ 不带任何凭据的匿名调用方也读得到**(提交类 —— 驱动、续跑 —— 另受 `ALLOW_UNAUTHED_WRITES` 管,缺省关 ⇒ 谁都提交不了)。
1269
+ 删除与会话列表只给 fleet 调用方与单机形(`REQUIRE_PRINCIPAL` 未开)的 `default` 主体。只想留给自己的,别做这一步:带 `anon:shell-live` 这只主体的请求照旧是它们的属主。
1270
+ **升级前做**:无。**滚动升级**:支持。**回滚**:零 DDL;改写过的行在 7.147.x 上读作无主(此前按字面量互认读到它们的那位调用方照读),规则口对它们在 7.147.x 上答 409(本版同)。
1271
+
1272
+ 87. **`settings.env` 里环境合成会拒的名 / 值(名字空 / 带 `=` / 带 NUL / 带孤立代理项,值带 NUL / 孤立代理项)在受理口 `400 request.field_invalid`(`field:"settings.env"`),此前 `202`、到 hook 子进程起时才抛(行为收紧;wire 加性一臂;部署零动作)**:
1273
+ 判官是引擎合成本体的拒因读口,受理口与合成同问一只;判官放行的形(名字不是标识符、值带 CR LF)照旧受理。续跑重放存量体不过这道门。**出路**:删掉或改写句子点名的变量后原样重发。
1274
+
1275
+ 88. **「`<坐标> must be a boolean`」一族的 `400 request.field_invalid` 拒体(`promptLean` · `attachments.*` 的布尔键 · `settings.ultracode` / `autoCompactEnabled` · `resilience.*` · 顶层布尔键)多一个键 `field`(= 体内坐标;wire 加性;句子、码、状态不变;部署零动作)**:
1276
+ 按整体相等比对这几口拒体的消费方要放宽(按 `errorCode` 分流、按 `field` 定位)。**出路**:无需动作;要定位坏键读 `field`,不要解析句子。
1277
+
1278
+ 89. **`images` 的条目形 / 键名 / 类型在新提交面受理口判(`400 request.field_invalid` / `request.body_shape`,体带 `field` · `index` · `unknownKeys`):`images:[null]` 由 `500` 变 `400`;非对象条目、缺 / 非串的 `data` · `mimeType` · `url`、两臂并带、本臂以外的键此前受理,现在 `400`;`mcpServers` / `a2aPeers` / `images` 的 `request.field_invalid` 拒体多 `field`、条目级多 `index`(行为收紧 + wire 加性;部署零动作)**:
1279
+ 形对的 `images`(`{ data, mimeType }` 或 `{ url }`)照旧受理,字节与 URL 的准入仍是引擎的;续跑重放存量体不判。按整体相等比对这几口拒体的消费方要放宽(按 `errorCode` 分流、按 `field` / `index` 定位)。**出路**:每张图选一臂、删掉多余键;句子逐字不变。
1280
+
1281
+ 90. **同步腿零工作的 `config.skill_deny_unreadable`(点名的运维技能,拒侧条目被引擎读成空)答 `409`,此前 `200` + failed 体;零工作的拒不再占提交幂等键(行为修复;新码入册;部署零动作)**:
1282
+ 按 `terminal.code` 读同步腿 200 体识别这一失败的消费方改读 4xx 体的 `errorCode`;该码 ⇒ 运维改那只技能的拒侧条目,调用方原样重发即可。`/v1/runs` 与流式腿 HTTP 2xx、同码落终态 run 行,不变。**出路**:无需改请求。
1283
+
1284
+ 91. **停驻后被批准复活的后台子代:复活那一轮的 fleet 帧照常发 —— 行翻终态、常开流一帧 `bg_notification`(行为修复;wire 零新键、零新码;部署零动作)**:
1285
+ 旧形:复活轮零 fleet 帧,行停在首轮的 `running`,直到 60 s 一拍的对账把它摘掉(只有摘除、没有终态帧、没有 `bg_notification`)。
1286
+ 新形:复活轮与首轮同一只观察者,收尾时出终态帧并摘行,`bg_notification` 一帧。**谁受伤**:无。**升级前做**:无。
1287
+
1288
+ 92. **workflow 子代停驻卡在 run 仍在跑时被决:决定交给那条活 run 当场用上,200 体换成 `{ taskId: <workflow run id>, status: "resuming", decision }`;带续跑重述键的决断在活 run 上答 400(行为修复;wire 加性;零新码;部署零动作;多副本已知限制)**:
1289
+ 旧形:决定交给宿主会话的新一跑(200 `{ taskId: <宿主新一跑>, sessionId, status: "resuming", bindingEnforced: true }`),模型去调 `Workflow({resumeFromRunId})` 被引擎拒(run 还在跑),`parked: true` 挂到整条 run 结束。
1290
+ 新形:持有这张卡的 run 在本进程里跑 ⇒ 引擎在原 run 里驱动停驻的子代,200 `{ taskId: <workflow run id>, status: "resuming", decision }`(无结清证据);同卡同决定再决 ⇒ 同一张回执,另一个决定 ⇒ `409 decide.claim_lost`;
1291
+ 卡已离开 pending / run 不在这张卡上等 ⇒ `409 decide.gate_moved`;checkpoint 店读不出 ⇒ `503 decide.store_unreachable`;带 `mcpServers` / `a2aPeers` ⇒ 卡仍待决时 `400 decide.parked_restatement_unsupported`(卡恰在此刻离开 pending ⇒ `409 decide.gate_moved`)。run 已不在本进程里跑 ⇒ 续跑车道照旧。
1292
+ **谁受伤**:拿这一形的 `taskId` 轮 `GET /v1/runs/:id` 的客户端(读到 404,改读 `GET /v1/workflows/:id`);多副本部署上决定落在不跑这条 run 的副本 ⇒ 照旧走续跑车道、`parked: true` 可能持续到 run 结束(与上一版同形)。
1293
+ **升级前做**:无。
1294
+
1295
+ 93. **`/health` 世代账的 `configAppliedVersion` / `configAppliedOrdinal`(与心跳 `engineSignal.configAppliedVersion`)在应用那一拍收口时才推进,与该拍的 `restart` 判定同一段写(推进时刻后移;wire 键零变;部署零动作)**
1296
+ 旧形:刷新拍(与迟到的起服拉取)一提交新一代,世代账就记「已应用」;之后才采用提示词层、落 LKG(含技能正文预热)、算重启判定 —— 这段时间里 `/health` 读到 applied 已是新一代、`restart` 还是上一拍的。
1297
+ 新形:applied 与重启判定(签 / 撤 / 带 `withheld` 扣)同一段写、先于心跳即刻再报;读到 applied 到某一代时,同一次读数里的 `restart` / `restartRequired` 已是那一拍的判定。拍在收口之前失败 ⇒ applied 停在上一代、`configApplyStaleMs` 持续,下一拍重放同一代收口。起服 / 从 LKG 起服 / 凭证换人降档三种拍没有重启判定,收口紧接提交(时刻不变)。已发布的重启信号只在收口改;上一拍扣着的候选在新一代提交那一刻作废,扣着形(`restart.withheld`)那一位可能在收口之前消失(与此前同)。接力账 `configHandoff` 与诊断端点 `configApply.groups[*].appliedVersion` 照旧在提交那一刻记。
1298
+ 同批:手动刷新口撞上 env 起服进程正在收口之前的迟到起服拉取时,汇入那一拍、等它收口才返回(修前当场 200,那一拍还没收口);刷新拍与迟到起服拍走同一个车道入口。
1299
+ **谁需要**:按 applied 等配置收敛、再按 `restart` 决定是否滚动重启的编排器与运维脚本(不再需要「applied 到版之后再等一会儿」)。
1300
+ **谁受伤**:把 applied 推进当作提交时刻计时的读者 —— 推进晚了 LKG 落盘那一段(慢盘、技能正文慢时可到秒级)。
1301
+ **补偿**:要提交时刻的读数看诊断端点 `configApply.groups[*].appliedVersion`;要等一拍完整收口也可调 `POST /v1/admin/config/refresh`(返回时该拍已收口)。
1302
+ **升级前做**:无。**回滚**:无持久面变更,回到上一版即回到提交即推进。
1303
+ 94. **日志面:进程写进 stdout / stderr 的每一行过同一只秘密形筛 —— 凭据形字节换成 `«redacted:<类>»`;五只 `(事件, 字段)` 形缺省落点从散文改成 JSON 行;两只 process warning 改走日志行 / fail-open 兜底臂;`npm_` / `hf_` / `ya29.` 三族在全部脱敏面成记号(安全轴,fail-closed;日志面字节变;部署零动作)**:
1304
+ 旧形:结构化日志器原样写字段;各模块自己的 `console.*` / `process.stderr.write` 原样写;店没接日志座时的腐读披露、`createPgPool` 直用时的连接错等落 `事件名 { 字段 }` 散文行(`[pg-pool] pg_pool_idle_client_error { … }`);会话规则 SQL 店注入的日志座抛 ⇒ 封键披露落 `[session-policy] session_policy_erase_sealed_keys — the injected logger threw (…)` 散文行;字段序列化不出的结构化行只剩 `ts` / `level` / `msg`;内存嵌入器观测腿抛 ⇒ process warning `MemoryEmbedderObservabilityWarning`;配置型 URL 展示铸点 fail-closed ⇒ 每进程一次的 process warning `SemaRedactionFailClosed`;leader 推送腿的 git 诊断直通 stderr;hardened-vm 守卫自写一行 `hardened-vm: un-awaited script rejection contained: …`;`npm_…` / `hf_…` / `ya29.…` 在 wire 与日志上原样。
1305
+ 新形:每行出门前过脱敏器,凭据形字节读作记号(行仍是一条 JSON;筛自己抛 ⇒ 固定的 `{"ts","level","msg":"log_line_withheld","reason":"secret_screen_failed"}`);散文行的过筛自己抛 ⇒ 这一行是 `«redacted:oversized»`;那几只缺省落点写 `{"ts","level":"warn","msg":"<事件名>",…字段}` 一行 JSON(`[pg-pool] ` 前缀去掉;会话规则店注入的日志座抛时,封键披露同形落接缝 —— `msg: "session_policy_erase_sealed_keys"`);字段序列化不出 ⇒ 头三键 + `"fieldsWithheld":"<异常类名>"`;筛把记录行的 JSON 结构遮坏 ⇒ 同按筛自己抛(扣下句 + 同一计数);嵌入器观测腿抛 ⇒ stderr 一条 JSON warn `msg: "memory_embedder_observability_hook_threw"`(`err` 字段);展示铸点 fail-closed ⇒ fail-open 兜底臂 `server.redact.display-safe-fail-closed`(`fail_open_total{tag=…}` 逐次计数,一次性 `[sema] fail-open: server.redact.display-safe-fail-closed` 宣告行);git 诊断只进推送结果的 `error`;hardened-vm 的容纳只剩 `unhandled_rejection_script_realm_contained` 一个事件(boot 进程照旧;worker 车道由主线程写同一事件;不装 boot 钩子的嵌入方只容纳不出声);地板上真遮掉的凭据计进 `redactions_applied_total`;`npm_…` / `hf_…` / `ya29.…` 在 wire / 审批卡 / 日志上成 `«redacted:key»`。`run-local` 的任务结果与 y/N 问句不变。
1306
+ **谁受伤**:按日志原文匹配凭据片段的排障脚本;按 `[pg-pool] ` / `[session-policy] ` 散文前缀或 `事件名 {` 散文形告警的规则;按 warning 名 `MemoryEmbedderObservabilityWarning` / `SemaRedactionFailClosed` 或 `hardened-vm: un-awaited script rejection contained` 散文告警的规则;把这三族原文当正常输出读的消费方。**出路**:按事件名(`msg`)与同行的非凭据字段读;告警规则改按 JSON 的 `msg` 匹配(两只 warning 分别换成上面的 `msg` 与 fail-open tag)。**升级前做**:无。**滚动升级**:支持。**回滚**:零持久面。
1307
+
1308
+ 95. **覆盖站上不带标签的请求 PreToolUse 钩子的问照问、只给上下文照收(行为变更;wire 零新键、零新码;部署零动作)**:
1309
+ 旧形(7.147.x):任务座之下有部署座链成员(运维 mod 在 `classic.PreToolUse` 上以 `append` 档挂了链成员)的站上,不带托管标签的请求钩子答问或只给上下文 ⇒ 被引擎座位信任律拒,零问零执行;带托管标签的同形照问 / 照收。
1310
+ 新形:两条车道同一个结局 —— 问照问(要人批),只给上下文照收、调用落到常规门;放行 / 改写照旧拒。它的问压在下方的问之上时问句先列下方那一句、再列 `(a PreToolUse hook also asks: …)`。
1311
+ **谁受伤**:靠「不带标签的问在覆盖站上整次拒」挡住调用的部署 —— 那一形本版要人批之后执行。**出路**:要挡,让运维 handler 自己答否决或问(它的判决恒在请求钩子之前、恒作数)。**回滚**:回到上一版即回到这两形被拒;数据零改动。
1312
+
1313
+ 96. **e2b 车道:建命令失败而供应商没有答「拒」时,这只环境此后不挂起(行为修复;wire 零新键、零新码;部署零动作)**:
1314
+ 旧形:建命令以失败告终(含 SDK 自己的 60 s 握手到点)⇒ 在途保护即撤,挂起(`suspendVM`)照常可成 —— 供应商若其实已起了进程、只是回执丢了,快照里可能有一条在跑的命令(7.129.1 节写明的已知缺口)。
1315
+ 新形:只有供应商答了拒(参数错 / 未认证 / 查无 / 限流 —— SDK 的四只具名拒)才撤在途保护;其余失败(握手期限到点、断流、沙箱不可达、别的错)⇒ 保护不撤,这只环境此后挂起恒以 `command_in_flight` 拒,
1316
+ 一行 warn `e2b_start_outcome_unknown`(沙箱 id + 错误类名)。**谁受伤**:建命令回执丢了的那只环境不能停驻挂起,VM 计费到任务结束或 `E2B_SANDBOX_MAX_MS`。**升级前做**:无。
1317
+
1318
+ 97. **k8s 车道工作区快照的上传以 worker 对对象的回读(预签 `HEAD`)判成败;`latest` 写的应答丢了 ⇒ 回读指针定结局(行为修复;wire 零新键、零新码;部署零动作)**:
1319
+ 旧形:上传(run 末快照与停驻挂起同一只)以 pod 里 `curl -fsS` 退出 0 判成功 —— 存储答 3xx 或空操作也算存成,`latest` / 停驻快照 id 可以指着存储里没有的对象(下一条 run / 续跑从空目录开始);
1320
+ 对象落了而 curl 丢应答 ⇒ 判失败。`latest` PUT 落了而应答丢 ⇒ 报失败而指针已移。
1321
+ 新形:上传成没成只看 worker 对刚写的对象发的预签 `HEAD`(2xx = 在),`latest` 在它之后才动、停驻快照 id 在它之后才交给引擎;不在 ⇒ `workspace_snapshot_failed{stage: upload}`(停驻挂起答 `connect_failed`)。
1322
+ `latest` 写 / 删的应答没回到 worker ⇒ 回读一次指针定结局。**谁受伤**:不答预签 `HEAD` 的对象存储(或改答非 2xx 的代理)上每次上传判失败。**升级前做**:无(MinIO / S3 都答;所需权限与读 `latest` 同一条 `s3:GetObject`)。
1323
+
1324
+ 98. **k8s 车道恢复工作区时归档 GET 答 `404 NoSuchBucket` ⇒ 这只执行环境以 `connect_failed` 拒(`snapshot_bucket_missing`),不再在空目录上续跑(行为修复;wire 零新键、零新码;部署零动作)**:
1325
+ 旧形:恢复命令把归档 GET 的任何 404 都读成「归档不在」⇒ 悬空恢复点(`workspace_latest_dangling`)、空目录起 —— 快照桶在停驻与续跑之间被删时,续跑的那条腿静默拿到空工作区。
1326
+ 新形:pod 原样交回存储的答复,由 worker 用读 `latest` 时的同一只判据读:`NoSuchBucket` ⇒ 与读 `latest` 得同一答案时同拒(句子带 `snapshot_bucket_missing`、桶名与出路)、同一行 `workspace_snapshot_bucket_missing`
1327
+ (停驻车道带 `sessionId`)、刚建的 pod 释放;其余 404 仍是悬空恢复点。**谁受伤**:快照桶被删时有停驻 run 的部署 —— 这些 run 续跑失败。**升级前做**:无(桶删了的部署建桶,或把 `WORKSPACE_SNAPSHOT_BUCKET` 指向已有的桶)。
1328
+
1329
+ 99. **配置根是工作区本身或它的祖先 ⇒ 起服 warn 恰一行 `sema_config_root_encloses_workspace`(日志面,加性;不拒启、不改任何行为;wire 零变化;部署零动作)**:
1330
+ 旧形:配置根(`SEMA_CONFIG_DIR`,缺省 `~/.sema`)设成工作区本身或它的祖先(容器里 `SEMA_CONFIG_DIR=/workspace` 而项目在 `/workspace/proj`、直接设成 `HOME`)时,根之内每一次写都过 `write_protection` 一问
1331
+ (allow 规则清不掉、`acceptEdits` 不放、无人值守腿拒),而起服与首条任务都零行 —— 第一次知道是第一次写。
1332
+ 新形:起服时判一次 —— HTTP 服务在装配第 2 段(执行车道合成)之后,`run-local` 在工作区定下之后。配置根与「工作区」各取一次规范形(符号链接按 realpath 展平,尚不存在的尾巴接在最深既存祖先之后)后,
1333
+ 配置根等于工作区或是它的祖先 ⇒ 运维日志 warn 恰一行(`level:"warn"`、`msg:"sema_config_root_encloses_workspace"`,字段 `configRoot` / `workspace` / `workspaceFrom` / `note`);不相交 ⇒ 零行;首条任务之后不再多报。
1334
+ 「工作区」只有一条读链:`run-local` 的 `--workspace` ?? `REMOTE_EXEC=host` 的 `HOST_WORKSPACE_BASE` ?? 进程工作目录(`workspaceFrom` = `workspace-flag` / `host-workspace-base` / `process-cwd`);手不在本机盘上的车道(沙箱 / 远程)不判。
1335
+ 规范形在盘上竞态里读不出 ⇒ 另报一行 `sema_config_root_workspace_check_unavailable`(类名 + 机器码,不带消息原文),起服照常。规范形对尚不存在的尾巴只比字串、不折大小写:大小写不敏感的盘上,两个只差大小写且尾巴都还不存在的拼写读成两处,这一行会漏报。
1336
+ **看不见的一半(如实)**:请求体里按任务给的 `cwd` 起服时不可知,这一行看不见它 —— 项目只靠请求 `cwd` 落在配置根之下的部署,第一次知道仍是第一次写。
1337
+ **勘误(7.123.0 节第 4 条「起服不报、首条任务也不报:本服务不拿配置根与工作目录比」;已发节不改字节,本条即订正)**:那一句写的是 7.123.0 的现状,本版起起服会比这一次(只比配置根与起服时的工作区,不比请求里的 `cwd`)。
1338
+ **谁受伤**:故意把配置根设在工作区祖先的部署多这一行 warn(包括已用整表替换去掉 `.sema` 行的部署:这一行只说位置关系、不读写保护表,句子里写明它们可忽略),按「warn 行 = 告警」过滤日志的运维会多收到一个事件名。**出路**:行本身就是提示(无旋钮);要消掉它 ⇒ 把配置根指到项目之外的专用目录(不设即缺省 `~/.sema`),
1339
+ 确实要保留祖先形配置根的 ⇒ `WRITE_PROTECTED_TABLE_REPLACE` 给一张不含 `.sema` 行的整表(代价见 `USAGE.md` 写保护名表一节)。
1340
+
1341
+ 100. **补登(引擎 7.62.0 起,7.144.0 已到货;已发节不改字节):审批卡的卡词 `approvalCard` 多两个词 `computer-access` / `computer-control` —— 输出闭集放宽,7.144.0 起两词原样过境却没登进那一版的清单与本文件(文字补全;本版行为零变;部署零动作;消费方有动作)**:
1342
+ 事实:引擎 7.62.0 给卡词闭集 `TOOL_APPROVAL_CARDS` 加了这两个词;本服务按这只闭集校验、原样放上 `approval_request` 帧的 `card.approvalCard`(活铸帧 · 落库卡信封 · 断连重放三面同源)与帧活面事实 `approvalCard`。7.144.0 的 wire 变更清单与本文件 7.144.0 节都没写这一条。
1343
+ 读法:对卡词写穷举 `switch` 的消费方给这两个词加臂。自本版起,清单把这类逐字过境的 core 词表登在 `coreVocab` 一层,引擎加词那一版清单就有 `added`。
1344
+
1345
+ 101. **勘误(7.132.0 节第 50 条第一点与 7.134.0 节第 7 条里 `a2aPeers[i].toolAxes` 坏形的处置句;已发节不改字节,本条即订正):新提交上这个形自 7.136.0 起是入口 `400 request.field_invalid`,不是「那一条对端不挂 + 运维 warn `a2a_injection_dropped`」(文书;本版行为零变;部署零动作)**:
1346
+ 那两句写的是 7.132.0–7.135.0 的现实(7.135.0 及以前 `a2aPeers` 条目只有 `url` / `cardUrl` 带凭据与个数超界两道入口拒,`toolAxes` 没有入口判官:坏形的对端照常 200 受理,只在运维 warn 里点名)。7.136.0 给 `a2aPeers` 加了条目判官表(与 `mcpServers` 同一副拒绝骨架),`toolAxes` 是表里的一格:
1347
+ 新提交(`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs`)的 `a2aPeers[i].toolAxes` 被引擎判官读不出(出词表 · `egress` 非布尔 · 记录里多一个成员 · `__proto__` 键 · 某只 skill 的值不是对象 · 请求侧不收的 `boundaryFlow`)⇒ 入口 `400 request.field_invalid`,
1348
+ 拒句点名 `a2aPeers[i].toolAxes` 与 peer 名(形如 `a2aPeers[0].toolAxes (peer "<名>") is not a usable declaration — <判官原因句>`),整份请求不收、零 run,**没有** warn `a2a_injection_dropped`。那两句现在只对**耐久续跑重放存下的旧请求体**成立:
1349
+ 重放腿不拒(拒会砖死升级前停驻的任务),坏条目不挂、运维 warn `a2a_injection_dropped` 点名,一次性迁移窗内的重读规则照 7.132.0 节第 50 条与 7.134.0 节第 7 条所述。以码为准。
1350
+ **谁受伤**:照已发两节的句子写调用方的人 —— 以为坏形 `toolAxes` 只是「那一条对端没挂、任务照跑」的脚本,在 7.136.0 起拿到的是 400、任务不起。**出路**:改对那个键(或删掉它);完整的拒形与判序见 `USAGE.md` 9.5h。
1351
+
1352
+ 102. **命令钩子跑完 / 超时 / 被叫停之后整棵进程树被清:脱离进程组的后代不再活过超时;钩子正常退出后留在同组的后台进程也被清;同步与 `async` 条目同一把梯子(安全轴;行为变更;运维日志多一个事件 `hook_command_tree_swept`;零新旋钮;wire 零变化;部署零动作 —— 靠钩子起长命后台进程的壳除外)**:
1353
+ 旧形:超时只向钩子的进程组发一枪 SIGKILL 就放手 —— 脱离进程组的后代(自立会话的后代、钩子壳自己起的新会话)活过超时;叫停(预算到 / 任务取消)宽限到点只看「组长还在不在」,组长吃 SIGTERM 就退时组里屏蔽 SIGTERM 的成员被留下;
1354
+ 钩子自己跑完(组长正常退出、管道关闭)时留在同组的后台进程(`sleep 300 >/dev/null 2>&1 & exit 0` 这一形)没有任何一拍会去清它。
1355
+ 新形:跑完 / 超时 / 叫停三条结局一个 —— 钩子的整棵进程树(进程组 ∪ 往下的后代)被清:跑完 = `close` 之后树里还有后台成员 ⇒ 整组 SIGKILL(树里本来就空 ⇒ 零信号零日志;管道里的输出不被截);
1356
+ 超时直接 SIGKILL、立即返回(不等孙进程放开管道,结局仍是非阻断故障);叫停 = SIGTERM → 1 秒 → 树里还有进程则 SIGKILL;SIGKILL 之后 1 秒复核整棵树,
1357
+ 清净 ⇒ info `hook_command_tree_swept`(`end` = `exit` / `timeout` / `halt`,`clean: true`),还有 ⇒ 补一枪并 warn(`clean: false`,`shots: 2`)。组长已被收割之后只向「还有原来成员」的进程组发信号(进程号可能已是别人的)。`timedOut` / `aborted` 读数形与 `HOOK_KILL_GRACE_MS`(1 秒)不变。
1358
+ 射程如实:钩子壳在被清扫之前就已退出、后代又在新会话里的形(后代被过继给 init、自成一组),与叫停时 SIGTERM 之后组长退了、屏蔽 SIGTERM 的自立会话后代,按进程号 / 进程组 / 父链找不到,不在这一把梯子上。
1359
+ **谁受伤**:依赖钩子起一只长命后台进程并让它活过钩子自己(含钩子正常退出后留下的后台进程)的壳 —— 现在那只进程随钩子跑完 / 超时 / 被叫停一起被清。**出路**:长命的活放到钩子之外起(服务单元 / 编排器),钩子只负责触发;钩子本身要跑得更久 ⇒ 条目的 `timeout`(上限 600 秒)与 `HOOKS_TIMEOUT_MS`。
1360
+
1361
+ 103. **🔴 `loadConfig()` 要求本进程先声明自有凭据:包根导出的 `loadConfig()` 在没调过 `declareServerWithheldEnv()` 的进程里抛(安全轴,fail-closed;嵌入方行为 BREAKING;包根加一个值导出;服务进程部署零动作)**:
1362
+ 旧形:嵌入方直接 `loadConfig()` 照返回配置;名单型旋钮点到本服务凭据名照收,宿主子进程在 `inheritEnv:"all"` 下照拿本服务凭据(引擎的自有凭据声明为空)。
1363
+ 新形:`loadConfig()` 第一步核本进程的自有凭据名已被引擎扣下,没有 ⇒ 抛,句含 `declareServerWithheldEnv()`。包根新增值导出 `declareServerWithheldEnv`。
1364
+ **升级前做**(嵌入方):在 `loadConfig()` 之前、任何执行环境构造与子进程之前调一次 `declareServerWithheldEnv()`(零参)。一个进程只调一次即可;同一进程里多次 `loadConfig()` 不需要再调。
1365
+ 之后点到本服务凭据名的名单型旋钮按既有规则拒启 —— 那一形要给沙箱 / 子进程另铸一把凭据(名与值都不同于本服务的)再点名。服务进程(HTTP 服务 / `run-local` / bake-runner)零动作。
1366
+
1367
+ 104. **运维日志字段的扫描窗改读脱敏器导出的最长识别跨度(日志面;安全;wire 零变化;部署零动作)**:
1368
+ 旧形:有界日志字段(hook 输出 / 工具输出预览 / 标题 …)只扫头一段,窗 = `max(4 KiB, 界 × 8)` 读法单元,前半出门区、后半余量(座自定的数)。
1369
+ 新形:窗 = 出门区(`max(2048, 界 × 4)` 读法单元,与此前同)+ 余量(脱敏器导出的 `MAX_RECOGNITION_SPAN`,本版 8274 读法单元 —— 识别表里最长的有界结构,SSH2 私钥块的总长上界)。起于出门区、总长不超过余量的有界结构整段落在窗内,与整段脱敏逐字同判。
1370
+ **谁受伤**:总长越过余量的结构不保证与整段读法同判(窗读法从起点遮到窗尾:同记号、零明文,遮蔽范围只到窗尾);体长越过识别表上界(8192)的 SSH2 块整段读法本来不认,日志字段上此前被旧窗截断而多遮,现在与整段读法同读;窗变大,每次扫描量毫秒内。
1371
+
1372
+ 105. **🔴 脱敏器的不可见码点删除集改成一张 Unicode 属性表(`Default_Ignorable_Code_Point` ∪ `Mn` ∪ C1):夹在凭据中段的变体选择符 / 组合符 / C1 控制符 / 蒙古文自由变体选择符 / 谚文填充符 / 高棉固有元音不再让整枚凭据逃过识别(行为面;安全;脱敏产物可能变;wire 零新键;部署零动作)**:
1373
+ 旧形:读法格的删除集 = core 的格式字符(`\p{Cf}`)+ 契约包的剥除集(C0 / DEL / 双向控制符);一枚 `sk-…` 凭据中段夹一个 U+FE0F / U+E0100 / U+0301 / U+034F / U+0085 / U+180B / U+3164 / U+FFA0 / U+17B4(或它们的 `\uXXXX` 转义写法),整段读法与出口座的窗读法都原样放过。
1374
+ 新形:这些码点(与表里其余成员)按「留着当分隔 / 删掉当不存在」两种读法取并集,拼回完整的值就遮;没有凭据形的文本逐字节不变。读到的面与上一版同(trace 帧 / 终局文本 / 账本 / 审批预览 / 运维日志字段 / MCP 面板 …)。
1375
+ **谁受伤**:带这类码点的文本多读一遍(组合符写法的越南语 / 泰语 / 阿拉伯语 / 日语浊点、emoji 的变体选择符):脱敏产物只会多遮不会少遮,计算量随之翻倍(1 MiB 泰语文本实测约 18 ms → 约 47 ms;六类齐在的病态文本读法数上界 16 → 64);**升级前已落库的行**回放读面再过一遍脱敏的那几类面按新读法遮,已落库的原字节不改。
1376
+
1377
+ 106. **运维日志里嵌在句子里的 http(s) URL 按 URL 的 authority 文法收(日志面;安全;wire 零变化;部署零动作)**:
1378
+ 旧形:`a2a_peer_unavailable` / `mcp_server_unavailable` 的 `info` 里,URL 的扫描界到第一个空白或引号 / 括号类界符(含 `[` `]`)为止 —— userinfo 里带括号 / 引号的口令只换到前半段、后半段留句;IPv6 字面地址的 URL(`https://[::1]/x?token=…`)整条不被认作 URL;路径 / query 里的括号处同样截断。
1379
+ 新形:`http(s)://` 之后先收 authority(`userinfo@`?、主机或 `[IPv6]`、`:端口`?;最后一枚 `@` 才是 userinfo 的界),再收路径 / query / fragment 到空白为止;展示形仍是 `scheme://host[:port]` + `/…`。句末句读与闭合符(`. , ; : ! ?` 与 `) ] } > ' " \``)留在句里。
1380
+ **谁受伤**:URL 后面紧贴(无空白)的非 URL 文字被一并吞进这条 URL;userinfo 里的**裸空白**不是 URL 文法的一部分(第一个空白处结束,余下留句;受理口对该形一律 400)。按这两条日志的 `info` 字面值做匹配 / 告警的运维脚本留意展示形的变化。
1381
+
1382
+ 107. **🔴 主体长度改按 UTF-8 字节:至多 190 字节(此前 190 个 UTF-16 码元)—— 多字节、超 190 字节的主体名此后 400 `principal_too_long`;同一把尺管收件箱键、记忆退出名单、`?scope=` 查询与规则面的运维目标(行为 BREAKING;wire 句子改;码不变;零 DDL;部署动作:核一遍身份源会不会签出超 190 字节的名字)**:
1383
+ 旧形:边界判官数码元 —— 64–190 个 CJK 字(192–570 字节)的主体过判官,随后在按字节计宽的身份键列(收件箱 / 后台子代 / 名册 `VARBINARY(190)`)上写入失败(500);配额三表按码元 × 3 建成 `VARBINARY(570)`;
1384
+ 记忆退出名单、`GET /v1/sessions` 与名册读面的 `?scope=`、规则面 `POST` / `DELETE /v1/rules` 体里的 `principal` 各自数 190 个码元(后者连判官都不过)。
1385
+ 新形:唯一的尺 = 190 个 UTF-8 字节(`Buffer.byteLength`)。超了 ⇒ 主体头 / SSO 令牌 / bearer / 直连门 JWT 的 sub 同答 `400 principal_too_long`(句子报字节数);`?scope=` 两处 `400 request.query_invalid`;记忆退出路由 `400 request.path_malformed`;
1386
+ 规则面运维目标过鉴权边界同一只判官(名字 ∧ 良构、非保留、≤ 190 字节),过不了 ⇒ `400 request.field_invalid` `{ field: "principal" }`(在 operator 判之后;非 operator 照旧先拿 403)。新建库的配额三表列宽 190(两方言);
1387
+ 存量库(7.133.0 – 7.147.x 建)保留 `VARBINARY(570)`,不需要 ALTER(更宽、装得下;起服列集对账不比宽度)。主体头按 latin1 一字节一字符读:0x80–0xFF 的字节在 UTF-8 里各占 2 字节,含高位字节的头值上限约减半。
1388
+ **谁受伤**:用超过 190 字节的名字认证的身份(长 CJK / 表情名、长 email 形主体)—— 升级后 400,它名下已有的会话 / 审批 / 记忆行留在库里,该名认证不进来。**出路**:升级前让身份源把这类名字映射成 ≤ 190 字节的形(哈希或短 id),映射后的新名是一位新主体(旧行不随迁)。
1389
+
1390
+ 108. **🔴 含孤立代理项(不是良构 Unicode)的主体是 `principal_not_a_name`(行为收紧;安全轴;wire 零新码;部署零动作)**:
1391
+ 旧形:引擎名判不拒孤立代理项,鉴权边界照收;两只 SQL 驱动把它存成 U+FFFD ⇒ `"a\ud800"` 与 `"a\ufffd"` 等落在同一行(会话 / 问账属主、配额、规则桶、记忆 scope、限流键 ……)。
1392
+ 新形:SSO 桥 / bearer / 直连门 JWT 的 `sub`、组织投递收件人、A2A `audience` 与组织记忆名单配置、规则面运维目标里的孤立代理项一律按「不是名字」拒(边界 `400 principal_not_a_name`;投递门答 `not_member`;配置拒启)。主体头与 URL 带不进孤立代理项,这些入口零变化。
1393
+ **谁受伤**:签出带孤立代理项身份的签发方(坏数据)。**出路**:签发方修正身份编码。
1394
+
1395
+ 109. **删会话同拍删审批问账:`DELETE /v1/sessions/:id` 与 SQL 后端的托管留存清扫带走问账两表(`approval_ask` / `approval_batch`;local 的 `approval-asks/asks.jsonl` 同律)里挂靠该会话的问与它们的批;问表加索引 `idx_ask_source_session`(起服自动补建);嵌入方类型面 `ApprovalAskStore.deleteByTask` → `deleteBySession`(行为变更;删除面;嵌入方 BREAKING;local 账本里的退役动词记录走一次性迁移 M50;部署零动作)**:
1396
+ 旧形:删会话不碰两表,挂靠的问(卡上带工具实参字面)留到保留窗(`APPROVAL_ASK_RETENTION_MS`,缺省 30 天)按龄删;店接口的唯一删除动词 `deleteByTask(taskId)` 本服务从不调用。
1397
+ 新形:挂靠 = 问的宿主会话格或发问那条腿的会话格是被删的会话(没有会话的 adhoc 腿把 run id 填进会话格,那样的行不算),批随它的问走;已经没有问的空批照旧由保留窗收;审批审计账(`approval-ask-audit/ledger.jsonl`)不随会话删。
1398
+ `DB_BACKEND=local`:被删的问的字节离开账本才算删完 —— 账本压实失败 ⇒ 这次删除答 500、会话行留着,重发删除即补压。SQL 后端:存量库起服时补建 `idx_ask_source_session (source_task_id)`(既有的补索引机制;大表上是一次在线建索引)。升级前已删会话留下的问不做一次性清理,照旧由保留窗收。
1399
+ **嵌入方**:`ApprovalAskStore` 的 `deleteByTask` 删除、`deleteBySession(sessionId)` 新增(自带实现要补;直调的改调)。**local 账本(一次性迁移 M50,零动作)**:账本里若留着一条 `deleteByTask` 记录(只在嵌入方调过它、且进程停在那一次压实之前时出现),窗内起服按写下它的那一版的读法重放
1400
+ (删那条 run 名下的问与批)、起服压实把记录改写掉,stderr 一行点名条数与账本;窗(本版发布日起 30 天)关之后仍有 ⇒ 拒启,拒句点名账本、本条与出路 —— 用早于本版的版本起服一次(它的起服把删行记录压实掉),再升本版。
1401
+ **谁受伤**:删会话之后仍想从问账里查这只会话审批历史的运维(本来只保 30 天)。**出路**:要留底就在删会话之前导出;审计痕迹在审计账里照留到它的保留窗。
1402
+
1403
+ 110. **🔴 会话删除是一只三态(活 → 删除中 → 没了):删除与提交至多各赢一个;删除答 409 时什么都没删;删完之后这只会话名下不留 run 行;同一只会话的删除已在进行 ⇒ `409 conflict.session_deleting`(行为修复;wire 新码;持久面:SQL 后端一句 ALTER + 一次性迁移 M51,停-迁-起,不可滚动;`DB_BACKEND=local` 零动作)**:
1404
+ 旧形:`DELETE /v1/sessions/:id` 在 run 账腿判一次「没有在跑的 run」、删行时再判一次,两判之间不挡认领 —— 提交在这一段认领时,删除可能答 409 而会话规则等子数据已删,或删除与提交两边都答成功、这次 run 的 run 行留在已删会话名下。
1405
+ 新形:删除先在会话根行的锁里判认领并写下这次删除的令牌(删除中;SQL = `session_ext.deleting_token`,local = 会话元数据那一格),判到认领 ⇒ 409 `conflict.session_active_run`,一个字节没写;写下之后到删完,这只会话对删除门之外的读者与写者读作不在
1406
+ (头读 / 列表 / 导出 / 新 run 认领答 404 `resume.session_not_found` / 同 id 登记不新建),删除的每一步之前复核令牌仍是这一次的,删行那一刀在根行锁里判令牌。删除中不回到活:某一步失败 ⇒ 500,同一属主重发接着删完,下一次起服由删除协调器收尾删完。
1407
+ 同一只会话的另一次删除仍在进行 ⇒ `409 conflict.session_deleting`(这次请求不等它、自己不删任何东西;那一次已经进了删行的事务 / 锁节 ⇒ 这次等它提交、答 `{ deleted: false }`;删完之后重发答 `{ deleted: false }`;SQL 多副本上别的副本那一次删除开始后 10 分钟内不被接管)。会话同步导入 / 会话规则写 / 附件绑定在门判过之后才撞上删除中 ⇒ 同码,什么都没写。
1408
+ **升级前做(SQL 后端)**:① `ALTER TABLE session_ext ADD COLUMN deleting_token VARCHAR(36) NULL`(MySQL 协议)/ `ALTER TABLE session_ext ADD COLUMN deleting_token VARCHAR(36) COLLATE "C"`(PostgreSQL);不执行 ⇒ 起服拒 `config.schema_mismatch`,拒句给该方言那一句。
1409
+ ② 停光全部旧版本副本再起本版:本版第一只副本起服时(一次性迁移 M51)判活窗内还有 `running` run 在心跳 ⇒ 拒启 `config.session_deleting_switch_refused`(一个字节不写;拒句给出可再起的时刻),否则落启用标记,此后不再判。心跳只是探测器 —— 没有在跑 run 的旧副本探测不到,停光旧副本是前提。
1410
+ **谁受伤**:按「删除失败之后会话还在」做重试判断的客户端 —— 删除中途失败(500)之后,会话此刻已读作不在;原样重发 `DELETE` 即可删完。**出路**:按码分支:`conflict.session_deleting` 等一会儿再发,`conflict.session_active_run` 先停在跑的 run。
1411
+ **回滚(SQL)**:先确认 `SELECT COUNT(*) FROM session_ext WHERE deleting_token IS NOT NULL` 为 0(不为 0 ⇒ 用本版起一次让收尾删完),再 `ALTER TABLE session_ext DROP COLUMN deleting_token`。`DB_BACKEND=local`:回滚前用本版起一次,日志里没有 `session_delete_recovery_unfinished` 再换旧版。
1412
+
1413
+ 111. **前台命令超时转后台缺省开:新旋钮 `AUTO_BACKGROUND_ON_TIMEOUT`(缺省 `true`);`/health` 多一键 `autoBackgroundOnTimeout`(行为变更;wire 加性;部署零动作)**:
1414
+ 旧形:前台 Bash 命令撞上它自己的超时一律被杀(工具结果 = 超时错误 + 已捕获的输出)。
1415
+ 新形:host(单用户、后台 shell 开着)/ k8s / e2b 车道上,合格的命令(引擎判:命令里没有 `git`、首词不是 `sleep`)超时到点转成后台任务继续跑,工具结果是「超时了但仍在跑,已转后台(task_id=…)」;后台 shell 满了照旧杀;同一个开关还让引擎在有人的输入(steer / 排队的消息)等着、而合格命令还在跑时把它转后台,好让输入先送达。其余车道行为不变。`GET /health.autoBackgroundOnTimeout` = `armed` / `off` / `unsupported`(本车道上生不生效)。
1416
+ **谁受伤**:依赖「超时即杀」回收资源或判失败的部署与脚本 —— 超时之后命令仍在跑、仍占进程或沙箱算力(受后台 shell 并发上限与后台超时硬上限约束);假定「steer 之后前台命令先跑完」的调用方。**出路**:写 `AUTO_BACKGROUND_ON_TIMEOUT=false` 回到超时即杀、steer 等前台命令跑完(逐字节同旧形)。**回滚**:回到上一版时这根 env 被忽略,`/health` 这一键消失。
1417
+
1418
+ 112. **订正 7.147.0 节第 5 条的闭集:SQL 起服建 `session_ext` 的「确定拒」两个方向一起收 —— 补齐 MySQL 协议建外键整族;1005 按内层错误号分(盘满等资源类不再当场拒启);拒句按失败类带出路与库答原码(起服拒启面:更多形当场拒、盘满一形改为重试;wire 零新键、零新码;部署零动作)**:
1419
+ 旧形:确定拒的闭集只含外键两侧不相容 3780 / 加不上外键 1215 / 被引列缺索引 1822 / 存储引擎拒建表 1005(整码)/ 表级权限拒 1142 / 缺表 1146。① MySQL 9.x 对「被引表 `session_meta` 打不开(不是 InnoDB)」答 1824、对「被引表缺唯一键(无主键)」答 6125,两码在闭集之外 ⇒ 开库等待窗(`STORE_LOCK_WAIT_MS`,缺省 60 s)重试满窗后才拒,窗尾拒句指「修 `MYSQL_*` 坐标 / 连通性」。② 1005 整码判确定拒,含内层号 28(盘满)的那一形 ⇒ 首次建 `session_ext` 撞盘满当场拒启并点名 `session_ext`。
1420
+ 新形:闭集补 1821 / 1824 / 1825 / 1826 / 3734 / 6125(建外键族,按码登记;1823 与运行期的 1451 / 1452 / 3008 不在其中),这些形当场拒启 `config.schema_mismatch`;拒句带库答的 `errno <数字> <符号>, SQLSTATE <五位>`,出路是 `session_meta` 的引擎(InnoDB)/ 主键或唯一键 / 字符列、TiDB 版本、CREATE 授权。1005 是包装码:只在库消息模板里的内层号是 150(外键形不成)/ 121(约束名已占)时才当场拒启;内层 28(盘满)等资源类与读不出内层号的形原样上抛、走开库等待窗重试(窗尾拒句带着库的原句,句尾出路仍是通用的「修坐标 / 连通性」,该清的是盘)。开库拒句对库确定拒了一条语句的失败(同一只判官)同样改写出路(不再指坐标 / 可达性);连不上 / 超时 / 认不出的句子不变。缺对象存储的启动拒句(`DB_BACKEND=pg`)改写 PostgreSQL 的事实,不再写 TiDB 与 mysql 协议的墙。
1421
+ **谁受伤**:无(前两形本来就起不来,只是更早、出路写对;盘满一形由当场拒启变重试到窗尾再拒,多等至多一个窗,出路不变:清盘 —— 要当场拒就设 `STORE_LOCK_WAIT_MS=0`)。**出路**:按拒句修 `session_meta`(`ALTER TABLE session_meta ENGINE=InnoDB` / 补主键)后重起;盘满清盘;其余部署零动作。
1422
+
1423
+ 113. **一次性迁移 M10 / M11 退役:local 车道会话属主的窗内认领与 SQL 起服的持久规则坏 scope 行删除删码;`OneTimeMigrationReport` 去三键、起服日志去一条认领行与两种逐行 / 逐桶告警(持久数据面;行为变更〔无主存量会话不再被认领;`conflict.session_ownerless` 的句子只剩一条出路〕;运维日志形变更;嵌入方 BREAKING,类型面)**:
1424
+ 7.119.0 / 7.120.0 引入的两条一次性迁移,窗(发布日 2026-10-08 + 30 天)于 2026-11-07 关,本版删了它们的码。M12 / M13 的窗(2026-11-08 / 11-09 关)本版不动,随后续版本窗关即删。逐处删了什么、删后存量形由谁接住:
1425
+ - **M10(`DB_BACKEND=local`:会话属主的窗内认领)**:7.119.0 起 local 店把会话属主落盘;7.118.x 及更早写下的会话,边档那一格只有化身、没有属主事实,升级窗内由带 principal 的第一次提交 / 登记认领(一行 info `session_owner_claimed`)。
1426
+ 本版删认领臂:`LocalSessionStore.register` 对这种会话只补化身、不记属主;授权口不再为已存在的无主会话调 `register`;窗读口与认领日志行 `session_owner_claimed` 不再有。**认领本身删码零行为变化** —— 窗按日历日判(2026-11-07 关〔含当日〕,UTC 2026-11-08 00:00 起认领就已不生效),与哪个版本在跑无关。**唯一可观测的差在授权口**:它不再为已存在的无主会话调 `register`(那一步的存在性探针会读存档),所以存档读不出(`corrupt_session`)的无主存量会话,带 principal 的提交不再在授权口被这一步拒掉 —— 授权通过,存档的故障改由读存档那一步按腿答(同步 500 / 流式终帧 / 后台行 `corrupt_session`),与认领面其余各口同一条契约(门只判归属、不碰存档)。
1427
+ 没有响亮的起服臂。属主从没被记下的存量会话(7.119.0–7.147.x 的窗内从没被带 principal 的提交认领过的)照旧读作无主:它的会话规则这条路由读不了也改不了(`409 conflict.session_ownerless`),已存的规则对写下它们的 principal 的 run 照旧生效;
1428
+ 任何 principal 仍可附着它(普通无主行)。**该 409 的句子改了**:原句末「Ways out: on the local backend, during the upgrade window, … claims it for that principal …; or delete the session …」两条出路里,认领那一条没了,只剩「Way out: delete the session (DELETE /v1/sessions/:id), which removes its rules with it」(码与状态不变)。
1429
+ 出路 = 删会话(规则随之删)。SQL 后端(`mysql` / `pg`)的属主一直在 `session_meta.owner` 列上,没有这一半。
1430
+ - **M11(`DB_BACKEND=mysql|pg`:持久规则桶里坏 scope 行的起服删除)**:起服不再逐桶扫描 `permission_rule`、不再把 project scope 的 root 不是完整绝对路径的行(7.119.x 及更早的入口按「root 非空」收下的;引擎 7.46.0 起读侧丢它)回写删掉。
1431
+ 存量的那种行留在桶里:引擎读侧继续在有效视图里丢它、每次 run 一条 `permission.rule_row_dropped`(点名规则与 root),那一行不参与任何检查(其中一条 deny / ask 行什么都没保护),撤销口删不动它(引擎的写臂对这种 scope 同样拒)。
1432
+ 出路 = 运维在库里把那只桶的那一行删掉(整桶 OCC 回写,指纹按 `buildRuleBucketChecksum` 重算)。读腿整桶拒的桶照旧整桶拒(出路是人)。店内判官与写法不动(它们是读腿 / 写臂本身)。`DB_BACKEND=local` 的持久规则在引擎自己的 File 分区里,这一半对它本来就是空转。
1433
+ - **运维日志**:起服行 `one_time_migrations_applied` 与被打断时的 `one_time_migrations_interrupted` 去掉 `undurableScopeRuleRowsRemoved` / `undurableScopeRuleBucketsDeferred` / `undurableScopeRuleBucketsUnreadable` 三个读数字段(`removableAfter` 读数去掉 `M10` / `M11` 两个键,`note` 不再叙述它们);
1434
+ 逐行的 `permission_rule_row_removed` 与逐桶的 `permission_rule_bucket_unreadable` 两种告警、认领行 `session_owner_claimed` 不再有。按这些行名或字段做告警 / 看板的规则要改。
1435
+ - **嵌入方(类型面)BREAKING**:`StoreBackend.runOneTimeMigrations()` 的返回型 `OneTimeMigrationReport`(经包根导出的 `StoreBackend` 可达)去掉 `undurableScopeRuleRows` / `undurableScopeRuleBucketsDeferred` / `undurableScopeRuleBucketsUnreadable`;
1436
+ 读它们的代码、把值标成 `OneTimeMigrationReport` 再写这些键的对象字面量 tsc 红;自实现该方法、未标注类型就直接返回含这些键的字面量的代码 tsc 不报(多出的键没有人读),也请一并删掉。`LocalSessionStore` 的构造参数不变(`log` 位还服务其余运维行)。
1437
+ - **谁需要**:所有部署 —— 起服少走一步(SQL 少一次规则表扫描)、日志少几种行。
1438
+ - **谁受伤**:① `DB_BACKEND=local` 上从 < 7.119.0 直接升到本版、或升级窗内从没带 principal 提交过的存量会话(属主仍是「没被记下」,不会再被认领;规则路由 409 句子换了);② 从 ≤ 7.119.x 直接升到本版、中间没在 7.120.0–7.147.x 任一版对这只库起过服的 SQL 部署 —— 桶里仍有坏 scope 的存量行(读侧每次 run 丢一行并通告,删除要运维手工);③ 按被删日志行名 / 字段做告警的运维;④ 按 409 句子里「upgrade window」那半句匹配的客户端。
1439
+ - **补偿 / 做法**:**M11 那一类**:直升的 SQL 库先在 7.120.0–7.147.x 任一版上起服一次(那几版的起服会删掉这些行),再升本版;或升级后在库里手工删那几行。**M10 那一类**:没有按版本补的路 —— 认领按日期判,UTC 2026-11-08 00:00 起任何版本都不认领;不要的无主会话删掉(`DELETE /v1/sessions/:id`)。
1440
+ **升级前做**:常规从 7.147.x 升级的部署无须动作;**回滚**:回到 7.147.x 即恢复旧读法(认领臂按日期已停、M11 的起服删除重新开始跑),本版没有写任何新的存储形。
1441
+
1442
+ 114. **勘误(7.140.0 节第 7 项末句「引擎侧修好之前请别对 cascade 任务开耐久审批」自本版起过期;已发节不改字节;文书,本条零新行为;部署零动作)**:
1443
+ 那一句写的是 7.140.0 当时的已知限制:`cascade:true` 任务的某一级停在审批上时,行 `failed` + `unexpected.suspended`,卡在 `GET /v1/approvals` 里看得见却决不掉(409 `conflict.resume_context_unavailable`)。
1444
+ 这个限制的两半都已收齐:引擎那一半已随 core 7.61.0 到货(引擎在级上的卡上记下它属于哪个宿主会话);本服务那一半即本段第 84 条(`checkpoint.host_session_id` 记下卡归在哪只会话上;cascade 的级上停驻是这条 run 的停驻;决定那张卡 ⇒ 200 带 `taskId`、同一条 run 行接着跑)。
1445
+ 所以 **cascade 任务可以开耐久审批了** —— 「请别开」自本版起不再适用;本版的行为由第 84 条定,本条不引入任何新行为。7.140.0 节第 7 项的原文保持不动(已发节与 tag 逐字一致)。
1446
+
1447
+ 115. **嵌入方:`createHttpServer` 的鉴权桥验签器席(`ServiceDeps.webAdminJwtVerifier`)与配置里的桥必须成对 —— 注入了验签器而配置没声明桥,或配置声明了桥(`authBridgeIssuer`;缺席而接了中心 ⇒ 中心基址回退)而没注入验签器,构造期都拒启(嵌入方装配面 BREAKING;服务入口零变化;wire 零变化;部署零动作)**:
1448
+ 旧形:「这台部署接了哪几个身份来源」读装配(验签器在不在):`/health.auth.kinds` 的 `sso`、属主门的 dev-open 判据、受限技能的身份边界座都看它 —— 配置里有桥而没注入验签器的嵌入读成没有桥,注入了验签器而配置没桥的嵌入读成有桥。
1449
+ 新形:这件事只从配置读(与一次性迁移同一只读法,迁移在验签器建好之前就跑);服务入口起服时按配置里同一个 issuer 建验签器,两者恒一致。嵌入方两者不一致 ⇒ `createHttpServer` 抛,
1450
+ 句子以 `createHttpServer: a webAdminJwtVerifier was injected but the config declares no auth bridge` 或 `createHttpServer: the config declares an auth bridge` 起头。
1451
+ **谁受伤**:自己装配 `createHttpServer`、配了中心或 `authBridgeIssuer` 却不注入验签器(或注入了验签器、配置里却没有桥)的嵌入方。
1452
+ **补偿 / 做法**:两边对齐 —— 配置声明了桥就注入一只验那个 issuer 的验签器;不要 SSO 就把 `authBridgeIssuer` 与中心都从配置里拿掉(接了中心的部署恒有桥)。
1453
+ **升级前做**:嵌入方按上面对齐;服务入口(`sema-server` 进程 / 镜像 / chart)无。**回滚**:无存储形变化。
9
1454
 
10
1455
  ## 7.147.0 —— 1–30 条见下
11
1456
 
@@ -751,14 +2196,14 @@
751
2196
  没开缓存卷的部署也持有 `deletecollection persistentvolumeclaims`,没转发 env 的部署也持有 `secrets create`。
752
2197
  新形:这两条规则只在对应开关开着时授 —— `WORKSPACE_CACHE=volume` ↔ chart 值 `sandbox.workspaceCacheVolume`(布尔,缺省 `false`;`--set-string …=false` 这类字符串渲染即拒)、
753
2198
  `K8S_SANDBOX_ENV` 非空 ↔ chart 值 `sandbox.sandboxEnv`(`NAME,NAME` 名单字符串,缺省空)。同一个 chart 值**同时写引擎 env**(主 worker 与 v4pro 变体)与 Role 规则,开关与引擎旋钮只有一个写者;
754
- cluster 静态清单里这两条规则是注释块,给 server 设了对应 env 时取消注释。规则表只写在源码的一张表里,chart / 静态清单 / 随包 `deploy/facts/sandbox-rbac.json` 与部署前置文档(仓库 docs 目录下 DEPLOY-PREREQS)的规则表都从它生成。pod / exec / log 与出网自检的两只只读照旧恒授。
2199
+ cluster 静态清单里这两条规则是注释块,给 server 设了对应 env 时取消注释。规则表只写在源码的一张表里,chart / 静态清单 / 随包 `deploy/facts/sandbox-rbac.json` 与源码仓里的部署前置文档(内部记录)的规则表都从它生成。pod / exec / log 与出网自检的两只只读照旧恒授。
755
2200
  **谁需要**:按最小权限部署 k8s 沙箱车道的 owner(没开缓存卷 / 没设沙箱 env 的部署不再持有这两条规则),以及整份拷走 chart 沙箱 RBAC 模板的取用方(规则与开关同表驱动)。
756
2201
  **谁受伤**:用随包 chart 或静态清单、引擎旋钮是**手补在 Deployment 上**(chart 之外)的存量部署 —— 升级后 Role 里没有对应规则:
757
2202
  `K8S_SANDBOX_ENV` 点到了本进程环境里有的键而 `secrets` 缺 `create` ⇒ **起服拒**,拒句带 `[sandbox-secret-rbac]`、点名缺的动词与要加的 Role 规则原文;
758
2203
  `WORKSPACE_CACHE=volume` 而 `persistentvolumeclaims` 缺动词 ⇒ 服务起得来,但每条 run 拿不到缓存卷(run 照起、不挂卷),fail-open 计数 `server.workspace-cache.unavailable` 涨。
759
2204
  **补偿 / 怎么改**:用 chart 的 —— 在 values 里开对应开关(`sandbox.workspaceCacheVolume: true` / `sandbox.sandboxEnv: "NAME,NAME"`),chart 同时写引擎 env,之前在 Deployment 上手补的同名 env 可以去掉;
760
2205
  用静态清单的 —— 取消对应规则注释块的注释;自维护 chart / 手写 RBAC 的 —— 照随包 `deploy/facts/sandbox-rbac.json`(`when` 列 = 开关)补那一行规则。把 `templates/sandbox-rbac.yaml` 整份拷进别的 chart 的取用方,只需在自己的 values 里补这两个键(模板自带开关判官;键缺席渲染即拒)。
761
- **升级前做**:两个旋钮都没设 ⇒ 零动作(升级后 Role 少了两条多余权限);设了的部署按上一条在升级前开好开关。语句与读法同部署前置文档(仓库 docs 目录下 DEPLOY-PREREQS)7.146.0 节。**回滚**:回到 7.145.x 即恢复无条件渲(零持久形变化)。
2206
+ **升级前做**:两个旋钮都没设 ⇒ 零动作(升级后 Role 少了两条多余权限);设了的部署按上一条在升级前开好开关。语句与读法以上一条为准。**回滚**:回到 7.145.x 即恢复无条件渲(零持久形变化)。
762
2207
 
763
2208
  23. **引擎 7.63.0 → 7.64.0(`@sema-agent/core` 与 `@sema-agent/primitives` 同版精确钉):① 🔴 会话帧与会话盒按住客投 —— 升级前让旧副本排空会话盒,混版副本共一只信箱时旧副本领不动装着本版记录的盒、本版副本弃掉旧副本写下的记录;② 🔴 File 记忆店的「绑定之前」账本形退役 —— 先用上一版引擎开一次再升级;③ 共用一只记忆控制面的副本一起升级,隔离席文件名换形;④ 停驻行三处判坏(门 × 待决动作配对、`checkpointId` 空串、资源账非对象);⑤ 规则提议里无 kind 的批成员整批丢;⑥ 兑付腿的店故障只在店没变时可重试,规则导入的成员结局不知 ⇒ 不落定、同票重走;⑦ 一次性迁移(导入层根的全局放行退役)local 腿读得更全、坏桶点名跳过;⑧ 拒绝回显 `tool_end.gate.disposition.echoed` 上帧 · 扣信回执分 `held` / `held_by_policy` · 委派腿通告投树根 · 记忆通告改走首个请求;⑨ `DB_BACKEND=local`:删会话连文件历史的 v1 基线一起删,`overwrite-dst` 同步重推整段替换目的端文件历史(行为变更 + 硬破坏三条;wire:一帧键加性;升级前做见本条)**:
764
2209
  换钉:`@sema-agent/core` 7.63.0 → 7.64.0 精确,`@sema-agent/primitives` 随之 7.64.0。下列各项按「谁看得见」排。
@@ -906,7 +2351,7 @@
906
2351
  **补偿**:老 server 不带这个键 ⇒ 按原读法(本端提交的 run / 行的会话 = 当前会话)。**升级前做**:无。**回滚**:回到上一版即不带这个键;落盘数据不受影响(本版不写任何新形)。
907
2352
 
908
2353
  3. **订正 7.144.0 节第 12 条「远端五车道不变」一句:k8s / local-docker / ssh / adb / e2b 上家目录主张证不了时,第一句拒是哪一形按命令形、执行面与会话分(文字订正;零行为变更)**:
909
- 7.144.0 节第 12 条(与契约附录 A 的 `env.home_unconfirmed` 行、USAGE §9 的同一行、DEPLOY-PREREQS 的 `REMOTE_EXEC_HOME_DIR` 节)写这些车道「照旧在开环境那一拍拒、拒句落在工具结果里;递归读形与 adb 上连带路径的普通读先被读边界拦下」。
2354
+ 7.144.0 节第 12 条(与契约附录 A 的 `env.home_unconfirmed` 行、USAGE §9 的同一行)写这些车道「照旧在开环境那一拍拒、拒句落在工具结果里;递归读形与 adb 上连带路径的普通读先被读边界拦下」。
910
2355
  7.144.0 发出后的复跑(真引擎 Runner,五条车道的供方换成假的;每格另跑一遍主张 = 实测的负控,只记两遍不同的形)读到的形比这句多,读法以本条为准(已发节原文不改):
911
2356
  ① **环境在开跑前就被打开**:新提交腿上,引擎拿到执行环境后的第一件事是把任务根读成规范路径,这一读就让车道建连、问 `$HOME`、判出拒;引擎把这次失败读作「任务根读不成规范形」,照样开跑(模型照常被调),拒句要等模型的第一条工具调用才再被答出来。模型要跑的命令一条都没进环境(车道自己建根、探 shell、问 `$HOME` 的命令照跑)。
912
2357
  ② **全 shell 面**:不带路径的命令(`echo hi`、`ls`)⇒ 工具结果 `shell_unavailable` + 判官的拒句(点名声明值、实测值与改法)。带路径的命令(路径不在读拒表上 —— 读拒表命中的路径照旧先答读拒表的拒)先撞引擎的读边界(要人批,句子「could not establish what is read」,不点名家目录)的范围:
@@ -1519,7 +2964,7 @@
1519
2964
  ② 两端同版后的第一轮:每一层带基线的游标(升级前写下的,没有化身)被中心拒 `absent`,本机那一层停驻(`GET /v1/sessions/:id/memory-status` 的 `memorySync.parked[]`、运维行 `memory_sync_layer_parked { axis: "incarnation", found: "absent" }`),停驻层每一轮仍发一次请求、被中心在写之前拒掉;
1520
2965
  ③ 中心从备份恢复:恢复回来的化身就是备份时那一只,读作同一份状态 —— 备份之后设备上的新条目照旧会被删掉或回滚(引擎的已知限制)。
1521
2966
  **补偿**:① 两端都升到本版,先后不限(升级期只是不同步,不丢数据);② 删掉停驻层的游标文件(运维行 `cursorPath` 逐字;`<记忆引擎根>/sync-cursors/<scope 的 sha256 前 32 位>.json`),下一轮从空基线重收敛:
1522
- 两边都改过的条目按冲突报,上一轮之后一侧删掉的条目会从另一侧回来;③ 中心从备份恢复之后、起服之前删掉 `agent_memory_engine_sync_partition` 的全部行(轮换化身):每个客户端下一轮被拒 `other`、按 ② 处置(DEPLOY-PREREQS)。
2967
+ 两边都改过的条目按冲突报,上一轮之后一侧删掉的条目会从另一侧回来;③ 中心从备份恢复之后、起服之前删掉 `agent_memory_engine_sync_partition` 的全部行(轮换化身):每个客户端下一轮被拒 `other`、按 ② 处置。
1523
2968
  **升级前做**:无(新表起服时 `CREATE TABLE IF NOT EXISTS` 自建;库账号已有建表权限)。**回滚**:旧中心不认 `/v2` ⇒ 同步再停;本版写下的游标带 `peerIncarnation`,旧二进制按名挑员时丢掉它 —— 回到旧版即回到旧语义;新表留着无读者。
1524
2969
  **嵌入方**(自建 `ServiceDeps`):`memorySync` 的答型改为 `MemorySyncAnswer`(结果或拒答);自建 `MemorySyncStore` 多一口 `partitionIncarnation(scope)`(TypeScript 编译红即通知)。
1525
2970
 
@@ -3014,7 +4459,7 @@
3014
4459
  **升级序**:先把读同一只会话规则店的**全部**副本升到本版,再放会话规则的写(`PUT /v1/sessions/:id/policy`、2c 同步导入);做不到就先排空旧副本。单进程部署零动作。
3015
4460
  **回滚**:本版写下的行旧版读不了(同上的整行拒),而且在本版上重写一遍没有用 —— 本版的写口判官照样盖戳 `4`;旧版的 `PUT` 也改不了它(写前先读那一行,读不出 ⇒ `500 corrupt`)。
3016
4461
  要回滚,这些会话在旧版上只有两种结局:每一次工具调用都拒(失效关闭),或删会话(规则随之删)。**不要**在库里把戳改回 `2`:同一条目在文法 2 里意思不同
3017
- (`toolDeny` 的 `mcp__*` 在文法 2 里什么也不拒),改戳 = 静默放宽。混版实测读数与部署前置写在仓库的部署前置清单(不随包)7.135.0 节。
4462
+ (`toolDeny` 的 `mcp__*` 在文法 2 里什么也不拒),改戳 = 静默放宽。混版实测读数是内部记录。
3018
4463
  **人的持久规则(同一件事的另一只店)**:引擎 7.55.0 起持久规则桶带文法戳,新文法写下的 deny(Bash 中段 `*` 的模式形、`Agent(<类型>)`)在 7.54.x 上**什么也不拒**
3019
4464
  (旧引擎不读戳,把模式形读成「无形」)—— 同一份规则目录(`DB_BACKEND=local`)或同一只库不要混跑两版,先升全部进程;**降级到 7.55.0 之前**:先把这类 deny 改写成覆盖它的前缀 deny
3020
4465
  或整工具 deny,或不降。SQL 持久规则店自本版起也写 / 读这只戳(`permission_rule` 加一列,见第 16 条),且**戳算进桶的完整性指纹**:本版副本读到更晚文法写下的桶整桶拒、每次调用问人;7.134.x 副本(引擎 7.54.1)不读戳,
@@ -3326,7 +4771,7 @@
3326
4771
  adb 仍照单全收。**升级前对 k8s 部署核一遍**:在镜像里跑 `printf %s "$HOME"`,与声明值比;对不上的按拒句改声明(或让镜像以声明的用户运行)。**谁受影响**:① 此前为了消掉起服 warn 而手填了 `REMOTE_EXEC_HOME_DIR` 的部署 —— 不必改,声明仍胜;想让车道自己测就删掉它,**但**用了 `~/` 形权限规则的部署必须保留声明:
3327
4772
  `~/` 形规则的下单门与规则基仍只认声明(提交任务那一刻执行环境还没开),没声明 ⇒ 照旧 `422`;② 按起服行 `execution_lane_home_undeclared` 配了告警的运维 —— 这一行现在只在 device 车道起服时响;k8s / local-docker / ssh / adb 没声明时起服不再响,
3328
4773
  改成**某只环境实测缺席时**响同一只事件码(字段仍是 `provider` + `note`,note 点名读到了什么;同一部署同一句只响一次),把告警条件从「起服出现」改成「运行期出现」;③ 没声明的部署上引擎对这四条车道的家锚拒读行落位变了
3329
- (由「没有家目录时在任何位置按路径段判」落到实测的家目录下,并另锚引擎宿主的账户家、每条 run 的落位多一次经该车道 `canonicalPath` 的账户家探针,上限 2 s —— 引擎对「声明了家」的远端车道的既有口径,见部署前置文档(仓库 docs 目录下 DEPLOY-PREREQS)该节;本版未在真集群上实测)。
4774
+ (由「没有家目录时在任何位置按路径段判」落到实测的家目录下,并另锚引擎宿主的账户家、每条 run 的落位多一次经该车道 `canonicalPath` 的账户家探针,上限 2 s —— 引擎对「声明了家」的远端车道的既有口径;本版未在真集群上实测)。
3330
4775
  **做法**:k8s 部署核声明与镜像用户的 `$HOME`(上一段);其余无需动手;想看到实测值是否生效,看运行期是否出现 `execution_lane_home_undeclared`(出现 = 那只环境的 `$HOME` 读不出绝对路径:修环境的 `HOME`,adb 上也可以声明;k8s / local-docker / ssh 上声明替代不了一个读不出的 `$HOME`,会被拒)。
3331
4776
  12. **SQL 后端(`DB_BACKEND=mysql` / `pg`):workflow 续跑日志(journal)的属主 scope 搬进新表 `workflow_journal_owner`,`workflow_journal` 起服一次性按新主键重建(持久数据;🔴 先停旧副本再起新)**:
3332
4777
  7.132.x 及以前 scope 是 journal **每一行**上的一列,读面按它判、写面不判(别的 scope 能往一条 run 里写)。本版起一条 run 的属主 scope 只记在 `workflow_journal_owner` 一行(主键 `run_id`,
@@ -5179,7 +6624,7 @@
5179
6624
  - **🔴 回滚到 7.115.x 之前排空停驻行**:7.116.0 停驻的行可能带 7.115.x(引擎 7.40)不读的技能授予节 / 卡绑定,或续跑上下文里某只技能声明的非空 `disallowedTools`(那只技能停驻时还没被激活、没有授予行可冻 —— 回滚后模型再激活它,上一版什么也不拒)—— 在 7.115.x 上续跑这种行,这一 run 的技能禁止行会丢。
5180
6625
  回滚前在 7.116.0 上跑排空配方(随包只读 SQL:`node_modules/@sema-agent/server/scripts/drain-check.pg.sql`(`psql "<连接串>" -f …`)/ `drain-check.mysql.sql`(`mysql … < …`),`skill-grants-rollback` 那一行 `hit_rows` 为 0 才回滚;
5181
6626
  `DB_BACKEND=local` 用随包 `node scripts/drain-check-local.mjs [<数据根>]`,首行 `SKILL-GRANTS rows=0 …` 才回滚)。本脚本的末行从两行变四行(含下面的升级前判据):`SKILL-GRANTS …` 排第一,倒数第二行仍是 `PERMISSIONS-ALLOW-LIST …`、最后一行仍是 `RETIRED-MODE-SEED …`。
5182
- - **🔴 排空配方现在在包里(7.116.0 起)**:此前排空 SQL 只写在不随 npm 包出的 `docs/DEPLOY-PREREQS.md` 里,只装 npm 包的部署读不到。现在两只可直接执行的 SQL 文件随包出(`scripts/drain-check.mysql.sql` / `scripts/drain-check.pg.sql`,与本地脚本同一目录、
6627
+ - **🔴 排空配方现在在包里(7.116.0 起)**:此前排空 SQL 只写在不随 npm 包出的部署文档里(内部记录),只装 npm 包的部署读不到。现在两只可直接执行的 SQL 文件随包出(`scripts/drain-check.mysql.sql` / `scripts/drain-check.pg.sql`,与本地脚本同一目录、
5183
6628
  每条判据一段、整只文件一次跑完出一行读数 `criterion | hit_rows | sessions`),文档里不再持有 SQL。**还没升到 7.115.0 的部署**(要在升级前数):不必先升级服务 ——
5184
6629
  `d=$(mktemp -d) && (cd "$d" && npm pack @sema-agent/server@7.116.0 && tar xzf sema-agent-server-7.116.0.tgz)`,拿解开的 `$d/package/scripts/drain-check.<mysql|pg>.sql`(或本地后端的 `drain-check-local.mjs`)去跑;
5185
6630
  四条判据各自该在哪个版本边界跑看该条所在的那一节(`permissions-allow-list` 见 7.115.0 节、`retired-mode-seed` 见 7.113.0 节、`skill-grants-rollback` 与 `retired-skill-manifest` 见本节)。判据与读数不变,只是搬了家并多一条。
@@ -5463,7 +6908,7 @@
5463
6908
 
5464
6909
  ### 运维日志事件名退役一族(车 UQ / 车 UR)—— 按事件名配告警 / 数行的运维要改配
5465
6910
  - **退役(不再逐记录发 warn)**:`session_repo_corrupt_read` · `workflow_journal_corrupt_read` · `workflow_run_corrupt_read` · `roster_corrupt_read` · `background_agent_corrupt_read`(该座已删,披露归 backend 的 `file_store_corrupt_read`)· `mailbox_corrupt_read`(车 UQ 六座);`approval_ask_journal_corrupt_read` · `run_store_corrupt_read` · `resume_anchor_corrupt_read` · `send_file_ledger_corrupt_read` · `approval_ask_audit_corrupt_read` · `workflow_notify_journal_corrupt_read` · `workflow_agent_session_ledger_line_rejected` · `user_input_ledger_corrupt_read`(车 UR 八座)。
5466
- - **替代读法(F 类座纪律,同一只记录器)**:每座一个 tag —— 进程内**一次** `fail_open` warn(首条明细 + 指路)、`fail_open_total{tag}` 计数每命中 +1、`SEMA_FAILOPEN_PROBE=1` 时每命中一行探针(`kind=record path= line= form= reason=`);tag 名见 `docs/FAIL-OPEN-CENSUS.md`(第 110–113 / 115 / 117 行与其余既有行)。
6911
+ - **替代读法(F 类座纪律,同一只记录器)**:每座一个 tag —— 进程内**一次** `fail_open` warn(首条明细 + 指路)、`fail_open_total{tag}` 计数每命中 +1、`SEMA_FAILOPEN_PROBE=1` 时每命中一行探针(`kind=record path= line= form= reason=`);tag 名 = 随包 `dist/observability/fail-open.js` 里 `FAIL_OPEN_TAGS` 的键(`server.<座>.corrupt-record-skipped` 形与其余既有项)。
5467
6912
  - **保持逐命中响亮(安全轴混座,不退役)**:`file_store_corrupt_read`;其 session-policy 脸的坏读今天仍 fail-open(引擎修后改拒),server 7.113.0 起同时计 `server.session-policy.corrupt-read-fail-open`(P-DEBT)。
5468
6913
  - **run-local 车道**(前台 CLI 进程)的会话 repo 仍走混座逐命中 warn,不降。
5469
6914
 
@@ -5485,7 +6930,7 @@
5485
6930
  - **会话删除 / 托管留存级联接上用户输入受理账本(车TC;零 DDL、零动作)**:`DELETE /v1/sessions/:id` 与 SQL 后端的托管留存清扫自本版起连带删掉该会话的受理行(SQL `user_input_acceptance` 按 `session_id` 删;local `ledger.jsonl` 追加一行会话级墓碑 `{"kind":"erased","sessionId":…,"at":…}`);`DELETE` 回执形不变。**回滚**(local 车道):≤7.110.x 不认 `erased` 行 —— 启动 warn `user_input_ledger_corrupt_read`,被删会话的行在旧进程里复现;要干净回滚,停服后删 `<localDataRoot>/user-input-ledger/ledger.jsonl`(代价 = 丢掉还没告知的崩溃丢失提醒)。SQL 车道回滚无影响。**嵌入方(类型面硬破坏)**:`UserInputLedgerStore`(包根导出型)新增必选 `deleteBySession(sessionId): Promise<number>`;自建 `StoreBackend.userInputLedger()` 的嵌入方 tsc 红即通知。
5486
6931
  - **同步子代的 steer 入用户输入受理账本(车TF;零 DDL、零动作)**:`POST /v1/runs/:id/subagents/:target/steer` 自本版起与 run 自己的 steer 同一本账(先账后引擎;行记在回执上的那条 run 名下)——进程在子代收场前崩了 ⇒ 同会话下一条 run 首拍的 `task.user_steer_undrained{cause:"crashed"}` 把它并进那条 run 的条数;账本写不进 ⇒ 该路由回 **503 `steering.ledger_unavailable`**(此前 200);200 回执 additive 多一个 `messageId`(按封闭 schema 校验回执的消费方加这一可选键)。workflow agent 的 steer 不变(不入账,崩溃丢失仍零告知,另票)。**回滚**:无数据动作(行形不变;≤7.110.x 读得懂这些行,照常收敛 / 告知)。
5487
6932
  - **用户输入受理账本收敛判词合一 / SQL 坏行逐行跳过(车TD;零 DDL、零动作)**:local 车道 boot 收敛自本版起读 run 行 —— 前世进程没结清、而承载它的 run 已正常收场 / 已挂起的受理补结清、不再告知(7.110.x 一律按崩溃告知);SQL 表里读不出的行逐行跳过 + 计数 `server.user-input-ledger.corrupt-record-skipped`,其余照常(7.110.x 整页读失败)。**嵌入方(类型面硬破坏)**:`UserInputLedgerStore.listOpen` 返回 `Promise<OpenScanPage>`(`{ open, next? }`,`next` = 这一页原始末行的键、缺席 = 扫到底;包根新导出 `OpenScanPage`)—— 自建店改交页对象、读不出的行自己跳过并照原始行给游标;`WriterGoneEvidence` 改为 `{ kind, runs }`(两臂都带 run 店读口)。tsc 红即通知。**回滚**:回到 7.110.x 无数据动作(账本行形不变)。
5488
- - **`@sema-agent/core` 7.38.0 → 7.38.2(车TG;两只 patch,core 硬破坏 0、wire 键 / 码 / 闭集零变化,零动作)**:① 内建读拒表的家锚定行(`~/.sema/settings.json` 等)另落**账户家**(core 7.38.1)—— 引擎进程的 `HOME` 被改指时,账户真实家下的同名文件由「读得到」变为 `read_path_denied`;真要读的部署用 `READ_DENY_BUILTIN_EXCLUDE` 删那一行。当时按 DEPLOY-PREREQS 加的 `READ_DENY_PATTERNS` 不锚家同名行可撤(不撤无害)。账户查询无答的主机上这些行在任何位置判(项目自己的 `.sema/settings.json` 也拒,一次 `console.warn`,下一条 run 重问)。② local 车道 File 店族的 JSONL 末段整条记录缺换行 ⇒ 认下并在下次打开补换行(core 7.38.2);末段非对象 ⇒ 截 + 多一条 `corrupt-record-skipped` 计数。**回滚**到 ≤7.110.x:回退版本的 core 会把「只缺换行」的末行截掉(只在崩溃留下的那一形上;盘上格式不变,零数据动作)。
6933
+ - **`@sema-agent/core` 7.38.0 → 7.38.2(车TG;两只 patch,core 硬破坏 0、wire 键 / 码 / 闭集零变化,零动作)**:① 内建读拒表的家锚定行(`~/.sema/settings.json` 等)另落**账户家**(core 7.38.1)—— 引擎进程的 `HOME` 被改指时,账户真实家下的同名文件由「读得到」变为 `read_path_denied`;真要读的部署用 `READ_DENY_BUILTIN_EXCLUDE` 删那一行。当时为补这个缺口加的 `READ_DENY_PATTERNS` 不锚家同名行可撤(不撤无害)。账户查询无答的主机上这些行在任何位置判(项目自己的 `.sema/settings.json` 也拒,一次 `console.warn`,下一条 run 重问)。② local 车道 File 店族的 JSONL 末段整条记录缺换行 ⇒ 认下并在下次打开补换行(core 7.38.2);末段非对象 ⇒ 截 + 多一条 `corrupt-record-skipped` 计数。**回滚**到 ≤7.110.x:回退版本的 core 会把「只缺换行」的末行截掉(只在崩溃留下的那一形上;盘上格式不变,零数据动作)。
5489
6934
 
5490
6935
  ## 7.110.0(车ST;小车 SV;车SX;小车 SA;主会话;车SW)—— `@sema-agent/core` 7.38.0(minor,core 硬破坏 0):通告码受众 / 铸者改读 core 表 · `terminal.failed.detail` 过境 · hook 载荷 `permission_mode` = 腿实时模式 · 类对判据走 core 屏 · run-local 无 TTY 拒记部署政策名下 · 复合体读不出词的 PreToolUse 结果交引擎屏 · 🔴 `MEMORY_SYNC_SCOPE` 缺省不再从非 v2 `MEMORY_SCOPE` 派生(拒启) · 崩溃丢掉的 200-applied steer 下一条 run 告知(用户输入受理账本)
5491
6936
 
@@ -5626,8 +7071,7 @@
5626
7071
  - **wire:`READ_FACE=roots` 面上 Read / Grep / Glob 读工作区外 = 一张卡**(`default` / `acceptEdits` / `plan`;`auto` 先交分类器、`bypassPermissions` 释放)(修前当场拒);新 `tool_end.errorCode` `read_unestablished`;`permission_denied_total`
5627
7072
  的 `deniedBy` 标签 `plan_mode` → `mode`。
5628
7073
  - **🔴 安全面(部署):git 的 env 配置族(`GIT_CONFIG_*` / `GIT_CONFIG_PARAMETERS`)与代理变量现在**连同凭据**原样到达宿主子进程(含模型可驱动的 host shell)。**
5629
- **迁移**:把凭据挪出服务进程 env 的这两族 —— git 走 credential helper 的配置文件、ssh key 文件或 `durableRemote` URL,代理按来源免密(`docs/DEPLOY-PREREQS.md`
5630
- 「宿主子进程拿到的 env 改成参照实现的剥除形」节)。`SSH_AUTH_SOCK` 与 `OTEL_*` 自本版起不到宿主子进程:经 ssh-agent 推送的 leader 部署改 key 文件;
7074
+ **迁移**:把凭据挪出服务进程 env 的这两族 —— git 走 credential helper 的配置文件、ssh key 文件或 `durableRemote` URL,代理按来源免密(或 git 侧只带用户名的 `http.proxy` + credential helper 供口令)。`SSH_AUTH_SOCK` 与 `OTEL_*` 自本版起不到宿主子进程:经 ssh-agent 推送的 leader 部署改 key 文件;
5631
7075
  语言服务器 / bake-runner 要 OTel 用 `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。`secret_env_scrubbed_total` 的 `kind` 标签换成 core 五词,按
5632
7076
  `suffix-rule` / `family-rule` 写的告警规则改标签。
5633
7077
  - **升级窗**:升级前把**耐久子代 park**(父链经过部署治理层的子代审批)答完或取消 —— 7.105.0 上 park 的这类行在 7.106.0 上可能拒 `resume.parent_constraint_mismatch`
@@ -5830,7 +7274,7 @@
5830
7274
  #### `401 auth.unauthorized` 的 message 换成出路句
5831
7275
 
5832
7276
  - **`401 auth.unauthorized` 的 `error` 换句(wire 文案,码不变)**:此前恒为 `unauthorized` 一个词,现在按这道门收什么给三句出路句之一(凭据门 /
5833
- 运维口 / 要调用方身份,逐字见 `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 A.1)。按 `error == "unauthorized"` 字面判的调用方改按 `errorCode`
7277
+ 运维口 / 要调用方身份,句子就在应答的 `error` 字段里)。按 `error == "unauthorized"` 字面判的调用方改按 `errorCode`
5834
7278
  (`auth.unauthorized`)判 —— 状态码与码都没变。
5835
7279
 
5836
7280
  #### `GET /v1/capabilities` 多一段 `sealedKey`(模型钥匙 sealed 形的公钥发现面;additive,零迁移)
@@ -6046,7 +7490,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
6046
7490
  #### 内部构造面(对包消费方零影响)
6047
7491
 
6048
7492
  - 内部面(非公开导出):三家 run 店的 `setSuspended` / `setNeedsReview` 收第二个必填参数 `result`(结果或 `null`),`result` 列经同一只入口
6049
- `sealRunRowResult`(封口 + 脱敏)落列。契约全文见 `docs/ASSISTANT-WIRE-CONTRACT.md` §5.0c。(正文见「wire」小节与「存储与一次性迁移」小节)
7493
+ `sealRunRowResult`(封口 + 脱敏)落列。(正文见「wire」小节与「存储与一次性迁移」小节)
6050
7494
  - **内部构造面(对包消费方零影响)**:`observability/corrupt-read-seat.ts` 的 `createCorruptReadSeat` 多一个可选第 4 位 `leg`;`plugins/session-event-payload.ts`
6051
7495
  的 `decodeSessionEventPayload` 对坏体抛 `SessionError("corrupt_session")`(此前是 `StoreCorruptError`)。都不在包的导出面上。(正文见「wire」小节)
6052
7496
  - **内部构造面(对包消费方零影响)**:`createFilePermissionRuleStores` 的 opts 多一个 `warn`(两份日志的腐读座;`onError` 只接 core 规则文件);
@@ -6061,7 +7505,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
6061
7505
  ⇒ 整只不交(7.103.1 上第 4 条起放行;鉴权头 / URL userinfo / 口令旗等其它凭据形任何位置早就整只扣),同一只里无害的 `-c` 一起没了。
6062
7506
  **迁移**:凭据别写进 `GIT_CONFIG_PARAMETERS`;无害设置按腿分 —— project-memory / center-plugins 两条 git 腿隔离宿主全局配置(`GIT_CONFIG_GLOBAL` / `GIT_CONFIG_SYSTEM`
6063
7507
  = `/dev/null`),只能留在 env 里:从 `GIT_CONFIG_PARAMETERS` 删掉凭据条目只留无害设置,或改用 `GIT_CONFIG_COUNT` 组(一条一判、被扣的一条原位占位、其余照到);
6064
- host shell / leader 推送 / 语言服务器 / bake-runner 四条腿另可写进宿主 `~/.gitconfig` / `GIT_CONFIG_GLOBAL`(`docs/DEPLOY-PREREQS.md` 同段)。
7508
+ host shell / leader 推送 / 语言服务器 / bake-runner 四条腿另可写进宿主 `~/.gitconfig` / `GIT_CONFIG_GLOBAL`。
6065
7509
  - `OTEL_EXPORTER_OTLP_{TRACES,METRICS,LOGS,PROFILES}_HEADERS` 与旧拼法 `_SPAN_` / `_METRIC_HEADERS` 不再交给宿主子进程(`OTEL_EXPORTER_OTLP_HEADERS` 此前已由本服务
6066
7510
  按名剥)。**迁移**:语言服务器 / 构建里要用 ⇒ `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。**观测面**:`OTEL_EXPORTER_OTLP_HEADERS` 被剥时计数改记
6067
7511
  `secret_env_scrubbed_total{kind="exact-name"}`(core 的桶),不再记 `kind="config-catalog"`(本服务目录臂的桶)—— 按 `config-catalog` 桶数它的看板改看 `exact-name`;
@@ -6134,7 +7578,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
6134
7578
  KL-1129a)**:`GIT_CONFIG_VALUE_<i>` **不在** core 的凭据形状判据里 —— 组里 KEY 是 `http.extraHeader`、VALUE 是 `Authorization: Bearer …`
6135
7579
  这一形会**原样**进宿主子进程(含模型能驱动的 host shell),并在 `isolateConfig` 的 git 腿上作为命令级配置**生效**(`GIT_CONFIG_GLOBAL /
6136
7580
  SYSTEM=/dev/null` 挡不住 env 这一层)。**迁移**:不要把凭据放进服务进程 env 的 git 配置组;要给 git 带凭据,走 credential helper / ssh key /
6137
- 写在 `durableRemote` 里(见 DEPLOY-PREREQS)。⤷ **7.103.0 已随 core 7.33.2 修掉**(车PA 提货):core 给凭据侧加了**值族表**,
7581
+ 写在 `durableRemote` 里。⤷ **7.103.0 已随 core 7.33.2 修掉**(车PA 提货):core 给凭据侧加了**值族表**,
6138
7582
  `GIT_CONFIG_VALUE_<i>` 的值是 `Authorization:` / `Proxy-Authorization:` / `Cookie:` 头(任一行、含折行续写)、带 userinfo 的 URL
6139
7583
  (`<scheme>:/+<user>[:<secret>]@…`),或 proxy 地址键(`http.proxy` / `http.<url>.proxy` / `remote.<name>.proxy`)下的 `user[:secret]@host`
6140
7584
  ⇒ 按凭据剥(遥测 `secret_env_scrubbed_total{kind="family-rule"}`),被剥的那一条不到子进程(7.103.0 是本仓**整组**扣、该组里别的配置
@@ -6172,12 +7616,12 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
6172
7616
  由展开给出的程序名)core 读不到、照原样交出;③ `http.extraHeader` 下的**非凭据**头(trace / 路由头)照样按键扣,要它到达写进 git 配置文件。
6173
7617
  **带口令的代理(core 7.33.5 / 7.33.6)**:`http_proxy` / `https_proxy` / `all_proxy` 与 `npm_config_https_proxy` / `npm_config_proxy` /
6174
7618
  `ftp_proxy`(大小写两形)值里带 userinfo / `%40` ⇒ 宿主子进程拿不到它(`family-rule`);只有地址的代理与 `NO_PROXY` 照到;写死口令的 `GIT_SSH_COMMAND` /
6175
- `GIT_PROXY_COMMAND`(`sshpass -p <口令>` …)同样不到。出路见 `docs/DEPLOY-PREREQS.md`(服务进程自己的出网不受影响)。
7619
+ `GIT_PROXY_COMMAND`(`sshpass -p <口令>` …)同样不到。出路:代理按来源免密,或 git 侧 `http.proxy=http://<user>@<proxy>:<port>`(只带用户名)+ credential helper 供口令(服务进程自己的出网不受影响)。
6176
7620
  ⤷ **`GIT_CONFIG_PARAMETERS`随 core 7.33.5 收口**:git 的命令级配置 env(`git -c` 传给子进程的那一份)按 git 自己的引号语法读,
6177
7621
  任一条带凭据(或 git 会拒的写法)⇒ 整只不到宿主子进程;干净的列表逐字节原样。7.103.0 此处「不在剥密族表里」的披露降级为「core 扣它」。
6178
7622
  ⤷ 7.103.2(core 7.33.8)起按判、不论第几条(7.103.1 / core 7.33.6 上第 4 条起的嵌套命令凭据助手 `!sh -c '…'` 读不到、整只原样到;其它凭据形任何位置
6179
7623
  都整只扣);任一条带凭据 ⇒ 整只变量不交,同一只里无害的 `-c` 一起没了。凭据别写进它;无害设置按腿分(隔离配置的 project-memory / center-plugins 两腿只能留在 env:
6180
- 删掉凭据条目或改用 `GIT_CONFIG_COUNT` 组;其余四腿另可写进宿主 git 配置文件)—— 出路见 `docs/DEPLOY-PREREQS.md` 同段。
7624
+ 删掉凭据条目或改用 `GIT_CONFIG_COUNT` 组;其余四腿另可写进宿主 git 配置文件)。
6181
7625
 
6182
7626
  ## 7.103.0(车OW 部分)—— `/health.modelRefusals` 是**免鉴权面**上的新键(7.103.0 验收 G2 格补披露)
6183
7627
 
@@ -6216,7 +7660,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
6216
7660
  - **被拒条目的名字撞档位词 / CC 别名 ⇒ 这份候选的模型面整组被拒(行为面)**:目录里一条不可用(本机无 brain / 形坏被读腿丢掉)的条目恰好叫 `sonnet` / `opus` / `haiku` / `pro` / `flash` / `best` 之类,而档位表会铸出这个词 ⇒ 模型面停在上一代(码 `config.model_refused_name_minted`,warn `sema_registry_model_plane_refused` 点名「被拒名 → 目标条目」);此前(7.101.0 开发期)这个词被静默铸到另一条条目上,显式点它 / 绑它的角色跑在别人的端点与账号上。**迁移**:改名、修好那条条目,或改绑铸出这个词的档位绑定;多台 worker 共用一份中心目录、只有部分 worker 配了 anthropic 凭据(目录里 anthropic 条目叫 `opus` / `sonnet` / `haiku` 且激活了档位组)时,无凭据的 worker 上这一形**每一代**都会出现 —— 在中心按 worker 的 roster(`SEMA_REGISTRY_WORKER`)里把这些条目排出那些 worker,或给它们配凭据,或至少设 `MODEL_ID` 让它们起得来(已记债务)。没有字符串名的被丢行不触发本条(没有可保留的名字,与停用同处置)。同批:模型面三条不变量(缺省模型 / 路由端点 / 本条)不成立时只拒**模型面这一组**(目录,以及带模型引用、随它同代的 collab 模板 —— boot 按组回落盘上 LKG 时同样整组取 LKG 那一代),同候选的审批名单 / 限额照落(此前整份候选不落,boot 腿日志还写成 `config_source_unreachable_using_env`;拉取成功而应用失败现在是 `config_apply_refused`)。
6217
7661
  - **`MODEL_ID` 不再是 loadConfig 期的硬要求**:目录有可用条目即可省;目录应用之后仍没有缺省模型 ⇒ 拒启(`config.default_model_missing`,句首保留 `MODEL_ID is required`)。中心超出 `CONFIG_BOOT_FETCH_BUDGET_MS` 且无 LKG 时 boot 那一刻没有目录:没写 `MODEL_ID` 就拒启 —— 写一个 `MODEL_ID` 兜底或调大预算。
6218
7662
  - **类型面**:`ServiceConfig.modelRefusals`(新必填席;手铸 `ServiceConfig` 的消费方 tsc 即红 —— env 形写 `{}`)与 `ServiceConfig.lspEnvAllow`(新必填席 `readonly string[]`,同样 tsc 即红 —— 缺省形写 `[]`);`SealedKeyPoisonReason` 删 `unsupported_alg`(形错的 sealed 密文现在让整条不可用,到不了毒丸臂);`FoldedReadWarning` 带 `scope` 判别位、`FetchEffectiveResult` 新键 `droppedEntries`。
6219
- - **记忆抹除面的 409 `memory.layer_unwritable` 撤销(随 core 7.31.0 提货;wire 码删除 + 行为面)**:`POST /v1/memory/erase`、`POST /v1/memory/origin/entries/:entryId/clear`、`POST /v1/sessions/:id/memory/erase` 不再在引擎之前做盘上可写预检,这个码不再出现(7.100.0 那条「按 409 体 `chmod u+w <dir>` 后重试」的指路随之撤)—— core 7.31.0 的挂载**一个模式位都不改**(只读层是会话策略:往会话不写的层里写在写点被拒,绕过工具写进去的字节永不被采纳)。7.100.0 上被 409 盖住的三种答复回到 core 自己的读数(非法选择子 400 `config.memory_erasure_request`、清标空理由 422 `memory.origin_clear_invalid`、已提交抹除同 `requestId` 重放的 200 收执),锁住的是别的层时抹除可写层条目照常 200。**升级(一次性)**:存量已锁目录在**最后一个 ≤7.30.x 会话结束后**(= 7.100.0 及更早的 server 副本全部停掉之后)执行 `chmod -R u+w <memoryDir>`(file 记忆引擎的 `<数据根>/memory`)—— 混跑期旧引擎每次只读挂载都会再锁一次,7.31 不替你解。**谁受伤**:没做这一步、又去删一条住在锁住目录里的条目的部署 ⇒ `500`(日志带 core 的同一条 `chmod -R u+w` 补救句),journal 留盘、下次起服失败,照补救句做完即自愈(`docs/DEPLOY-PREREQS.md` 同名段)。**滚动窗内这一形会反复出现**:同一数据根上还有 7.100.0 及更早的副本在跑时,它每次只读挂载一层都会把那一层再锁一次 —— 窗内做过的 `chmod` 会被撤回,7.101.0 副本在那一层上删条目照样 `500` + journal 卡盘。7.101.0 起服时对记忆挂载面探一次:有锁住的层 ⇒ 一条 warn(`engine_notice`,码 `memory.layer_locked_legacy`,`detail.layers` = 层名、`detail.remedy` = 同一句 `chmod -R u+w '<memoryDir>'`),**照常起服**(不拒启:窗内每次 boot 都可能刚被旧副本锁过);看到这一行就先别在那几层上抹除 / 清标,等旧副本全停后执行那一句。按码分支 `memory.layer_unwritable` 的消费方(sdk 错误码目录)删掉那一臂。
7663
+ - **记忆抹除面的 409 `memory.layer_unwritable` 撤销(随 core 7.31.0 提货;wire 码删除 + 行为面)**:`POST /v1/memory/erase`、`POST /v1/memory/origin/entries/:entryId/clear`、`POST /v1/sessions/:id/memory/erase` 不再在引擎之前做盘上可写预检,这个码不再出现(7.100.0 那条「按 409 体 `chmod u+w <dir>` 后重试」的指路随之撤)—— core 7.31.0 的挂载**一个模式位都不改**(只读层是会话策略:往会话不写的层里写在写点被拒,绕过工具写进去的字节永不被采纳)。7.100.0 上被 409 盖住的三种答复回到 core 自己的读数(非法选择子 400 `config.memory_erasure_request`、清标空理由 422 `memory.origin_clear_invalid`、已提交抹除同 `requestId` 重放的 200 收执),锁住的是别的层时抹除可写层条目照常 200。**升级(一次性)**:存量已锁目录在**最后一个 ≤7.30.x 会话结束后**(= 7.100.0 及更早的 server 副本全部停掉之后)执行 `chmod -R u+w <memoryDir>`(file 记忆引擎的 `<数据根>/memory`)—— 混跑期旧引擎每次只读挂载都会再锁一次,7.31 不替你解。**谁受伤**:没做这一步、又去删一条住在锁住目录里的条目的部署 ⇒ `500`(日志带 core 的同一条 `chmod -R u+w` 补救句),journal 留盘、下次起服失败,照补救句做完即自愈。**滚动窗内这一形会反复出现**:同一数据根上还有 7.100.0 及更早的副本在跑时,它每次只读挂载一层都会把那一层再锁一次 —— 窗内做过的 `chmod` 会被撤回,7.101.0 副本在那一层上删条目照样 `500` + journal 卡盘。7.101.0 起服时对记忆挂载面探一次:有锁住的层 ⇒ 一条 warn(`engine_notice`,码 `memory.layer_locked_legacy`,`detail.layers` = 层名、`detail.remedy` = 同一句 `chmod -R u+w '<memoryDir>'`),**照常起服**(不拒启:窗内每次 boot 都可能刚被旧副本锁过);看到这一行就先别在那几层上抹除 / 清标,等旧副本全停后执行那一句。按码分支 `memory.layer_unwritable` 的消费方(sdk 错误码目录)删掉那一臂。
6220
7664
  - **settings 层里残留的 `crossSessionInbound: "accept"` ⇒ 跨会话消息 hold(core 7.31.0,行为面)—— 本服务不受影响(只 env 层接线)**:本服务三层来源里只有 env 管理层 `CROSS_SESSION_INBOUND` 接线(user / repo 两层不读),而 env 写 `accept` 自 7.100.0 起就拒启 ⇒ 下面这一形只波及**自持 settings 层的嵌入方**。7.30.x 把这个退役词读成 `next-turn` 并每腿通告一次(7.100.0 本节那句「由引擎自己读成 `next-turn`」随之过期);7.31.0 起它与任何未知词同路 —— 该层进 `invalidLayers`、fail-closed 落 `hold`(每条跨会话消息以 `invalid-setting` 因由扣住,`peer.inbound_disposition` 披露 `held`)。env `CROSS_SESSION_INBOUND=accept` 自 7.100.0 起就拒启,不受影响;`@sema-agent/settings-schema` 6.0.0 的文件层本就拒这个词,所以只有绕过 schema 写进去的 settings 文件会撞上。**迁移**(仅嵌入方):把每一层的 `accept` 改写成 `next-turn`。
6221
7665
  - **子进程剥名收窄(core 7.31.0,运行面;7.100.0 本节「子进程按名剥凭据形变量」一条的修正)**:十个预算名(`MAX_NEW_TOKENS` `MAX_COMPLETION_TOKENS` `AIDER_MAP_TOKENS` `AIDER_MAX_CHAT_HISTORY_TOKENS` `MAX_BATCH_PREFILL_TOKENS` `MAX_WAITING_TOKENS` `MAX_TOP_N_TOKENS` `RATE_LIMIT_TOKENS` `PROMPT_TOKENS` `CONTEXT_TOKENS`)与两个开关(`DB_FOREIGN_KEYS` `JSON_SORT_KEYS`)按**精确名**豁免,重新到得了工具子 shell、git 子进程与本地语言服务器;装饰过的变体(`USERS_MAX_NEW_TOKENS`、`MAX_NEW_TOKENS_2`)仍剥。为这五名改过名的部署可以撤回那一手(留着也无害);`inheritEnv:[names]` 是嵌入方构造执行环境时的选项,不是部署级放回旋钮(7.104.0 起文档写明)。
6222
7666
  - **SQL 后端:`session_meta` 新列 `instruction_source`(存储面)**:存量 MySQL 协议 / PostgreSQL 库升级后**拒启**(`config.schema_mismatch`,拒因里逐字给出 `ALTER TABLE session_meta ADD COLUMN instruction_source VARCHAR(64) NULL;`,PG 为 `… VARCHAR(64) COLLATE "C";`),照它加列(由部署者自己执行;列集对账与拒启句永不改库);滚动序恒为「**先升库、再升副本**」(加列之后,旧副本重启会把它看成幽灵列而拒启)。`DB_BACKEND=local` 与内存形零动作。见上方「SQL 存储面 BREAKING」表。
@@ -6234,12 +7678,12 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
6234
7678
  - **`UNATTENDED_APPROVAL_POLICY=deny` 下「无人可答」记在部署政策名下(行为面;点名 cli)**:没人能答的受门调用,`tool_end.gate.settlement` 从 `{kind:"human_refused", who:{party:"person"}}` 变 `{kind:"policy_refused", who:{party:"none"}}`;模型读到引擎的策略句,run **不再**以 `haltedOnUserRejection:true` 收束、接着跑(auto 模式否决限回落那一问被拒时改为 `failed` / `classifier.denial_limit`);持久 ask 行当场落 DECIDED(deny) + `settled_by="policy"`,重入回放同一个政策拒。**谁受伤**:按 `haltedOnUserRejection` 或 `settlement.kind === "human_refused"` 判「用户拒了」的壳。**迁移**:改读 `policy_refused`;模型多跑的拍数由部署的 `maxTurns` / 墙钟兜顶。
6235
7679
  - **记忆抹除面:三个既有端点新答 409 `memory.layer_unwritable`(行为面)**:`POST /v1/memory/erase`、`POST /v1/memory/origin/entries/:entryId/clear`、`POST /v1/sessions/:id/memory/erase`。锁住且有条目的记忆层在场时(默认路径 core 7.30.1 每次项目会话都会锁 `memory/local`),operator / 属主抹除与清标先答 409 `memory.layer_unwritable`(7.99.0:项目层条目 200、`local` 条目 500 + journal 卡盘、下次起服 fatal);同一门序让这种层在场时的非法选择子(400 `config.memory_erasure_request`)、清标空理由(422 `memory.origin_clear_invalid`)与已提交抹除同 `requestId` 重放的 200 收执也先答 409。挂载面里有指向树外目录的软链 ⇒ 未分类 500(判不了,日志点名软链)。**迁移**:按 409 体点名的目录 `chmod u+w <dir>` 后**用同一个 `requestId`** 重试(得到原答复);软链形把软链移出记忆层。core 7.31.0提货版撤销本预检与这个码。
6236
7680
  - **审批名单热应用(行为面)**:`governance.approvalRequire` 从「改了要重启」变热,`/health.restart.reasons` 与 `GET /v1/config/catalog` 的 `restartSlices` 不再有 `runtime-gates`(同版波 0:`models-tiers` 出、`memory-consolidation` 进 ⇒ 闭集 7 词)。三处行为变化:① 中心下发的名单形错(非数组 / `null` / 非字符串项)或拼法匹配不到 ⇒ 审批组**整组拒**:活配置零变化、候选不成为 LKG、每拍重判直到修好(改前只 warn、候选照样成为 LKG);没有 checkpoint 店的部署收到非空名单同样整组拒(改前重启后拒启 = 崩溃环);② 中心撤掉这一键 ⇒ 立刻回 env 底 `APPROVAL_REQUIRE`(改前保留到下次重启);③ 开了 leader 端点、有 checkpoint 店、只配 `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO` 而 require 为空的部署,leader worker **开始执行**这两张表(改前一张都不执行;收紧向)。**迁移**:按 `sema_registry_approval_require_invalid` 日志修名单;依赖「leader 不执行 deny / never-auto」的部署核对名单。
6237
- - **回滚到 7.99.0(local 车道 + `UNATTENDED_APPROVAL_POLICY=deny`)要先收敛 / 压实 ask 账本(NP-9,持久数据面)**:7.100.0 起部署政策拒当场落 ask 行,File 形账本(`<数据根>/approval-asks/asks.jsonl`)把它记成新动词 `claimTerminalRefuse`。账本里只要还留着这种记录,7.99.0 **启动即拒启**并点名(「verb outside this build's closed set (a DOWNGRADE …)」)—— 不会静默把政策拒读成 VOID,但也起不来。**回滚步骤**:①停止接新任务,等所有 run 收敛(`GET /v1/approvals` 的 `pending` / `livePending` 都空,没有停驻或在飞的审批);②再二选一:让 7.100.0 继续跑到账本到阈压实(压实后账本只剩行快照,7.99.0 读得动,政策结算原样保留),或停机把 `asks.jsonl` 移开(已收敛的部署上只丢已决历史 —— 与 `docs/DEPLOY-PREREQS.md`「要清就停机删文件」同一动作);③再启 7.99.0。SQL 车道(`mysql` / `pg`)不受影响:政策结算是行上的列,7.99.0 原样读得动。
6238
- - **子进程按名剥凭据形变量(core 7.30.1,运行面)**:工具子 shell、git 子进程与本地语言服务器收不到名字以 `KEYS` / `TOKENS` / `PASSWORDS` 结尾的宿主变量;计数豁免只看紧挨结尾词的那一个词 ⇒ `MAX_NEW_TOKENS` / `MAX_COMPLETION_TOKENS` / `MAX_BATCH_PREFILL_TOKENS` / `DB_FOREIGN_KEYS` / `JSON_SORT_KEYS` 这五个 7.30.0 不剥的非密钥名也被剥(core 收紧过头,归 core 修)。**迁移**:给变量改个不以这三形结尾的名字(模型可驱动的 host shell 没有部署级放回旋钮 —— `inheritEnv:[names]` 只是嵌入方构造执行环境时的选项,7.104.0 起文档写明;语言服务器 7.101.0 起有 `LSP_ENV_ALLOW`);规则全文见 `docs/DEPLOY-PREREQS.md`。
7681
+ - **回滚到 7.99.0(local 车道 + `UNATTENDED_APPROVAL_POLICY=deny`)要先收敛 / 压实 ask 账本(NP-9,持久数据面)**:7.100.0 起部署政策拒当场落 ask 行,File 形账本(`<数据根>/approval-asks/asks.jsonl`)把它记成新动词 `claimTerminalRefuse`。账本里只要还留着这种记录,7.99.0 **启动即拒启**并点名(「verb outside this build's closed set (a DOWNGRADE …)」)—— 不会静默把政策拒读成 VOID,但也起不来。**回滚步骤**:①停止接新任务,等所有 run 收敛(`GET /v1/approvals` 的 `pending` / `livePending` 都空,没有停驻或在飞的审批);②再二选一:让 7.100.0 继续跑到账本到阈压实(压实后账本只剩行快照,7.99.0 读得动,政策结算原样保留),或停机把 `asks.jsonl` 移开(已收敛的部署上只丢已决历史);③再启 7.99.0。SQL 车道(`mysql` / `pg`)不受影响:政策结算是行上的列,7.99.0 原样读得动。
7682
+ - **子进程按名剥凭据形变量(core 7.30.1,运行面)**:工具子 shell、git 子进程与本地语言服务器收不到名字以 `KEYS` / `TOKENS` / `PASSWORDS` 结尾的宿主变量;计数豁免只看紧挨结尾词的那一个词 ⇒ `MAX_NEW_TOKENS` / `MAX_COMPLETION_TOKENS` / `MAX_BATCH_PREFILL_TOKENS` / `DB_FOREIGN_KEYS` / `JSON_SORT_KEYS` 这五个 7.30.0 不剥的非密钥名也被剥(core 收紧过头,归 core 修)。**迁移**:给变量改个不以这三形结尾的名字(模型可驱动的 host shell 没有部署级放回旋钮 —— `inheritEnv:[names]` 只是嵌入方构造执行环境时的选项,7.104.0 起文档写明;语言服务器 7.101.0 起有 `LSP_ENV_ALLOW`)。
6239
7683
 
6240
7684
  ## 7.99.0 —— 三条 BREAKING(行为面 / 类型面 / 运行时下限)
6241
7685
 
6242
- - **显式签发方不再算托管证据(7.99.0;按 clay 裁定「显式签发方不算托管证据」)**:`PRINCIPAL_JWT_*` / `AUTH_BRIDGE_ISSUER` 在场而 `REQUIRE_PRINCIPAL` 未设的部署,7.95–7.98 拒启,7.99.0 起服;托管 ⇔ 运维显式声明 `REQUIRE_PRINCIPAL=true`。**谁受伤**:靠这条推断顶着没设 `REQUIRE_PRINCIPAL` 的多租机器,升级后不再被拦(召回缺口如实登记)。**迁移**:多租机器自己设 `REQUIRE_PRINCIPAL=true`(+ `OPERATOR_PRINCIPALS`),见 `docs/DEPLOY-PREREQS.md` 托管形前置。
7686
+ - **显式签发方不再算托管证据(7.99.0;按 clay 裁定「显式签发方不算托管证据」)**:`PRINCIPAL_JWT_*` / `AUTH_BRIDGE_ISSUER` 在场而 `REQUIRE_PRINCIPAL` 未设的部署,7.95–7.98 拒启,7.99.0 起服;托管 ⇔ 运维显式声明 `REQUIRE_PRINCIPAL=true`。**谁受伤**:靠这条推断顶着没设 `REQUIRE_PRINCIPAL` 的多租机器,升级后不再被拦(召回缺口如实登记)。**迁移**:多租机器自己设 `REQUIRE_PRINCIPAL=true`(+ `OPERATOR_PRINCIPALS`)。
6243
7687
  - **`ServiceConfig.configCenter.token` 删除,换成 `credential`(7.99.0,类型面)**:凭证改为一只每次请求取值的活对象;新旋钮 `SEMA_REGISTRY_TOKEN_FILE`(与 `SEMA_REGISTRY_TOKEN` 二选一,都设 ⇒ 拒启)。手铸 `ServiceConfig` 的消费方 tsc 即红。**盘上数据**:旧 LKG 文件(`config-lkg-<worker>.json`,formatVersion 1)按凭证身份分箱后一次性迁移 —— 此刻凭证是该 worker 的拉取令牌且新箱无文件 ⇒ 迁进新箱、旧文件改名 `.migrated-v1`;其它形响亮拒一行(点名旧路径与出路);迁移代码到期删除(10-31)。旧 prompt 活动状态目录暂不迁移。
6244
7688
  - **Node 运行时下限改成实测值 `^20.19.0 || >=22.12.0`(7.99.0)**:此前 `>=20` 是假话 —— 7.98.0 在 Node 20.0–20.18 与 22.0–22.11 上本就起不来(依赖 e2b 的 CJS 入口撞 chalk@5 纯 ESM);开了 engine-strict 的安装在范围外会失败。**迁移**:Node 升到 20.19+ 或 22.12+。
6245
7689
 
@@ -6259,7 +7703,7 @@ schema **拒启并打印要执行的 `ALTER TABLE … ADD COLUMN …`**,不会
6259
7703
  | **7.14.0**(2026-08-12) | `tool_result` 换代(随 core 5.26.0 的 ref 格式换代):ref 四段单射形、主键 `VARCHAR(190)→518`、新增出处两列 `owner_session_id`/`owner_task_id` | 升级前两方言 **`DROP TABLE tool_result`**(不删=boot 拒启;offload 产物是可恢复窗缓存,转录内联预览不受影响) |
6260
7704
  | **7.101.0** | `session_meta` 新列 `instruction_source VARCHAR(64) NULL`(PG `COLLATE "C"`;项目指令换源通告的基线) | 两方言按拒启句里给出的 `ALTER TABLE session_meta ADD COLUMN …` 由部署者自己加列;**先升库、再升副本**(加列后旧副本重启见幽灵列拒启) |
6261
7705
 
6262
- > 列增批此前只记在 CHANGELOG / `docs/DEPLOY-PREREQS.md`(7.92.0 `session_policy`、7.93.4 `approval_ask.settled_by` 各加过一列),自 7.101.0 起同样入本表。7.101.0 这一列的拒启句自带可粘贴的 `ALTER`,本仓仍不替你执行。
7706
+ > 列增批此前只记在 CHANGELOG 与内部部署记录里(7.92.0 `session_policy`、7.93.4 `approval_ask.settled_by` 各加过一列),自 7.101.0 起同样入本表。7.101.0 这一列的拒启句自带可粘贴的 `ALTER`,本仓仍不替你执行。
6263
7707
 
6264
7708
  ## server 3.0.0 —— BREAKING 四条(2026-07-31)
6265
7709
 
@@ -6284,7 +7728,7 @@ schema **拒启并打印要执行的 `ALTER TABLE … ADD COLUMN …`**,不会
6284
7728
  | `HOST_EXEC_SPOOL_DISABLED` | `HOST_EXEC_SPOOL_ENABLED=false` | 开 | host lane exec 的 spool 形 stdio |
6285
7729
  | `LSP_ENABLED=false`(拆分前用来关 host 腿) | `LSP_HOST_ENABLED=false` | 开 | host lane 本地 LSP。⚠️ `LSP_ENABLED=true` **不受影响**——那是沙箱腿自己的 opt-in |
6286
7730
 
6287
- **② 的完整码表**见 `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 A;机器执行面是 `test/error-code-key-gate.test.ts`
7731
+ **② 的完整码表**是服务端 wire 契约的附录 A(内部记录,不随包);机器执行面是 `test/error-code-key-gate.test.ts`
6288
7732
  (`src/` 全树的 error 帧 + `src/http/` 全树的 4xx/5xx 错误体,两面都不许漏码)。
6289
7733
 
6290
7734
  ## core 引擎侧 BREAKING(经 `@sema-agent/core` 依赖传入)