@sema-agent/server 7.146.0 → 7.148.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 (850) hide show
  1. package/MIGRATION.md +1423 -24
  2. package/README.md +21 -8
  3. package/README.zh-CN.md +15 -9
  4. package/USAGE.md +537 -216
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +18 -7
  7. package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +42 -4
  9. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  10. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  11. package/deploy/sema-up/chart/values.yaml +4 -3
  12. package/deploy/sema-up/cluster-up.sh +75 -176
  13. package/deploy/sema-up/kube-up.sh +29 -49
  14. package/deploy/sema-up/lib/chart-run.sh +23 -0
  15. package/deploy/sema-up/lib/dataroot.sh +3 -3
  16. package/deploy/sema-up/lib/flagshape.sh +4 -0
  17. package/deploy/sema-up/lib/health.sh +62 -13
  18. package/deploy/sema-up/lib/helm-values-cluster.py +18 -0
  19. package/deploy/sema-up/lib/helm-values-kube.py +35 -0
  20. package/deploy/sema-up/lib/lanes.json +2 -5
  21. package/deploy/sema-up/lib/regcred.py +8 -0
  22. package/deploy/sema-up/lib/remote/helm-install.sh +3 -0
  23. package/deploy/sema-up/lib/remote/image-import.sh +6 -0
  24. package/deploy/sema-up/lib/remote/machine-precheck.sh +11 -0
  25. package/deploy/sema-up/lib/remote/region-probe.sh +3 -0
  26. package/deploy/sema-up/lib/remote/stack-ready.sh +26 -0
  27. package/deploy/sema-up/lib/remote/vxlan-guard.sh +8 -0
  28. package/deploy/sema-up/lib/render-stack.py +17 -0
  29. package/deploy/sema-up/lib/shell-text.sh +87 -0
  30. package/deploy/sema-up/lib/usage-flags.txt +10 -0
  31. package/deploy/sema-up/lib/usage-head.txt +1 -0
  32. package/deploy/sema-up/lib/usage-tail.txt +13 -0
  33. package/deploy/sema-up/preflight.sh +10 -8
  34. package/deploy/sema-up/sema-up.sh +26 -48
  35. package/deploy/sema-up/smoke.sh +7 -6
  36. package/deploy/sema-up/stack/compose.dataroot.yaml +3 -0
  37. package/deploy/sema-up/stack/compose.yaml +18 -5
  38. package/deploy/sema-up/stack/sema-stack-cluster.yaml +25 -3
  39. package/dist/adoption/plan.d.ts +24 -0
  40. package/dist/adoption/plan.js +53 -1
  41. package/dist/adoption/runner.d.ts +10 -1
  42. package/dist/adoption/runner.js +36 -16
  43. package/dist/adoption/wire.d.ts +3 -3
  44. package/dist/approval-card.d.ts +32 -34
  45. package/dist/approval-gate-currency.js +3 -2
  46. package/dist/approval-reconciler.d.ts +4 -13
  47. package/dist/approval-reconciler.js +2 -2
  48. package/dist/approval.d.ts +16 -14
  49. package/dist/approval.js +3 -3
  50. package/dist/audit.d.ts +10 -3
  51. package/dist/audit.js +17 -9
  52. package/dist/auth-bridge.d.ts +0 -14
  53. package/dist/auth-bridge.js +0 -7
  54. package/dist/auto-mode-face.d.ts +10 -7
  55. package/dist/auto-mode-face.js +7 -4
  56. package/dist/background-agent-name.d.ts +19 -1
  57. package/dist/background-agent-name.js +12 -2
  58. package/dist/background-session-reap.d.ts +1 -1
  59. package/dist/bake-runner/main.js +9 -6
  60. package/dist/bench/s1/arms.js +6 -5
  61. package/dist/bench/s1/live-deps.js +8 -3
  62. package/dist/bench/s1/run-firm.js +6 -5
  63. package/dist/bind-host.d.ts +25 -0
  64. package/dist/bind-host.js +25 -0
  65. package/dist/boot/adoption.d.ts +3 -0
  66. package/dist/boot/adoption.js +1 -0
  67. package/dist/boot/crash-last.js +2 -1
  68. package/dist/boot/deployment-mods.d.ts +1 -1
  69. package/dist/boot/device-lane.js +5 -5
  70. package/dist/boot/engine-lease.d.ts +12 -11
  71. package/dist/boot/execution-env.d.ts +19 -8
  72. package/dist/boot/execution-env.js +80 -62
  73. package/dist/boot/execution-lane.d.ts +37 -9
  74. package/dist/boot/execution-lane.js +74 -20
  75. package/dist/boot/exit-boundary.d.ts +3 -3
  76. package/dist/boot/exit-boundary.js +6 -5
  77. package/dist/boot/exit-last.js +2 -1
  78. package/dist/boot/fatal-exit.d.ts +3 -5
  79. package/dist/boot/fatal-exit.js +2 -2
  80. package/dist/boot/governance-seams.d.ts +2 -2
  81. package/dist/boot/leader.d.ts +15 -0
  82. package/dist/boot/leader.js +18 -16
  83. package/dist/boot/memory-boundary.d.ts +11 -11
  84. package/dist/boot/memory-boundary.js +3 -3
  85. package/dist/boot/memory-consolidation.d.ts +50 -53
  86. package/dist/boot/memory-consolidation.js +11 -18
  87. package/dist/boot/org-memory.js +4 -3
  88. package/dist/boot/parked-revive-gate.d.ts +1 -1
  89. package/dist/boot/parked-revive-gate.js +3 -3
  90. package/dist/boot/reapers.d.ts +4 -3
  91. package/dist/boot/reapers.js +20 -17
  92. package/dist/boot/resolve-spec.d.ts +5 -3
  93. package/dist/boot/resolve-spec.js +133 -165
  94. package/dist/boot/retention-lane.d.ts +7 -45
  95. package/dist/boot/retention-lane.js +2 -2
  96. package/dist/boot/runner-deps.d.ts +28 -7
  97. package/dist/boot/runner-deps.js +11 -4
  98. package/dist/boot/runtime-caps.d.ts +2 -2
  99. package/dist/boot/runtime-caps.js +16 -2
  100. package/dist/boot/session-faces.d.ts +17 -7
  101. package/dist/boot/session-faces.js +122 -96
  102. package/dist/boot/shutdown.d.ts +5 -4
  103. package/dist/boot/shutdown.js +6 -4
  104. package/dist/boot/stage-01-config.d.ts +1 -1
  105. package/dist/boot/stage-01-config.js +14 -2
  106. package/dist/boot/stage-02-web-admin-pull.d.ts +2 -1
  107. package/dist/boot/stage-02-web-admin-pull.js +15 -8
  108. package/dist/boot/stage-03-store-backend.d.ts +4 -1
  109. package/dist/boot/stage-03-store-backend.js +4 -3
  110. package/dist/boot/stage-04-stores.d.ts +3 -1
  111. package/dist/boot/stage-04-stores.js +2 -2
  112. package/dist/boot/stage-05-execution-env.d.ts +9 -5
  113. package/dist/boot/stage-05-execution-env.js +5 -5
  114. package/dist/boot/stage-06-runners.d.ts +13 -15
  115. package/dist/boot/stage-06-runners.js +24 -18
  116. package/dist/boot/stage-07-capability-layer.d.ts +14 -11
  117. package/dist/boot/stage-07-capability-layer.js +9 -12
  118. package/dist/boot/stage-08-reapers.d.ts +14 -11
  119. package/dist/boot/stage-08-reapers.js +3 -3
  120. package/dist/boot/stage-09-leader.d.ts +16 -18
  121. package/dist/boot/stage-09-leader.js +12 -4
  122. package/dist/boot/stage-10-http-server.d.ts +16 -18
  123. package/dist/boot/stage-10-http-server.js +9 -5
  124. package/dist/boot/store-evidence.d.ts +20 -0
  125. package/dist/boot/store-evidence.js +13 -0
  126. package/dist/boot/stores.d.ts +12 -0
  127. package/dist/boot/stores.js +39 -17
  128. package/dist/boot/task-list-lane.d.ts +4 -4
  129. package/dist/boot/web-admin.d.ts +4 -2
  130. package/dist/boot/web-admin.js +58 -38
  131. package/dist/boot/webfetch-summarize-lane.d.ts +1 -1
  132. package/dist/boot-reclaim.d.ts +3 -1
  133. package/dist/boot-reclaim.js +1 -1
  134. package/dist/brain.d.ts +7 -18
  135. package/dist/brain.js +5 -17
  136. package/dist/budget.js +6 -6
  137. package/dist/capabilities/center-plugins.d.ts +9 -1
  138. package/dist/capabilities/center-plugins.js +37 -11
  139. package/dist/capabilities/center-wiring.js +1 -1
  140. package/dist/capabilities/composite-members.d.ts +3 -2
  141. package/dist/capabilities/composite-members.js +3 -2
  142. package/dist/capabilities/execution-lane.d.ts +7 -7
  143. package/dist/capabilities/execution-lane.js +2 -2
  144. package/dist/capabilities/hands-lane.d.ts +1 -1
  145. package/dist/capabilities/repo-tools.d.ts +2 -0
  146. package/dist/capabilities/repo-tools.js +14 -12
  147. package/dist/capabilities/scenarios.d.ts +38 -33
  148. package/dist/capabilities/scenarios.js +24 -25
  149. package/dist/capabilities/settings-contract.d.ts +29 -0
  150. package/dist/capabilities/settings-contract.js +14 -0
  151. package/dist/capabilities/skills.d.ts +6 -6
  152. package/dist/capabilities/tool-defer.d.ts +1 -1
  153. package/dist/capability-facts.d.ts +69 -4
  154. package/dist/capability-facts.js +77 -5
  155. package/dist/card-void.d.ts +4 -4
  156. package/dist/card-void.js +1 -1
  157. package/dist/center-credential-renewer.d.ts +6 -2
  158. package/dist/center-credential-renewer.js +10 -5
  159. package/dist/config-catalog.d.ts +16 -1
  160. package/dist/config-catalog.js +68 -61
  161. package/dist/config-dir-trust.d.ts +37 -4
  162. package/dist/config-dir-trust.js +88 -44
  163. package/dist/config-invariants.d.ts +58 -4
  164. package/dist/config-invariants.js +104 -23
  165. package/dist/config-lkg.d.ts +24 -2
  166. package/dist/config-lkg.js +22 -9
  167. package/dist/config-provider.d.ts +9 -9
  168. package/dist/config-provider.js +25 -108
  169. package/dist/config-pull-failure.d.ts +50 -0
  170. package/dist/config-pull-failure.js +48 -0
  171. package/dist/config-types.d.ts +215 -202
  172. package/dist/config.d.ts +69 -14
  173. package/dist/config.js +188 -96
  174. package/dist/degenerate-instrument.js +1 -1
  175. package/dist/delegated-session-owner.d.ts +1 -1
  176. package/dist/deleted-session-ids.d.ts +3 -2
  177. package/dist/deploy-facts.js +3 -2
  178. package/dist/deployment-governance.d.ts +3 -3
  179. package/dist/deployment-shape.d.ts +51 -16
  180. package/dist/deployment-shape.js +31 -6
  181. package/dist/egress-redirect.d.ts +25 -7
  182. package/dist/egress-redirect.js +20 -2
  183. package/dist/elicitation.d.ts +6 -5
  184. package/dist/elicitation.js +23 -22
  185. package/dist/engine-identity.d.ts +28 -0
  186. package/dist/engine-identity.js +10 -0
  187. package/dist/entry-problems.d.ts +5 -7
  188. package/dist/entry-problems.js +1 -1
  189. package/dist/env-facts.d.ts +7 -5
  190. package/dist/env-facts.js +12 -7
  191. package/dist/env-witness.d.ts +7 -0
  192. package/dist/env-witness.js +16 -0
  193. package/dist/execution-config-root.d.ts +5 -5
  194. package/dist/execution-config-root.js +5 -5
  195. package/dist/execution-env-purpose.d.ts +14 -0
  196. package/dist/execution-env-purpose.js +29 -0
  197. package/dist/execution-lane-caps.d.ts +53 -103
  198. package/dist/execution-lane-caps.js +51 -83
  199. package/dist/execution-placement.d.ts +65 -9
  200. package/dist/execution-placement.js +58 -0
  201. package/dist/field-conflict.d.ts +7 -11
  202. package/dist/field-conflict.js +3 -3
  203. package/dist/file-history-capture.d.ts +3 -3
  204. package/dist/file-history-disclosure.d.ts +2 -2
  205. package/dist/file-history-disclosure.js +1 -0
  206. package/dist/fleet/drain-entry.d.ts +17 -10
  207. package/dist/fleet/drain-entry.js +1 -1
  208. package/dist/fleet/fleet-bus.d.ts +21 -3
  209. package/dist/fleet/fleet-bus.js +35 -25
  210. package/dist/fleet/fleet-reconciler.js +2 -2
  211. package/dist/fleet/serving-lease.js +6 -7
  212. package/dist/fleet-client.js +3 -3
  213. package/dist/fleet-lease.d.ts +0 -1
  214. package/dist/fleet-lease.js +4 -5
  215. package/dist/history-anchor.d.ts +42 -0
  216. package/dist/history-anchor.js +34 -0
  217. package/dist/hitl-delivery.d.ts +90 -0
  218. package/dist/hitl-delivery.js +98 -0
  219. package/dist/hooks/classic-stations.d.ts +8 -11
  220. package/dist/hooks/classic-stations.js +0 -7
  221. package/dist/hooks/command-spawn.d.ts +1 -4
  222. package/dist/hooks/command-spawn.js +0 -11
  223. package/dist/hooks/hook-llm.d.ts +5 -1
  224. package/dist/hooks/hook-llm.js +24 -15
  225. package/dist/hooks/hook-runner.d.ts +119 -65
  226. package/dist/hooks/hook-runner.js +415 -217
  227. package/dist/host-lsp-manager.d.ts +22 -8
  228. package/dist/host-lsp-manager.js +4 -1
  229. package/dist/http/active-run-conflict.d.ts +2 -43
  230. package/dist/http/active-run-conflict.js +3 -7
  231. package/dist/http/admission.d.ts +4 -18
  232. package/dist/http/admission.js +75 -78
  233. package/dist/http/approval-sweeps.d.ts +5 -8
  234. package/dist/http/approval-sweeps.js +55 -30
  235. package/dist/http/caller-trust.d.ts +8 -10
  236. package/dist/http/caller-trust.js +1 -2
  237. package/dist/http/checkpoint-ctx.d.ts +17 -0
  238. package/dist/http/checkpoint-ctx.js +6 -0
  239. package/dist/http/claim-heartbeat.d.ts +49 -0
  240. package/dist/http/claim-heartbeat.js +46 -0
  241. package/dist/http/claim-latency.d.ts +10 -0
  242. package/dist/http/claim-latency.js +12 -0
  243. package/dist/http/claimed-run.d.ts +4 -3
  244. package/dist/http/dispatch.d.ts +8 -1
  245. package/dist/http/dispatch.js +77 -31
  246. package/dist/http/durable-run-leg.d.ts +3 -3
  247. package/dist/http/durable-run-leg.js +18 -12
  248. package/dist/http/execution-context.d.ts +18 -42
  249. package/dist/http/execution-context.js +11 -5
  250. package/dist/http/health-reader.d.ts +36 -0
  251. package/dist/http/health-reader.js +21 -0
  252. package/dist/http/health-self-report.d.ts +9 -9
  253. package/dist/http/health-self-report.js +4 -4
  254. package/dist/http/idempotency.d.ts +9 -5
  255. package/dist/http/idempotency.js +4 -4
  256. package/dist/http/memory-compliance-failure-reply.d.ts +15 -16
  257. package/dist/http/memory-compliance-failure-reply.js +7 -2
  258. package/dist/http/memory-face-fault-reply.d.ts +67 -0
  259. package/dist/http/memory-face-fault-reply.js +71 -0
  260. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  261. package/dist/http/memory-store-refusal-reply.js +6 -0
  262. package/dist/http/owner-access.d.ts +391 -56
  263. package/dist/http/owner-access.js +372 -33
  264. package/dist/http/principal-gate.d.ts +26 -94
  265. package/dist/http/principal-gate.js +24 -81
  266. package/dist/http/refusal-body.d.ts +35 -2
  267. package/dist/http/refusal-body.js +34 -0
  268. package/dist/http/request-guards.d.ts +10 -14
  269. package/dist/http/request-guards.js +34 -68
  270. package/dist/http/resume-composition.d.ts +37 -0
  271. package/dist/http/resume-composition.js +18 -0
  272. package/dist/http/resume-ctx-read.d.ts +35 -12
  273. package/dist/http/resume-ctx-read.js +25 -6
  274. package/dist/http/resume-legs.d.ts +24 -24
  275. package/dist/http/resume-legs.js +260 -171
  276. package/dist/http/retired-skill-manifest.d.ts +1 -1
  277. package/dist/http/rewind-files-reply.d.ts +34 -0
  278. package/dist/http/rewind-files-reply.js +36 -0
  279. package/dist/http/route-ctx.d.ts +56 -47
  280. package/dist/http/route-table.js +2 -0
  281. package/dist/http/routes/a2a-serve.d.ts +43 -5
  282. package/dist/http/routes/a2a-serve.js +58 -37
  283. package/dist/http/routes/admin-config-refresh.js +2 -2
  284. package/dist/http/routes/admin-drain.js +2 -2
  285. package/dist/http/routes/admin-memory-optout.js +4 -3
  286. package/dist/http/routes/adoption.d.ts +3 -0
  287. package/dist/http/routes/adoption.js +17 -10
  288. package/dist/http/routes/agents-roster.js +13 -7
  289. package/dist/http/routes/approvals-assistant.js +73 -88
  290. package/dist/http/routes/attachments.js +2 -2
  291. package/dist/http/routes/background.d.ts +3 -3
  292. package/dist/http/routes/background.js +9 -17
  293. package/dist/http/routes/capabilities.js +23 -20
  294. package/dist/http/routes/config-catalog.js +2 -2
  295. package/dist/http/routes/devices.d.ts +3 -3
  296. package/dist/http/routes/devices.js +5 -5
  297. package/dist/http/routes/diagnostics.d.ts +27 -3
  298. package/dist/http/routes/diagnostics.js +27 -21
  299. package/dist/http/routes/engine.js +2 -2
  300. package/dist/http/routes/fleet.js +5 -3
  301. package/dist/http/routes/images.js +10 -6
  302. package/dist/http/routes/leader.d.ts +7 -2
  303. package/dist/http/routes/leader.js +12 -3
  304. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  305. package/dist/http/routes/mcp-reconnect.js +7 -15
  306. package/dist/http/routes/memory-bundle.js +4 -7
  307. package/dist/http/routes/memory-compliance.js +4 -4
  308. package/dist/http/routes/memory-consolidation.js +6 -9
  309. package/dist/http/routes/memory-origin.d.ts +3 -1
  310. package/dist/http/routes/memory-origin.js +7 -8
  311. package/dist/http/routes/memory-policy.js +17 -12
  312. package/dist/http/routes/notify-wake.js +12 -20
  313. package/dist/http/routes/observability.js +3 -3
  314. package/dist/http/routes/principal-inbox.d.ts +1 -1
  315. package/dist/http/routes/principal-inbox.js +2 -2
  316. package/dist/http/routes/projects.d.ts +70 -0
  317. package/dist/http/routes/projects.js +87 -0
  318. package/dist/http/routes/retention-ops.js +6 -9
  319. package/dist/http/routes/rules.js +50 -7
  320. package/dist/http/routes/run-memory-capture.d.ts +2 -2
  321. package/dist/http/routes/run-memory-capture.js +6 -12
  322. package/dist/http/routes/run-permission-mode.d.ts +2 -2
  323. package/dist/http/routes/run-permission-mode.js +10 -17
  324. package/dist/http/routes/runs.js +148 -233
  325. package/dist/http/routes/session-memory-sync.d.ts +2 -2
  326. package/dist/http/routes/session-memory-sync.js +7 -13
  327. package/dist/http/routes/session-sync.d.ts +4 -2
  328. package/dist/http/routes/session-sync.js +48 -30
  329. package/dist/http/routes/sessions-list.d.ts +3 -3
  330. package/dist/http/routes/sessions-list.js +9 -9
  331. package/dist/http/routes/sessions.d.ts +7 -1
  332. package/dist/http/routes/sessions.js +177 -112
  333. package/dist/http/routes/shared-memory.js +6 -6
  334. package/dist/http/routes/side-query.js +2 -2
  335. package/dist/http/routes/tasks.js +144 -122
  336. package/dist/http/routes/trace-usage.d.ts +0 -12
  337. package/dist/http/routes/trace-usage.js +40 -46
  338. package/dist/http/routes/workflows.d.ts +39 -4
  339. package/dist/http/routes/workflows.js +42 -14
  340. package/dist/http/run-concurrency-cap.d.ts +20 -12
  341. package/dist/http/run-concurrency-cap.js +39 -26
  342. package/dist/http/run-read-face.d.ts +3 -5
  343. package/dist/http/run-read-face.js +8 -13
  344. package/dist/http/send.d.ts +12 -3
  345. package/dist/http/send.js +42 -6
  346. package/dist/http/server.d.ts +63 -50
  347. package/dist/http/server.js +52 -16
  348. package/dist/http/sse-log.d.ts +17 -10
  349. package/dist/http/sse-log.js +7 -7
  350. package/dist/http/stored-body-replay.d.ts +17 -3
  351. package/dist/http/stored-body-replay.js +11 -2
  352. package/dist/http/submit-ctx.d.ts +16 -8
  353. package/dist/http/submit-ctx.js +6 -2
  354. package/dist/http/submit-replay.d.ts +19 -6
  355. package/dist/http/submit-replay.js +18 -6
  356. package/dist/http/sync-submit-body.d.ts +3 -4
  357. package/dist/http/sync-submit-body.js +4 -5
  358. package/dist/http/wire-types.d.ts +23 -13
  359. package/dist/identity-source.d.ts +36 -5
  360. package/dist/identity-source.js +27 -0
  361. package/dist/index.d.ts +3 -2
  362. package/dist/index.js +2 -1
  363. package/dist/instruction-source-notice.d.ts +1 -1
  364. package/dist/key-resolver.d.ts +32 -0
  365. package/dist/key-resolver.js +23 -9
  366. package/dist/leader/diffup.js +2 -1
  367. package/dist/leader/endpoint.d.ts +26 -5
  368. package/dist/leader/endpoint.js +154 -14
  369. package/dist/leader/fanout.d.ts +3 -0
  370. package/dist/leader/fanout.js +78 -63
  371. package/dist/leader/leader.d.ts +16 -0
  372. package/dist/leader/leader.js +43 -3
  373. package/dist/leader/merge.d.ts +9 -1
  374. package/dist/leader/merge.js +16 -1
  375. package/dist/leader/repair-wire.js +1 -1
  376. package/dist/leader/wire.d.ts +36 -3
  377. package/dist/leader/wire.js +59 -18
  378. package/dist/lsp-evict.d.ts +6 -4
  379. package/dist/lsp-evict.js +2 -3
  380. package/dist/memory-embedder-reembed.d.ts +38 -0
  381. package/dist/memory-embedder-reembed.js +20 -0
  382. package/dist/memory-incident-sink.d.ts +0 -28
  383. package/dist/memory-incident-sink.js +5 -0
  384. package/dist/memory-operator-faces.d.ts +5 -4
  385. package/dist/memory-operator-faces.js +1 -1
  386. package/dist/memory-scope.d.ts +31 -4
  387. package/dist/memory-scope.js +65 -16
  388. package/dist/memory-store-refusal.d.ts +20 -4
  389. package/dist/memory-store-refusal.js +1 -1
  390. package/dist/memory-sync-client.d.ts +5 -2
  391. package/dist/memory-sync-client.js +19 -14
  392. package/dist/memory-sync.js +1 -1
  393. package/dist/model-compat.d.ts +51 -28
  394. package/dist/model-compat.js +55 -23
  395. package/dist/model-context-window.d.ts +18 -0
  396. package/dist/model-context-window.js +2 -0
  397. package/dist/model-entry-headers.d.ts +46 -4
  398. package/dist/model-entry-headers.js +2 -2
  399. package/dist/model-entry-refusal.d.ts +46 -17
  400. package/dist/model-entry-refusal.js +47 -27
  401. package/dist/model-plane-face.d.ts +19 -11
  402. package/dist/model-plane-face.js +9 -1
  403. package/dist/model-plane-probe.d.ts +2 -0
  404. package/dist/model-plane-probe.js +17 -0
  405. package/dist/model-provider.d.ts +3 -3
  406. package/dist/model-route-endpoint.d.ts +9 -5
  407. package/dist/model-route-endpoint.js +29 -7
  408. package/dist/model-select.d.ts +16 -0
  409. package/dist/model-select.js +4 -0
  410. package/dist/mountinfo.d.ts +37 -0
  411. package/dist/mountinfo.js +47 -0
  412. package/dist/namespaced-rule-name.d.ts +28 -2
  413. package/dist/namespaced-rule-name.js +10 -1
  414. package/dist/net-address.d.ts +1 -1
  415. package/dist/observability/corrupt-read-seat.d.ts +4 -4
  416. package/dist/observability/corrupt-read-seat.js +5 -3
  417. package/dist/observability/fail-open.d.ts +75 -47
  418. package/dist/observability/fail-open.js +77 -47
  419. package/dist/observability/logger.d.ts +22 -1
  420. package/dist/observability/logger.js +89 -12
  421. package/dist/observability/metrics.d.ts +2 -0
  422. package/dist/observability/metrics.js +5 -4
  423. package/dist/observability/otel-exporter.js +2 -1
  424. package/dist/observability/principal-context.d.ts +14 -7
  425. package/dist/observability/principal-context.js +8 -3
  426. package/dist/observability/run-terminal.d.ts +7 -1
  427. package/dist/observability/run-terminal.js +5 -2
  428. package/dist/observability/secret-env-scrub.d.ts +30 -4
  429. package/dist/observability/secret-env-scrub.js +15 -3
  430. package/dist/orchestration/hardened-vm-runner.d.ts +1 -0
  431. package/dist/orchestration/hardened-vm-runner.js +11 -5
  432. package/dist/orchestration/hardened-vm-worker-runner.d.ts +0 -14
  433. package/dist/orchestration/hardened-vm-worker-runner.js +5 -0
  434. package/dist/orchestration/hardened-vm-worker.js +2 -1
  435. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  436. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  437. package/dist/orchestration/workflow-completion-inbox.d.ts +29 -9
  438. package/dist/orchestration/workflow-completion-inbox.js +65 -46
  439. package/dist/org-delivery-gate.d.ts +5 -4
  440. package/dist/org-delivery-gate.js +7 -6
  441. package/dist/org-memory-admission.d.ts +5 -2
  442. package/dist/org-memory-admission.js +25 -10
  443. package/dist/outbound-dispatcher.d.ts +1 -1
  444. package/dist/outbound-dispatcher.js +6 -12
  445. package/dist/owner-brands.d.ts +81 -0
  446. package/dist/owner-brands.js +42 -0
  447. package/dist/owner-faces.d.ts +531 -0
  448. package/dist/owner-faces.js +126 -0
  449. package/dist/parked-decide.d.ts +100 -31
  450. package/dist/parked-decide.js +162 -48
  451. package/dist/parked-revive-surface.d.ts +14 -4
  452. package/dist/parked-revive-surface.js +5 -4
  453. package/dist/peer-directory.d.ts +6 -8
  454. package/dist/peer-directory.js +3 -2
  455. package/dist/permission-rule-vocab.d.ts +53 -8
  456. package/dist/permission-rule-vocab.js +30 -2
  457. package/dist/plugins/adoption-log-sql.d.ts +0 -22
  458. package/dist/plugins/adoption-log-sql.js +5 -3
  459. package/dist/plugins/approval-ask-retired-delete-by-task-m50.d.ts +7 -0
  460. package/dist/plugins/approval-ask-retired-delete-by-task-m50.js +17 -0
  461. package/dist/plugins/approval-ask-store-file.d.ts +28 -9
  462. package/dist/plugins/approval-ask-store-file.js +74 -18
  463. package/dist/plugins/approval-ask-store-memory.d.ts +17 -7
  464. package/dist/plugins/approval-ask-store-memory.js +35 -12
  465. package/dist/plugins/approval-ask-store-sql.d.ts +42 -20
  466. package/dist/plugins/approval-ask-store-sql.js +44 -11
  467. package/dist/plugins/approval-exemption-skill-m46.d.ts +20 -0
  468. package/dist/plugins/approval-exemption-skill-m46.js +25 -0
  469. package/dist/plugins/approval-exemption-store.d.ts +6 -1
  470. package/dist/plugins/approval-exemption-store.js +14 -0
  471. package/dist/plugins/approval-nonce-store.d.ts +39 -12
  472. package/dist/plugins/approval-nonce-store.js +72 -23
  473. package/dist/plugins/blob-backend.d.ts +40 -195
  474. package/dist/plugins/blob-backend.js +41 -234
  475. package/dist/plugins/caching-session-store.d.ts +22 -5
  476. package/dist/plugins/caching-session-store.js +43 -4
  477. package/dist/plugins/checkpoint-index-columns.d.ts +33 -6
  478. package/dist/plugins/checkpoint-index-columns.js +39 -3
  479. package/dist/plugins/checkpoint-store-face.d.ts +84 -11
  480. package/dist/plugins/checkpoint-store-face.js +18 -1
  481. package/dist/plugins/device-store-sql.d.ts +2 -2
  482. package/dist/plugins/device-store-sql.js +6 -10
  483. package/dist/plugins/ensure-index.d.ts +13 -1
  484. package/dist/plugins/ensure-index.js +154 -21
  485. package/dist/plugins/ensure-schema-lock-policy.d.ts +0 -15
  486. package/dist/plugins/ensure-schema-lock-policy.js +3 -2
  487. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  488. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  489. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  490. package/dist/plugins/execution-placement-sql.js +94 -54
  491. package/dist/plugins/file-run-store.d.ts +89 -35
  492. package/dist/plugins/file-run-store.js +197 -142
  493. package/dist/plugins/host-platform.d.ts +24 -3
  494. package/dist/plugins/host-platform.js +15 -1
  495. package/dist/plugins/image-bake-store-sql.js +2 -0
  496. package/dist/plugins/imported-layer-root-retirement.d.ts +19 -10
  497. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  498. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  499. package/dist/plugins/inbox-payload-column.js +13 -0
  500. package/dist/plugins/k8s-pod-reaper.d.ts +1 -3
  501. package/dist/plugins/k8s-pod-reaper.js +0 -1
  502. package/dist/plugins/leader-run-store-sql.d.ts +22 -0
  503. package/dist/plugins/leader-run-store-sql.js +34 -4
  504. package/dist/plugins/local-checkpoint-store.d.ts +63 -23
  505. package/dist/plugins/local-checkpoint-store.js +204 -81
  506. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  507. package/dist/plugins/local-data-dir-modes-m39.js +183 -0
  508. package/dist/plugins/local-docker-capacity.d.ts +93 -0
  509. package/dist/plugins/local-docker-capacity.js +194 -0
  510. package/dist/plugins/local-docker-reaper.d.ts +92 -0
  511. package/dist/plugins/local-docker-reaper.js +102 -0
  512. package/dist/plugins/local-engine-high-water.d.ts +13 -0
  513. package/dist/plugins/local-engine-high-water.js +62 -0
  514. package/dist/plugins/local-session-store.d.ts +442 -143
  515. package/dist/plugins/local-session-store.js +941 -289
  516. package/dist/plugins/local-session-window.d.ts +3 -2
  517. package/dist/plugins/local-session-window.js +3 -2
  518. package/dist/plugins/local-sidecar-quarantine.js +3 -2
  519. package/dist/plugins/local-task-attachment-store.d.ts +20 -1
  520. package/dist/plugins/local-task-attachment-store.js +32 -12
  521. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  522. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  523. package/dist/plugins/memory-embedder.d.ts +1 -1
  524. package/dist/plugins/memory-embedder.js +11 -9
  525. package/dist/plugins/memory-engine-pg.d.ts +7 -5
  526. package/dist/plugins/memory-engine-pg.js +18 -9
  527. package/dist/plugins/memory-engine-sql-apply.d.ts +21 -8
  528. package/dist/plugins/memory-engine-sql-apply.js +7 -9
  529. package/dist/plugins/memory-engine-tidb.d.ts +12 -7
  530. package/dist/plugins/memory-engine-tidb.js +18 -10
  531. package/dist/plugins/memory-optout-grant-store-sql.d.ts +1 -1
  532. package/dist/plugins/memory-optout-grant-store-sql.js +3 -3
  533. package/dist/plugins/memory-run-store.d.ts +39 -27
  534. package/dist/plugins/memory-run-store.js +72 -70
  535. package/dist/plugins/one-time-migration-marker.d.ts +10 -0
  536. package/dist/plugins/one-time-migration-marker.js +7 -0
  537. package/dist/plugins/one-time-migrations.d.ts +325 -74
  538. package/dist/plugins/one-time-migrations.js +705 -230
  539. package/dist/plugins/org-delivery-quota-store.js +2 -1
  540. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  541. package/dist/plugins/owner-only-file-mode.js +141 -0
  542. package/dist/plugins/permission-rule-store-file.d.ts +11 -11
  543. package/dist/plugins/permission-rule-store-file.js +14 -2
  544. package/dist/plugins/permission-rule-store-sql.d.ts +4 -63
  545. package/dist/plugins/permission-rule-store-sql.js +6 -86
  546. package/dist/plugins/pg-pool.d.ts +3 -32
  547. package/dist/plugins/pg-pool.js +27 -11
  548. package/dist/plugins/release-version.d.ts +20 -0
  549. package/dist/plugins/release-version.js +28 -0
  550. package/dist/plugins/remote-env-adb.d.ts +20 -4
  551. package/dist/plugins/remote-env-adb.js +39 -11
  552. package/dist/plugins/remote-env-e2b.d.ts +19 -28
  553. package/dist/plugins/remote-env-e2b.js +40 -29
  554. package/dist/plugins/remote-env-host.d.ts +11 -10
  555. package/dist/plugins/remote-env-host.js +40 -27
  556. package/dist/plugins/remote-env-k8s.d.ts +45 -47
  557. package/dist/plugins/remote-env-k8s.js +122 -62
  558. package/dist/plugins/remote-env-local-docker.d.ts +152 -15
  559. package/dist/plugins/remote-env-local-docker.js +370 -75
  560. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  561. package/dist/plugins/remote-env-ssh.js +26 -24
  562. package/dist/plugins/remote-scratchpad.js +4 -0
  563. package/dist/plugins/remote-shell.d.ts +59 -30
  564. package/dist/plugins/remote-shell.js +175 -62
  565. package/dist/plugins/retention-declaration.d.ts +37 -0
  566. package/dist/plugins/retention-declaration.js +9 -0
  567. package/dist/plugins/retention-deployment.d.ts +158 -0
  568. package/dist/plugins/retention-deployment.js +119 -0
  569. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  570. package/dist/plugins/retention-lane-store-sql.js +103 -1
  571. package/dist/plugins/retention-sql.d.ts +29 -0
  572. package/dist/plugins/retention-sql.js +8 -0
  573. package/dist/plugins/run-preview-m45.d.ts +11 -0
  574. package/dist/plugins/run-preview-m45.js +19 -0
  575. package/dist/plugins/run-store-sql.d.ts +56 -68
  576. package/dist/plugins/run-store-sql.js +127 -116
  577. package/dist/plugins/s3-answer.d.ts +2 -1
  578. package/dist/plugins/sandbox-reaper.d.ts +26 -0
  579. package/dist/plugins/sandbox-reaper.js +2 -0
  580. package/dist/plugins/scenario-prefix-switch-m42.d.ts +54 -0
  581. package/dist/plugins/scenario-prefix-switch-m42.js +55 -0
  582. package/dist/plugins/scheduler-support.d.ts +16 -1
  583. package/dist/plugins/scheduler-support.js +22 -2
  584. package/dist/plugins/schema-consistency.d.ts +42 -15
  585. package/dist/plugins/schema-consistency.js +213 -13
  586. package/dist/plugins/schema-drift-sentence.d.ts +4 -1
  587. package/dist/plugins/schema-drift-sentence.js +4 -4
  588. package/dist/plugins/schema-ensure-legs.d.ts +10 -1
  589. package/dist/plugins/schema-ensure-legs.js +12 -2
  590. package/dist/plugins/schema-indexes.js +3 -0
  591. package/dist/plugins/schema-live-columns.d.ts +14 -5
  592. package/dist/plugins/schema-live-columns.js +10 -10
  593. package/dist/plugins/send-user-file.js +2 -1
  594. package/dist/plugins/session-birth.d.ts +37 -0
  595. package/dist/plugins/session-birth.js +38 -0
  596. package/dist/plugins/session-epoch-anchor.d.ts +40 -12
  597. package/dist/plugins/session-epoch-anchor.js +33 -11
  598. package/dist/plugins/session-ext-table.d.ts +98 -0
  599. package/dist/plugins/session-ext-table.js +134 -0
  600. package/dist/plugins/session-fork.d.ts +16 -2
  601. package/dist/plugins/session-fork.js +3 -0
  602. package/dist/plugins/session-ownership.d.ts +1 -1
  603. package/dist/plugins/session-placement.d.ts +22 -16
  604. package/dist/plugins/session-placement.js +15 -12
  605. package/dist/plugins/session-row-sql.d.ts +20 -7
  606. package/dist/plugins/session-row-sql.js +16 -8
  607. package/dist/plugins/session-run-rollup.d.ts +29 -0
  608. package/dist/plugins/session-run-rollup.js +40 -0
  609. package/dist/plugins/session-store-sql.d.ts +157 -0
  610. package/dist/plugins/session-store-sql.js +398 -0
  611. package/dist/plugins/session-withdraw-sql.d.ts +36 -0
  612. package/dist/plugins/session-withdraw-sql.js +42 -0
  613. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  614. package/dist/plugins/session-workspace-cell.js +2 -2
  615. package/dist/plugins/shared-memory-store-sql.d.ts +10 -69
  616. package/dist/plugins/shared-memory-store-sql.js +15 -14
  617. package/dist/plugins/shell-sentinel-owner-m48.d.ts +20 -0
  618. package/dist/plugins/shell-sentinel-owner-m48.js +3 -0
  619. package/dist/plugins/snapshot-bucket-presence.d.ts +2 -1
  620. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  621. package/dist/plugins/sql-driver.d.ts +24 -8
  622. package/dist/plugins/sql-driver.js +43 -9
  623. package/dist/plugins/sql-errors.d.ts +35 -5
  624. package/dist/plugins/sql-errors.js +55 -3
  625. package/dist/plugins/sql-json-column.d.ts +8 -7
  626. package/dist/plugins/sql-json-column.js +10 -6
  627. package/dist/plugins/store-backend.d.ts +114 -18
  628. package/dist/plugins/store-backend.js +340 -87
  629. package/dist/plugins/store-contracts.d.ts +97 -30
  630. package/dist/plugins/store-contracts.js +23 -1
  631. package/dist/plugins/store-fault.d.ts +28 -2
  632. package/dist/plugins/store-fault.js +20 -2
  633. package/dist/plugins/task-attachment-store.d.ts +21 -11
  634. package/dist/plugins/task-attachment-store.js +37 -19
  635. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  636. package/dist/plugins/text-column-capacity.d.ts +21 -0
  637. package/dist/plugins/text-column-capacity.js +5 -0
  638. package/dist/plugins/tidb-pool.d.ts +3 -2
  639. package/dist/plugins/tidb-pool.js +42 -39
  640. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  641. package/dist/plugins/web-search.js +5 -3
  642. package/dist/plugins/workflow-run-store-sql.d.ts +6 -1
  643. package/dist/plugins/workflow-run-store-sql.js +11 -5
  644. package/dist/principal-jwt.d.ts +4 -4
  645. package/dist/principal-jwt.js +20 -5
  646. package/dist/principal-shape.d.ts +41 -0
  647. package/dist/principal-shape.js +19 -0
  648. package/dist/question.d.ts +13 -23
  649. package/dist/question.js +21 -39
  650. package/dist/read-face-posture.d.ts +6 -6
  651. package/dist/read-face-posture.js +2 -2
  652. package/dist/request-declaration-refusal.d.ts +35 -12
  653. package/dist/request-declaration-refusal.js +21 -9
  654. package/dist/request-form.d.ts +58 -0
  655. package/dist/request-form.js +72 -0
  656. package/dist/request-image-urls.d.ts +8 -2
  657. package/dist/request-image-urls.js +2 -1
  658. package/dist/request-images.d.ts +20 -0
  659. package/dist/request-images.js +59 -0
  660. package/dist/request-key-closure.d.ts +6 -7
  661. package/dist/request-key-closure.js +15 -2
  662. package/dist/request-value-closure.d.ts +5 -5
  663. package/dist/request-value-closure.js +1 -1
  664. package/dist/resource-suspend.d.ts +7 -16
  665. package/dist/resource-suspend.js +1 -1
  666. package/dist/retired-name-host-notice.d.ts +21 -0
  667. package/dist/retired-name-host-notice.js +12 -0
  668. package/dist/rule-entry-list.d.ts +2 -2
  669. package/dist/rule-entry-list.js +3 -4
  670. package/dist/rule-issue-reading.d.ts +58 -0
  671. package/dist/rule-issue-reading.js +14 -0
  672. package/dist/rules-consent.d.ts +46 -16
  673. package/dist/rules-consent.js +102 -53
  674. package/dist/run-acceptance.d.ts +3 -1
  675. package/dist/run-acceptance.js +3 -0
  676. package/dist/run-local.d.ts +14 -6
  677. package/dist/run-local.js +109 -93
  678. package/dist/run-stale-default.d.ts +7 -0
  679. package/dist/run-stale-default.js +2 -0
  680. package/dist/runs.d.ts +73 -44
  681. package/dist/runs.js +65 -43
  682. package/dist/runtime-caps-resolver.d.ts +36 -14
  683. package/dist/runtime-caps-resolver.js +31 -14
  684. package/dist/runtime-governance.d.ts +2 -2
  685. package/dist/runtime-governance.js +5 -3
  686. package/dist/sealed-key-layout.d.ts +12 -6
  687. package/dist/sealed-key-layout.js +5 -1
  688. package/dist/sealed-key.d.ts +12 -2
  689. package/dist/sealed-key.js +116 -26
  690. package/dist/security.d.ts +133 -161
  691. package/dist/security.js +163 -59
  692. package/dist/sema-config-dir.d.ts +20 -0
  693. package/dist/sema-config-dir.js +27 -2
  694. package/dist/server-secret-env.d.ts +23 -5
  695. package/dist/server-secret-env.js +14 -4
  696. package/dist/service-version.d.ts +2 -1
  697. package/dist/service-version.js +2 -2
  698. package/dist/session-children-retire.d.ts +7 -5
  699. package/dist/session-children-retire.js +7 -2
  700. package/dist/session-deletion.d.ts +88 -0
  701. package/dist/session-deletion.js +8 -0
  702. package/dist/session-erase.d.ts +145 -0
  703. package/dist/session-erase.js +115 -0
  704. package/dist/session-error-wire.d.ts +6 -6
  705. package/dist/session-error-wire.js +1 -1
  706. package/dist/session-incarnation.d.ts +60 -10
  707. package/dist/session-incarnation.js +19 -2
  708. package/dist/session-policy-wire.d.ts +6 -3
  709. package/dist/session-policy-wire.js +11 -1
  710. package/dist/session-resident-background.d.ts +29 -47
  711. package/dist/session-resident-background.js +77 -8
  712. package/dist/session-row.d.ts +3 -2
  713. package/dist/session-rules-seat.d.ts +12 -0
  714. package/dist/session-rules-seat.js +19 -0
  715. package/dist/session-sync-kernel.d.ts +1 -1
  716. package/dist/session-titler.d.ts +7 -15
  717. package/dist/session-titler.js +1 -1
  718. package/dist/session-workspace.d.ts +11 -2
  719. package/dist/session-workspace.js +5 -0
  720. package/dist/sighup-idle.d.ts +1 -1
  721. package/dist/spec-fields.d.ts +57 -3
  722. package/dist/spec-fields.js +72 -51
  723. package/dist/store-posture.d.ts +138 -21
  724. package/dist/store-posture.js +188 -3
  725. package/dist/stored-request-hooks-m20.d.ts +3 -2
  726. package/dist/stored-request-hooks-m20.js +21 -16
  727. package/dist/stores-sql/background-agent-store-sql.d.ts +11 -2
  728. package/dist/stores-sql/background-agent-store-sql.js +73 -20
  729. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  730. package/dist/stores-sql/blob-index-sql.js +154 -0
  731. package/dist/stores-sql/checkpoint-store-sql.d.ts +34 -29
  732. package/dist/stores-sql/checkpoint-store-sql.js +86 -71
  733. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  734. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  735. package/dist/stores-sql/mailbox-store-sql.d.ts +7 -4
  736. package/dist/stores-sql/mailbox-store-sql.js +31 -32
  737. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +30 -81
  738. package/dist/{plugins → stores-sql}/pg-session-storage.js +123 -244
  739. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +197 -223
  740. package/dist/{plugins → stores-sql}/retention-store-sql.js +148 -207
  741. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  742. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  743. package/dist/stores-sql/session-policy-store-sql.d.ts +33 -11
  744. package/dist/stores-sql/session-policy-store-sql.js +44 -36
  745. package/dist/stores-sql/session-write-hooks.d.ts +65 -0
  746. package/dist/stores-sql/session-write-hooks.js +2 -0
  747. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +14 -15
  748. package/dist/{plugins → stores-sql}/tidb-session-storage.js +22 -28
  749. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +67 -138
  750. package/dist/{plugins → stores-sql}/tidb-session-store.js +130 -200
  751. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  752. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  753. package/dist/stores-sql/windowed-session-storage.d.ts +61 -0
  754. package/dist/stores-sql/windowed-session-storage.js +70 -0
  755. package/dist/submission-exit.d.ts +50 -0
  756. package/dist/submission-exit.js +108 -0
  757. package/dist/task-a2a.d.ts +7 -1
  758. package/dist/task-a2a.js +18 -17
  759. package/dist/task-cwd.d.ts +31 -3
  760. package/dist/task-cwd.js +25 -1
  761. package/dist/task-mcp.d.ts +11 -3
  762. package/dist/task-mcp.js +16 -19
  763. package/dist/task-settings.d.ts +23 -14
  764. package/dist/task-settings.js +35 -13
  765. package/dist/terminal.d.ts +25 -43
  766. package/dist/terminal.js +31 -11
  767. package/dist/tool-approval.d.ts +152 -137
  768. package/dist/tool-approval.js +199 -199
  769. package/dist/trace/core-keyset-guard.d.ts +22 -9
  770. package/dist/trace/core-vocab-wire.d.ts +95 -0
  771. package/dist/trace/core-vocab-wire.js +15 -0
  772. package/dist/trace/engine-notice-wire.d.ts +1 -1
  773. package/dist/trace/engine-notice-wire.js +2 -0
  774. package/dist/trace/exit-seat.d.ts +52 -4
  775. package/dist/trace/exit-seat.js +43 -36
  776. package/dist/trace/extension-call-face.d.ts +3 -2
  777. package/dist/trace/extension-call-face.js +3 -1
  778. package/dist/trace/ledger-events.d.ts +4 -7
  779. package/dist/trace/ledger-sink.d.ts +1 -30
  780. package/dist/trace/ledger-sink.js +0 -11
  781. package/dist/trace/model-segment.d.ts +5 -5
  782. package/dist/trace/model-segment.js +5 -5
  783. package/dist/trace/project.d.ts +88 -58
  784. package/dist/trace/project.js +64 -28
  785. package/dist/trace/redact.d.ts +124 -28
  786. package/dist/trace/redact.js +936 -328
  787. package/dist/trace/self-minted-wire.d.ts +750 -29
  788. package/dist/trace/self-minted-wire.js +262 -25
  789. package/dist/trace/sema-provenance.d.ts +45 -41
  790. package/dist/trace/sema-provenance.js +81 -10
  791. package/dist/trace/task-notification-facets.d.ts +70 -2
  792. package/dist/trace/task-notification-facets.js +71 -1
  793. package/dist/trace/wire-projection-faces.d.ts +43 -8
  794. package/dist/trace/wire-projection-faces.js +28 -3
  795. package/dist/unread-request-members.d.ts +66 -0
  796. package/dist/unread-request-members.js +41 -0
  797. package/dist/upstream-body.d.ts +23 -0
  798. package/dist/upstream-body.js +16 -0
  799. package/dist/url-refusal.d.ts +3 -3
  800. package/dist/url-refusal.js +11 -4
  801. package/dist/user-authored-text.d.ts +1 -1
  802. package/dist/user-input-ledger.d.ts +7 -8
  803. package/dist/user-input-ledger.js +1 -1
  804. package/dist/web-admin-client/apply-effective.d.ts +6 -3
  805. package/dist/web-admin-client/apply-effective.js +33 -40
  806. package/dist/web-admin-client/apply-ledger.d.ts +16 -7
  807. package/dist/web-admin-client/apply-ledger.js +5 -2
  808. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  809. package/dist/web-admin-client/candidate-gate.js +53 -5
  810. package/dist/web-admin-client/center-request.d.ts +6 -3
  811. package/dist/web-admin-client/center-request.js +17 -16
  812. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  813. package/dist/web-admin-client/effective-keys.js +1 -2
  814. package/dist/web-admin-client/entry-metadata.d.ts +8 -0
  815. package/dist/web-admin-client/entry-metadata.js +13 -0
  816. package/dist/web-admin-client/facade.d.ts +1 -1
  817. package/dist/web-admin-client/http-client.d.ts +2 -1
  818. package/dist/web-admin-client/http-client.js +40 -13
  819. package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
  820. package/dist/web-admin-client/mcp-revocation.js +2 -1
  821. package/dist/web-admin-client/read-warnings.d.ts +1 -0
  822. package/dist/web-admin-client/read-warnings.js +1 -0
  823. package/dist/web-admin-client/restart-signal.js +13 -6
  824. package/dist/web-admin-client/skills-mcp.d.ts +22 -8
  825. package/dist/web-admin-client/skills-mcp.js +26 -21
  826. package/dist/web-admin-client/types.d.ts +35 -51
  827. package/dist/workspace-space.d.ts +3 -2
  828. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +4 -4
  829. package/package.json +16 -12
  830. package/scripts/drain-check-local.mjs +118 -173
  831. package/scripts/drain-check.mysql.sql +20 -16
  832. package/scripts/drain-check.pg.sql +20 -16
  833. package/wire-changes/server@7.147.0.json +813 -0
  834. package/wire-changes/server@7.148.0.json +1517 -0
  835. package/dist/http/memory-control-plane-corrupt-reply.d.ts +0 -25
  836. package/dist/http/memory-control-plane-corrupt-reply.js +0 -19
  837. package/dist/http/memory-layer-reply.d.ts +0 -30
  838. package/dist/http/memory-layer-reply.js +0 -24
  839. package/dist/lsp/e2b-bridge.d.ts +0 -57
  840. package/dist/lsp/e2b-bridge.js +0 -139
  841. package/dist/lsp/e2b-manager.d.ts +0 -93
  842. package/dist/lsp/e2b-manager.js +0 -178
  843. package/dist/lsp/lsp-frames.d.ts +0 -14
  844. package/dist/lsp/lsp-frames.js +0 -25
  845. package/dist/lsp/manager.d.ts +0 -129
  846. package/dist/lsp/manager.js +0 -127
  847. package/dist/lsp/types.d.ts +0 -12
  848. package/dist/lsp/types.js +0 -2
  849. package/dist/lsp/ws-transport.d.ts +0 -40
  850. package/dist/lsp/ws-transport.js +0 -210
package/MIGRATION.md CHANGED
@@ -1,11 +1,1411 @@
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.148.0 —— 1–115 条见下
12
+
13
+ 1. **删净一只会话只有一个执行体:SQL 上在线删除与留存同一段事务;删后收尾两者同一只(行为统一;嵌入方类型面 BREAKING;wire 零变化;零 DDL;部署零动作)**:
14
+ 旧形:在线删除逐店调删除动词;SQL 会话店带 `deleteSession(id, owner)`;留存删除不写完成信箱围栏、不丢会话信箱盒、不释放附件字节;留存回执带 `endedSpaces`。
15
+ 新形:SQL 后端的在线删除由后端的 `sessionEraser(opts)`(与 `retention(opts)` 同一份选项)完成:`erase({ sessionId, owner, token })`(`token` = 本版会话三态一条里删除围栏写下的那一只)在会话行锁下一个事务里比属主、判令牌、删全部行(完成信箱围栏、会话盒都在里面),答 `superseded`(被接管 / 已删完,一行没删)或 `erased`;SQL 会话店不再有 `deleteSession`;
16
+ local 会话店的 `deleteSession` 改为 `deleteSession(id, owner, token, legs)`(删除锁节:比属主、判令牌,`legs(住客)` 在锁里跑各店的删除,答删掉的那一位或 `undefined`);执行器选项多两只必填 `mailboxTables`(收件箱四表在不在)/ `completionInbox`(完成信箱在不在用);
17
+ `TaskAttachmentStore` 多一只必填 `releaseBytes(shas)`(回 `{ failed }`,不抛);留存回执的 `endedSpaces` 换成 `erased`(删掉的会话 + 删前属主 + 住客、附件字节哈希、无出处卸载结果数),交同一只收尾。
18
+ **谁受伤**:自建会话店 / 附件店 / 留存执行器的嵌入方(tsc 红即通告)。**出路**:按新签名实装;服务进程部署零动作。
19
+
20
+ 2. **🔴 配了服务凭据的部署上,`GET /health` 对没出示凭据的调用方只给闭集 `status` / `auth` / `operator` / `center`(wire BREAKING:对匿名读者收窄;零新旋钮;部署零动作 —— 读匿名 `/health` 里身份 / 路径 / 后端字段的脚本改带凭据)**:
21
+ 旧形:不论部署配没配服务凭据,匿名调用方 `GET /health` 都拿整张体(含 `dataRoot` 数据根绝对路径、`pid`、`configHash`、`startedAt`、`sessionBackend`、`store`、`version`、`engineSignal`、排空 / 租约窗等)。
22
+ 新形:没配任何服务凭据(`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` 不变。
23
+ 谁要动:① 嵌入宿主(桌面 / 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`,身份判不出)。带不带凭据是调用方逐次的选择:只对自己起的、已信任的端点带,不向复用端口上的陌生进程出示。
24
+
25
+ 3. **同一个凭据值在每个出口面上是同一枚记号:相接 / 部分重叠的两枚凭据在结果面、审批面、终局错误、账本行、活流上合成一枚(行为变更;wire 零新键、零新码;部署零动作)**:
26
+ 旧形:`AKIA…sk-…` 一类零分隔相接、或 `xoxb-AAAsk-…_XYZ` 一类部分重叠的两枚凭据,trace 帧 / 完成帧 / 运维日志上一枚记号,`result` / 账本行 / 审批卡 / run 的 `error` / 活流上两枚(`«redacted:aws-key»«redacted:key»`)。
27
+ 新形:每张面一枚段首记号(`«redacted:aws-key»`);格式字符隔开、原文上不相接的两段仍两枚;遮住的字节不变;`redactions_applied_total` 不变。跨引擎块相接的两枚在活流与段末帧上两枚、结果面一枚。
28
+ **谁受伤**:按记号个数推断凭据枚数、或按第二枚记号的标签分支的消费方。**出路**:把每一处 `«…»` 当「这里遮了一段」读,不读个数与标签组合(契约原有规定)。
29
+
30
+ 4. **运维日志:上游应答「体不是 JSON」的报错句不再带体的片段;记忆同步对端非 2xx 只带码 + 体长(行为变更;wire 零变化;部署零动作)**:
31
+ 旧形:`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 字原文。
32
+ 新形:`SyntaxError: the response body is not JSON (<n> characters; the body is not echoed)`;记忆同步 `HTTP <码> (<n> characters; the body is not echoed)`。
33
+ **谁受伤**:按 V8 原句匹配日志告警的规则;靠记忆同步行里对端拒因排障的运维。**出路**:改匹配 `the response body is not JSON`;拒因读对端(`MEMORY_SYNC_SERVE` 那一台)同一时刻的运维行。
34
+
35
+ 5. **run 终局里库驱动的原句不再上 wire:`internal.store_error` 的失败句改成固定对外句(行为变更;wire 零新键、零新码;部署零动作)**:
36
+ 旧形:持久层失败折成 `internal.store_error` 时,`GET /v1/runs/:id` 的 `error` 与 `result.terminal.message`(同一次失败的 `done.result` / 账本行 / 同步提交 200 体同)逐字带库驱动的原句(库账号、主机、表名、约束名都可能在里面)。
37
+ 新形:句 = 「<类别句> [original code: <码>]」,类别(连接类 / 部署错配类 / 其余)由整仓一只店故障判官按码说,与库写了什么无关(句子只断言码证明得了的事:只有缺表 / 权限拒两类库专有码才说「数据库」);原句只进 worker 日志里同一条 `outward_failure_code_folded … at=exit` 行的 `message=` 格。`terminal.code` 不变(仍 `internal.store_error`),`error` 与 `terminal.message` 是同一句;没有码、或码在本仓词法内的失败文本不变(码在词法之外的 —— 持久层的驱动错与少数系统错误码如 `ENOENT` —— 同样换句)。
38
+ **谁受伤**:按这句失败文本分支的调用方(它一向是自由文本,判别读 `terminal.code`),与靠 wire 上库原话排障的运维。**出路**:判别读 `terminal.code` 与句尾 `[original code: …]`;要库的原话读 worker 日志那一行。已落盘的旧行不改写。
39
+
40
+ 6. **workflow 完成的 `diagnostics`:live `task_notification` 帧不再带部署路径 / 内部 URL 原文,与 `workflow_complete` 补投帧同一读法(行为变更;wire 零新键、零新码;部署零动作)**:
41
+ 旧形:同一次 workflow 完成,补投帧 `diagnostics` 里的 journal 坐标是 `[redacted-path]`,live 帧上是部署路径原文(引擎在两条腿上递的不是同一份,本服务两条腿各接一行座、都不读「读者是人」的档)。
42
+ 新形:两张脸读座表的同一行,整条 URL / 绝对路径换 `[redacted-url]` / `[redacted-path]`,同一次完成逐字节相等(主机身份这一维);live 帧同补投帧界 4000 码元(此前不设界)。读取手柄句与续跑句不含路径、不变。顺带:所有有界座行的切点律认引擎的记号族,`[redacted-path]` 一类恰被界切到时切在记号前(此前留半枚)。
43
+ **谁受伤**:按 live 帧上 journal 路径文本分支的调用方(极罕见)。**出路**:读 `ReadToolResult (ref …)` 手柄句与 `resumeFromRunId` 续跑句,不读路径。
44
+
45
+ 7. **取消一次 wake 不再收掉它续的那张会话 park(行为变更;wire 零新键、零新码;部署零动作)**:
46
+ 旧形:wake 在入口屏 / 预检上被取消(`checkpoint.resume_aborted`)⇒ 合成行取消终局,会话的 `task_done` park 被 expire,再 wake 答 `404 not_found.parked_checkpoint`。
47
+ 新形:合成行照旧取消终局(`errorCode:"cancelled"`)、放认领;park 留 pending,再 wake 续它(与 wake 跑起来之后失败 / 取消时的结局同一个)。
48
+ **谁受伤**:把「取消 wake」当成「结束这条会话的 park」的调用方。**出路**:新提交一条任务(新 run 与 park 并存),或等审批窗到期收割。
49
+
50
+ 8. **local-docker 车道容器帽:新旋钮 `DOCKER_MAX_CONTAINERS`(缺省 `0` = 关);新提交可能拿到 429 `limit.rate_exceeded` 的第二个机读 `reason`:`"sandbox_capacity"`;`/health` 多一格 `sandboxCapacity`(行为加性,缺省关;wire 加性;部署零动作)**:
51
+ 旧形:`REMOTE_EXEC=local-docker` 下沙箱容器的总量服务侧不封顶(每条 run、每只委派子代各一只,停驻期不销毁;`DOCKER_MEMORY` 只封单只)。
52
+ 新形:`DOCKER_MAX_CONTAINERS` 是 `0` / 不设 ⇒ 不建闸、不读 daemon;帽关着也生效的只有三处 —— 每只 `docker run` 恒带本 worker 标签 `--label sema.local-docker=<worker>`(惰性元数据);连接还没完成时被取消的工具调用立刻答 `aborted`(此前等连接完成后答同一个码),
53
+ `docker` CLI 的 spawn 同步抛(argv 过长等)不再让适配器的 promise 拒掉、改答 `spawn_error`。开了之后:`DOCKER_MAX_CONTAINERS` = 本 worker 同时在跑的容器数上限(上限只有这一只旋钮;按内存定上限自己换算:
54
+ `floor(愿给容器的总内存 / DOCKER_MEMORY)`)。计数读 docker daemon:本 worker 起的每只容器都带标签 `sema.local-docker=<worker>`(标签恒在,上限随时可开 —— 上限关着时起的也计;停驻期的、委派子代的都计),加上 `docker run` 回执丢了而 daemon 仍列着的。
55
+ 射程 = 本 worker:worker 是本服务数据根绝对路径的摘要,同一数据根上重起不变 —— 上一次进程崩掉留下的容器照计;别的数据根是别的 worker,不计;多只 worker 共用一只 daemon 时整机合计不在本旋钮。
56
+ 只有本版之前起的容器不带标签、不计。
57
+ 起容器没空位 ⇒ 每只执行环境等一份预算(缺省 60 s),到期这一次工具调用拿到带 `limit.rate_exceeded` · `sandbox_capacity` 的拒句(run 不被终结;句里给本 worker 的标签过滤式)。
58
+ 闸里有起动在等空位时,新提交的四个口(`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`;续跑 / 唤醒 / 作答不判。
59
+ `GET /health` 多 `sandboxCapacity: { lane, limit, inUse, readAt, waiting }`(帽开着才在场;`inUse` 是最近一次读 daemon 的数,还没读过 / 读不出 ⇒ `null`)。
60
+ **谁需要**:local-docker 车道上有内存预算的多租 / 家用常驻部署。**谁受伤**:没空位时的工具调用(等满预算后拒)与有人在等时的新提交(429);停驻的 run 占格(续跑腿接着用它,不另要一格;停驻期间被停掉的那只不占格,续跑时重新经准入);
61
+ **开了上限的部署里,本版之前起的容器占位**(旧名带随机尾,本服务不认;停驻中取消 / 停驻过期的 run 留下的、上一次进程崩掉留下的都在内)—— 看 `/health.sandboxCapacity.inUse` 与拒句里的过滤式,手删残留即放;
62
+ 本版起,停驻中取消 / 停驻过期 / 重起之后才结清的 run 的容器由维护 tick 上的回收腿按 run 行终局删掉(见下一条的「谁受伤」),不再占位。
63
+ **部署方**:一个数据根只跑一只服务进程(准入的互斥只在进程里:同一数据根上同时跑的两只进程看得见对方在跑的容器,看不见对方正在起的,同时起动时合计可超过上限);按内存换算上限时,改小 `DOCKER_MEMORY` 之前先清掉残留(旧容器按起动时的限额占内存);升级后第一次开帽之前先清掉旧版留下的无标签残留(`docker ps -a --filter name=sema-docker-`)。**消费方**(按 `limit.rate_exceeded` 分支的 sdk / cli / 控制台 / 编排):`reason` 闭集多一词 `sandbox_capacity`,
64
+ 按 `Retry-After` 退避即可;按 `reason` 穷举分支的读者补这一词(未知词按「稍后再来」处理)。
65
+ **补偿**:缺省关;`Retry-After: 5`。**升级前做**:无。**回滚**:去掉这根 env 即关;回到上一版时它被忽略,`sandboxCapacity` 格与 `sandbox_capacity` 词消失。
66
+
67
+ 9. **local-docker 停驻 → 续跑:续跑腿接着用停驻时那只容器,续跑腿收场时删它;容器名改由 run 的身份确定(行为修复;运维面容器名形变;wire 零变化;部署零动作)**:
68
+ 旧形:每只执行环境一只新容器,名 `sema-docker-<身份>-<8 位随机>`;续跑腿另起一只空容器(看不到停驻前的文件),停驻时那只一直跑(开了上限时占格)。
69
+ 新形:名 `sema-docker-<身份>-<12 位摘要>`(身份 = 顶层 run 的 run 号 / 委派子代自己的会话号;摘要含本 worker 标签),同一身份恒同名;续跑腿用停驻那只(同一进程:同一只执行环境;
70
+ 服务重起之后:`docker inspect` 见它在跑且带本 worker 标签 ⇒ 附着),收场时删恰一次。每次起容器前多一次 `docker inspect`;本 worker 的同名容器停着(`exited`)⇒ 经容器帽准入后 `docker start` 再附着;
71
+ 建了没跑过(`created`)⇒ 删掉再起;`paused` / `restarting` / `removing` / `dead`、不带本 worker 标签的同名容器、读不出的答 ⇒ 这一次连接拒(`connect_failed`,不起、不删)。
72
+ 执行环境只碰它负责的那只容器实例(`docker exec` / `docker rm -f` 按容器 id);删除证实不了的那只永不再附着,先删它再起新的。
73
+ 重起之后那只容器已经不在 ⇒ 续跑腿起一只新的空容器(工厂分不出续跑腿)。
74
+ **谁受伤**:停驻期间 daemon 重起 / 宿主重启的 run —— 续跑时那只容器被 `docker start`(文件在,停之前在跑的进程不在);停在 `paused` / `dead` 一类状态的 ⇒ 续跑的工具调用拒,
75
+ 运维用 docker 处置后重试;停驻中取消 / 停驻过期的 run 的容器由维护 tick 的回收腿按 run 行终局删(下一条)。
76
+ **部署方**:按名前缀找容器的脚本照旧(`sema-docker-`);升级前已停驻的 run 续跑时仍另起新容器、旧的留下 —— 升级后清一次:`docker ps -a --filter name=sema-docker- --format '{{.Names}} {{.Label "sema.local-docker"}}'`
77
+ 列出的容器里只删第二列为空的(不带标签 = 上一版起的,同第 8 条);带 `sema.local-docker` 标签的是本版起的(含在跑与停驻的),不碰。
78
+ **升级前做**:无。**回滚**:回到上一版即回到随机尾;本版起的容器上一版不认(按标签清)。
79
+
80
+ 10. **local-docker 无主容器回收:停驻中取消 / 停驻过期 / 重起之后才结清的 run,它的容器在 run 终局后由维护 tick 的回收腿删掉(行为修复;新运维读数;wire 零变化;部署零动作)**:
81
+ 旧形:停驻中被取消 / 过期的 run,停驻时那只容器没有销毁者(引擎只在自己结清停驻时销毁;本服务的取消与过期扫描在店层结清),一直在跑,开了 `DOCKER_MAX_CONTAINERS` 的部署里一直占一格。
82
+ 新形:维护 tick 上的沙箱回收腿(k8s 车道 pod 回收的同一只座,起服后第一个维护 tick 跑一轮、此后每 5 分钟一轮;没有旋钮)对 local-docker 车道多回收一类:本 worker 标签下、名字读得回 run 号、且那条 run 的行已终局并过了 5 分钟保持窗的容器(引擎在 `done` 帧之后还要用环境收尾,窗内不动)——
83
+ 按容器 id 删(证实才清;证实不了的仍欠着,下一轮先删它)。run 行是活的(跑着 / 停驻着)⇒ 不动;读不回身份 / 没有 run 行 / 读 run 账本抛 / 状态词不在词表 / 终局时刻读不出 / 没有存储后端 ⇒ 都不动。
84
+ 每轮一行 `local_docker_reap_round`、每删一只一行 `local_docker_reaped`、计数 `local_docker_containers_reaped_total{reason}`、退化口 `server.local-docker-reaper.degraded`;
85
+ 维护 tick 的沙箱回收腿连败告警(`reaper_leg_repeated_failure`)的 `reaper` 字段由 `sandbox_pod_reap` 改为 `sandbox_reap`(两条车道共一只座)。
86
+ **谁受伤**:被取消 / 过期的 run 的容器此前能留着供事后进去看,现在终局 5 分钟后的下一轮被删(与一条 run 正常收场时被删同一件事);**不覆盖**:本版之前起的容器(名带随机尾)、委派子代的容器(身份是会话号、不在 run 账本里)
87
+ ⇒ 仍要手删:本版之前起的容器不带标签,按第 9 条的命令找(名前缀列出、只删标签列为空的);委派子代的容器带本 worker 标签,按标签过滤式找。**升级前做**:无。**回滚**:回到上一版即回到「无主容器无人收」。
88
+
89
+ 11. **🔴 leader run 的取消口 `POST /v1/leader/:id/cancel` 与取消终局;SQL 后端 `leader_run` 表加五列(升级前先加列;持久数据,不能删表重建;新口 + wire 加性;嵌入方类型面 BREAKING)**:
90
+ 旧形:leader run 没有停止口;`leader_run` 行不记受理时验过的凭据来源;`GET /v1/leader/:id` 体 = `{ id, status, result?, error? }`。
91
+ 新形:`POST /v1/leader/:id/cancel` —— 行还在跑 ⇒ 翻耐久取消旗,`202 { leaderRunId, status: "cancelling", cancelRequested: true }`,驱动副本当场(同副本)或下一个存活心跳拍(别的副本)中止;行已终局 ⇒ 幂等 `202`(带终局词与 `note`),同时过期这条 run 留下的待决 worker 停驻(并发结算抢先的那几张 ⇒ `409 conflict.approval_settled`)。
92
+ run 停在中止核点 ⇒ 终局 `failed` + `errorCode: "cancelled"`、零 push;取消晚到、push 已发出 ⇒ 终局照实。读面多两键 `cancelRequested`(恒在)/ `errorCode`(只在取消终局),结果多一键 `stopped`(只在停在中止核点时在场,恒 `true`)。
93
+ **升级前做(SQL 后端:`DB_BACKEND=mysql|pg`;开了 leader 端点的部署)**:本服务不发 `ALTER`,存量库缺列 ⇒ 起服列册对账拒启(`config.schema_mismatch`,拒句带同样的语句)。先在库上执行(先升库再升副本):
94
+ MySQL 协议:
95
+ `ALTER TABLE leader_run ADD COLUMN error_code VARCHAR(64) NULL;`
96
+ `ALTER TABLE leader_run ADD COLUMN cancel_requested SMALLINT NOT NULL DEFAULT 0;`
97
+ `ALTER TABLE leader_run ADD COLUMN identity_source VARCHAR(32) NULL;`
98
+ `ALTER TABLE leader_run ADD COLUMN identity_scope VARCHAR(190) NULL;`
99
+ `ALTER TABLE leader_run ADD COLUMN identity_principal_inc VARCHAR(64) NULL;`
100
+ PostgreSQL:
101
+ `ALTER TABLE leader_run ADD COLUMN error_code VARCHAR(64) COLLATE "C" NULL;`
102
+ `ALTER TABLE leader_run ADD COLUMN cancel_requested SMALLINT NOT NULL DEFAULT 0;`
103
+ `ALTER TABLE leader_run ADD COLUMN identity_source VARCHAR(32) COLLATE "C";`
104
+ `ALTER TABLE leader_run ADD COLUMN identity_scope VARCHAR(190) COLLATE "C";`
105
+ `ALTER TABLE leader_run ADD COLUMN identity_principal_inc VARCHAR(64) COLLATE "C";`
106
+ 存量行:`cancel_requested` 由列缺省填 0,其余四列为空 —— 身份元组为空 = 不合格(没有事实可回填,不回填)。表还没建过的库(从没开过 leader 端点)零动作,起服照常建全列。
107
+ **回滚到上一版:只回退二进制不可行**(两方言皆然)—— 加过列的库上,上一版的起服列册对账把多出的五列读成幽灵列、起服拒。回滚 = ① 先停光全部本版副本;② 手工 `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;`(分五句,两方言同);③ 再起上一版。
108
+ **嵌入方**:`createLeaderEndpoint` 的 `runLeader` 收第二参 `signal: AbortSignal`(必须把它交给 `runLeaderTask` 的 `deps.signal`,否则取消停不下 run);`createLeaderRunner` 的返回函数多一个可选第二参 `signal`(端点交给它;直接调它而不交 = 这次调用停不下,与上一版同);自带 `LeaderRunStore` 实现的要补 `requestCancel(id)`,`LeaderRunRecord` 多 `cancelRequested` / `identity`(必填)与 `errorCode?`;`NewLeaderRun` 多必填 `identity`。
109
+ **行为变更(只涉调低过 `LEADER_RUN_STALE_MS` 的部署)**:驱动副本每个存活心跳拍读一次自己的行,行已被陈旧清算判了终局 ⇒ 停下;它的终局写因此打空,落定时过期它的残留停驻(旧形:照跑,可能在一条写着 `failed` 的行背后照 push)。缺省 26 h 大于 run 上限,零动作;调低过的把它调回大于真实 run 时长。
110
+ **谁受伤**:拿取消晚于 push 的 run 当「已取消」读的消费者(看 `errorCode`,不看 `cancelRequested`);事后想对一条已取消 run 的 worker 停驻 `/decide` 续跑的运维(取消就是把它们过期)。**出路**:要续跑就别取消;按 `errorCode === "cancelled"` 判「停下了、没推」。
111
+
112
+ 12. **只改条目备注 `notes` / 名册标签 `rosters` 的配置编辑不再签重启、不换装模型面;已撤的 MCP 服务器改了这两键再加回照常恢复(行为修复;wire 零变化;部署零动作)**:
113
+ 旧形:中心(或本地 `config.d`)上一条模型 / 技能 / MCP / 场景条目只改了 `notes`(技能 / MCP 另有 `rosters`)⇒ `/health.restart` 签 `skills` / `mcp` / `scenarios` 片、模型面换装一次;已撤的 MCP 名带着改过的备注加回仍被撤。
114
+ 新形:这两键不进三处指纹(只减条目顶层键);MCP 条目的分组标签 `source` 按挂载口的判据进指纹(坏形与缺席同值);改任何运行期字段(含合法分组标签)照旧签 / 换装 / 保持撤销。本地配置源交给消费方的视图与配置中心的 `/effective` 同形(消费方读数不变)。
115
+ **谁受伤**:靠「改备注触发滚动重启」的手动流程。**出路**:要重启就显式重启。
116
+
117
+ 13. **dry-run 行 `web_admin_dry_run` 的 `wouldOverrideModels` 改报「这份候选管不管模型面」:只有被读腿丢掉的启用条目(或载体形不对)的候选报 `true`,与 `wouldRefuseModelPlane` 同在(日志面读数变;wire 零变化;部署零动作)**:
118
+ 旧形:只数幸存的启用条目 —— 条目全被读腿丢掉的候选报 `false`,而同一行带 `wouldRefuseModelPlane`(真 apply 照常判它、组拒)。
119
+ 新形:与真 apply 同一只判决位;`true` + `wouldRefuseModelPlane` = 「管,但会被组拒,模型面不动」。只有停用条目的候选照旧 `false`。
120
+ **谁受伤**:只读 `wouldOverrideModels` 判「会不会动模型面」的上线前核验脚本。**出路**:两格并读 —— 动模型面 ⇔ `wouldOverrideModels` 且没有 `wouldRefuseModelPlane`。
121
+
122
+ 14. **`MODEL_PROVIDER=anthropic` 而没有 anthropic 钥匙、又要服务 env 模型表 ⇒ 起服拒,网关在场也拒(行为收紧;wire 零新键、零新码)**:
123
+ 旧形:env 写了 `MODEL_PROVIDER=anthropic`、`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 都没设、`MODEL_GATEWAY_BASEURL` 设着 ⇒ 起得来,env 模型的请求由网关腿服务(OpenAI 兼容线路、网关钥匙),
124
+ 模型行上的 `api` / 缓存族仍按 anthropic 写;只有网关也没有时才拒(`config.model_route_endpoint_missing`,缺口 `lane_credential_missing`)。
125
+ 新形:同一个码、同一个缺口词,网关在不在都拒;目录在服(env 模型表不服务)时不判 env 表,照常起。
126
+ **谁受伤**:env 模型表在服、靠这一形走网关的部署。**出路**:三选一 —— 补 `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN`;把 `MODEL_PROVIDER` 改成 `gateway`(或 `vllm`)—— 就是此前实际在走的线路;不设 `MODEL_ID`,让目录的缺省条目服务。
127
+ 15. **中心配置的盘上 LKG 与调度共享店过本地配置根的同一只目录信任判官:别人改得动 ⇒ LKG 不读回、调度店读写整条拒(安全轴,fail-closed;零新旋钮;日志面多一事件;部署零动作 —— 两只文件落在组 / 他人可写处的部署除外)**:
128
+ 旧形:LKG(`<SEMA_CONFIG_DIR>/config-lkg-*.json` 或 `CONFIG_LKG_PATH`)读回只判 JSON / 信封 / 身份,不判属主与模式;调度共享店(`SCHEDULER_STORE_PATH`,缺省 `<SEMA_CONFIG_DIR>/scheduled_tasks.json`)读写不判。
129
+ 新形:两者读之前过本地配置根的同一只判官(从 `/` 起逐级判;属主 ∈ {本服务用户, root, `CONFIG_LOCAL_OWNER_UID`};非链接组件不得组 / 他人可写;常规文件 ≤ 16 MiB)。
130
+ LKG 有发现 ⇒ 不读回,`config_lkg_unusable` 的 `reason` = 同族拒句(`config.dir_untrusted: refusing to read the last-known-good config …`),env 兜底;
131
+ 调度店有发现 ⇒ 这一次读写整条拒(`io`),日志 `scheduler_store_untrusted`(`path` / `refusal`)。`CONFIG_LOCAL_OWNER_UID` 对三只读者同一格。
132
+ 判的是读者真正打开的路径(不做词法归一:`链接/..` 按链接目标的物理父目录解);调度店目录还不在 ⇒ 本服务首写前建成 `0700`(与 umask 无关)。
133
+ **谁受伤**:`SEMA_CONFIG_DIR` / `CONFIG_LKG_PATH` / `SCHEDULER_STORE_PATH` 落在组 / 他人可写目录(或属主是别的 uid)的部署。
134
+ **升级前做**:按拒句改 —— `chmod go-w <路径>` / `chown` / 声明 `CONFIG_LOCAL_OWNER_UID=<uid>` / 把文件挪到只有本服务用户或 root 写得动的目录;本服务自己首建的配置根是 `0700`,零动作。
135
+
136
+ 16. **🔴 单用户声明要有一道身份边界:`OPERATOR_SINGLE_USER=true` ∧ 没配服务凭据 ∧ 监听地址不只在本机回环 ⇒ 服务进程起服拒(安全轴;行为 BREAKING:起服拒启面;零新旋钮;符合这一形的部署升级前补一行)**:
137
+ 旧形:声明之后,没配 `SERVICE_AUTH_TOKEN` / `SERVICE_AUTH_TOKENS` 的部署照常起服、监听全接口 —— 能连上端口的任何人都是运维(只写在 USAGE 里)。
138
+ 新形:起服第 1 段(声明必填之后)判 —— 声明 ∧ 无凭据 ∧ 监听地址不只在本机回环(缺省全接口 / `0.0.0.0` / 局域网地址 / 主机名;`ALLOW_UNAUTHED_WRITES=true` 且无凭据时自收窄到 127.0.0.1,算回环)⇒ 非零退出,
139
+ stderr 一行拒句(不变量 `operator-single-user-boundary`)点名监听在哪与三条出路。热路径上删光凭据的候选同判拒。`run-local` 不判。
140
+ **谁受伤**:本地单机 dev 监听全接口、没配凭据、写了声明的部署;`docker-compose.yml` 写了声明而没填 `SERVICE_AUTH_TOKEN` 的部署。
141
+ **升级前做**(三选一):配 `SERVICE_AUTH_TOKEN`(或 `SERVICE_AUTH_TOKENS`);或 `BIND_HOST=127.0.0.1` 只听本机回环(容器端口要发布给别的主机时这一条不适用,改配凭据);
142
+ 或撤掉 `OPERATOR_SINGLE_USER`、在 `OPERATOR_PRINCIPALS` 里具名运维。`sema-up` / chart 部署恒带凭据,零动作。
143
+
144
+ 17. **🔴 单用户部署上不带主体的 run 读本机属主的规则桶:桶里持久的 deny / ask / allow 行开始约束不带 `x-agent-principal` 的 run(安全轴;行为变更;零新旋钮;零 DDL;部署零动作 —— 本机属主桶里存着旧行的部署先看一眼)**:
145
+ 旧形:不带主体的 run(裸 HTTP / 没设主体的 SDK / 本机控制台)读零条持久规则 —— 规则店里本机属主那只桶(file 后端 `<数据根>/permission-rules/local-owner.json`;SQL 后端 `permission_rule` 表 `owner_kind='local-owner'` 的行)对它不生效。
146
+ 新形:单用户部署(`REQUIRE_PRINCIPAL` 未开)∧ 规则店装配了(`PERMISSION_RULES_ENABLED` 开着且后端有规则店)⇒ 不带主体的 run 读这只桶;运维手动整理阀门(`POST /v1/admin/memory/consolidation/run`)不带主体的调用方同读它。
147
+ 带主体的 run(含 cli —— 它恒带主体)读自己的桶,不变;多租形(`REQUIRE_PRINCIPAL=true`)零变化。不带主体的问卡照旧不给「不再询问」。
148
+ **谁受伤**:本机属主桶里存着旧行的单用户部署 —— 那些行(包括 allow 行)从本版起对不带主体的 run 生效。
149
+ **升级前做**:看一眼那只桶(file 后端读上面那只文件;SQL 后端查 `permission_rule` 表 `owner_kind='local-owner'` 的行),不要的行在存储层删(本版没有它的 HTTP 自助口);要整条关掉 ⇒ `PERMISSION_RULES_ENABLED=false`。
150
+
151
+ 18. **🔴 单用户部署上不带主体的 run 要有一道身份边界:单用户 ∧ `ALLOW_UNAUTHED_WRITES=true` ∧ 没配服务凭据 ∧ 显式 `BIND_HOST` 不只在本机回环 ⇒ 服务进程起服拒(安全轴;行为 BREAKING:起服拒启面;零新旋钮)**:
152
+ 旧形:显式 `BIND_HOST=0.0.0.0`(或局域网地址 / 主机名)把无鉴权写面暴露出去照起 —— 网络上任何人都能不带主体提交 run,而单用户部署上这样的 run 就是那个用户(读本机属主的规则桶,上一条)。
153
+ 新形:起服第 1 段(排在 `operator-single-user-boundary` 之前;两条同时成立时先报本条,本条两条出路照做那一条也随之不成立)判这一形 ⇒ 非零退出,stderr 一行拒句(不变量 `single-user-anonymous-boundary`)点名监听在哪与两条出路。
154
+ 没设 `BIND_HOST` 时无鉴权写面本来就只听 127.0.0.1,照起;写面要凭据而没配凭据的部署没人能提交 run,不归本条。热路径上删光凭据的候选同判拒。`run-local` 不判;多租形不归本条。
155
+ **谁受伤**:单用户部署里显式暴露无鉴权写面的 —— 含容器里 `BIND_HOST=0.0.0.0`、宿主只把端口发布到回环(`-p 127.0.0.1:…`)的那一形(进程看不见宿主怎么发布端口)。
156
+ **升级前做**(二选一):配 `SERVICE_AUTH_TOKEN`(或 `SERVICE_AUTH_TOKENS`);或只听本机回环(删掉 `BIND_HOST`,或 `BIND_HOST=127.0.0.1`;容器端口要经 `-p` 访问时改配凭据)。
157
+
158
+ 19. **运维手动整理阀门 `POST /v1/admin/memory/consolidation/run` 的写判官读人:发起者的规则桶(不带主体 ⇒ 本机属主桶)里点名记忆库的 deny / ask 行拦得住这一轮折叠(安全轴,行为收紧;wire 零新码;部署零动作)**:
159
+ 旧形:阀门只读匿名地板 —— 人的持久行拦不住手动整理(自动整理腿一直照判)。
160
+ 新形:按发起这一轮的调用方读人的桶(并入正在跑的那一轮的调用方用起跑者的判官);拒 ⇒ 既有的 `409 memory.consolidation_refused` 与引擎通告。
161
+ 部署的调用方策略(审批名单 `APPROVAL_DENY` / `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO`、敏感路径守卫 `SENSITIVE_WRITE_PATTERNS`)仍不参与手动阀门(自动腿照判)。
162
+ **谁受伤**:有人的 deny 行点名记忆库、又靠手动阀门整理记忆的部署 —— 现在与自动整理腿同答(拒)。**出路**:删掉或收窄那条行,或接受与自动腿同样的结局。
163
+
164
+ 20. **勘误(7.114.0 节「运维面」一条;已发节不改字节):`server.session-policy.corrupt-read-fail-open` 不再是债,改 R 类(有界放行,计数长期保留);三条读路的「仍按无规则」收窄到只剩无从归属的坏行(文书 + 遥测分类;本版行为零变;部署零动作)**:
165
+ 那一条写「另三条路仍把坏规则行当作『无规则』」。7.116.0 起有归属的坏行(行里的 `__sid`,否则同名高水位标记的 `__sid`)在枚举 / 别的会话抹除 / 数据根重绑三条路上也拒(或不动 / 带走);
166
+ 只剩无从归属的坏行(行里读不出 `__sid`,标记也不在、坏了或不带 `__sid`)照旧按无规则 —— 这一形按 core 已知限制接受(无从归属 ≠ 本会话),是这一臂的终形。计数、探针行、告警不变,告警 / 看板照留。
167
+
168
+ 21. **🔴 审批证明店的持久时间地板:店钟被往回拨之后,已清扫的 plan_review 证明不再能被再受理;SQL 后端一张新表 `approval_nonce_floor`(起服自建);local 消费账多一种行(安全轴,行为修复;零 ALTER;新 warn 事件;部署零动作)**:
169
+ 旧形:消费记录按店钟到期、按店钟清扫;店钟往回拨 Δ 之后,刚清掉的证明在回拨后的钟下重新过验签,同一 nonce 可再消费一次。
170
+ 新形:店钟 = max(原始钟, 地板),地板 = 清扫用过的删除线(先落地板再删);原始钟低于地板 ⇒ 店钟答地板 + 一行 warn `approval_nonce_clock_rollback`(`rolledBackMs` / `floorMs` / `clockMs` / `store`)。
171
+ SQL 后端:新表 `approval_nonce_floor(singleton CHAR(1) PK DEFAULT 'x', floor_ms BIGINT NOT NULL)` 由起服 DDL `CREATE TABLE IF NOT EXISTS` 自建(零 ALTER、零一次性迁移;没有那一行 = 从没清扫过)。
172
+ local 后端:`<数据根>/approval-nonces/consumed.jsonl` 每次压实把一行地板 `{"f":<ms>}` 与幸存记录一起写下(老账零迁移)。
173
+ **谁受伤**:local 数据根降级到上一版 —— 上一版把地板行读成坏记录、整本消费账拒用(直连门 plan_review 5xx);多 tidb-server 部署的钟差会在清扫后表现为 warn 行。
174
+ **出路**:降级前等在途证明的 TTL(约 150 秒)过去后移开 `approval-nonces/consumed.jsonl`(上一版拒句给的同一出路);warn 行按句中出路核时间同步。DDL 账号要能建表(与起服其余表同)。
175
+
176
+ 22. **随包排空检查多一条回滚判据 `prompt-lean-rollback`(随包工具加一条;行为零变;零 DDL;部署零动作 —— 从 7.137.0 及以后回滚到 7.136.x 之前多跑这一段)**:
177
+ 7.137.0 节第 4 条说「回滚到 7.136.x:被改写过的停驻任务在 7.136.x 上续跑回到缺省形(长形丢,零通告)—— 回滚前先决完或取消停驻的任务」;本版起随包 `scripts/drain-check.{mysql,pg}.sql` 与 `scripts/drain-check-local.mjs` 有一条同名判据数出这些行:
178
+ 续跑上下文的提交体里 `promptLean` 为 `false` 的停驻行(一次性迁移改写出的、与 7.137.0 起新提交时就带 `false` 的都在;7.136.x 不认这个键,续跑时回到缺省形、不报错)。读到 0 再回滚;非 0 ⇒ 逐条决完或取消。
179
+ 还跑着 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 <数据根>`。
180
+ **谁受伤**:按行数 / 按位置读整只文件输出的脚本(SQL 多一行;local 末行多一行 `PROMPT-LEAN-ROLLBACK`,在 `RETIRED-MODE-SEED` 之前)。**出路**:按判据名读。
181
+
182
+ 23. **读续跑上下文失败答 `503 state.resume_context_unreadable`,不再落 `409 conflict.resume_context_unavailable`(行为修复;wire 多一码;零 DDL;部署零动作)**:
183
+ 旧形:库断连 / 拒连 / 超时、缺表 / 权限拒、认不出的库错发生在读续跑上下文那一读上 ⇒ 决断、续跑、唤醒、`plan_review`、workflow 决定的宿主新一跑、终态 run 的 steer、`permission-mode` 一律答 `409 conflict.resume_context_unavailable`(「上下文没了」);本服务自己的程序错同落那一码。
184
+ 新形:这些读失败 ⇒ `503 state.resume_context_unreadable`(`error` / `errorCode` 两键;这一请求没有执行:续跑入口上卡仍待决、行字节不动;终态 steer 没入队,铸卡之后复核那一读失败则撤回铸出的卡,撤回自己失败 ⇒ 运维 warn `steer_wake_card_withdraw_failed`、卡留在待决里),程序错 ⇒ `500 internal.error`;行真的不在仍是 `409 conflict.resume_context_unavailable`,坏行仍是 `500 corrupt`。
185
+ **谁受伤**:按 `409 conflict.resume_context_unavailable` 自动重提新任务的客户端(读失败那一形不再是它);错误码的穷举 `switch`(多一个成员)。**出路**:`state.resume_context_unreadable` 一臂 = 稍后原样重发同一请求(一直如此 ⇒ 报运维查库);`conflict.resume_context_unavailable` 一臂不变。
186
+
187
+ 24. **起服前的模型面读数:新入口 `dist/model-plane-probe.js`(子路径 `@sema-agent/server/model-plane-probe`)在引擎起来之前答 `GET /v1/models` 的 `modelPlane` 同一格,stdout 一行(新入口,加性;部署零动作)**:
188
+ env 与工作目录 = 将要起的那只引擎的;跑起服前两段到模型表定形即停,不开店、不监听;日志在 stderr。退出码 `0` = 答案在 stdout,非 `0` = 起服会在这两段拒(stderr 是同一条 `fatal` 行)。
189
+ 同一份配置下与起服第 2 段末的那一格字节同;起服拉取超过 `CONFIG_BOOT_FETCH_BUDGET_MS`(或预算写 0)时答的是那次拉取落地之前的回落读数(stderr 有 `config_boot_fetch_deferred`),探针不等迟到的那一份。
190
+ 动作与起服前两段相同(配置根上的一次性迁移、`SEMA_CONFIG_DIR` 不在就建、封签钥匙保管店与提示词店的目录;远端配置源另有中心拉取、LKG 落盘、执行公钥上报、文件形凭证的续签 —— 已发出的续签落盘之后才退)
191
+ ⇒ 在本会起服的地方调;引擎已在服就读它的 `GET /v1/models`。
192
+ 订正 7.133.0 节「没有起服前的预判口」一句(已发节不改字节,本条即订正)。
193
+
194
+ 25. **运维审批队列上后台委派子代的停驻行 `taskId` = 子代自己的 `a…` 句柄(此前恒 `null`)(行为修复;wire 零新键;零 DDL;部署零动作)**:
195
+ 旧形:停驻行的 `taskId` 只读行的会话上的 run 认领;后台委派子代的会话不进 run 账本 ⇒ 它的停驻行 `taskId` 恒 `null`(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)。
196
+ 新形:`taskId` = 停在这道门上的那条腿以哪个 task 在跑 —— 引擎在停驻行上记下的登记行(后台子代的 `a…` 句柄,与 `/decide` 复活它的回执 `taskId`、placed 子代的 `agent.id` 同一个串)⇒ 否则会话认领的 run(与旧形同)⇒ 否则 `null`。
197
+ 引擎 7.61.0 起停驻的后台子代行升级后即带(零迁移);订阅流在升级后那一拍对这些行各补一帧 `pending`(投影变了;按键覆盖即可)。
198
+ **谁受伤**:拿「`taskId === null`」判子代行的消费者;拿行上 `taskId` 拼 `/v1/runs/:id` 的消费者(后台子代行上答 404 —— 它是代理句柄,不是 run 资源 id)。
199
+ **出路**:判子代与发起会话读 `agent`;子代本身按句柄寻址(`TaskStop` / `SendMessage` 用的同一个串),宿主 run 按 `agent.rootSessionId` / `parentSessionId` 的会话找。
200
+
201
+ 26. **勘误(7.139.0 节第 23 条 ④;已发节不改字节):host 车道上名字逼近 255 字节上限的文件写得进,那条「已知缺口」不再成立(文书;本版行为零变;部署零动作)**:
202
+ 那一条写「名字超过约 230 字节的文件写不进(引擎的暂存名超出 255 字节上限 ⇒ `unknown` / `ENAMETOOLONG`)」。引擎 7.61.0 起暂存名逼近上限时截短到上限之内,本服务 7.143.0 起所钉的引擎都含这一修(7.139.0 – 7.142.x 有这一缺口),
203
+ host 车道的整文件替换(新建与覆盖)对 255 字节以内的名字照常写成,与远端五车道同。按那一条绕开长文件名的做法可以撤掉。
204
+
205
+ 27. **领养 `POST /v1/adoption` 在没有可选存储面的部署上走完(此前裸 500),回执 `legs[]` 只列真跑的腿;接线了的面缺表答新码 `409 adoption.table_missing`(行为修复;wire:多一码、这类部署的 `legs[]` 少七条腿;零 DDL;部署零动作)**:
206
+ 旧形:缺省 file 记忆引擎、没配对象存储的 SQL 部署上 `POST /v1/adoption` 答 `500 internal.error`(`agent_memory_engine_*` 六张表与 `task_attachment` 在这类部署上不存在,收编的探针 / 迁移腿 / 残留计数逐腿发 SQL 打在它们上);回执 `legs[]` 恒是计划表全集(那七条腿也在)。
207
+ 新形:腿集由库上在场的表定 —— 核心腿恒跑,这七张可选表的腿其表在库上才跑,回执 `legs[]`(`agent_memory_engine_{entry,cursor,sync_cursor,sync_partition,push_queue,history}#scope`、`task_attachment#owner`)只列真跑的;
208
+ **没接线但表在**(曾配过对象存储后撤掉配置)腿照跑;**接线了(记忆引擎 DB 后端 / 附件店构造过)而库上缺表** ⇒ `409 adoption.table_missing`,体 `{ adoptionId, tables[] }` 点名缺的表,弧不落终态(零 UPDATE),重启一个副本建好缺的表后重发同一请求即续。
209
+ **谁受伤**:按腿名逐条对账收编回执的下游围栏(缺省 file 记忆引擎 / 没配对象存储的部署上 `legs[]` 少七条 —— 那七条在这类部署上从未跑成过);`adoption` 错误码的穷举 `switch`(多了一个成员)。**出路**:按「真跑的腿」对账(`legs[]` 里有的腿逐条核,不要求七条可选腿在场);错误码穷举补 `adoption.table_missing` 一臂(重试语义:修表后重发同一请求);有记忆 DB 后端 / 对象存储的部署回执与上一版逐字同,无动作。
210
+
211
+ 28. **`POST /v1/approvals/:id/decide` 对载入的停驻行先问一次行形判官,坏行一律答这一行自己的带码拒:缺 `pendingAction` 的行不再 `500 internal.error`,坏行也不再先答 `approval_stale` / `400 decide_requires_binding` / `conflict.resume_context_unavailable`;`request_error` 运维行多一格 `at`(栈顶帧)(行为修复;wire 零新码;日志面加一格;部署零动作)**:
212
+ 旧形:判官只在门型守卫里对「非工具审批门」的行问;工具审批门上的坏行越过它 —— 缺 `pendingAction` ⇒ 读 `cp.pendingAction.kind` 抛 ⇒ `500 internal.error`;判官判坏的其它形(缺 `state` 等)按调用方交了什么先答 `409 approval_stale`(旧 `boundCallId`)/
213
+ `400 decide_requires_binding`(没回显绑定)/ `409 conflict.resume_context_unavailable`(续跑上下文缺),续跑第一级才被引擎拒。
214
+ 新形:行级属主复核之后、门型守卫 / 绑定判 / stale 臂 / 续跑上下文之前问一次判官(与运维队列行 `rowVerdict` 同一只);判非 `ok` ⇒ 答判官的判决:`409` + `errorCode: "checkpoint.invalid_outcome"` + `reason: "requirements_damaged"`(更新引擎停驻的行 ⇒ `checkpoint.unsupported_version`,同续跑腿),
215
+ `retriable: true`,卡仍 pending。工具审批行的拒句是判官的固定句,不再带引擎续跑第一级附的 `Diagnostic:` 尾。`request_error` 运维行多一格 `at`(`<src | dist | node_modules 起的尾段路径>:<行>`,抛出物栈顶第一条读得出位置的帧;读不出则无此键)。
216
+ **谁受伤**:按「坏行决断先答 `approval_stale` / `400`」写分支的壳(这些坏卡此前得到的是会把壳带去重拉坐标的答案,重拉不会让坏行变好);按「决断口 500 = 存储故障」重试的壳(缺 `pendingAction` 的行此前就是不会好的 500)。
217
+ **出路**:读 `errorCode` / `reason`,按 `GET /v1/approvals` 里同一行的 `rowVerdict` 定位这张卡;`request_error` 行的 `at` 是出处。
218
+ 29. **🔴 live 应答口 `POST /v1/tool-approvals/:id/respond` 与按问读口 `GET /v1/tool-approvals/:id`:看不见这只问(查无 / 不是你的 / 行读不出 / 本 worker 没有问账)⇒ `404 not_found.ask`(与耐久决断口同码),不再答 `tool_approval.not_pending`(wire BREAKING;部署零动作;消费方有动作)**:
219
+ 旧形:这几形答 `404 tool_approval.not_pending`,有问账时带 `cause: "unknown_or_other_replica"`,没有问账的 worker 上不带 `cause`(包括窗到期 / 已答 / 转耐久停驻之后再答同一张卡)。
220
+ 新形:`404` `{ errorCode: "not_found.ask", error: "no such approval ask (never existed, no longer kept, or not yours)" }`,不带任何状态位。`tool_approval.not_pending` 只对属主出:
221
+ 行 `VOID` / `DENIED`(`cause` = 行上的成因词)、行仍待决而本副本没有在等它的登记(`cause: "unknown_or_other_replica"`)、坏行 / 赎回席缺席(无 `cause`),这些形逐字不变。耐久决断口零变。
222
+ **谁受伤**:只认 `tool_approval.not_pending` 才消卡的壳 / SDK 映射;断言非属主拿 `unknown_or_other_replica` 的契约套。**出路**:live 应答口与按问读口上 `not_found.ask` 同样消卡(与耐久决断口同处置);
223
+ 没有问账的 worker 上按 `404` 改走 `/v1/approvals` 读面 + `/decide` 的出路不变。
224
+
225
+ 30. **委派 / 后台子代那条腿的停车行已提交时,它的问收成 `PARKED`,不再在宿主 run 终局时收成 `DENIED` / `routing_failure_fail_closed`(local 起服收敛不再收 `VOID`)(行为修复;wire 零新键、零新码;零 DDL;部署零动作;嵌入方店接口一处改名 BREAKING)**:
226
+ 旧形:子代卡转耐久停驻后,收敛器按问行上的投递会话(根会话)找停车行,而子代的停车行落在子代自己的会话上 ⇒ 找不到;宿主 run 终局时问被收成 `DENIED`,按问读口读 `void` + `cause: "routing_failure_fail_closed"`,决断口 `410 gone.ask`,live 应答口 `404 tool_approval.not_pending`。
227
+ 新形:按问的发起会话找(与停车行同一个会话)⇒ 问 `PARKED`:按问读口读 `parked`,决断口 `410 gone.ask_parked`,live 应答口照答即走停驻赎回。根腿的卡零变。
228
+ 「去哪决它」三处同读停车行自己的会话(= 问的发起会话):决断口 `410 gone.ask_parked` 回显的 `sessionId`、按问读口 `parked` 与迟到回决口 `202` 的 `decidePath` 对子代卡都指子代会话的耐久回决口(此前 410 回显根会话;
229
+ 更正 7.122.0 节第 5 条「`decidePath` 对委派子代腿缺席、句子指父会话」—— 现在只有发起会话是 taskId 替身的问缺席、句子照旧);根腿零变。照 410 回显 / `decidePath` 去 `/decide` 即决得到那张卡。
230
+ **谁受伤**:把子代卡的 `routing_failure_fail_closed` 当作「这张卡没地方答了」消卡的壳。**出路**:按停驻卡处置(`parked` 态 / `gone.ask_parked`),经耐久审批门决。
231
+ **嵌入方(类型面 BREAKING)**:经包根导出型 `StoreBackend` 的 `approvalAsk()` 可达的问答账本店,停车行提交那一拍的找行读口 `listParkingBySession(sessionId)` 改名
232
+ **`listParkingBySourceSession(sourceSessionId)`**,按行的**发起会话**(`sourceSessionId`,SQL 列 `source_task_id`)筛仍 `PARKING` 的行(此前按投递会话 `sessionId` 筛);tsc 红即是提示,零别名。
233
+ **升级时做**:自实现该店的嵌入方改名并把谓词换成发起会话(序仍 `created_at_ms ASC, ask_id ASC`);本服务自带三店(SQL 两方言、local、内存)已是这个读法,用它们的部署零动作。
234
+
235
+ 31. **`/decide` 赎回的后台子代按停驻时的代理定义续上:内建 / 部署定义的子代(Explore / Plan …)工具面与停驻前相同,不再按 general-purpose 形复活;逐请求 `agents` 定义的子代赎回 fail-closed —— `409 decide.agent_definition_unavailable`、不复活、卡仍待决(安全轴,行为修复 + 新拒;wire 加性:新码;部署零动作)**:
236
+ 此前每一只带定义的子代被批准之后都拿回定义拒掉的工具(Explore 拿回 `Agent`);逐请求 `agents` 定义的子代同样按通用形续上。现在在册的(内建 / 部署)定义照定义赎回;
237
+ 名册外的(逐请求定义 —— 不随耐久卡保存;停驻之后部署撤了的定义;名叫 `fork` 的定义)approve 与 deny 都答 409,委派工具零调用、认领回滚、卡留待决(体带 `taskId` + `rollback`:`rolled_back` = 卡仍待决)。
238
+ **谁受伤**:依赖「批准之后子代变通用」的用法;用请求里的 `agents` 定义派后台子代、又靠 `/decide` 批准它复活的调用方。
239
+ **出路**:要通用子代就派 general-purpose;要「批准后按定义续」就用内建 / 部署定义派;已停驻的逐请求定义子代,它的卡随过期收场,或 `POST /v1/sessions/:id/children/retire` 结清会话的后台子代(停驻卡作废);
240
+ 逐请求定义的子代按定义赎回,待存下的任务注册重铸逐请求定义表(引擎侧的契约)到货。**升级前做**:无。**回滚**:无(没有委派调用、没有子代被复活;认领已回滚,卡仍待决)。
241
+
242
+ 32. **`GET /v1/agents/roster` 缺省读调用方自己那一格(与引擎写后台行同一只读法):dev-open 上带主体头 ⇒ 那位主体的行;带场景头的主体 ⇒ 人那一格的行(行为修复;wire 形不变;部署零动作)**:
243
+ 此前 dev-open 上带主体头的名册缺省读 `default`,带场景头的主体按带场景前缀的分区键读,两形都答 `agents: []`。**谁受伤**:dev-open 上带主体头、靠缺省看 `default` 那一格的脚本。
244
+ **出路**:带 `?scope=default`(fleet-wide 调用方照旧可指定任何格)。
245
+
246
+ 33. **委派子代改的文件进根会话的 rewind 历史:子代的首次触碰与父会话同一条「记不下就拒」规则(行为修复;部署零动作)**:
247
+ 此前子代跑的那只 Runner 没有历史店,子代的编辑不记,父会话 rewind 撤不回它们;现在记。**谁受伤**:历史店写失败的部署 —— 子代那次编辑被拒(此前照做不记)。
248
+ **出路**:修好历史店;或 `FILE_HISTORY_CAPTURE=false` 关掉首次触碰捕获(已存历史照常还原)/ 请求带 `fileHistory: "disabled"`。
249
+
250
+ 34. **🔴 「持久」一个读数:能力位 `store.durable` 删、换三态 `store.durability`;`/health.durable` 删、`/health.store.durability` 加;`/health.sessionBackend` 只写后端种类;引擎声明会话店持久而会话店落在易失介质上 ⇒ 起服拒 `config.store_not_durable`(wire BREAKING;起服拒启面;local 店落在容器可写层 / emptyDir 上的部署有升级动作;消费方有动作)**:
251
+ 旧形:`GET /v1/capabilities.store.durable: boolean`(= 后端不是 memory,local 店不论落在什么文件系统上恒 `true`);`/health.sessionBackend` = `durable(pg)` / `durable(mysql)` / `durable(local)` / `memory`;降级时 `/health` 带 `durable: false` + `storeDegraded: true`;起服布线审计按后端种类认 local 为持久介质,恒过。
252
+ 新形:`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、不拒。
253
+ **谁受伤**:按 `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`。
254
+ 35. **local 排空脚本 `scripts/drain-check-local.mjs` 的账本读法换成引擎包根的 `readCheckpointLedger`:账本里有 `delete` 事件的 `DB_BACKEND=local` 数据根不再 rc 2「无结论」;每条判据末行的 `unknownEvents` 键退役(随包脚本的读数面变更;部署零动作)**:
255
+ 旧形:脚本自抄六个事件词并自己折叠账本;引擎自 7.56.0 起写 `delete` 事件(引擎删某个会话的检查点行时写),脚本把它记成 `unknownEvents` ⇒ rc 2、九行末行都是 `unknownEvents=1`、不给结论 —— 账本里带 `delete` 事件的 local 数据根读不出结论。
256
+ 新形:账本经引擎包根的 `readCheckpointLedger` 读(引擎自己的折叠 + 快照换新时的有界重读),`delete` 事件折掉对应的行,有结论(rc 0 / 1)。读期间服务在追加账本不再逼出 rc 2:读口只比快照的身份(压实才换快照),账本只追加,读到的是读那一刻的一致前缀(旧脚本连账本的身份也比);rc 0 / 1 仍只是那一刻的视图,换钉 / 回滚前先停写、排空。末行少一个键:`… total=<n> unknownEvents=<n> corrupt=<n> root=…` 变 `… total=<n> corrupt=<n> root=…`;
257
+ 账本里有引擎不认的事件词(新版 worker 写下的,或引擎已退役的词)⇒ rc 2,九行末行是 `rows=- pending=- total=- corrupt=- reason=ledger-event-unknown`,stderr 一句列出「引擎认得的词」;崩在半行的尾行(无换行结尾)与店的重放同判,不再计 `corrupt`。
258
+ **谁受伤**:按键解析末行、读了 `unknownEvents=` 的运维脚本(键没了;`rows=` / `pending=` / `total=` / `corrupt=` / `root=` / `reason=` 不变)。**出路**:删掉对 `unknownEvents` 的读取;不认的事件词改读 `reason=ledger-event-unknown`。
259
+ **升级前做**:无。**回滚**:无(只读脚本,不改数据根)。
260
+
261
+ 36. **治理命令规则的命令名在配置应用期由契约包判:超过 128 字符的 `commandPolicy[].command` 被拒(`web_admin_commandpolicy_invalid`,保留上一份规则)(行为收紧;部署零动作)**:
262
+ 中心发布与本地 `config.d` 两条读腿本来就按契约判这一格;只有绕过读腿的输入(手改的盘上 LKG、直塞的配置)此前能带进超长名(那条规则照样生效)。**出路**:命令名写在契约的 128 字符以内;被拒时上一份规则保留。
263
+
264
+ 37. **记忆整理席所用条目的凭据身份随座冻结:重贴 `sealedApiKey` / 换 `apiKeyEnv` 变量名之后要重启才进座,`/health` 报 `restartRequired`(`memory-consolidation`)(安全轴;行为变更;部署零动作)**:
265
+ 此前整理席的模型在启动时定,凭据却跟着热应用 —— 同名条目把端点与凭据一起换掉时,重启前整理请求带新凭据打旧端点。现在两者同一代:重启前打旧端点、带旧凭据;
266
+ 凭据身份变了与端点变了一样签重启。**谁受伤**:靠重贴托管密钥即刻轮换整理条目 key 的运维。**出路**:按 `restartRequired` 重启;或改用 `apiKeyEnv` 引用做同名轮换(值热、不用重启)。
267
+
268
+ 38. **默认路径上 7.98.0 及以前的 LKG 旧文件(`config-lkg-<worker>.json`,formatVersion 1):本身份的箱缺席时起服一行 `config_lkg_unusable` 点名它(日志面加一行;读回结局不变;部署零动作)**:
269
+ 此前这只旧文件不被读、也零日志(只有 `CONFIG_LKG_PATH` 指到旧文件时才有这一行)。现在两形同一行、同一句 `reason`(`pre-identity LKG (formatVersion 1) — not read back: …`),
270
+ `path` 是那只旧文件,`note` 写出路。**谁受伤**:按「这一行只在覆写时出现」写的告警规则 —— 按 `path` 区分。**出路**:删掉那只旧文件(缓存,不是数据);中心可达时第一份干净候选写出本身份的箱。
271
+
272
+ 39. **审批登记的属主跟行走:收编(`POST /v1/adoption`)之后本副本的活卡按新属主列(`livePending` / `live_pending`),店抖动那一支不再按前属主放行(行为修复;安全轴收紧;wire 零新键;部署零动作)**:
273
+ 旧形:收编改写问行属主之后,本副本上有引擎腿在等的活卡在列表面仍只给前属主列;决议写与确认读都因店抖动失败时,按前属主的决定放行一次。
274
+ 新形:有行的问,登记上那一位是行上属主的读缓存:每读到仍待决的行就对齐,收编落成回执之前本副本全部重读一遍。别的副本在它下一次读到这一行之前仍按旧属主列。
275
+ **谁受伤**:收编之后还按旧账号看审批列表的前属主(店正常时本来就答不了)。**出路**:用新账号看与答;卡在别的副本上时按问读一次即跟上。
276
+
277
+ 40. **live 应答口的决议写失败之后,确认读与 CAS 同答:读不回行 ⇒ `500 internal.error`(与耐久决断口对店不可用同答),不再按本副本登记上的属主放行;读得出「没有这一行」⇒ `404`;读到别处已落的终局 ⇒ 按行答(安全轴,fail-closed;行为变更;wire 零新键、零新码;部署零动作)**:
278
+ 旧形:决议 CAS 抛错且确认读也读不出时,活卡按本副本登记上记下的属主答 `200`、把这一答交给在等的 run(收编在别的副本落定时那一位是前属主);接管登记同一形答 `404`。
279
+ 确认读读到别处已落的终局(反向决议 / 作废 / 停驻)或读得出行不在时,活卡同样答 `200` 并按这次的决定结算在等的 run。
280
+ 新形:确认读读不出 ⇒ `500 internal.error`,这一次请求不按自己的决定结算卡(那次写可能已落 ⇒ 随后按行收、重答回放首决;属主门那一读就读不出 ⇒ 照旧 `404`);读得出没有这一行 ⇒ `404`;读到别处已落的终局 ⇒ 按行答(已决 ⇒ `200` 回放首决、run 按行上的决议结算)。
281
+ CAS 抛而确认读读到仍待决的行(属主在域)时照旧交给在等的 run。
282
+ **谁受伤**:店整个不可用期间答卡的人(上一版 `200`、run 续上)。**出路**:店恢复后原样重答 —— 落了 ⇒ 回放首决;没落 ⇒ 这一次写成。按 `404` 消卡的壳对 `500` 不要消卡。
283
+
284
+ 41. **审批队列读失败:本服务自己的程序错答 `500 internal.error`(订阅流发 `internal.error` 帧后收流),不再落可重试的 `503 approvals.read_unavailable`(行为修复;wire 零新码;部署零动作)**:
285
+ 旧形:读审批队列的四个面把程序错(代码缺陷 / 读腿漂移)与店此刻读不出同答 `503 approvals.read_unavailable`;订阅流发可重试帧、流不收、每拍重读。
286
+ 新形:程序错 ⇒ `500 internal.error` + 运维行 `request_error`;流面一帧 `internal.error` 后收流。坏行 `500 approvals.read_corrupt`、店此刻读不出 `503 approvals.read_unavailable` 照旧。
287
+ **谁受伤**:靠 `503` 自动重试等程序错「自己好」的客户端。**出路**:`503 approvals.read_unavailable` 照旧重试;`500 internal.error` 不重试、报运维(看 `request_error`)。
288
+
289
+ 42. **停驻卡的门被引擎重开之后,live 应答口按原决议再答即续跑(受理回执的键带门世代;行为修复;wire 零新键、零新码;部署零动作)**:
290
+ 旧形:同一副本上受理过的停驻卡被重开之后 1 小时内再答,`POST /v1/tool-approvals/:id/respond` 回放首次受理(`idempotent:true`)、不续跑,出路只有 `decidePath`。
291
+ 新形:门站开在比受理所决更新的一代 ⇒ 照常进赎回腿、真续跑;门还站在受理的那一代 / 已不在待决 / 此刻读不出 ⇒ 照旧回放。
292
+ **谁受伤**:无(那一形此前不续跑)。**出路**:按原决议在原卡上再答即可;`decidePath` 照旧可用。
293
+
294
+ 43. **SLA 拒扫按页轮转走全部到期审批(每拍从上一拍取到的最后一行之后取一页,一页取不满回到队首);取行序回到「到期时刻、行键」两键,「卡列为空的排后」那一键退役(行为修复;SQL 店与 local 文件后端同律;零 wire 变化;零 DDL;部署零动作)**:
295
+ 旧形:每拍只取到期最早的 100 张;拒扫拿它没办法、留在停驻且到期时刻不变的行(引擎认领前拒、停驻子代、本版不重放的存量体)积满 100 张,后面的到期审批就一直不被拒扫,等终局兜底(缺省 30 天)收割。SQL 店另把卡列为空的行排在后面。
296
+ 新形:拒扫在过期集上记一个进程内的位置,每拍从它之后取一页,一页取不满回到队首;一圈 ⌊N/100⌋ + 1 拍,每张到期审批每圈被试一次;一行的存体读法抛出只让这一行这一拍不续(`deny_sweep_row_failed`)。重启从队首起;位置不落盘、不上 wire。
297
+ **谁受伤**:到期审批多于 100 张时,原本每拍都会被试到的最早那一批要等轮到它那一页;按「卡词已知的行先取」排查拒扫顺序的运维。**出路**:缩短 `REAP_INTERVAL_SEC` 即缩短一圈的墙钟时长;拒不掉的行照旧由 `APPROVAL_TERMINAL_BACKSTOP_MS` 兜底收。
298
+
299
+ 44. **勘误(7.136.0 节第 6 条「起服之后桶才没的」一句):拒的是这条 run 的沙箱,不是 run 本身(文书;行为零变;部署零动作)**:
300
+ 读 `latest` 得 `404 NoSuchBucket` ⇒ 一行 `workspace_snapshot_bucket_missing`、一只 pod 不建、这只执行环境此后每次连接都答同一个 `connect_failed`(句子带 `snapshot_bucket_missing` 与出路);
301
+ 要动工作区的工具调用逐个以它失败,run 的终态照常由引擎定(模型收尾 ⇒ `completed`)。那一条写的「该 run 以 `connect_failed` 拒」应读作「该 run 的沙箱以 `connect_failed` 拒」。
302
+ 7.140.0 之前工具结果是「任务根目录不在了」那句(文件面把拒报成未知);7.140.0 起是带 `snapshot_bucket_missing` 的拒句。
303
+
304
+ 45. **勘误(7.136.0 节漏写一条:入站 MCP elicitation 没人应答的释放词由 `decline` 改 `cancel`;已发节不改字节,本条即订正;wire 词改,零新键、零新码;按 action 分两支的已 opt-in MCP server 升级时改一处)**:
305
+ 旧形(7.135.x 及以前):入站 elicitation 的答题窗(`MCP_ELICITATION_TTL_MS`)到期、与开帧没送达(表单没到任何人面前)时,回给 MCP server 的结果与 `elicitation_complete.action` 的词都是 `decline`。
306
+ 新形(自 7.136.0 起):这两种「没人应答」的释放都回 `cancel`(run 中止、腿退出时仍挂着的原本就是 `cancel`);本服务自己放出的 `decline` 只留给有判据的拒 —— 没有 run 上下文、url 形、节流越界(并发帽 / 总量帽 / 同一 server 的最小间隔);用户经应答口答的词原样落地(含 `decline`)。
307
+ 词表仍是 MCP 的 `accept` / `decline` / `cancel` 三词,帧形不变;词律是 `src/elicitation.ts` 里 `RELEASE_ACTION` 一张表,回给 MCP server 的与 `elicitation_complete.action` 是同一个词。
308
+ **谁受伤**:开了入站 elicitation(`MCP_ELICITATION_ENABLED=true` 且该 MCP server 自己 opt-in `elicitation: true`)、并把 `decline` 与 `cancel` 走两支的 MCP server —— 答题窗到期与表单没送达现在落到它的 `cancel` 支,不再是 `decline` 支(此前被读成「用户明确拒绝」);
309
+ 按 `elicitation_complete.action` 渲染终局的壳,到期那一帧的词随之由 `decline` 变 `cancel`。没开入站 elicitation 的部署(缺省)零影响。
310
+ **升级前做**:按 action 分两支的 MCP server 把到期分支改读 `cancel`;不分两支的(任何非 `accept` 都当没授予、且不把到期缓存成会话级拒绝)两个词读法没有差别,零动作。窗长仍由 `MCP_ELICITATION_TTL_MS` 调,没有词义开关。
311
+
312
+ 46. **补记(7.147.0 节漏写一条:7.147.0 起写下的会话行在 ≤7.146.x 版本上续跑不保证;文书;行为零变;部署零动作 —— 回退的部署先读专条)**:
313
+ USAGE 的「已知限制」里有专条「混版回退」:把部署回退到 ≤7.146.x 再续跑 7.147.0 起写下的会话(SQL 后端的 `session_ext` 旁表与精简后的 `session_meta`,local 数据根的引擎版本高水位 marker),一次续跑可能照常跑到终答,也可能被拒,两种都不保证。
314
+ 出路:回退前先排空(让待续跑的停驻 run 先收完;随包的排空检查 `scripts/drain-check-local.mjs` / `scripts/drain-check.mysql.sql` / `scripts/drain-check.pg.sql` 只读),或不跨版回退;唯一支持形仍是恢复升级前的数据根 / 库备份。已发的 7.147.0 节不改字节,本条即补记。
315
+
316
+ 47. **补记(7.147.0 节漏写一条:请求体 `mcpServers[i].transport.headers` / `.env` 里成员名 `constructor` / `prototype` 起拒;已发节不改字节,本条即订正;行为收紧;wire 零新键、零新码)**:
317
+ 旧形(7.146.x):这两处记录里只有名叫 `__proto__` 的成员被拒;名叫 `constructor` / `prototype` 的成员照收(200)。
318
+ 新形(自 7.147.0 起,契约包的保留成员名只有一张表):`__proto__` / `constructor` / `prototype` 三个名字同拒,同一个 `400 request.field_invalid`,`field` 点名成员级路径(如 `mcpServers[0].transport.headers.constructor`),不回显值;名字大小写敏感(`Constructor`、`X-Prototype` 照收)。
319
+ 范围如实:`a2aPeers[i].headers` 这一座**没有**收进这张表,仍只拒 `__proto__`(本服务自己的 A2A 头读法只认这一个名字),`constructor` / `prototype` 作 A2A 头名照收。存盘的续跑体里带这样 MCP 成员的条目,续跑时同样读不出 ⇒ 按「请求成员读不出」那一只判据拒续跑(`409 resume_blocked_by_policy`,`blockedBy` = `request.field_invalid`)。
320
+ **谁受伤**:把 `constructor` / `prototype` 当 MCP 头名或环境变量名写进请求体的调用方(极罕见)。**出路**:改名。
321
+
322
+ 48. **sema-up 三条交付路径同形挂钥匙卷:cluster 静态清单(`cluster-up.sh` 缺省 `STACK_ENGINE=render`)与单机 compose 的 server 也把钥匙保管目录挂成持久卷,三条路径都显式设 `SEALED_KEY_DIR=/root/.ai-agent/sealed-key`(部署形变更;零 DDL;部署有动作)**:
323
+ 静态清单新增 PVC `sema-server-sealed-key`(与图表同名;`ReadWriteMany`、存储类 `longhorn`、64Mi);compose 新增具名卷 `<项目>_sealedkey`(`--data-root` 时 bind 到 `<数据根>/sealedkey`,sema-up 落定时建目录)。
324
+ 图表持久开时两只 worker 多一条 `SEALED_KEY_DIR`(值 = 原挂载位,存量 PVC 里的钥匙原位可读)。`kube-up.sh` 的 `STORAGE_CLASS` 同样用于钥匙卷(此前它走集群缺省类)。
325
+ **动作(静态清单路径)**:重跑 `cluster-up.sh` **之前**给每个节点装 NFS 客户端(Debian / Ubuntu `nfs-common`,RHEL 系 `nfs-utils`)—— Longhorn 的 RWX 卷由它挂载;缺了 ⇒ server 新 Pod 挂不上卷、
326
+ 第 7 步等不到就绪而失败(旧 Pod 照常服务)。空卷上多副本并发首启只出一把钥匙(本版的首把钥匙创建口;NFS 的独占创建按协议原子),升级后不必重启。
327
+ **动作(compose)**:无;下次 `sema-up.sh` 重跑建卷。`--teardown-volumes` 起连钥匙卷对象一起删:docker 管的卷钥匙随之没了(之前停驻的任务续跑 409 `key_not_held`,web-admin 贴的 `sealedApiKey` 要对着新公钥重封);
328
+ `--data-root` 时卷是 bind,盘上 `<数据根>/sealedkey` 留着,落回同一条数据根重装即读回原钥匙。
329
+ **动作(kube-up 显式 `STORAGE_CLASS` 的存量部署)**:无;钥匙卷已在时 kube-up 沿用它建好时的存储类(PVC 的存储类建好后不可改,7.134.0–7.147.x 建的钥匙卷走的是集群缺省类),`STORAGE_CLASS` 只用于新建的钥匙卷。
330
+ **谁受伤**:升级之前停驻、带请求凭据的任务照旧续不了 —— 那时的钥匙从没持久过,本版之后的停驻行才跨得过重启。节点装不了 NFS 客户端的集群改走图表路径(`STACK_ENGINE=helm`,可单副本 / RWO / 关持久)。
331
+
332
+ 49. **🔴 能力位 `sessionReadRedaction` 的值由 `true` 改成历史读面过脱敏的叶名表 `string[]`(`<形>.<键>`,今天十一员;键名不变,布尔形整删)(wire BREAKING;部署零动作;消费方有动作)**:
333
+ 旧形:`sessionReadRedaction: true`(7.120.0 起恒真;7.120.0–7.122.x 报真而 `assistant` 的 `errorMessage` / `diagnostics` / `repetition` 叶仍是存档原形)。
334
+ 新形:`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` 行。
335
+ **谁受伤**:按布尔读本位的壳(`=== 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 起才脱)。
336
+
337
+ 50. **配置拉取失败行多一个闭集键 `cause`:起服 `config_source_unreachable_using_env`、刷新拍与迟到起服 `web_admin_refresh_failed`、迟到起服重拉 `config_boot_arrival_repull_failed`、run-local 同名行;门控域读拒 / 本地目录不被信任 = `rejected`(日志面加性;事件名不变;部署零动作)**:
338
+ 旧形:中心连不上、中心发了门控域判形失败的配置(或载荷不是有效视图),起服都记 `config_source_unreachable_using_env { source, err }`;刷新拍上这两形与本地配置目录不被信任都记 `web_admin_refresh_failed { err }`,分不出因(起服遇目录不被信任一向是拒启,不变)。
339
+ 新形:四行带 `cause` —— `unreachable`(没拿到候选:传输 / HTTP 非 2xx / 凭证 / 重定向 / 超时 / 本地腿读目录撞文件系统错)、`rejected`(配置源答了,本引擎拒收:读腿整包抛或本地目录不被信任)、`superseded`(应答属于在飞期间被换掉的中心凭证);刷新失败行另有 `apply_refused`(拉取已成、应用段抛)。拉取失败三行另带一句 `note`。`err` 逐字不变。
340
+ **谁受伤**:按 `config_source_unreachable_using_env` 一律认「中心连不上」的告警(读拒此前也在里面,本版不更糟);按整行字段集比对的解析器。**出路**:按 `cause` 分流;`rejected` 的 `err` 带读腿那一句与字段路径(不单列域名)。
341
+
342
+ 51. **run-local 执行本地目录的 `models.atMention`:objective 内联 `@name` 点了名单外的模型 ⇒ exit 2、零模型请求,拒句与 HTTP 400 `request.model_not_allowed` 同一句;`@<档位词>` 按本地目录的档位绑定解析(行为变更;wire 零变化;部署零动作)**:
343
+ 旧形:run-local 判 `@name` 取契约缺省 `{mode:"all"}`,本地目录里的 `atMention` 在这条腿上不生效;解析用的目录不含档位词 / CC 别名,`@pro` 落缺省模型。
344
+ 新形:run-local 与 HTTP 提交腿调同一只入口(同一张可选目录、本代 `atMention`)。名单外 ⇒ stderr `cannot run: @-mention "<名>" is not @-mentionable on this deployment (it resolves to catalog model "<目录名>") — …`,退出码 2。
345
+ **谁受伤**:靠 run-local 点名单外模型的脚本。**出路**:把那只模型写进 `config.d/models.json` 的 `atMention.models`(或改 `{mode:"all"}`),或不带 `@name`。
346
+ 52. **补登(引擎 7.61.0 起,7.143.0 已到货):停驻行可带挂起行 `heldRows` 与要求词 `held_rows` —— 7.142.x 及更早的副本不认这个词,对带它的行在认领前拒、行留 pending(7.142.x 答 `checkpoint.unsupported_version`、`reason: "version_newer"`)(文字补全;零行为变化;零 DDL;部署零动作)**:
347
+ 事实:停驻那一刻端口里若有挂起的会话行(扩展在一轮进行中经 `$.session.append` 记下、还没写进会话的行),引擎把它们按序带进这一行(`heldRows`),并给行的要求表加 `held_rows`;续跑腿在恢复的会话里把它们写一次。没有挂起行的停驻行不带这一员、不带这个词 —— 7.143.0 之前停驻的行形不变。
348
+ 存法:SQL 后端把整只检查点存在 `checkpoint` JSON 列,这一员随整行落列、随整行读回(零 DDL、零回填);`DB_BACKEND=local` 整只文档存回。收件箱 / 调度视图 / 运维队列的行不投这一员。
349
+ 混跑窗:7.142.x 的副本(引擎 7.60.x)读到带 `held_rows` 的行,认领前拒(`checkpoint.unsupported_version`,`version_newer`),行留 pending、不认领,落到 7.143.0 及以后的副本上可再决;更早的副本同样拒认领、行留 pending,拒码按它那一版自己的读法(读不懂带要求表的行形的老副本答的是它那一版的不可读码,不是这一个)。
350
+ **升级前做**:多副本滚动升级时先把会续跑 / 决卡的副本都升到 7.143.0 及以后,再放新的停驻。**回滚到 7.142.x 及更早**:先把带挂起行的停驻决完或取消,否则它们在旧副本上一直 pending。
351
+
352
+ 53. **目录条目只有一种读法:绕过读腿的条目(盘上被手改的 LKG、手写 effective)与两条读腿交来的条目同读,schema 补的缺省(`api` / `tier` / `provider` / `quotaWeight`)随之进 Model(行为修复;只有绕过读腿的输入可感;wire 零新键;部署零动作)**:
353
+ 旧形:两条读腿(中心 `/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 } }`)选不中 ⇒ 模型面整组拒、上一代继续。
354
+ 新形:判与铸读同一份 schema 读数:缺 `api` 的 gateway 条目按 `openai-completions` 服务;缺 `api` 的 anthropic 条目由 provider ↔ api 配对拒(`config.model_entry_invalid`、字段 `api`);缺 `tier` 的条目 `params.tier` 为 `"standard"`;缺 `quotaWeight` 的条目以 1 进配额表(计量不变)。读腿交来的条目不变。
355
+ **谁受伤**:无(这些条目此前要么服务不了、要么让整面被拒)。**升级前做**:无;想让某条目走别的线路或档位,在条目上写明 `api` / `tier`。
356
+
357
+ 54. **🔴 `POST /v1/runs/:id/interrupt` 不再收 `text`:体带任何键 ⇒ `400 request.body_shape`(键在 `unknownKeys`,判在查 run 之前);「切断并说话」改发 `POST /v1/runs/:id/steer { text, priority:"now" }`(wire BREAKING;零 DDL、零数据迁移;部署零动作,调用方有动作)**:
358
+ 旧形:`/interrupt {text}` = 切断在飞 turn 并带这句话继续,run 在本副本在飞 ⇒ `202 delivery:"queued-immediate"`;run 不在本副本跑(停驻 / 他副本 / 终局)⇒ 一律 409、什么都不写。
359
+ 新形:`/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` 才送。
360
+ **与旧口的差别(谁受伤)**:新形在停驻 / 终局 run 上**写一笔停放**(停放条目 / 候唤醒卡),旧口在这两态零写。旧口那条「在飞才收、否则零写」的原子保证**本版起没有替代**:先读 run 状态再发有竞态(读到在飞,发出那一拍流刚落定,steer 照样停放);事后见 `delivery !== "applied"` 时那笔停放已经落盘、撤不回。7.116.0 节「想要不停放的切断用 `/interrupt`」那句补偿自本版失效(已发节不改,本条即勘误)。
361
+ **另两处读法**:`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`)。
362
+
363
+ 55. **SQL 库的唯一键归起服补建、且不只按名判:八条此前只随建表到货的唯一键,存量表缺了就在起服时补建;唯一索引同名在场时再判形(列集 / 唯一性 / 整表);存量有重复行或同名形不对 ⇒ 起服拒启并点名(起服拒启面变更;SQL 开库的等待窗不重试;wire 零新键;新库与已齐的库零 DDL)**:
364
+ 旧形:`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` 到货:存量表缺了它们永远补不上,库不再对「不许重复行」执法而起服是绿的;索引原语只按名字判在不在,同名而形不对的旧索引(普通索引 / 列集不同 / 局部或前缀索引)也被当作已有。
365
+ 新形:八条进索引声明,存量表缺了就在起服时补建(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。
366
+ **重复行的出路**:拒句里是去重查询 `SELECT <列>, COUNT(*) FROM <表> WHERE <各列> IS NOT NULL GROUP BY <列> HAVING COUNT(*) > 1`(任一列为 NULL 的行不冲突,已排除),删除或合并多余的行 —— 留哪一行是你的决定,本构建不替你选 —— 再起服。PG 上失败的构建会留下一个 INVALID 的同名索引,下一次起服自己摘了重建,不必手摘。
367
+ **同名错形的出路**:停掉该表的写入,执行拒句里的那一条摘除语句(MySQL 协议 `ALTER TABLE <表> DROP INDEX <索引>;`,PG 独立索引 `DROP INDEX CONCURRENTLY IF EXISTS <schema>.<索引>;`,PG 约束底座 `ALTER TABLE <schema>.<表> DROP CONSTRAINT <约束>;`,PG 上语句里的 schema 是索引所在的那个),再起服 —— 下一次起服按声明的形建;摘除到重建完成之间库不执法唯一性。重复行仍在,则那一次起服转为「重复行」拒启。
368
+ **谁需要**:带存量表的 SQL 部署(升过多版的库:这八张表上的唯一键可能从没存在过)。**谁受伤**:存量表里已有重复行(唯一键缺席期间写进去的)或留着同名错形索引的库 —— 升级后起服拒,直到按拒句出路处理;表较大时首次起服多一次建唯一索引。**补偿**:拒句逐处点名并带可执行的出路;新库零 DDL;不加旋钮。
369
+ **没做的(如实)**:普通索引不判形;PG 协议面不认 `CONCURRENTLY` 时的回退臂不读目录、不判形。
370
+ **升级前做(可选,省一次拒启)**:对每对 (表, 列) 跑一遍去重查询,无行即零动作 —— `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)`;表不在或为空也无需动作。
371
+ **回滚**:回到上一版无需动作 —— 本版补建的唯一索引留在库里,旧版不读它,它继续在库里执法;多个副本滚动升级无先后要求(旧版副本不读索引,只比列集)。
372
+
373
+ 56. **`DB_BACKEND=local`:会话删除先落持久的「删除中」标记(会话元数据边档 `session-incarnations.json` 里那一格多一位 `"dropping": true`);回滚到 7.147.x 及更早之前先用本版起一次(持久面;行为修复;升级零动作)**:
374
+ 旧形:那一格只有化身 / 属主 / 建档时刻 / 执行位 / fork 键;删除逐只删四只行边档、存档、格,中途失败或进程被杀留下半删的会话(旧标题挂到同 id 的下一位住客、fork 中间态 409、补铸出的无主会话)。
375
+ 新形:删除第一步把那一格写上 `"dropping": true`(文件与目录 fsync),收尾完成时连格一起删;带这一位的格对一切读者是「不在」,同属主重发删除、下一次碰这只 id、或下一次起服把它收完(起服扫收不完 ⇒ warn `session_drop_unfinished`,照常服务)。
376
+ 正常收完的删除不在盘上留这一位;只有删除中途失败 / 进程被杀之后、还没收完时它才在。local 上 run 认领先锁根会话:受理之后会话被删 ⇒ 404 `resume.session_not_found`;删除 / 委派子代转录的收尾撞上活 run ⇒ 拒(删除答 409 `conflict.session_active_run`)。
377
+ **谁受伤**:回滚到 7.147.x 及更早时数据根里还留着标记格 —— 旧版的严格边档读不认识这一位,起服整只拒。依赖「换装半失败后同键 fork 从源补回内容」的调用方:存档保持空,由换装重试补齐。
378
+ **补偿 / 回滚**:回滚之前先用本版起一次(起服扫收完全部标记格;起服日志里没有 `session_drop_unfinished` 即收完),再换旧版。收不完的(warn 点名 id 与故障)先按故障修(权限 / 盘满),再起一次本版。
379
+ **升级前做**:无。SQL 后端零动作(删除本来就是一个事务)。
380
+ **与本版「会话删除是一只三态」一条合读**:会话删除先在那一格写下令牌 `"deleting"`,删行那一刀才带 `"dropping"`;带令牌的格由删除协议收完(同属主重发 = 接管;起服之后删除协调器的收尾,收不完 ⇒ warn `session_delete_recovery_unfinished`),
381
+ 不由「下一次碰这只 id」的写或店的起服扫收;上面「同属主重发、下一次碰这只 id、或下一次起服」这一句在会话删除上读作「同属主重发、或下一次起服」。只带 `"dropping"` 的格(placed release / 提交出口撤回)照旧。回滚前用本版起一次,日志里两种 warn 都没有再换旧版。
382
+
383
+ 57. **起服列集对账多问一件事:本构建声明非空(`NOT NULL` 或主键成员)的列在库里仍允许 NULL ⇒ 拒启,拒句逐列给配方;缺列的拒句按列的声明分类 —— 自填列一句 ADD COLUMN(与历史同)、要值列三步、主键列不出语句(行为收紧 + 文字订正;wire 零新键;SQL 部署有升级动作)**
384
+ 旧形:对账只问「列在不在」;缺列的拒句对每一列打印 `ALTER TABLE … ADD COLUMN <原文>;`。要值列(声明 `NOT NULL`、无缺省)的那一句原文在已有行的 PostgreSQL 表上被引擎拒,部署者常把列加成可空 —— 此后起服转绿,而这一列在已有行上是 NULL(`file_history_boundary.publish_seq` 是这一形)。
385
+ 新形:同一次对账(列册只有一个读者,一次读回「列在不在 + 可不可空」)再问「本构建声明非空的列在库里是否也非空」,否 ⇒ 拒启(同一个拒启码 `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;`(缺省是本构建声明的)再收紧,自增 / 生成列只收紧;主键成员 ⇒ 不出语句,一句话(出路是部署与库匹配的构建)。
386
+ **哪类库升级后会拒启**:某张表里有「本构建声明非空」而库里可空的列 —— 含带 `DEFAULT` 的列;典型是以前照拒句把某列手工加成可空、从没补值收紧的存量 PostgreSQL / TiDB 库,以及曾被手工放宽过 `NOT NULL` 的列。**不拒**:本就声明可空的列在库里可空;构建可空、库里非空的反方向不判。
387
+ **升级前做**:不确定自己的库属不属于上面那一类时,先在测试库按拒句演练:拒句逐表逐列给配方,要值列的回填值(注释行里的 `…`)由你按自己的数据填,有缺省的列配方里的 `UPDATE` 已是声明的缺省;执行完毕后再起服。空表上打印的语句逐字全部可执行。
388
+ **回滚**:回到上一版即回到只问列名的对账;数据零改动(已收紧的列在上一版照常工作)。
389
+ 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、零一次性迁移)**
390
+ 换钉:`@sema-agent/core` 7.65.0 → 7.66.0 精确(`package.json` 只钉 core),`@sema-agent/primitives` 随 core 的精确依赖到 7.66.0。下列各项按「谁看得见」排。
391
+ ① **mods 契约号 9(硬破坏)**:旧形:部署 mod 包写 `"contract": 8`。新形:引擎的 mods kernel 契约号是 9,写 8 的包起服拒 `config.mods_invalid`(拒句点名两个号)。9 = 扩展可经 `$.prompt.submit({ text })` 给自己的腿交一条提示,扩展帧多 `handler.event`。
392
+ **升级前做**:把包的 `contract` 改成 9 并按新契约重建。没声明 `MODS_PACKAGES` 的部署零动作。
393
+ ② **`MODEL_DEFAULT_THINKING=off`(行为变更)**:旧形:`off` 是哨兵词,与不设同义(不铸模型级缺省,提供方自己的缺省说了算;缺省开思考的网关照样思考)。
394
+ 新形:`off` 是七档之一,铸进引擎 `Model.defaultThinking: "off"` —— 没点档的请求带显式「关」;配置目录行的 `effectiveValue` 回 `"off"`(此前 `null`);中心有效配置回填同一读法。七档以外的值照旧起服拒;端点梯子 `MODEL_REASONING_EFFORT_LEVELS` 仍只收六档。
395
+ **谁需要**:要「这只模型缺省不思考」的部署(缺省开思考的网关,便宜步不要思考)。**谁受伤**:已写 `MODEL_DEFAULT_THINKING=off` 而靠「等于不设」让网关缺省思考的部署 —— 升级后缺省关。
396
+ **补偿**:想要「不设」的把这一行删掉或留空。**回滚**:回到 7.147.x 时 `off` 照旧读成不设。
397
+ ③ **`GET /v1/models` 行加 `defaultThinking`(wire 加性,present-iff)**:这一行的模型缺省档原样(七档含 `off`);缺席 = 没有模型级缺省。读「缺省是不是关」读本键,读「关不关得掉」读 `supportsThinkingOff`。
398
+ ④ **人类输入帧(wire 加性)**:`human_input.author` / `human_input.extension`(不是本人时才在场:`extension` = 扩展交的提示,`observer` = 观察者的报告;`extension` 键是交提示的扩展注册名)与附件行 `declinedBy`(拒了这只附件的扩展)。缺席 = 操作者本人。把每条 `human_input` 都当成本人输入渲染的消费方:按 `author` 区分。
399
+ ⑤ **外源清标账(引擎型面硬破坏;本服务零动作)**:清标账列表的读法改为异步(嵌入方直接调运维面 `listClearances` 的,改 await)。抹除连同清标托管一起抹 ⇒ `GET /v1/memory/origin/clearances` 的行带 `custodyErased: true`(在场才发)、`custodyBytes: 0`;对这一行的 resume 拒 `memory.origin_clear_unknown`;抹除收执的载体类多 `clearanceCustody`(原样转发)。
400
+ ⑥ **capture 记录三名退出引擎包根(引擎导出面硬破坏;本服务零动作)**:`listSessionCaptureOptOut` / `markSessionCaptureOptOut` / `readSessionCaptureOptOut` 没了,读法是 `fileSessionCaptureRecordStore(<控制面目录>)` 的 `list` / `mark` / `read`(异步)。直接 import 这三名的嵌入方换读法。
401
+ ⑦ **退役且没有后继的工具名,剩下两道门也放行(行为变更)**:旧形:请求的选择器清单(`excludeTools` → `400 config.tool_face_control` / 子代 `denyTools` → `400 config.agent.unknown_tool` / 技能 `disallowedTools` → `400 request.field_invalid`)与请求体 `settings.permissions.neverAuto`(`422`)上这种名被拒。
402
+ 新形:照收;选择器 / 技能清单由引擎保留这一行并在准备期说一句(会话流通告 `config.legacy_tool_name`,`layer` = `task_selector` / `skill_table`);`neverAuto` 只有本服务读 ⇒ 本服务按引擎的退役名账铸那一句一次(`layer` = `host_table`,条目带 `source`)。改名了的旧名(有后继)照旧拒。
403
+ **谁需要**:写着这种名字的清单(壳从 CC 用户 settings 转投的常带)—— 不再因一行死项整份被拒。**谁受伤**:按 `400` / `422` 找这种名字的调用方 —— 改读通告。**补偿**:按通告点名的条目把它从清单里删掉。
404
+ ⑧ **店形拒族第四码 `memory.control_plane_strays`(本服务的部署形零动作)**:后端自带治理店而引擎控制面里还留着旧治理记录 ⇒ 引擎构造期拒、一个字节不写;引擎不自动搬旧记录。本服务三种记忆后端都构造不出这一形(File 后端的治理店就是它控制面上那只;`pg` / `mysql` 不带治理店)。
405
+ 码按族入族:两受众同答 409 + 原码(会话所有者面固定句)。自己接带治理店后端的嵌入方:**升级前一步** = `adoptReplicaControlPlane(<控制面目录>, <那只治理店>)`。
406
+ ⑨ **`PRINCIPAL_INBOX_ASSISTANT` 的值形(收窄)**:旧形:任何非空白串照收(`asst-1` 也收),收件箱等一只永远不会来的读者。新形:必须是 agent handle(`a` + 6–32 位小写十六进制);不是 ⇒ 起服拒,拒句是引擎原句(引用值至多 96 字符)。
407
+ **谁需要**:跨主体投递要真能被一条助理腿读到的部署。**谁受伤**:值不是 handle 形的部署 —— 起服拒。**补偿**:换成那只助理的 handle,或删掉这一键。引擎这一版有读信的助理腿(以这只 handle 作任务 id 跑),本服务今天没有起它的入口,信照旧留在箱里。
408
+ ⑩ **URL 主机读法(行为变更)**:插件克隆 URL 对 `PLUGINS_ALLOW_HOSTS` 的判与 `GIT_API_BASEURL` 的主机族判改读引擎 `hostOfUrl`。旧形:插件 `new URL(url).hostname.toLowerCase()`(尾点主机被拒、带凭据的照放);`GIT_API_BASEURL` 去一只尾点 + 小写(不是 http(s) / 带凭据照过起服)。
409
+ 新形:小写、IDN 取 ASCII 形、尾点全读掉(`PLUGINS_ALLOW_HOSTS` 的名单项经同一只读法读,只认裸主机项);带凭据 / 不是 http(s) / 读不回一只主机 ⇒ 读不出:插件那一条不装(拒因是引擎那一句)、`GIT_API_BASEURL` 起服拒(这种值此前每次仓请求都失败)。
410
+ **谁受伤**:URL 里带凭据的这两种声明。**补偿**:凭据移到 `GIT_API_TOKEN` / 部署的 git 凭据,URL 只留主机与路径。
411
+ **引擎只读面的收窄,本服务零改(如实)**:个人挂载上坏掉的作用域登记簿与坏根锚同答(不带层座的状态面 `optOutSource: "fault"`、不带层座的记忆口 500 `internal.memory_control_plane_corrupt`);清标账更新删不掉已抹条目的托管对象 ⇒ 那一次清标操作失败关闭(500);
412
+ Runner 任务里委派工具的任务登记表不是这一跑的那只 ⇒ spawn 拒(本服务恒传这一跑的那只,不可达);模型缺省档在 `off` 以上的部署,记忆整理的蒸馏与 mod 的 `$.model.complete` 也按这一档请求(成本面)。
413
+ **升级前做**:① 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 后端不受这一条影响。
414
+
415
+ 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 码变;按码分支的客户端改读法;部署零动作)**:
416
+ 旧形:这四个入口上停驻行的存储体读不成检查点(JSON 字面 `null` / 数组 / 标量 / 非 JSON)答 `409 conflict.checkpoint_unreadable` + 店的原句(不带 `reason` / `retriable`);决断口与运维队列 / 收件箱行上的 `rowVerdict.code` 已是 `checkpoint.invalid_outcome`(MIGRATION 7.147.0 节第 29 条)—— 同一张坏卡一行两码。
417
+ 新形:五个停驻行读者(决断口 · `/resume` · `/wake` · `plan_review` · 应答口的停驻赎回席)同答这一行自己的拒:`409 checkpoint.invalid_outcome`,体顶层 `reason`(判官对这一格原样字节的判决)与 `retriable: true`,`error` 以行上 `rowVerdict.sentence` 开头、后接 ` Diagnostic: ` 与店的诊断;卡仍 pending、字节不动。
418
+ 店的别的失败(连接 / 读腿漂)仍 `409 conflict.checkpoint_unreadable` + 店的原话 —— 这是该码今天唯一的产生处。
419
+ **谁受伤**:对这四个入口的 `409 conflict.checkpoint_unreadable` 做专门分支(当「存储体坏了」处置)的客户端:坏行上拿到 `checkpoint.invalid_outcome`。
420
+ **补偿 / 升级前做**:`conflict.checkpoint_unreadable` 今后只表示店的别的失败;「这一行续不了」读 `checkpoint.invalid_outcome` + `reason`(`error` 句即出路,卡仍待决);按前缀 `checkpoint.*` / `conflict.*` 兜底的客户端零改。**回滚**:回到上一版即回到四口借码;数据零改动。
421
+
422
+ 60. **本服务自己发出的出站请求一律不跟重定向:出口只有一只,搜索后端 · 记忆同步 · repo 工具 · OTLP 出口 · bake-runner · 对象存储 · `http` hook 都在内;对端回 3xx(304 除外)⇒ 拒,不跟、不重试,拒句点名出路(行为收紧,安全轴 fail-closed;wire 零新键、零新码;端点原先靠重定向转发的部署要把最终地址写进配置)**:
423
+ 旧形:出站 `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` 里的鉴权头 + 指标体)·
424
+ 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`,不点名出路。
425
+ 新形:全局 `fetch` 在整个 `src/` 里只被读一次(`src/egress-redirect.ts` 的出口工厂);每个出站面各造一只带「出路句」的出口,请求只经它发出,注入的 `fetchImpl`(测试座 / 嵌入方)同样被它包住。出口强制 `redirect: "manual"`,对端回重定向(`opaqueredirect` 或除 304 外的任何 3xx)⇒ 抛类型化拒,
426
+ 拒句 `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`(这一层本轮零本地副作用)·
427
+ 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`)·
428
+ `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`。
429
+ **谁需要**:把上述端点放在会回 3xx 的前面的部署 —— 负载均衡的 http → https 跳转、缺尾斜杠的 301、改名 / 迁移后的仓 API(托管方对改名或转移的仓常回 301 指向新位置)、代理网关的 307 转发。这一类部署此前由传输层静默跟随,体与自定义凭据头被送去另一处。
430
+ **谁受伤**:端点原先靠重定向转发的部署 —— 升级后那一面的请求在第一跳就失败(拒句在上面各条失败臂里),不再静默成功:搜索工具报错、记忆同步那一层本轮失败、仓工具报错、指标出口断供(`server.otel.export-failed` 计数涨)、bake-runner 认领失败、对象存储读写失败。自家 http → https 跳转的部署:把配置里的 `http://` 改成 `https://`。
431
+ **补偿**:把最终地址写进上面点名的那一席(无新旋钮;不提供「跟随重定向」开关 —— 凭据只去被判过的那个根是这条律的全部意义);改名 / 转移后的仓,`GIT_API_BASEURL` 不动,工具里改用新的 owner / repo。
432
+ **升级前做**:逐个确认配置的端点在**该面实际用的方法**上不回 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,把那一个写回配置。没有重定向的部署零动作。
433
+ **回滚**:回到上一版即回到「传输层默认跟随」(上述面);无持久面变更。
434
+ **304 的读法变了(如实)**:304 没有 `Location`、传输层也不跟,它不是重定向 —— 判据把它放过(中心请求原来单列的例外并进了判据)。hook 直连腿与记忆 embedder 此前把 304 当重定向拒;现在 304 是普通的非 2xx:hook 直连腿答 `bad_response`(句 `hook llm HTTP 304`),embedder 抛 `HTTP 304`。这两面从不发条件请求,304 本就不是合法答复;结果同样是失败,只是失败句与码变了。
435
+ **没做的(如实)**:`ws` / `node:http(s)` 客户端口(k8s API、exec 的 WebSocket、本进程回环探针)不经这只出口 —— 它们的传输层本就不跟重定向;源码门把这几处与出口一并登记成闭集,新加一条出站腿必须登册。
436
+
437
+ 61. **🔴 属主判一张面表:提交挂接对「不是你的 / 委派子代的」会话答「没有这只会话」;直连门计划审阅对别人的 task 答证明拒;策略口对委派子代行答 404;只持部署 service 凭据的调用方在 run / 会话读面看得见各用户的行(安全轴;行为变更;wire 零新键、零新码;部署零动作)**:
438
+ 旧形 → 新形(逐格;其余各口的码与句逐字不变):
439
+ ① 提交挂接(`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 …」)不变。
440
+ ② 同三口 × 委派子代的无主 placed 会话(具名调用方、只持 service 凭据的调用方都算):修前执行席答 404 `resume.session_not_found`「the session this run was to start on no longer exists …」,不带执行席的嵌入装配上 `requireExistingSession` 形放行 → 属主门答 ① 那一体,嵌入装配同拒。那只会话的存档读不出时属主门不判这一格(执行席照判,存档的故障照旧按腿的形答 `corrupt_session`)。
441
+ ③ 直连门 worker × `POST /v1/assistant/tasks/:id/plan_review` × 证明有效、task 属于别人:404 `not_found.run` "task not found" → 401 `principal_unverified` "principal proof required",与查无此行同体。属主按这一次决定的证明推出的主体判;BFF 部署不变。
442
+ ④ `GET|PUT /v1/sessions/:id/policy` × 委派子代的无主 placed 会话 × 非 fleet、非运维调用方:409 `conflict.session_ownerless` → 404 `not_found.session`「session not found」。运维与普通无主会话仍 409。
443
+ ⑤ 放宽:只持部署 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 读口不再按主体头钉人,与会话读面同读;驱动面照旧按属主。
444
+ 另两处同读的收口(码不变):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 口答「没有这一行」(修前不报主体的调用方在续跑等口碰巧放行)。
445
+ **谁需要**:多租部署(「不是你的 ≡ 没有这一行」由构造保证);运维(拒因一行);代部署读舰队的中继(trace 与会话 / run 读面同答)。
446
+ **谁受伤**:按 ① – ④ 旧答分支的客户端 —— 按 403 / 401 判「挂接被拒、请带主体头」的前端改按 404 `resume.session_not_found` 读(指路句只在运维日志);直连门上持有效证明对别人的 task 下决定的调用方读到「principal proof required」;读策略口 409 判「无主」的管理面对 placed 行读到 404;dev-open 部署上靠主体头把别人的 run 藏起来的用法(那里主体头是谁都能自报的标签,不是身份)。
447
+ **补偿**:运维日志 `owner_gate_refused { policyFace, reason, principalPresent }` 一行(`policyFace` = 策略面)(`reason` = `missing` / `not_visible`;不记身份值)区分「缺行」与「看不见」;要「部署凭据看不见任何用户行」的部署声明 `SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT=false`(⑤ 不生效,其余各口按「过了凭据门、没有主体」那一臂答,与上一版同)。
448
+ **升级前做**:按 ① 的 403 / 401 或 ③ 的 404 分支的客户端改读新答;依赖 ⑤ 之前「部署凭据读不到用户行」的部署写一行 `SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT=false`。其余零动作。
449
+ **回滚**:无持久面;换回上一版即回到旧答。
450
+
451
+ 62. **🔴 拒体的机读位只有一种版式:`{ error, errorCode, ...机读事实 }`,根上不再有 `detail`;八条码路径的对象形 `detail` 摊到体根上(容器 `problems` / `fields` / `conflicts` 整只挂在根上),十一处串形 `detail` 并进 `error` 句尾;`settings.hooks` 面的拒体 `field` 改为精确坐标,`detail.path` 退役(wire BREAKING;码 · 状态不变;零持久化迁移;部署零动作,按 `detail` 读拒体的客户端要改)**:
452
+ 旧形 → 新形(逐码;「根上」= 与 `error` / `errorCode` 同层):
453
+ ① `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[` 起头认。
454
+ ② `400 / 409 / 422 request.field_conflict`:`detail: { kind, fields, count?, cap? }` → 根上 `reason`(原 `kind` 的词,逐字同)+ `fields` + `count?` + `cap?`。`kind` 改名 `reason`,词表不变。
455
+ ③ 条目问题(`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` 挪到根上。
456
+ ④ `409 conflict.session_placed`:`detail: { placement_kind }` → 根上 `placement_kind`。
457
+ ⑤ `503 state.scenario_assignment_unknown`(以及 `GET /v1/sessions/:id/mcp` 200 体里的 `scenarioRefusal`):`detail: { scenario, source }` → 根上(`scenarioRefusal` 里)`scenario` + `source`。
458
+ ⑥ `409 steering.duplicate_input_id`:`detail: { differs }` → 根上 `differs`。
459
+ ⑦ `400 config.user_attachment_invalid`(同步提交腿):`detail: { path, index? }`(引擎因由原样)→ 根上 `field`(引擎的 `path`,非空串才带)+ `index?`(非负整数才带);引擎在因由里多给的键不再进体。流式 `done.result` 与 run 记录上的 `terminal.detail.detail` 不变。
460
+ ⑧ `400 rules.invalid_shape` / `400 rules.inert_entry`:形不变(引擎的读数本来就在根上),改为按码逐键取:`invalid_shape` ⇒ `field` · `got`;`inert_entry` ⇒ `field` · `entry` · `reason` · `verdict` · `guidance` · `currentName` · `ambiguous` · `valueType`;表外的键不上 wire。
461
+ ⑨ 串形 `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`,与请求体其余各处的帽同一组键)·
462
+ `POST /v1/rules` 的 `400 request.field_invalid` + `reason`(句子不再说「`detail` says why」,原因接在句尾;规范拼写那一臂另带 `canonical` = 店会存的规范串,原样重发即收 —— 此前它写在串形 `detail` 的句子里)。
463
+ ⑩ `settings.hooks` 面 `400 request.body_shape` 的 `unknownKeys` 与该面拒句里的坐标:点分数字段(`settings.hooks.Stop.0.hooks.0.onFailure`)→ 方括号形(`settings.hooks.Stop[0].hooks[0].onFailure`),与拒体 `field` 同一种写法。
464
+ ⑪ 保留键:`error` · `errorCode` · `detail` · `toJSON` 不作机读事实的键;本服务自己的组体撞上它们 ⇒ 那一拒答 `500 internal.error`(内部故障,不是调用方能修的拒)。
465
+ **谁需要**:按拒体机读位分支的消费方 —— 同一类事实此前有两种版式(摊在根上,或嵌在 `detail` 里),每加一个读点就要先问「这个码是哪一种」。
466
+ **谁受伤**:按 `detail.*` 读这些码的客户端读空(壳的 hooks 拒提示、坏附件「第几件」、条目问题清单、场景拒、按 `detail.problems[].field` 认字段的读口;SDK 的 `differs`);按 `field === "settings.hooks"` 认 hooks 族的读口认不出;按 `kind` 读字段冲突的读口读空;按点分数字段解析 `unknownKeys` 的读口。
467
+ **混版窗(新 server + 旧客户端,逐码)**:①:旧壳的 hooks 专门提示消失,改为通用的提交失败句(句子本身照旧点名坐标与原因);旧壳在提交失败后重扫已发 hooks 的那条提示路径可能给出与真拒因不同的别名 / 坏正则提示。②:旧读口拿不到冲突类别,只剩码与句子。③:按条提示消失,只剩句子(前 5 条 + `; and K more`)。④⑤⑥⑦:对应的机读位读空,退回到码与句子(⑥:旧 SDK 的 `differs` 为 `undefined`,「换不换 key」只能读句子)。⑨:旧读口读 `detail` 读空,原串仍在 `error` 句尾。⑩:按点分数字段切 `unknownKeys` 的读口切错。旧 server + 新客户端:新读点在 < 7.148.0 的服务端上读空(该位在那里不在根上)。
468
+ **补偿**:码 · 状态 · 句子骨架不变(串形 `detail` 的内容仍在句尾);消费方二选一,**不要双读**:(a) 把支持的服务端地板抬到 7.148.0;或 (b) 读点只读新形,并在说明里逐读点写明「低于 7.148.0 的服务端上该位缺席」(与该位上线之前的服务端同形)。
469
+ **持久化**:零迁移 —— 存量行(领养日志的拒因、存体)不改,只改 HTTP 投影;≤ 7.147.0 写下的存体续跑时按新形答。
470
+ **升级前做**:按上表把读 `detail.*` / `kind` / `field === "settings.hooks"` / 点分数字段 `unknownKeys` 的分支改到新位。部署零动作。
471
+ **回滚**:无持久面;换回上一版即回到旧形(新形的读点在旧版上读空,见混版窗)。
472
+
473
+
474
+ 63. **🔴 场景子命名空间 —— 请求头 `x-agent-scenario`,保留前缀 `_scn:`,起服切换检查,直连门证明的 sub 完整形判**
475
+ **是什么**:`x-agent-scenario: <场景名>` 在验过的人之内选一格分区:run / 会话 / 问行属主、停驻行 scope、附件、提交幂等身份、列表视域、会话规则按「人 + 场景」分;成本配额、租约、用量窗、并发帽、运维名册、持久规则、组织成员、出站身份、device 域、记忆仍按人。没带头的请求逐字节同上一版。判序、错误码与人面 / 分区面全表见契约 §0.12。
476
+ **新码**:`400 request.scenario_without_principal`(头在而没有验过的人)· `400 scenario_unknown`(头里的名字不合文法或不在册;此前只来自提交体)· `400 scenario_conflict`(提交体 `scenario` 与头不同)。`principal_too_long` 对带头请求判「人 + 场景」编码后的宽度。
477
+ **保留前缀**:主体头 · SSO 令牌 sub · 直连门 JWT sub 三处以 `_scn:` 开头的人一律 `400 principal_reserved`。直连门证明的 sub 此前只判长度,本版起与主体头同一只判官(名形 / 保留 / 长度):sub 带控制字符 → `400 principal_not_a_name`,sub 是保留标识 → `400 principal_reserved`。
478
+ **起服切换检查(一次性迁移,只读)**:库里没有本条的标记 ⇒ 扫存量身份(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` 登记表。
479
+ **谁需要**:同一个人在不同场景(例:健康 / 财务)里各用一套会话与历史、互不看见的部署。
480
+ **谁受伤**:① 以 `_scn:` 开头的既有主体:边界 400,存量行让起服拒;② 直连门部署里 sub 带控制字符或是保留标识的证明:由放行改 400;③ 回显属主的读面(trace 列表、`?owner=` 收件箱)对带头写下的行显示 `_scn:<场景>:<人>`;④ 混版:更早版本的副本不读这只头,带头请求落到它上面写进人自己的分区;⑤ 引擎自己键控的面(工具登记轴、子代树域、恢复 rung、MCP 连接池、workflow scope、后台代理登记、peer 目录)与记忆本版仍按人,同一个人的不同场景在这些面上互见。
481
+ **补偿**:拒句点名每一处来源,运维改名或删除那些身份后重启;停-迁-起即无混版窗(SQL 起服守卫兜底:判活窗内有 run 在心跳就不写标记);不带头的调用方零改。
482
+ **嵌入方类型面(BREAKING,零别名)**:`RequestAuth` / `AuthContext` 的身份格 `principal` → `subject`(分区键);`withPrincipal` / `currentPrincipal` → `withSubject` / `currentSubject`(另有 `currentPerson`);`verifiedPrincipal` → `verifiedPerson`;`gatedPrincipal` → `gatedSubject` / `gatedPerson`;`ScenarioGate` 多一个成员 `known()`(在册名单);品牌型 `Principal` 拆成 `Person` / `Subject`(`DurableOwnerKey` 不变)。
483
+ **持久化**:零 DDL 进中央建表语句、零行改写;起服只读扫一次 + 一行标记(本条自己建的标记表)。
484
+ **升级前做**:① 停光全部旧副本、等判活窗(`REAP_RUN_STALE_SEC`)过去,再起本版(停-迁-起,不可滚动 —— 旧副本不保留 `_scn:` 前缀);② 自查主体 / 证明里以 `_scn:` 开头的身份(拒句会点名);③ 嵌入方按上面的改名改调用点。
485
+ **回滚**:回滚前把带场景写下的行处置掉(它们的属主是 `_scn:<场景>:<人>` 复合串,上一版把它当一个独立主体读);标记行 / 标记文件留着无害(上一版不读它)。
486
+
487
+ 64. **🔴 server-as-peer 的技能声明 `A2A_SERVE_SKILLS` 只认版本化外壳 `{"version":2,"skills":[…]}`;条目可带 `audience`(这条技能发布给谁);公开卡多一位 `supportsAuthenticatedExtendedCard`,新方法 `agent/getAuthenticatedExtendedCard` 回按人过滤的扩展卡;技能选择的拒句不再回显 id(行为变更 + wire 加性;设了 `A2A_SERVE_SKILLS` 的部署升级前改值形,镜像与 env 同一次滚动)**:
488
+ 旧形:`A2A_SERVE_SKILLS` 是裸 JSON 数组 `[{id, name?, description?, scenario}, …]`;条目里写了别的键被静默丢掉;卡上的每条技能对所有调用方公开;`message/send` 点名未知 skill id 的拒句回显那个 id,选中之后被场景门等拒的拒句点名 skill id;按调用方给的方法名查方法表会命中原型链成员(`toString` 等)。
489
+ 新形:值形只有外壳 `{"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`。
490
+ **迁移(运维动作,零持久化迁移)**:`A2A_SERVE_SKILLS` 的旧值(裸数组)整只放进 `{"version":2,"skills":<旧值>}`,内容不变;`audience` 只能写在外壳内。旧值的条目里若带着旧解析器容忍、被静默丢掉的多余键,新版会拒启并点名它 —— 删掉那一键。
491
+ **滚动与回滚**:镜像与 env 同在 pod 模板里一次滚动。外壳 env 遇上不认外壳的旧版:旋钮开 ⇒ 旧版整只拒启(根是对象);旋钮关 ⇒ 旧版不读这个值。回滚到不认外壳的版本时 env 一并退回裸数组,并先删掉受限条目 —— **不要**把 `audience` 写进裸数组:旧版对裸数组条目只取具名键,那条技能在旧版上是公开技能。
492
+ **发布 ≠ 授权**:`audience` 只管谁看得见、谁能按 id 点名,不管谁能跑背后的场景 —— 不带 `sema.skillId` 的消息、映射到同一场景的公开技能、原生提交族(`POST /v1/runs` / `POST /v1/tasks` / `POST /v1/tasks/stream` 体里的 `scenario`)都不经过它;受限技能不要映射到部署缺省场景,也不要与公开技能共用场景。
493
+ **谁需要**:同一台 worker 上有只该给部分调用方看见的技能(如家庭部署里的健康 / 理财技能)的部署。
494
+ **谁受伤**:① 每个设了 `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 的调用方拿不到回显。
495
+ **补偿**:①② 本条迁移句同滚 / 同回滚;③ 拒句点名下标与键;④ BFF 带主体头;⑥ 已拿到 taskId 的调用方 `tasks/get` 照常;⑦ 直连门(JWT)或 SSO 凭据;⑧ 它能看的技能名单就在它拉得到的卡上。
496
+ **升级前做**:设了 `A2A_SERVE_SKILLS` 的部署按上面的迁移句改值形,与镜像同一次滚动。没设这一键或没开 `A2A_SERVE_ENABLED` 的部署零动作。
497
+ **回滚**:无持久面;env 退回裸数组(先删受限条目)再换回旧版。
498
+ 65. **🔴 受理之前被拒的提交不再留下空会话(行为变更;持久面:SQL 加一列 + 一次性迁移 M43;wire 加性:新码一只 `409 conflict.claim_lost`)**:
499
+ 一次提交铸下的会话(不带 `sessionId` 的现铸、或带一个此前不存在的 `sessionId`)只在两件事之一发生之后才活过这次提交:引擎受理了它,或这次提交把结果交给了它自己的耐久 run
500
+ (`POST /v1/runs` 的 `202`;`POST /v1/tasks/stream` 带 `x-detach-on-disconnect: true` 且 run 行已建)。否则在**终局应答发出之前**条件撤回 —— 同步腿的应答体、流的 `done` 帧到达时,
501
+ `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)。
502
+ **保留条件**(任一在 ⇒ 留,与 7.147.0 同):已有消息 / 会进上下文的条目;客户端写过它(标题 / 置顶、会话规则、**已成功绑定**附件;无效附件 / 空数组 / 绑定之前的拒不算);本次之外的 run;
503
+ 认领还在;执行环境已为它留下按会话键的持久物(k8s 工作区空间 / 构建缓存卷);挂接已有会话。
504
+ **持久面(SQL)**:`session_ext` 加一列 `client_writes BIGINT NOT NULL DEFAULT 0`(客户端写的次数;四个写者在锁住根行之后同一事务 +1)。存量库缺这一列 ⇒ 起服列册对账拒启 `config.schema_mismatch`,拒句给
505
+ `ALTER TABLE session_ext ADD COLUMN client_writes BIGINT NOT NULL DEFAULT 0`(PostgreSQL 同句);执行后再起服。
506
+ **混版窗(SQL)**:7.147.x 副本的写者不计数 ⇒ 撤回只在本库的启用标记落下之后才生效(一次性迁移 M43;标记表 `one_time_migration_marker` 与 M42 同一张,由迁移自建)。标记在某一次起服落下:
507
+ 标记不在 ∧ 判活窗(`REAP_RUN_STALE_SEC`)内没有 `running` run 更新过;有 ⇒ 不落、**不拒启**,下一次起服再判。所以 **全部副本换成本版之后再起一次**(或在没有 run 在跑时起本版),
508
+ 标记落下、撤回生效;在那之前幽灵会话照旧(fail-closed:留)。看不见的边如实:空闲的旧副本(零 `running` run)没有心跳 —— 标记落下之后它对一只刚铸的会话做的客户端写不计数。
509
+ **local**:会话元数据格多一位 `clientWrites`(本版铸的格都带);数据根独占、没有混跑窗,撤回升级即生效。7.147.x 及更早的严格边档读认不得这一位 ⇒ 回滚的支持形 = 恢复升级前的数据根备份。
510
+ **谁需要**:每一只会话选择器(cli `/resume`、web-admin 会话区、sdk 列表)—— 配错 `allowTools` / 图片的客户端循环重试,此前每次一条无标题零消息的会话。
511
+ **谁受伤**:① 拿到了 `meta` 帧 / `x-task-id` 的交互流(没带断连转后台)被拒后读它们答 404;② 撤回候选的 `done` 晚到「引擎收尾 + 一笔事务」—— 那笔事务要等这只会话的根行锁,别的事务长持着它时一起等(与同一会话上的 `PATCH` 同),上界是库的锁等待超时与 `DB_QUERY_TIMEOUT_MS`(PG 池级 `statement_timeout`;不设则 PG 上不封顶),不另设期限;③ 同一只自选 id 上恰落在撤回窗里的并发提交者偶得
512
+ `404 resume.session_not_found`(可重试、零起);④ 运维失去「空行 = 有人被拒过」的痕迹。
513
+ **补偿**:新指标 `submission_exit_total{end, verdict}`(`verdict` = `withdrawn` | `kept_<词>`,`kept_upgrade_pending` = 标记还没落)+ 既有拒因日志;撤回抛 ⇒ 留 + fail-open 标签 `server.submission-exit.withdraw-failed`。无旋钮。
514
+ **升级前做**:SQL 部署执行上面那一句 `ALTER`(或先起一次本版读拒句);滚动升级完成后再起一次任一副本让标记落下。local / memory 零动作。
515
+ **删码点**:M43 的窗(`plugins/one-time-migrations.ts` 登记表)关闭之后的第一个 minor 删 M43 那一步与撤回判据里读标记的那一句(撤回无条件启用);标记行不再被读(标记表与 M42 同一张,留着无害)。删码之后跳版直升的库从第一次起服就启用撤回。
516
+ **回滚**:SQL:7.147.x 的起服列册对账见到多出的 `client_writes` 列按「库比本构建新」拒启 —— 出路是持有这一列的树;真要回到 7.147.x,先 `ALTER TABLE session_ext DROP COLUMN client_writes`(两方言同句)。多出的标记表 7.147.x 不读。local:见上。
517
+ 66. **请求形的拒先于授权器与执行上下文答,不再先铸会话(拒序变化;码 · 句 · 状态 · 机读位零变化;零 DDL;部署零动作)**:
518
+ 旧形: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` —— 在授权器登记会话、执行上下文解析之后才答,铸下的会话由上一条的条件撤回删掉。
519
+ 新形:这一批在授权器之前答(会话店零写)。一条请求同时撞上它们与留在铸点之后的拒(授权器 401 / 404、执行上下文、装配器的运维锁 `config.locked_key` / 场景门 / 模型名单 / 附件店 / 要任务根的规则条目 / 镜像索引、并发帽 429)时,答请求形那一只;`/v1/runs` 无键提交的坏 `taskId` 在体的其余值形门之前(与带键提交同位)。请求形之间的先后不变。运维锁 `mcp` / `a2a`、模型名单 / 不可用条目照旧在铸点之后。
520
+ **谁受伤**:按「同时坏两处时先得到哪一只码」写判定的客户端。**出路**:按码分别处置的客户端零改;要先拿到授权器的判(401 / 404)就先修请求形。
521
+
522
+ 67. **🔴 409 `conflict.session_active_run` 体与 `POST /v1/tasks/stream` 冲突 `done` 帧删 `stale` 键;心跳过期的 run 在第一次被读到 / 被新提交撞上时当场判死;run 的 `errorCode` 只读码列(BREAKING:删 wire 键;行为变更;wire 加性:死亡终帧带 `errorCode`、中止成因一词 `stall_verdict`;持久面:一次性迁移 M44,零 DDL)**:
523
+ **删了什么(BREAKING,零别名)**:409 `conflict.session_active_run` 体与 `POST /v1/tasks/stream` 冲突 `done` 帧 `result` 上的 `stale`(7.37.0 起的加性位:持有者心跳过期时为 `true`)。
524
+ **改读什么**:409 体此后只点名活着的持有者 —— 新提交撞上心跳过期(`updated_at` 早于 `REAP_RUN_STALE_SEC`)的持有者时,server 先把它判死、放掉认领、再认领一次,这次提交照常受理;
525
+ 所以 409 体上的 `activeTaskStatus:"running"` 就是行上存着的状态。要判「那条 run 死了没」读 `GET /v1/runs/{activeTaskId}` 的 `status` + `errorCode`(`run.stalled` / `run.orphaned` = 持有者死亡判决)+ `heldBy`。
526
+ 类型面按键删(消费方编译红即通知)。残窗(如实):持有者恰在认领冲突与组 409 体之间到期 ⇒ 体答 `running`;读一眼持有者或重发即成功。
527
+ **「死了没」只看 run 行(行为变更)**:死亡判决(`failed` + `errorCode:"run.stalled"` + `error:"run stalled (instance lost?)"` + 放认领,与收割器同一句)落在三处:收割器;
528
+ 观察面(过了属主门、把 run 的状态答给调用方的读口:`GET /v1/runs/:id`、`GET /v1/runs?idempotencyKey=`、`GET /v1/runs/:id/events`、`GET /v1/tasks/:id/stream`、四只句柄读腿、A2A `tasks/get` 与 `message/send` 的等待、两种同键重放);认领冲突。
529
+ ⇒ ① 死 run 上 `heldBy: null`(此前收割之前给失联副本的 id);② 判死之后不再翻回 `running`;③ 同键异步重放(`POST /v1/runs` 202)答 `status:"failed"`(此前 `running`);
530
+ ④ 句柄读腿答 `not_found.task_owner_settled`(此前 `task_owner_elsewhere`);⑤ 认领门(会话删除、会话同步导入、放置 / 设备门……)不判存活:持有者心跳过期而还没被观察、也还没被收割时仍 409 —— 读一眼持有者(`GET /v1/runs/{activeTaskId}`)即放开,再重发。
531
+ 判决写失败(库一时不通 / 锁超时)⇒ 这一次按行原样答(仍是 `running`)、计 F 类 fail-open `server.run-store.stall-verdict-unlanded`,收割器下一拍补;`runs_reaped_total{kind:"stale"}` 计三处落下的全部判决。
532
+ **死亡终帧带 `errorCode`(wire 加性)**:`GET /v1/runs/:id/events` 的死亡帧 `event: failed` `{type:"failed", errorMessage, errorCode}`(码 = 行上的码);trace 流 `event: error` `{type:"error", errorCode:"WORKER_DOWN", message:<行的 error>}`。
533
+ 两帧都从行合成,本连接投过账本终帧(`done` / `failed`)就不合成;收割之后才连上的流也收到它。消费端为「流断了没终帧」自己合成 `failed` 的兜底可以保留(断线 / 超时仍要它)。
534
+ **中止成因新词 `stall_verdict`(wire 加性)**:被判死的 run,原执行者的下一次心跳读到「行已不在跑」⇒ 中止自己的腿;那条腿自己铸的取消终局带 `result.abortCause: "stall_verdict"`(`errorCode` 仍是 `cancelled`)。
535
+ run 行上是那份死亡判决(`run.stalled`),`GET /v1/runs/:id` 读不到这个词。按闭集 `switch` 读 `abortCause` 的消费方加一臂;认不得的词按「server 中止,成因不认识」读。
536
+ **一次性迁移 M44(run 的 `errorCode` 只读码列;零 DDL)**:`errorCode` 的唯一读法是码列(SQL `task_run.error_code`;local:run 行的 `errorCode`)。写结果的三个写口同写这一列(`needs_review` 停驻写 `review.pending` —— 此前只在结果里),
537
+ 续跑认领清列。起服时(任何读者之前)改写存量行一次:带结果的非 `running` 行,码列改成结果投影的码(两代结果形同读、折码;结果无码则留原值);`running` 行带码的置空。
538
+ SQL 按 `task_id` 键集分批读,不等才写,按行版本(`status` + `updated_at` + 列原值)CAS,打空跳过、下一次起服再判;结果读不出的行跳过。窗内每次起服都跑,第二次起零命中。
539
+ 读数键 `runErrorCodeColumnRewritten`(起服迁移读数行;非零 = 真改写了存量行)。**窗** = 本版发布日 + 30 天(与停驻行终局兜底 `APPROVAL_TERMINAL_BACKSTOP_MS` 的缺省同长;窗口见 `plugins/one-time-migrations.ts` 登记表)。
540
+ 窗内 SQL 的读侧只对停驻行补读:列空的 `suspended` / `needs_review` 行读结果投影的码,`running` 行只答空 —— 滚动升级中更早版本的副本写下的不带列的停驻也读得对。窗关之后第一个 minor 删改写、读侧与读数键。
541
+ **改写之后变了的(如实)**:`GET /v1/runs/:id` 的 `errorCode` 前后不变;码列的其它读者对旧行随之改口、与 `GET` 对齐 —— 例:结果码 `cancelled`、列空的旧行,A2A 由 `failed` 改答 `canceled`,审批对账走取消分支(此前按非取消处理)。
542
+ **更长的停驻兜底(如实)**:调长了 `APPROVAL_TERMINAL_BACKSTOP_MS`(> 30 天)的部署,窗关时还可能有更早版本写下、没结清的停驻:删码之后那些行的 `errorCode` 缺席(`review.pending` 仍在结果里)。
543
+ 跳过本版直接升上来的库同此(旧行按列答:缺席或没折过的原码;`result.terminal.code` 仍在结果里)。出路 = 升级时先过一次本版并起服。
544
+ **`DB_BACKEND=local` 的认领接管(行为变更)**:接管一条「停驻无可续」的 `needs_review` 行之后答 `failed`、无码、`result: null`(此前 `failed` + `review.pending` + 停驻结果)。
545
+ **谁需要**:异步提交的调用方(sdk 轮询、壳断线重连)在副本崩掉之后要一个稳定终局;在同一只会话上重新提交的人;A2A 对端;看 `heldBy` 的运维。
546
+ **谁受伤**:① 读 409 `stale` 的客户端(键没了);② 活着而心跳停了一个判活窗的 run:此前只有收割器某一拍恰好落在那段时间里才判死,现在那段时间里任何一次观察都会判死它,判死后回不来,执行者随之停下;
547
+ ③ 读口会写(一次读碰到到期行写一笔 CAS);④ 升级时整表扫一遍带结果的 run 行。
548
+ **补偿**:旋钮 `REAP_RUN_STALE_SEC`(已有;起服与热发布都拒不大于心跳周期的值);CAS 条件里带心跳,先落下的心跳赢;被判死的执行者自停,不与新提交同写一只会话;只有过了属主门的观察才判;写失败按行原样答 + 收割器补。
549
+ **升级前做**:读 409 `stale` 的客户端改读 `GET /v1/runs/{activeTaskId}`;按闭集读 `abortCause` 的客户端加 `stall_verdict` 一臂。部署零动作(零 DDL、零新旋钮;起服多一次整表扫)。
550
+ **回滚**:零 DDL。改写过的码列与本版写下的停驻列对 7.147.x 无害(它先读结果里的码)—— 例外:7.147.x 续跑认领不清列,它续跑本版写下的 `needs_review` 停驻之后,在跑期间 `GET` 答 `errorCode:"review.pending"`,到终局被覆盖。
551
+ 68. **会话列表预览两后端同读 run 行的预览列 —— `GET /v1/sessions` 行的 `objectivePreview` 是这只会话最近一条预览非空的 run 的那一句;`?q=` 两后端都搜任一 run 的这一列;一次性迁移 M45 剥净以注入块起头的旧预览(行为变更;wire 键 / 型不变、读数变;持久面:一次性迁移 M45,零 DDL;部署零动作)**:
552
+ 旧形:一个问题两个读者。SQL 后端读最近一条 run 行的预览列(那条 run 的提示里没有用户正文 ⇒ 列是空串 ⇒ 行答 `null`);`DB_BACKEND=local` 从会话条目现算 —— 往回找最近一条用户消息,截 200 字,
553
+ 引擎包好的 steer 说明句(`The user sent a new message while you were working:` 起头)与 prompt 屏改写之后的文本也算,零 run 的会话(fork / 导入 / 同步来的)也有预览;`?q=` 在 SQL 上搜任一 run 的列,在 local 上只搜合成的那一句。
554
+ 新形:一条律 —— 预览 = 这只会话的 run 行里按建行序(`created_at` 降序、同刻按 `task_id` 降序)最近一条「预览列按字符长度非空」的那一列;没有 ⇒ `null`(含零 run 的会话)。
555
+ `?q=`(trim 之后非空)命中 ⟺ 这只会话有一条 run 的预览列含 q(大小写不敏感、按字面)。两后端读同一列、同一条谓词;`lastRunId` / `lastStatus` 仍取最新一条 run(与预览解耦)。
556
+ 列由提交建行时写下(剥注入块 → 脱敏 → 截约 120 字;装 prompt 屏的腿在引擎交付目标之后补写),与 `GET /v1/tasks` 等面读的是同一列。
557
+ **变了的(如实)**:SQL —— 最近一条 run 的提示只有注入块 / 回显块的会话,预览从 `null` 变成更早一条 run 的那一句。`DB_BACKEND=local` —— 零 run 的会话 `null`(此前是转录里的最近一句);预览截 120 字(此前 200);
558
+ steer 包装句与屏后文本不再进预览与搜索;`?q=` 能搜到更早 run 的词,搜不到零 run 会话的转录;存档头读不出的会话行(带 `unreadable`)照出 run 行的预览(此前 `null`)。只有空格的旧值算有预览(两后端同)。
559
+ **一次性迁移 M45(以注入块起头的旧预览;零 DDL)**:较早版本写下的 run 预览没有剥注入块,引擎前置的块(`<system-reminder …>…`)原样落在列的开头 —— SQL 的各读列面今天就显示它们,local 的会话列表改读列之后也会。
560
+ 起服时(任何读者之前)两后端各扫一遍:列值以闭集注入块的开标签起头的行,新值 = 对列值反复取今天的预览写法(剥块 → 脱敏 → 截 120)到不动点;不动点仍以开标签起头(开标签本身被 120 字截断)⇒ 空串。
561
+ SQL 按十四个标签前缀 `LIKE '<tag%'` 粗筛、进程内精判,按 `task_id` 键集分批(每页 500 行),按列原值 CAS,打空跳过、下一次起服再判;`DB_BACKEND=local` 内存里逐行算、改的行落盘。窗内每次起服都跑,第二次起零命中。
562
+ 读数键 `runObjectivePreviewRewritten`(起服迁移读数行;非零 = 真改写了存量行)。**窗** = 本版发布日 + 30 天(窗口见 `plugins/one-time-migrations.ts` 登记表);窗关之后第一个 minor 删改写与读数键。
563
+ **改写之后变了的(如实)**:块在 120 字之内闭合 ⇒ 剩用户正文;块被截断(多数旧值是这一形:引擎前置的块通常比 120 字长)⇒ 列变空串 ⇒ 会话列表回落到更早一条 run 的那一句(没有就 `null`),
564
+ `GET /v1/tasks` 等读列面上那一行的预览键缺席。用户自己在提示开头写了闭集开标签字面的行同样被剥(与正文里写开标签字面的那一段被剥同向)。
565
+ **认不出、不迁(披露)**:较早版本在装 prompt 屏的腿上建的 run,列里是屏判之前的原文 —— 行上没有「当时有屏」的记号,迁移认不出;此后 local 的会话列表也显示它(属主本人写的那句;列表的属主门不变)。
566
+ 跳过本版直接升上来的库,以注入块起头的旧预览照旧显示;出路 = 升级时先过一次本版并起服。
567
+ **谁需要**:同一只会话在 SQL 与 local 上该看到同一句预览、同一组搜索结果的壳与控制台(会话选择器、最近会话面);升级到 local 的单机用户。
568
+ **谁受伤**:① local 上靠预览认 fork / 导入会话的人(零 run ⇒ `null`;标题与会话视图照旧);② 想按 steer 文本或屏后文本搜会话的人;③ 7.124.0 之前那批旧会话的预览多数变空、回落到更早一句或 `null`;④ 起服多一遍粗筛扫。
569
+ **补偿**:会话标题(`title`)与会话视图不受影响;迁移窗关即删。不提供「回到旧读法」的旋钮(那就是第二个读者)。
570
+ **升级前做**:无(零 DDL、零新旋钮)。按 `objectivePreview` 渲染会话列表的壳不需要改码 —— 键与型不变,`null` 本来就是合法值。
571
+ **回滚**:零 DDL。改写过的预览列对 7.147.x 无害(各读列面读到剥净后的那一句或缺席;7.147.x 的 local 会话列表不读列);回到 7.147.x 即回到两种读法。
572
+
573
+ 69. **🔴 嵌入方:只交 run 店的 `createHttpServer` 嵌入,`GET /v1/sessions` 改答 501;三只 run 店的 `listSessions` 删(嵌入方类型面 BREAKING;服务进程部署零动作)**:
574
+ 删了什么(零别名):run 店(SQL / 内存 / 文件三只)身上的 `listSessions` 会话聚合,以及会话列表路由与能力事实「会话店不能列就读 run 店」的兜底。「有哪些会话」只有一只 lister —— 会话店的 `listSessions`。
575
+ **改读什么**:自建 `createHttpServer`、只交 `runStore`、`sessionStorage` 缺席或没有 `listSessions` 的嵌入,`GET /v1/sessions` 答 501 `capability.session_store_required`(与「会话店缺席」的既有形同),
576
+ `GET /v1/capabilities` 的 `sessionList` / `sessionSearch` 为假。类型面:`RunStore` 上不再有 `listSessions`(调它的嵌入方编译红即通知)。
577
+ **出路**:交一只带 `listSessions` 的会话店(`sessionStorage`);本服务自己的三种后端都交,服务进程部署零动作。
578
+ **谁需要**:无 —— 本条是删第二个读者(run 店的聚合按旧律出预览)。**谁受伤**:只交 run 店的自建嵌入(本服务没有这种部署形;会话店是起服必需)。**补偿**:见出路。
579
+ **升级前做**:自建嵌入核一遍交给 `createHttpServer` 的依赖里有没有带 `listSessions` 的会话店。**回滚**:回到上一版,run 店的聚合回来;零持久面变更。
580
+
581
+ 70. **调度者出身词 `runOrigin`(引擎 7.58.0 起的归因位)四面同投:`GET /v1/assistant/inbox` 行、`human_input` 帧、`wiring_manifest.leg`、会话读面的 `user` 消息都把引擎记下的这个词逐字带过去;本服务自己不铸它;部署里另有铸词方时有升级序(行为修复 + wire 加性:三个面各多一个可选键、`differs` 词集多一词;零新码;部署零动作)**:
582
+ 旧形:会话读面按「用户行每个键逐字」带着它;帧登记表、清单 `leg` 段、inbox 白名单三处各自记成「不投」。引擎一旦记下这个词(嵌入方自带的 `resolveSpec` 铸词;导入进来的会话里引擎的导入门保留的 `UserMessage.runOrigin`),读帧 / 清单 / inbox 的客户端把调度者交来的输入读成人敲的。
583
+ 新形:一条规则 —— 引擎铸的、只作归因的闭集词,引擎报它的每一面本服务逐字带过去(成员判用引擎的 `isRunOrigin`;集外词在帧与清单上丢这一位并计一次;缺席 ⇒ 缺席,从不补一个词,也从不读成「人发的」)。`human_input.runOrigin` · `wiring_manifest.leg.runOrigin`(租户帧与 operator 帧同投)· inbox 行 `runOrigin` 三个可选键;
584
+ 409 `steering.duplicate_input_id` 体的 `differs` 词集随引擎多一词 `runOrigin`(本服务读引擎活常量,原本就认;契约句同步)。
585
+ **本服务不铸词**:铸词点只能是部署自己的调度器触发路径(引擎的信任契约:不从请求体直通);本服务只有调度店的写侧,到点触发的 daemon 在仓外,没有「调度器触发出一个 spec」的路径可盖词。所以:请求体带 `runOrigin`(提交口与三个送话口)⇒ 400 `request.body_shape`(与任何词表外键同一只门,上一版同);
586
+ 装配出的 spec(fresh / resume)与续跑配置不带它(引擎:续跑配置带词即拒 `config.run_origin_invalid`,本服务的续跑配置触不到这一拒)。要在本服务上盖词,得先有一条可信的触发路径(设计件),不在本版。
587
+ **谁需要**:渲染 `human_input` 帧 / inbox / 会话的壳(cli · client-core · web-client)—— 把调度者的输入渲成调度者的;读审计面的运维。**谁受伤**:严格按键白名单解析这三个面的消费方(多一个可选键,只在引擎记了词时在场);按 `differs` 全集穷举分支的客户端(多一词)。**补偿**:无旋钮;键缺席是常态,读成「宿主没说话」;未知键忽略。
588
+ **升级前做**:无。
589
+ **混版升级序(只在有人铸词时才有)**:只跑本服务的部署上没有带词的停驻行 / 带词的 steer / 带词的唤醒,混版窗零影响;本版读旧副本写下的行 / 帧 / 清单 = 没有词 ⇒ 四面缺席,与上一版逐字同。部署里另有铸词方(嵌入方自带 `resolveSpec`;与本服务共用检查点库的仓外调度 daemon)时,引擎 7.58.0 给的序是 —— **先把全部 worker 与店适配器升到引擎 ≥ 7.58.0(本版引擎 7.66.0),再让铸词方开始铸词**。引擎的话:引擎 < 7.58.0 的 worker 把带词的停驻行读成「格式比本引擎新」
590
+ (本服务把它答成 409 `checkpoint.unsupported_version`、`retriable: true`、行留 pending,体带 `writerVersion` / `readerVersion`,换成新 worker 再决),对带词的唤醒消息或 `setPendingSteer` 在认领之前拒(未知的转向字段);旧 worker 认领新宿主停驻的带词 steer、又在投递前重停它时,旧 worker 自己的写口会拒这条目 —— **那条指令丢**。
591
+ **回滚**:回到上一版:三个面少一个可选键;无持久面变更(本服务没有写下任何带这个词的字节)。
592
+
593
+ 71. **🔴 `LSP_ENABLED` 退役:设了它(任一值)的部署起服拒 `config.env_key_retired`;沙箱车道的 LSP 桥与它的四族指标删除(BREAKING,部署;每条车道的挂载与上一版逐格同;wire 行为零变化;部署动作:撤掉 `LSP_ENABLED`)**:
594
+ 旧形:e2b / k8s 设 `LSP_ENABLED=true` 照常起服并打一行 `lsp_not_mounted`(7.127.0 起这两条车道本来就不挂 LSP:引擎只读执行环境绑定持有的对象,沙箱两车道不实现绑定读);
595
+ `LSP_ENABLED=false` 拒启,但拒句是本服务另铸的一句、不带墓碑码;`/metrics` 恒出 `lsp_bridge_start_total` / `lsp_bridge_dead_total` / `lsp_session_open_total` / `lsp_session_heal_total` 四族(只有 HELP / TYPE,零样本)。
596
+ 新形:`LSP_ENABLED` 是 settings-schema 墓碑表的一行(族 `removed`):在场即拒启,`true` / `false` 同码同句,拒句点名 host 车道的开关 `LSP_HOST_ENABLED`;空串 = 未设,照常起服。
597
+ 配置目录 `GET /v1/config/catalog` 的 `retired[]` 多一条 `{ name: "LSP_ENABLED", kind: "removed", reason }`、`rows[]` 少这一行;起服行 `lsp_not_mounted` 没了;`/metrics` 少上面四族。
598
+ **挂载律不变,只是收成一处**:本机语言服务器只在 host 车道、未设 `REQUIRE_PRINCIPAL=true` 时按 `LSP_HOST_ENABLED`(缺省开)挂,其余车道一律不挂 —— 与上一版逐格同;服务入口与 `run-local` 读同一只铸点。`wiring_manifest.lsp` 的形与在场律不变。
599
+ **做法**:撤掉 `LSP_ENABLED`(e2b / k8s 上本来就没有 LSP,撤掉之后行为零变化);要关 host 车道的语言服务器用 `LSP_HOST_ENABLED=false`。抓 `/metrics` 的面板删掉那四族(它们自 7.127.0 起恒零)。
600
+ 运维面:e2b 模板月度重烤的缺省名单去掉 `ai-agent-code-lsp`(不再维护,用 `dev-base`);三只模板的 verify 只证语言服务器在场(`command -v` + 版本读数),不再跑桥。
601
+ **谁需要**:读配置的人 —— 一个开了也什么都不挂的旋钮被换成一句真话(这两条车道没有 LSP);维护者 —— 挂载判据只剩一处。
602
+ **谁受伤**:① 设了 `LSP_ENABLED`(任一值)的部署升级后起服拒(此前 `true` 只换来一行告警);② 想在沙箱车道上要代码导航的人 —— 桥只在版本史里,回来要先有沙箱车道的绑定读,再另做设计;③ 抓那四族指标的面板。
603
+ **补偿**:拒句由墓碑表铸、点名旋钮与出路;本条;没有过渡窗。
604
+ **回滚**:回到上一版:`LSP_ENABLED` 重新被读(`true` 起服带一行告警、`false` 拒启);无持久面变更。
605
+
606
+ 72. **场景技能范围:内建 `code` 场景按自己的名字过滤部署技能 —— 只标了 `scenarios: code` 的技能开始进 `code` 的 run 与卡,只写 `scenarios: default` 的技能不再漏进 `code`(行为修复;wire 键 / 型 / 码零变化、读数变;零 DDL、零新旋钮;部署动作:靠 `code` 场景拿到 `default` 技能的部署,升级前在那些技能的原标签之外追加 `code`)**:
607
+ 旧形:技能范围从一张表读,`code` 一行是 `default`(`code` 与 `default` 共用一只场景工厂,技能范围跟着借走)—— 只标了 `scenarios: code` 的技能,`code` 与 `default` 的 run 与卡上都没有(标签里另有别的场景名的,只进那些场景);只写 `scenarios: default` 的技能同时进 `default` 与 `code`。
608
+ 新形:每个内建场景的技能范围就是它自己的名字:只标 `code` 的技能进 `code`(出厂缺省场景:`DEFAULT_SCENARIO` 缺省 `code`、无中心指派时,不带 `scenario` 的请求落在这里)、不进 `default`;只写 `default` 的技能进 `default`、不进 `code`;无标签的全局技能与 `scenarios: code, default` 两边都进。
609
+ 进 run 的技能、场景卡 `GET /v1/capabilities/scenarios/<name>` 的 `skills`、提交体 `userInvokedSkills` 的点名门读同一个范围,三处同步变。三条来路(`SKILLS_DIR` / 配置源 `config.d/skills.json` 或中心 skills 域 / 插件)同一条律。随包出厂技能不受影响(只有 `code-review` 打了场景标签,标的是 `code-review`)。
610
+ **谁需要**:想让技能只在编码场景出现、只标了 `scenarios: code` 的人;按场景分流技能的部署。
611
+ **谁受伤**:靠「只写 `default` 的技能漏进 `code`」拿到技能的部署 —— 升级后落在 `code` 的请求(不带 `scenario` 且无中心指派、`DEFAULT_SCENARIO` 缺省,或显式 `scenario:"code"`)不再装这些技能,点名它们 400 `config.user_invoked_skill_unknown`;只标了 `code` 的技能开始出现在 `code` 的 run 里(占技能清单与上下文)。
612
+ **补偿**:不提供「回到旧读法」旋钮(那就是第二个读者);技能自己的 `scenarios` 标签就是出路(下条)。
613
+ **升级前做**:列出部署里所有 `scenarios` 含 `default` 的技能(出厂目录的 `scenarios:` 行、`config.d/skills.json` 或中心 skills 域条目的 `scenarios`、插件技能的 frontmatter),逐条判断它要不要继续出现在 `code` 的 run 里:要 ⇒ 在**原标签之外追加** `code`(`default` → `default, code`;`default, scan` → `default, scan, code` —— 不要覆盖原有场景名,否则它会离开那些场景),或去掉 `scenarios` 变全局技能(那就进所有场景);不要 ⇒ 不动。
614
+ 同时列出含 `code` 的技能:升级后它们开始进 `code` 的 run(此前只标了 `code` 的哪个内建场景都没进;标了 `code, cowork` 这类多标签的此前已进 `cowork`),确认这正是你写它时的意图。配置源 / 插件的改动按各自的「重启生效」走(`/health` 的 `restart.reasons` 含 `skills`)。
615
+ **回滚**:回到上一版即回到旧读法;零持久面变更。
616
+ 73. **`DB_BACKEND=local`:`run-local` 与 HTTP 服务共用一个数据根时,同一只会话在两条入口上是同一位住客;一次性迁移 M47(无格会话收进行、沿用存档里的令牌);跳过 M47 的数据根拒启(行为修复;持久面一次性迁移,零 DDL;部署零动作)**
617
+ 旧形:一个数据根两只会话行店。HTTP 服务的 local 臂读会话元数据边档(`session-incarnations.json`)那一格的化身;`run-local` 经引擎的裸会话店读会话存档头上引擎另铸的那只令牌(两只恒不等,HTTP 每整段换装一次存档头还换代)。
618
+ 同一只会话在两条入口上是两位住客:一条入口上落下的记忆记录(`memory.capture:"off"` 的采集 opt-out、外部内容带来的污染标记)在另一条入口上不绑;`run-local` 新建的会话没有元数据格,不过引擎版本高水位与起服对账。
619
+ 新形:`run-local` 与 HTTP 服务的 local 臂经同一只打开函数打开数据根(取锁 → 引擎版本高水位的判与抬 → 本服务的店 → 起服对账 → 一次性迁移 → 才读会话);住客只有一处存放(那一格)。
620
+ **一次性迁移 M47(只 `DB_BACKEND=local`;零 DDL)**:升级后第一次起动(HTTP 服务或 `run-local`)给「存档在、会话元数据格缺」的会话建一格 —— 化身 = 存档头上的令牌(较早 `run-local` 的记忆记录绑的那一位;头里没有令牌 ⇒ 新铸),
621
+ 建档时刻 / fork 谱系取自存档头,属主不写(从没被记下)。已有格的会话一个字节不动。在起服对账段里跑、先于其余一次性迁移;一次边档提交;第二次起零命中。读数键 `localArchiveTokensAdopted` / `localArchiveTokensMinted`(起服迁移读数行;非零 = 真写了存量行)。
622
+ **窗** = 本版发布日 + 30 天(窗口见 `plugins/one-time-migrations.ts` 登记表);窗关之后第一个 minor 删迁移体与读数键。SQL 两后端没有存档头,读数恒 0。
623
+ **第一次起动被打断(收令牌欠账)**:引擎版本高水位在打开数据根那一刻就抬(先于 M47)。所以带 M47 的版本打开这只根时(高水位之前早于 7.148.0 或缺席、会话存档目录里有存档),
624
+ 在抬之前先在数据根顶层写一只 `archive-token-adoption.pending`(本服务内部的欠账记录,不是契约,宿主不读);M47 收齐、并按跳版拒启臂同一读法证明没有漏收之后才删它。
625
+ 第一次 7.148.x 起动被打断(进程被杀、M47 的写失败、嵌入方不调 `ensureSchema()`、会话目录列不出 ……)⇒ 它留着,下一次窗内起服重来;**收完之前,不带 M47 的版本拒开这只根**。
626
+ 标记在而根里已没有「存档在、格缺」的会话(收齐之后、删之前停了)⇒ 无事可收:打开它的任何版本在抬高水位之前删掉它、照起。
627
+ 起动时会话存档目录读不出 ⇒ 带 M47 的版本打开即拒(不抬高水位)。
628
+ M47 收不了的两类不挡销账:委派子代的转录(placed)、存档头读不出的会话(每只一行 warn `archive_token_adoption_skipped` 点名)—— 后者若到窗关之后才读得出,第一次读新铸令牌,那只会话的旧 `run-local` 记忆记录失绑(只响一行引擎事件)。
629
+ 窗内按 id 打开、登记一只还没格的旧会话(不调 `ensureSchema()` 的嵌入方也一样)同样沿用存档头令牌 —— 长第一格只有这一条规则。
630
+ **跳版拒启(常设,不随 M47 删)**:起动的版本已不带 M47,数据根里有「存档在、格缺」的会话,而打开之前的引擎高水位早于 7.148.0 或缺席,或 `archive-token-adoption.pending` 还在 ⇒ 起服拒 `config.schema_mismatch`
631
+ (`findings` 一段 `problem: "skipped-required-migration"`,带 `skippedMigration: { highWater, requiredSince, sessions }`;拒句点名会话数与版本;标记还在的那一种说「没收完」并点名标记文件)。拒在高水位抬之前、本服务零写(引擎内核取锁时自己的收拢除外,见 USAGE 高水位一节的「残余」):
632
+ 出路 = 先用一个仍带 M47、不低于 7.148.0 且不低于拒句里已记高水位的版本(HTTP 服务或 `run-local`)对这只根**完整**起一次(起服迁移读数行出现、`archive-token-adoption.pending` 不在),再起新版。
633
+ 带 M47 的版本不判这一道。拒句的闭集出路多一条(四条)。
634
+ **变了的(如实)**:① 已有元数据格、升级前 `run-local` 在存档令牌下落过记忆记录的会话(含 7.141.0 起 HTTP 服务起服时给 `run-local` 建的会话补过格的那些)——
635
+ 那些记录升级后在 `run-local` 上也不再生效(它们在 HTTP 上从来不生效):引擎每只实例每会话只响一行 `memory.session_incarnation_mismatch`(不分记录类别,第一条被判作另一位住客的记录响;`run-local` 每跑一次即一只实例;令牌只留前 8 位);
636
+ 其余静默,但那时 HTTP 上的同类记录照旧生效。需要时在那只会话上重提一次 `memory.capture:"off"`;污染标记没有可重提的用户动词。
637
+ ② `run-local` 起动多跑一遍起服对账与一次性迁移(升级后第一次慢一截);HTTP 服务拒启的数据根(会话元数据读不出、残留迁移快照、引擎高水位高于本构建、跳版)现在也挡住 `run-local`(一行 + 退 2)。
638
+ ③ `run-local` 写引擎版本高水位:此后比它旧的 HTTP 服务拒开这只根(与升级 HTTP 服务同一事实)。④ 会话同步导入落在「不在」的会话上时,不再读存档头当期望行:读间被抢建的存档答 `conflict`、零写。
639
+ **谁需要**:同一数据根上既起 HTTP 服务又用 `run-local` 的单机用户。**谁受伤**:见「变了的」①②。**补偿**:重提一次 opt-out;拒句自带出路。不设旋钮(住客只有一种读法)。
640
+ **升级前做**:备份数据根(回滚的唯一支持形)。部署零动作(零 DDL、零新旋钮)。
641
+ **回滚**:比本版旧的 HTTP 服务本来就拒开升级过的根(引擎版本高水位)。较早的 `run-local` 不读高水位、仍开得了它,但它读存档头令牌 —— 升级后新写的记忆记录它读不全,
642
+ 升级前那类旧会话与今天同病;**升级后不要再用较早的 `run-local` 打开这只根**,要回滚就恢复升级前的数据根备份。
643
+
644
+ 74. **`run_workflow` 问句门读会话豁免店改走与部署名单门同一只读口;一次性迁移 M46 删存量的引擎家 `Skill` 会话豁免行(行为收紧;wire 零新键、零新码;持久面:一次性迁移 M46,零 DDL;部署零动作,按旧事件名告警的运维有动作)**:
645
+ 旧形:会话豁免店有两种读法。部署名单门与审批席读它是 2 s 有界、答 `true` 才算命中、读失败照问,命中的审计行是 `approval_exempted`;`run_workflow` 问句门在装配点自包一只读口 —— 无期限、真值判、审计事件名 `workflow_gate_exempted`。
646
+ 店读黑洞化的那一次(连接被吞、池饿死)`Workflow` 调用永久悬挂;店答非布尔真值照样放行。另有一类存量行:更早版本(7.116.0 之前)为带摘要的 `Skill` 卡与点名 `Skill` 的名单问落下的 `(会话, "Skill")` 豁免行,
647
+ 今天它代答「不绑授予」的同名调用 —— 引擎说无技能时不挂自己的 `Skill`,同名调用是部署自挂的**另一只工具**,当年批的是「激活某技能」,代答的却是这只工具的调用(扩权,不是子集)。
648
+ 新形:读口一只铸点。名单门与 `run_workflow` 问句门经同一只读口:期限 2 s、判 `=== true`、读失败 / 超时 ⇒ 照问并 warn `session_grant_read_failed`(字段 `seat`:`deployment_list` / `workflow_gate`)、命中 ⇒ 一行 info `approval_exempted`(字段 `seat`)。
649
+ 事件 `workflow_gate_exempted` 退役。存量 `Skill` 行由一次性迁移 M46 删;读者一字不改,没有新列、没有按时间分流的读侧臂。
650
+ **一次性迁移 M46(存量的引擎家 `Skill` 豁免行;零 DDL)**:起服时(任何读者之前)删 `tool_name` = 引擎 `Skill` 工具名、首次放行(`created_at`)早于 T0 的行;**T0 = 本库第一次跑本步的时刻,先于删除落进标记**
651
+ (SQL:标记表 `one_time_migration_marker` 的 `M46` 行,与 M42 / M43 同一张;`DB_BACKEND=local`:数据根里的 `one-time-migration-M46.marker`(正文 = T0 的 ISO 时刻)),不按日历截(各部署升级日不同,日历截点会漏掉跳版直升的库里升级前几天写下的行)。
652
+ 第一次删升级前就在的全部 `Skill` 行 —— 不管哪一版写的:7.138.0–7.147.x 写下的合法行(部署自挂 `Skill`、无技能、「本会话放行」)一并删,方向 = 那些会话的人下一次 `Skill` 调用被问一次;之后各跑零命中、不碰本版自己写下的新行。
653
+ SQL:`session_id` 键集分批(每页 500 个会话),一页一句 `DELETE … IN`(删句自带 T0 谓词,读与删之间被撤销又重新放行的行不删);被打断 ⇒ 下一次起服读同一个 T0 接着删。`DB_BACKEND=local`:对命中行逐会话追加墓碑(与按名撤销同形),日志已判坏的会话不碰;标记文件在而读不出(手改坏了)⇒ 起服拒并点名文件,删掉它再起(本步取新的 T0)。
654
+ 读数键 `legacySkillExemptionsDropped`(起服迁移读数行;非零 ⇒ 另有一行 warn `legacy_skill_exemptions_dropped`)。无停-迁-起守卫(更早版本的副本窗内写下的 `Skill` 行是它们当时合法的行,T0 前后两个方向都是重问)。
655
+ **窗** = 本版发布日 + 30 天(窗口见 `plugins/one-time-migrations.ts` 登记表);窗关之后第一个 minor 删迁移步与读数键。跳过本版直接升上来的库,存量 `Skill` 行照旧代答「不绑授予」的同名调用;出路 = 升级时先过一次本版并起服(或手工 `DELETE FROM approval_exemption WHERE tool_name = 'Skill'` / 删会话)。
656
+ **文书改真(行为不变)**:豁免店的行 = 停驻行的 `remember:"session"` / 应答口 `allow_session` 与活卡上**名单自己的问**点的 `allow_session`;活卡上对**引擎的问**点的「本会话放行」记在审批席的进程内表(按副本、随进程),**不在**
657
+ `GET /v1/approvals/:sessionId/exemptions` 的列表里、`DELETE …/exemptions/:toolName` 撤不到(回 `revoked:true` 只说耐久那一行没了)、删会话与留存清理清不掉、换副本 / 重启即失。这是 7.106.0 起的形,本版只把文书写真;收口另有后续。
658
+ **谁需要**:读豁免列表决定「要不要撤」的人(会话面板、sdk 调用方、运维排障);开了 Workflow 自编排的部署(店慢 / 店坏时照问、不挂死)。
659
+ **谁受伤**:① 店读超 2 s 的 `Workflow` 调用(多问一次),店答非布尔真值的部署;② 升级前就在的 `Skill` 豁免行所在会话的人(下一次 `Skill` 调用多问一次);③ 按 `workflow_gate_exempted` 检索 / 告警的运维;
660
+ ④ 活卡上对引擎的问点过「本会话放行」的人 —— 列表仍空、无处可撤(未变,本版写真)。
661
+ **补偿**:前两项方向都是多问一次、没有新旋钮;事件改读 `approval_exempted` 且 `seat:"workflow_gate"`;④ 今天只有等副本重启 / 进程内表逐出(结束会话不算)。
662
+ **升级前做**:读 `workflow_gate_exempted` 的告警 / 检索改成 `approval_exempted` + `seat:"workflow_gate"`。部署零动作(策略构造函数的形变是内部接口,包根不导出)。
663
+ **回滚**:零 DDL。被 M46 删掉的行不会回来(回到 7.147.x 即那些会话的人下一次 `Skill` 调用被问一次,没有数据要还原);标记表里的 `M46` 行与数据根里的标记文件对 7.147.x 无害、无人读。回到 7.147.x 即回到两种读法。
664
+
665
+ 75. **人在环三族一条投递律:经腿投出的问题 / 表单 / 审批帧先落本 run 账本、再写 live,账本落不下 ⇒ 这一帧不上 live;sync 流腿的撤卡帧与旧族审批帧随账本回放;detach 断连之后才发起的问题不再当场放掉,卡在回放里等窗(行为变更;wire 帧型 / 键 / 码零变化;零 DDL;部署零动作)**:
666
+ 旧形:sync 流腿(`POST /v1/tasks/stream`)上,呈卡族审批卡账本与 live 并行写、任一接下即送到;撤卡帧 `approval_revoke` 与旧族 `tool_approval` / `tool_approval_complete` 只写 live,
667
+ 回放(`GET /v1/runs/:id/events`)里没有;问题卡在直写面已断(detach 断连之后才发起、或开帧落账那一刻面断)时当场按 `unavailable` 放掉,账本落下了也一样。
668
+ 新形:三族同一条律 —— 有 durable run 行的 sync 流腿先落本 run 账本、再写 live;账本落不下 ⇒ 这一帧不上 live。审批卡在 run 店写失败 / 挂住时这条连接不再 live 呈卡
669
+ (它若是唯一投递目标 ⇒ 按无人值守政策收场:缺省停驻,`UNATTENDED_APPROVAL_POLICY=deny` 时部署政策拒);收帧 / 撤卡帧账本写失败时同连接 live 也不收。
670
+ 回放里新增 sync 流腿的撤卡行与旧族 worker 的审批行。detach 断连之后才发起的问题(判决面已放行)卡落账本、等窗或被重连者答 —— 最多多等一个无人应答窗
671
+ (`QUESTION_TTL_MS`,出厂 5 分钟)。无 durable run 行的部署:表单开帧写向已断的流当场 `cancel`(此前满窗才 `cancel`)。后台 / 续跑腿逐字不变。
672
+ 运维面:三只 fail-open 计数退役 —— `server.hitl.frame-undelivered-stream-closed`(无账本部署上表单开帧写向已断的流)改由既有的 `server.elicitation.open-frame-undelivered` 计
673
+ (这一形自此当场 `cancel`);`server.question.complete-breadcrumb-dropped` / `server.elicitation.complete-breadcrumb-dropped`(收帧丢失)并进新的 `server.hitl.close-frame-dropped`
674
+ (问题 / 表单 / 审批三族的收帧与撤卡帧同一只,探针行带 `frame=`)。
675
+ **谁需要**:重载 / 重连后要从回放取回审批卡、撤卡与问题卡的壳;detach 断连后想回来答问题的人。
676
+ **谁受伤**:run 店写挂住时仍想在 live 上先答审批的人(尤其同会话别的 run 投来的问,此前照样呈出);detach 断连后的问题多等一个窗;按旧 tag 读 fail-open 计数的面板。
677
+ **补偿**:停驻的卡经 `GET /v1/approvals` 取回、`POST /v1/approvals/:sessionId/decide` 补批;账本写失败照旧有响亮计数;窗长由 `QUESTION_TTL_MS` 调。
678
+ **升级前做**:无;按 tag 读 fail-open 计数的面板:开帧那一只换读 `server.elicitation.open-frame-undelivered`,两只收帧计数换读 `server.hitl.close-frame-dropped`。
679
+ **回滚**:回到上一版即回到三种投法;零持久面变更(新增的账本行都是既有事件型,上一版读得动)。
680
+
681
+ 76. **`settings.hooks` 的 `Stop` 条目不再在委派子代结束时跑;`wiring_manifest.mods[].events` 不再列 `classic.SubagentStop`(行为变更;wire 值变化:注册的事件列表少一站;部署零动作)**:
682
+ 旧形:请求钩子的车道注册把 `Stop` 挂在两站 —— 主任务的停车点 `classic.Stop` 与委派子代的停车点 `classic.SubagentStop`;子代(同步 / 后台,含续跑的子代)结束时同一批 `Stop` 条目再跑一次,
683
+ 载荷写 `hook_event_name: "Stop"`,条目的推回作用在子代上;`once` 的 `Stop` 条目可能被子代那一次用掉。`SubagentStop` 条目服务端不跑(契约判给壳)。
684
+ 新形:`Stop` 只挂 `classic.Stop`(一事件一站,与参照实现同读:停车点按子代身份二选一);子代结束时服务端不跑任何 `Stop` / `SubagentStop` 条目。主任务结束时逐字不变。
685
+ `wiring_manifest.mods[]` 里 `settings.hooks` / `settings.hooks.managed` 的 `events` 不再含 `classic.SubagentStop`。
686
+ **谁需要**:照参照实现写 `Stop` 条件钩子的用户 —— 子代不再按主任务的条件被推回,同一守卫不再在子代上多跑一次。
687
+ **谁受伤**:靠 `Stop` 条目兼管子代结束的配置(子代结束不再有服务端请求钩子);按字面断言 `events` 含 `classic.SubagentStop` 的面板 / 脚本。
688
+ **补偿**:子代结束的守卫写成 `SubagentStop` 条目(壳属主,壳跑);运维要在服务端判子代结束,在部署座声明挂 `classic.SubagentStop` 的链成员。
689
+ **升级前做**:把兼管子代结束的 `Stop` 条目改写成 `SubagentStop` 条目;按 `events` 字面读的面板去掉 `classic.SubagentStop`。
690
+ **回滚**:回到上一版即恢复两站挂法(零持久面)。
691
+
692
+ 77. **hook 条目的 `once` 按结局消耗:一次请求里只在它成功之后算用掉,失败 / 拦下 / 没执行的那一次不算(行为变更;wire 零新键、零新码;部署零动作)**:
693
+ 旧形:同步的 `once` 条目(command 非 async / http / prompt / agent)在起跑之前就记成已用 —— 起不来、超时、退出非 0 非 2、输出读不成判词、闭集外判词、退出 2、`decision:"block"`、
694
+ `permissionDecision:"deny"` 的那一次之后,这次请求里它都不再跑;`async` / `asyncRewake` 条目交出即用掉。
695
+ 新形:判决只读一处 —— 这次事件的钩子翻译交出的判决(拒 / 拦 / 继续)同时决定拦停与 `once` 消耗。判决不是拒 / 拦 ⇒ 跑完且给出了裁决的 `once` 条目用掉
696
+ (`allow` / `ask` / 只给上下文 / 无输出;`PostToolUse` / `PostToolUseFailure` / `PostToolBatch` 的退出 2 与 `decision:"block"` 是反馈、也算;`Stop` × prompt 判词 `ok:false` 带 `impossible:true` 不拦停、也算);
697
+ 判决是拒 / 拦(`PreToolUse` 拒调用:退出 2 / `decision:"block"` / `permissionDecision:"deny"` / `continue:false`;`UserPromptSubmit` / `PreCompact` 交拦;`Stop` 本车道推回)⇒ 这次事件里跑过的 `once` 条目都不用掉;
698
+ 失败(没给出可采信的裁决,含观察站 `StopFailure` / `PostCompact` 上的退出 2、`PreToolUse` 上判在截断标记上的判词)与没执行(`if` 不匹配、matcher 不选、前面的组已经否决、墙钟耗尽、引擎叫停)都不用掉,
699
+ 下一次事件照跑;`async` / `asyncRewake` 照旧交出即用掉;托管相改写输入而整相重判时,作废的第一遍不决定消耗(只结算重判那一遍)。作用域不变:一次请求、每条车道一份去重账;
700
+ 账上记的是条目本身(不再按位置号:`Stop` 上 prompt 条目因证据不足被滤掉时,后面的条目不再用掉它那一格)。
701
+ **谁需要**:写 `once` 守卫的壳与嵌入方 —— 守卫失败一次不再在这次请求里永久失效,拦下一次不再放行下一次同类调用。
702
+ **谁受伤**:靠「`once` = 只试一次」做有副作用的初始化、而它会失败或拦下的配置(现在每次事件都重试,直到成功一次);同一请求里并发的两次事件上,成功之前的 `once` 条目可能各跑一次。
703
+ **补偿**:要「只试一次」的条目在命令里自己记标记文件(第二次直接退出 0)。
704
+ **升级前做**:无;依赖旧语义(失败即用掉)的 `once` 条目按上一条改写。
705
+ **回滚**:回到上一版即恢复起跑前用掉(零持久面)。
706
+
707
+ 78. **记忆面「定店 / 控制面说不清」一种答法:整理状态 · 中心记忆导出 · 中心记忆同步 · 会话记忆状态四口的控制面损坏改答 `500 internal.memory_control_plane_corrupt`,会话记忆抹除口的层拒改答 `400 request.memory_layer`(wire BREAKING:五口错误码值变;零持久面;部署零动作)**:
708
+ 旧形:这五形答通用 `500 internal.error`(四口控制面损坏的句子只有「… failed」,会话记忆抹除口把「请求可以改对」说成服务器坏了)。
709
+ 新形:九只记忆面对这一个故障源同答两形 —— 层拒 `400 request.memory_layer`、控制面损坏 `500 internal.memory_control_plane_corrupt`;operator 带引擎原句,
710
+ 中心记忆导出 / 同步的非 operator 层属主与会话所有者两口拿固定句(会话记忆状态一句只说「控制面读不清,运维修好后再读」),原句落运维行
711
+ (`memory_export_refused` / `memory_sync_refused` / `session_memory_status_refused` / `session_memory_erase_refused`);这两形不再落 `memory_export_failed` / `memory_sync_failed` / `request_error` 行。
712
+ 同批另一形(自由文本,不是码):SQL 记忆腿(`MEMORY_ENGINE_BACKEND=pg|mysql`)上目标名被别的条目占着的 update,冲突句由 `io error: <驱动原文>` 改为一句两方言同字的判者句,
713
+ 记忆同步口 `conflicts[].reason` 上可见。
714
+ **谁受伤**:按 `errorCode === "internal.error"` 判「记忆面坏了」的读者;按 `io error` 前缀给这一形报 I/O 故障的读者。
715
+ **补偿**:两个码都是错误码目录里既有的码,消费端按码分支;不加旋钮。**升级前做**:无。**回滚**:回到上一版即恢复旧答(零持久面变更)。
716
+ 79. **`DB_BACKEND=local`:运维队列行的身份格只读引擎对这一行的摘要 —— 引擎读不动的行不再从存储体回填任何一格、`createdAt` 读不成有限数 ⇒ 缺席;到期两扫按引擎的截止读法,截止或建行时刻读不成有限数的待决行升级后下一拍过期;嵌入方类型面 `PendingCheckpoint.createdAt` 变可选(嵌入方类型面 BREAKING;wire:local 坏行上的键可缺席 / 为 `null`;行为修复;零 DDL;部署零动作)**:
717
+ 旧形:local 运维队列(`GET /v1/approvals` · `/v1/approvals/stream` 的 `pending`)行的身份格与卡格取存储体原值 —— 引擎判坏的行照样带 `createdAt`(可以不是数)、`deadline`、`checkpointId`、
718
+ 绑定、描述符、卡位与 park 事实;同一行在收件箱上只带引擎读得出的身份。到期两扫自算截止(`deadline <= cutoff`):截止不是数的行永不过期;建行时刻不是数的行终局兜底永不触发,行永挂 pending。
719
+ 新形:身份格(`sessionId` / `scope` / `gateKind` / `createdAt` / `deadline` / `checkpointId`)读引擎对这一行投的摘要,好行与坏行同一读法、与收件箱同一读法;
720
+ 摘要读不动的行只带身份 + `rowVerdict` + `taskId`,`toolName` / `toolCallId` / `input` / `riskDescriptor` 为 `null`,`createdAt` 读不出 ⇒ 缺席、`deadline` 读不出 ⇒ `null`,其余可选键缺席
721
+ (路由层照常补的 `kind` / `rememberRefused` / `agent` 照带);
722
+ 好行门上的描述符在场却不是对象 ⇒ `riskDescriptor: null` + 计 `server.approvals.risk-descriptor-cell-unreadable`(与 SQL 后端同一只形读者、同一个计数)。
723
+ 到期两扫的截止判是引擎的 `checkpointDeadlinePassed`(在场而非有限数 ⇒ 已过);终局兜底公式的两格(建行时刻、截止)任一读不成有限数 ⇒ 兜底已过,下一拍过期 ——
724
+ 拒扫认领的门也一样(这种行引擎判坏,拒扫拒不成,不再每拍占一格拒扫窗)。
725
+ 队列与收件箱同一只分诊序(严重度降序、`createdAt` 升序;缺席或读不成有限数计 0 = 档内最老)。嵌入方导出型 `PendingCheckpoint.createdAt: number` 改为 `createdAt?: number`(零别名;SQL 后端恒在场)。
726
+ **谁需要**:local 上读审批队列的壳(同一坏行在收件箱与队列上同答);运维(坏行不再永挂 pending)。
727
+ **谁受伤**:按 `createdAt` 必在解析队列行的消费方(local 坏行上缺席);直接把 `PendingCheckpoint.createdAt` 当数用的嵌入方(TypeScript 编译红即通知);
728
+ local 上截止 / 建行时刻不是数的待决行在升级后第一拍被过期(这种行引擎判坏、本就续不了)。
729
+ **补偿**:按 `rowVerdict` 渲坏行;`createdAt` 缺席按档内最老排(与收件箱同读);被过期的行重跑任务。
730
+ **升级前做**:无;嵌入方把 `createdAt` 的读点改成可缺席。
731
+ **回滚**:回到上一版即回到存储体回填与自算截止;零持久面变更。
732
+ 80. **🔴 能力位 `rewindFiles` 删除:「这台部署能不能还原文件」只有 `restoreFiles` 一只位(wire BREAKING,读侧;零别名;零新码、零 DDL;部署零动作)**:
733
+ 旧形:`GET /v1/capabilities` 同时铸 `rewindFiles` 与 `restoreFiles`,两位同谓词(文件历史店在场)、恒同值。
734
+ 新形:`rewindFiles` 不再铸;`restoreFiles` 是唯一的还原位(值与旧 `rewindFiles` 逐字相同)。`rewindFilesTo` = `restoreFiles` ∧ `resumeAt`(谓词不变,只是文书改读唯一的那一位)。
735
+ **谁需要**:读能力位决定 `/rewind` 档位的客户端(一个事实一只位)。
736
+ **谁受伤**:仍按 `rewindFiles` 判「对话 + 代码」档的客户端 —— 在没有文件历史店的部署上该档从「不可用」退成「判不出」(照常给档,还原那一半由服务端如实拒)。
737
+ **补偿**:改读 `restoreFiles`。它自 7.52.0 起就与旧位同谓词同值,改读之后在任何受支持的 server 上读数不变,不需要按版本分流。
738
+ **升级前做**:客户端把 `capabilities.rewindFiles` 的读点换成 `capabilities.restoreFiles`(sdk 型面删这只键,tsc 红即通知)。部署零动作。
739
+ **回滚**:回到上一版即两位同铸;零持久面变更。
740
+
741
+ 81. **钥匙保管目录的首把钥匙只有一个创建口:多个副本在同一个空目录上同时首启只出一把(目录里没有可装载的钥匙时,先以 `wx` 独占创建 `<保管目录>/.keygen.lock` 分先后;模型钥匙与停驻行封签两个域同一律;行为修复;盘上多一只瞬时文件;零 DDL、wire 零变;部署零动作)**:
742
+ 旧形:保管店装载是「读目录 → 一把可装载的都没有 ⇒ 生成一把写文件」,读写之间没有互斥,钥匙文件按自己的指纹命名(两个副本生成的钥匙名字不同,独占创建挡不住):共享卷上多个副本在空目录上同时首启可能各建一把、各持自己那一把、互相答 `stale_ciphertext` / `key_not_held`,直到各自重启;所以首装要「先起一个副本再起其余」或首装后 `rollout restart` 一次。
743
+ 新形:创建口只有一个。目录里没有可装载的钥匙时,副本以 `wx`(`O_CREAT | O_EXCL`)独占创建互斥文件 `<保管目录>/.keygen.lock`;拿到的那一个再读一次目录、仍空才生成,经原子写(tmp 独占新建 + `rename`,模式 0600)发布后撤互斥;没拿到的重读目录,有钥匙就用它,最多等 15 秒,仍没有 ⇒ 建店失败(句子点名互斥文件的路径与出路),不越过别人的互斥自己生成。互斥只在目录里没有钥匙时才被问到,已有钥匙的目录起服零等待。
744
+ **谁需要**:共享保管卷的多副本部署(sema-up 图表多副本 RWX 首装、自备共享卷):首装并发起服不再需要「先起一个再起其余」与事后重启。
745
+ **谁受伤**:无新增拒绝面,除「目录里没有钥匙、互斥被别人占着超过 15 秒」(拿着互斥的进程崩在生成中途遗留 ⇒ 之后每次起服等 15 秒后建店失败,声明了 `SEALED_KEY_DIR` 或耐久审批在场 ⇒ 起服拒,否则告警);把保管目录里每个条目都当钥匙文件处理的外部脚本会看到一只瞬时的 `.keygen.lock`(不以 `.json` 结尾)。
746
+ **补偿**:崩溃遗留 ⇒ 没有副本正在起服时删掉拒句点名的互斥文件再起;外部脚本认 `*.json`。
747
+ **已知限制**:互斥的原子性取决于共享卷的 `O_EXCL` 独占创建(本地盘与 NFSv3 及以上按协议满足,别的网络文件系统请向存储方确认),且拿到互斥之后那一次读目录要读到别的客户端刚发布的文件(按网络文件系统客户端语义的推断,未在真实 RWX 存储类上验过);7.147.x 及更早的副本不取互斥,新旧版本混跑在同一个空目录上同时首启时旧副本仍可能另建一把;已经分叉的目录(多把钥匙)不会被合并,照旧重启一次让每个副本读到全部钥匙。
748
+ **升级前做**:无。**回滚**:回到上一版即回到「先读后写、没有互斥」(目录里留着的钥匙文件照常被读;互斥文件若恰在崩溃时遗留,上一版不认它,留着无害,可删)。
749
+
750
+ 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 的被丢条目载体行可带新词 —— 回滚见本条回滚句;部署零动作)**:
751
+ 旧形:逐条丢弃域(`models` `skills` `mcp` `plugins` `scenarios` `systems` `collab` `hosts` `projects` `a2a`)的条目体内带契约不认识的键 —— 契约读腿把键剥掉、报 `unknown-keys-dropped`,
752
+ 本服务把它折成域级错误:候选判官整份拒(起服 / 刷新 / 迟到起服同一只判官;起服一行 `config_candidate_rejected`,`domains` 含该域,回落盘上 LKG 或 env)。带未知键的条目若经别的读口放行,以剥过键的形装上。
753
+ `scenarios` / `plugins` / `skills` 里一条**坏形**条目(不是未知键,是形错)—— 只丢那一条、兄弟照装:被丢的覆盖条目让同名内建场景 / 同名出厂技能复活(带回它们自己更宽的工具面),被丢的引用让引用承运的 hooks 守卫缺席;
754
+ 线上的 skills 清单(`/effective` 的 `skills`)另走自己的一条读法 —— 恒逐条抢救、恒默认化:`skills: null` 读成空清单(零告警),同名两条都装。
755
+ 一张**值名单**(工具名单 / 范围名单 / 提示行)里坏一个元素 —— 只剔那个元素、条目带着更短的名单存活:被截短的拒绝名单(`skills[].disallowedTools`)比作者所写更松(少拒了作者要拒的),被截短的 `allowTools` 则少放了作者要放的(更窄,但同样不是作者写的那一张)。
756
+ 新形(条目缺席只会收窄可达面的七个域:`models` `mcp` `systems` `collab` `hosts` `projects` `a2a`):带未知键的条目整条丢 —— 逐条丢弃面一条 `entry-dropped`(日志行 `config_entry_dropped`,坐标 = 原文档下标,`reasonCode: "entry-unknown-key"`;诊断句点名那个未知键),
757
+ 目录条目同时进 `GET /v1/models.droppedEntries`(`{ index, reasonCode: "entry-unknown-key", identity? }`),其余条目照常服务、候选照收、零 `config_candidate_rejected`。
758
+ 新形(值名单,同七个域):**条目是对象,一张值名单是一个值** —— 名单里坏一个元素 ⇒ 持有它的那一条整条 `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`。
759
+ 新形(收紧域 `scenarios` / `plugins` / `skills`):不逐条丢。条目体内的未知键 ⇒ 剥键装上 + `unknown-keys-dropped`(本服务折成域级错误 ⇒ 候选判官整份拒:一行 `config_candidate_rejected`,`domains` 含 `scenarios` / `plugins` / `skills`;内建场景、守卫、出厂技能都不复活;拼错的 `disallowedtools` 不会以「没有拒绝名单」装上);
760
+ **坏形条目 ⇒ 整域读不进、读档 throw**:本地读腿(`config.d`)与中心读腿都整包抛,调用方整包回落 —— 起服:盘上 LKG,首启无 LKG 落回 env,起服行 `config_source_unreachable_using_env` 带 `cause: "rejected"`;
761
+ 刷新拍:`refreshNow()` 答 `failed`(运维刷新口 502)、`web_admin_refresh_failed` 带 `cause: "rejected"`,上一代继续服务。整份中心配置不收,而不是只丢那一条。
762
+ `skills` 的坏形条目 / 同名两条 / `skills: null`、`skills[].disallowedTools` / `allowedTools` 里的坏元素同走这一条(整域读不进,读档 throw;`null` 是坏形,缺席只有「键不在」一种);**线上清单与域文档同一只判官**(同两张表、同一只读法,只换判它的那张 schema:清单条目带 `contentHash`、域形条目带 `content`),中心发来的清单里任一条坏 ⇒ 整份候选不收。
763
+ 不变:域顶层的未知键(持键层不在任何条目体内)仍 `unknown-keys-dropped` ⇒ 整份拒;`tierGroups.<n>.tiers` 里五个档位词之外的键属条目体内未知键(见下);本来就不逐条丢的七个域(`rosters` `workers` `governance` `entitlement` `execution` `prompts` `limits`)不变;契约包的文档面不变。
764
+ 边界(如实,都是契约包的读法):丢这一条会让引用悬空 —— `roles` / `atMention` 点名的模型、活跃的 `tierGroups` 档位组带未知键 ⇒ 整个 `models` 域退缺省(候选门域错误、整份拒);
765
+ 一个顶层集合里的条目全带未知键(零幸存者;例:唯一一个档位组的 `tiers` 带 `budget`)⇒ 整域读不进、同走域错误;嵌套集合(collab 的槽位 / 成员、projects 的上下文条目)里全带未知键 ⇒ 拥有它的父条目整条丢、兄弟照留;
766
+ `projects` 域唯一一条登记带未知键 ⇒ 整份读取抛。有好兄弟、且不被引用的带未知键条目只丢它自己。`tierGroups.<n>` 这类非目录行的丢弃只进日志,不上 `droppedEntries`(它只收 `models[i]` 目录行)。
767
+ **谁需要**:在条目里加前瞻键的用户与跨版本写配置的管理面(一个键不再让整份候选被拒);拼错收紧键的运维(不再静默放宽成不设限);用 `scenarios` 覆盖内建场景名收窄工具面、用 `plugins` 引用承运守卫 hooks 的部署(拼错 / 前瞻键不再静默撤掉覆盖 / 守卫);用中心技能按名覆盖出厂技能(收窄工具面 / 加拒绝名单)的部署(一条坏技能不再静默让出厂技能回位、一个坏元素不再静默截短拒绝名单);在 mcp / a2a 条目上写 allow / 范围名单的部署(名单不再被静默改成作者没写过的那一张)。
768
+ **谁受伤**:依赖「条目有未知键 ⇒ 整份拒」保护的逐条丢弃域部署 —— 写错一个收紧键的条目现在被丢而不是整份拒(丢了比错装安全,但那层保护没有了;条目缺席会放宽的域仍整份拒);
769
+ 存量文档里条目带契约外键、此前剥键照装的部署 —— 升级后那一条不装;`scenarios` / `plugins` / `skills` 里有坏形条目(含 `skills` 同名两条、`skills: null`)的部署 —— 整份中心配置不再收(此前只丢那一条),落回上一份好配置 / 首启落回 env,直到那一条被改对或删掉;`CONFIG_PROVIDER=local` 的 `config.d/skills.json` 同(读档 throw,起服落回 env;整份内容是 `null` 的文件走文件层被拒文档、候选判官整拒,同样落回 env);
770
+ 值名单里有一个坏元素的 mcp 服务器 / a2a 对端 / 项目登记 / 主机 / 模型 —— 由「带着更短的名单装上」变「这一条不装」。
771
+ **已知限制**:契约包的写口(写入席 / 读改写)对带未知键的条目仍剥键后落盘(写错的收紧键经那条写路径落盘后,下次读不再带未知键、照常装上);写侧同判由契约包另立,本服务不改。
772
+ 收紧域条目体内的未知键是「剥键装上 + 告警」(契约包的读法):没有候选门的读方(把告警当日志的读口 —— 引擎本地车道、嵌入方)装上的是剥过键的条目,拼错的 `disallowedTools` 会以「没有拒绝名单」装上;本服务的两条读腿都过候选判官,同一告警是整份候选失败,所以在本服务上不成立。
773
+ `mcp` / `a2a` 的名字占位(契约包披露,本服务未另验):条目被丢后名字不再被部署占位,请求侧可补同名 —— 成立条件是读方放开请求侧注入的部署,即单用户 ∧ 未锁(`mcp` / `a2a` 锁)∧ 合规档位允许;值名单律让这类条目被丢的情形多了一种(名单里坏一个元素)。
774
+ `models`:一个模型的 `promptGuidance` 坏一个元素 ⇒ 整个模型被丢(此前少一行提示装上),`roles` 里一个角色覆盖被丢后该角色回落到缺省模型 —— 可用性收紧,方向是 fail-closed。
775
+ 盘上 LKG 读回的载荷不经契约读腿(本服务既有的读法,`projects` 同):由本版之前的服务落盘的 LKG 里若带着同名两条技能(此前的清单读法两条都收),读回起服仍按「同名后者赢」装并记一行 `web_admin_skill_duplicate_name`;之后每一份被采纳的候选落盘都会重写 LKG。
776
+ **补偿**:`droppedEntries` / `config_entry_dropped` 点名;`scenarios` / `plugins` 的拒收由 `config_candidate_rejected` / `config_source_unreachable_using_env` / `web_admin_refresh_failed`(成因 `rejected`)点名坏条目的坐标与问题;**删掉那个键或那一条、改对拼写即回**,不需要迁移。
777
+ **升级前做**:对存量配置文档跑契约包的 `parseDomainLoud(域, 文档, onWarning)`:逐条丢弃域里 `unknown-keys-dropped` 第一段是集合字段、第二段是下标 / Record 键坐标的,就是升级后会被丢的条目 —— 删键或改对拼写;
778
+ `scenarios` / `plugins` / `skills` 跑它抛了、或带 `unknown-keys-dropped`,就是升级后整份不收的文档 —— 先改对;对逐条丢弃域的存量文档跑契约包的 `salvageEntries(DOMAIN_SCHEMAS[域], 文档, 域)`,`dropped` 里坐标落在条目上、`error` 的 issue 落在名单元素上的,就是此前被截短、升级后整条丢的那几条;
779
+ 按 `reasonCode` 闭集三词分诊的消费方补第四词(sdk `DroppedEntryReasonCode` 随 sdk 同版锁步;认不出的词按「被丢,原因未知」渲)。
780
+ **回滚**:回到上一版即回到剥键 + 整份拒的读法(`skills` 回到逐条丢 / 清单恒抢救;值名单回到逐元素剔);配置文档原样、已丢弃的条目没有被改写。**持久面一处**:接配置中心的部署上,盘上 LKG(`config-lkg-*.json`)里被丢目录条目的载体行在本版可带词 `entry-unknown-key`,
781
+ 上一版的载体判形不认这个词 ⇒ 回滚后若中心不可达、从这份 LKG 起服,载体形不对 ⇒ 模型面整组拒(fail-closed:该组不落地,模型面停在 env 表;拒因码 `config.model_refused_name_minted`,日志行 `web_admin_model_plane_refused`,拒因句含 `malformed`);中心可达则第一拍拉取即覆盖。
782
+ 回滚前:确认中心可达,或删掉该 worker 的 LKG 文件让它从中心 / env 重起(`CONFIG_PROVIDER=local` 不读 LKG,不受影响)。
783
+
784
+ 83. **SQL 后端:`session_meta` 加两列 `forked_from` / `forked_from_incarnation`(fork 谱系;两句 ALTER,缺列拒启并给句;存量 fork 不回填);`DB_BACKEND=local` 的会话元数据那一格多一位 `forkedFromIncarnation`;会话列表行多一个加性键 `forkedFrom`(持久面加列;wire 加性;SQL 部署有升级动作)**:
785
+ 旧形:SQL 两方言的 fork 不记来源 —— 交出的会话元数据没有 `forkedFrom` / `forkedFromIncarnation`;`DB_BACKEND=local` 记 `forkedFrom`、来源住客读作未知;列表行不带来源。
786
+ 新形:fork 的建行那一笔记下来源会话 id 与来源那一刻的住客令牌(SQL:两列,与行同一句 INSERT;local:那一格的 `forkedFrom` / `forkedFromIncarnation`,同一笔写);
787
+ 交出的会话元数据带这两格,`GET /v1/sessions` 的行(与 `PATCH` 的 200 行同一只投影)带 `forkedFrom`(omit-when-absent)。
788
+ SQL 后端本版起新建的 fork 随之与 `DB_BACKEND=local` 同读引擎按来源走的几路(文件历史从源会话带过来;已有对话的 fork 上声明 `workspace` 按 fork 首腿分配,不再拒;记忆捕获按来源读退出记录)。
789
+ **升级前做(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;`;
790
+ 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";`。
791
+ 不执行 ⇒ 起服列册对账拒启 `config.schema_mismatch`,拒句给同两句。两列可空,存量行不需要回填:本版之前建的 fork 两格保持 NULL = 来源未知(源已不可知,不做一次性迁移)。
792
+ **谁受伤**:没加两列就起本版的 SQL 部署(拒启);对列表行做封闭形校验的消费方。**回滚**:7.147.x 的起服列册对账见到这两列按「库比本构建新」拒启 ⇒ 回滚前先 `ALTER TABLE session_meta DROP COLUMN forked_from, DROP COLUMN forked_from_incarnation;`(两方言同句;丢的是本版记下的 fork 来源);`DB_BACKEND=local` 的那一格多一位,7.147.x 及更早的严格读认不得 ⇒ 回滚 = 恢复升级前的数据根备份(与本版的「删除中」位同一形)。
793
+
794
+ 84. **🔴 SQL 后端:`checkpoint` 加一列 `host_session_id`(一张卡归在哪只会话上;**一句 ALTER**,缺列拒启并给句;存量行由一次性迁移 M49 自 `session_id` 回填);`DB_BACKEND=local` 数据根多一份归属索引 `checkpoint-host-sessions.json`;cascade 任务的级上停驻从此是这条 run 的停驻(行为修复;持久面;SQL 部署有升级动作)**:
795
+ 旧形:一张卡只按它自己的会话连回 run。cascade 的每一级在引擎现铸的会话里跑,级上停下的卡因此连不回 run:run 行 `failed` + `unexpected.suspended`、认领释放;
796
+ 那张卡在待决列表里看得见,对它决定答 409 `conflict.resume_context_unavailable`,到期自动收回;`RESOURCE_SUSPEND` 对 cascade 任务整只不开(撞限照旧 `failed`)。
797
+ 新形:卡的行上多记一个事实 —— 它归在哪只会话上(兑现它的那条 run 的会话:cascade 的级上卡 = 提交的会话,其余每一张卡 = 卡自己的会话;停驻那一刻记一次)。
798
+ 从 run 一侧找卡的读法(取消、steer 停放、活跃 run 409 的门材料、两条停驻收割、续跑输入回收、运维队列行的 `taskId`、收件箱行的目标预览、助手任务视图的门、
799
+ 托管留存过期 pending 卡时的「run 仍持认领」保护、SLA 拒扫的存体预检、按 task 续跑的 `/resume` 与 `/plan_review`)只读它;
800
+ 按卡的对话找卡的读法(`/v1/approvals/:sessionId/decide` 的 URL 会话、运维队列行与收件箱行的 `sessionId`)不变 —— cascade 级上卡的 `sessionId` 仍是级自己的会话,决定照旧对它发。
801
+ 于是 cascade 的级上停驻:`POST /v1/runs` 的行停在 `suspended` / `needs_review`、会话认领保留;`POST /v1/tasks` 答停驻回执;决定那张卡 ⇒ 200 带 `taskId`,同一条 run 行接着跑 ——
802
+ 续上停下的那一级、再按门判往上爬(引擎的梯子续跑入口);`POST /v1/runs/:id/cancel` 作废那张卡再终局;`RESOURCE_SUSPEND` 对 cascade 任务同样生效,撞限停驻、`POST /v1/assistant/tasks/:id/resume` 续梯子。
803
+ **升级前做(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";`
804
+ (不执行 ⇒ 起服的检查点列册探针拒启 `config.schema_mismatch`,拒句给同一句;索引 `idx_checkpoint_host_session_status` 由起服幂等补建,零动作)。
805
+ **起服一次回填(M49)**:任何读者之前,空归属的行按 token 分页自 `session_id` 回填(本版之前停下的卡一律按卡自己的会话连 —— 它们停下时就是这么连的;那时的 cascade 级上卡,它们的 run 早已终局)。
806
+ 窗内(本版发布日 + 30 天)每次起服都跑,第二次起零命中。`DB_BACKEND=local`:同一步自会话索引与此刻的待决行重建归属索引。
807
+ **滚动升级窗**:先升库再升副本;仍在跑的旧副本这段时间新停下的卡归属为空 —— 本版副本从 run 一侧找不到它们(取消不作废那张卡、收割把那条 run 当成卡已不在),直到下一次起服的 M49 补上。
808
+ ⇒ **全部副本换成本版之后,再起一次任一副本**(与 M43 同一个动作)。
809
+ **谁受伤**:没加列就起本版的 SQL 部署(拒启);把「cascade + 审批 ⇒ 立刻 `failed`」当信号的调用方(现在停驻等人:同会话再提交、删会话、换绑设备、会话同步都答 409,先取消再做 —— 与普通停驻同形);
810
+ 一张 `checkpoint-host-sessions.json` 读不出的 local 数据根(拒启;修好或移走这份文件再起,移走 ⇒ 下一次起服的 M49 重建)。
811
+ cascade 停驻续跑时,梯子在续上那一级之后的各级是同一任务的冷重跑,这一次续跑的预算 / 升级次数 / 墙钟只算续跑这一段;续上的那一级不再收提交时挂在目标上的
812
+ `userAttachments` / `images`(耐久续跑不收附件,与 verify 的续跑同一条重建规则),之后冷重跑的各级照原任务收到它们。
813
+ **回滚**:7.147.x 的起服列册对账见到这一列按「库比本构建新」拒启 ⇒ 回滚前先 `ALTER TABLE checkpoint DROP COLUMN host_session_id;`(两方言同句;丢的只是归属 —— 回滚后的副本照旧按卡自己的会话连,cascade 级上卡回到连不上的旧形);
814
+ `DB_BACKEND=local`:多出的 `checkpoint-host-sessions.json` 对 7.147.x 无害(不读它)。
815
+
816
+ 85. **SQL 后端:地板之下的 prompt epoch 锚沿会话当前分支读,不再按行序取最近一条 —— 回绕(resumeAt)之后留在废弃分支上的记录不再被当成锚(行为修复;零 DDL;wire 零变化;部署零动作)**:
817
+ 旧形:有界唤醒的窗里没有 epoch 载体时(回绕切掉了最近一次压缩;或压缩写于引擎复述 epoch 之前),SQL 两方言按行序取地板之下最近的载体 —— 更早一次回绕跨过过提示词版本变更的会话,run 与 `GET /v1/sessions/:id` 读到废弃分支上那条更新的记录。
818
+ 新形:沿地板那一条的父链往下找第一条载体(与 `DB_BACKEND=local` 同一只读法);受影响的会话下一次 run 按它当前分支的提示词版本组装,视图的 `promptEpoch` 随之。
819
+ **成本**:只在窗里没有载体时才问;那时一页翻地板之下的每一行(主键区间,每页 100 行),而不只是载体行。**没做的**:SQL 窗的地板仍按行序取最近一条压缩。
820
+
821
+ 86. **cli 哨兵属主改写成无主,属主读法里不再有字面量互认;dev-open 部署上规则口与 notify 与会话列表、详情同读(持久面一次性迁移 M48,零 DDL;行为变更;wire 零变化;部署零动作)**:
822
+ 旧形:cli ≤ 1.0.70 本地单用户自发的主体头 `anon:shell-live` 记成了那段时间会话 / run / leader run 的属主,属主面表按字面量让无身份调用方读到它们;规则口与 `…/notify` 不放这一格、也不放 dev-open。
823
+ 新形:起服时(任何读者之前)一次性迁移 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)`,只差尾空格的另一位属主不动;
824
+ `DB_BACKEND=local`:会话元数据格与 run 行),之后它们与任何无主行同读;规则口与 `…/notify` 在 dev-open 部署上不钉人。读数 `shellSentinelOwnersCleared`;窗内每次起服都跑,第二次起零命中。
825
+ 改写只在**没有身份边界**的部署上发生 —— 「哨兵 ≡ 不带主体的本地单用户」只在那里成立。判据只读配置,三种形:
826
+ · **没有身份边界**(dev-open:`REQUIRE_PRINCIPAL` 未开,且没配 `SERVICE_AUTH_TOKEN` / `SERVICE_AUTH_TOKENS`、没配鉴权桥 issuer —— `AUTH_BRIDGE_ISSUER`,或接了中心(`SEMA_WEB_ADMIN_URL`)⇒ 回退中心基址 —— 、没开直连门、没配只读 trace 凭据):改写,读数 = 改写的行数;
827
+ · **有身份边界、`REQUIRE_PRINCIPAL` 未开**(配了上面任一样,如带 service 凭据的单用户部署):零改写、读数 0,本条照样记完成。哨兵在这里是一位普通的具名属主,这些行成了孤儿:只有主体恰为 `anon:shell-live` 的请求按属主读写它们(与任何具名属主同);
828
+ 出示 service 凭据而不报主体的 fleet 调用方(`SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT` 没声明成 `false` 时)照旧读得到、删得掉,但不能驱动、挂接;续跑等运维动词另按运维身份放
829
+ (`OPERATOR_SINGLE_USER=true` 下每一位过了凭据门的调用方都是运维;具名 `OPERATOR_PRINCIPALS` 下只名单里的人);其余调用方 404。
830
+ 上一版不带主体的调用方经那一格按属主读写它们 —— **这是本版对这一形的收紧**(那一格退役、本迁移又不在这里改写);
831
+ · **`REQUIRE_PRINCIPAL=true`**:同上,零改写、读数 0 —— 这些行照旧按有主行读(与上一版同答:那一格本来就只在不要求主体的部署上放)。
832
+ **耐久面**:改写的是存量行的属主列 / 属主位(从哨兵字面量到无主);规则行、收件箱条目、问账行、检查点 scope 不动(哨兵键下的规则此前也不对无主体任务生效 —— 改键 = 放宽)。
833
+ **谁受伤**:仍用 cli ≤ 1.0.70 的客户端与新客户端混用的部署(新写下的哨兵行只有带那个头的请求读得到);dev-open 部署上原先靠规则口 / notify 404 当隔离的人(那从来不是隔离);
834
+ 有身份边界、`REQUIRE_PRINCIPAL` 未开的部署上,不带主体地续用 cli ≤ 1.0.70 时代会话的人(上面第二形:驱动 / 挂接 404,续跑看运维身份)—— **补偿** = 下面的手工一步。
835
+ 有身份边界的部署上的孤儿行(上面第二、三形)想收成无主,运维手工做(可核):SQL 后端对三张表各执行一句 —— MySQL 协议 `UPDATE session_meta SET owner = NULL WHERE CAST(owner AS BINARY) = CAST('anon:shell-live' AS BINARY)`
836
+ (`task_run` / `leader_run` 同句;逐字节比,只差尾空格的另一位属主不动),PostgreSQL `UPDATE session_meta SET owner = NULL WHERE owner = 'anon:shell-live'`(另两张表同句);核法 = 同条件的 `SELECT COUNT(*)` 读 0。
837
+ `DB_BACKEND=local` 没有手工口:窗内(本版发布日 + 30 天)以没有身份边界的形起服一次(上面第一形的配置,只听 loopback),起服读数 `shellSentinelOwnersCleared` = 改写行数,然后改回原配置;窗关后本条随删码退场,local 再没有这一步。
838
+ **放给谁**(如实):改写后的行是普通无主行 —— 过了凭据门的任何调用方都能读、驱动、挂接它们。配了 service 凭据的部署 = 每一位持凭据者与它代为报出的每一位主体;
839
+ **没配 service 凭据的部署(如只配了鉴权桥)全局凭据门不武装 ⇒ 不带任何凭据的匿名调用方也读得到**(提交类 —— 驱动、续跑 —— 另受 `ALLOW_UNAUTHED_WRITES` 管,缺省关 ⇒ 谁都提交不了)。
840
+ 删除与会话列表只给 fleet 调用方与单机形(`REQUIRE_PRINCIPAL` 未开)的 `default` 主体。只想留给自己的,别做这一步:带 `anon:shell-live` 这只主体的请求照旧是它们的属主。
841
+ **升级前做**:无。**滚动升级**:支持。**回滚**:零 DDL;改写过的行在 7.147.x 上读作无主(此前按字面量互认读到它们的那位调用方照读),规则口对它们在 7.147.x 上答 409(本版同)。
842
+
843
+ 87. **`settings.env` 里环境合成会拒的名 / 值(名字空 / 带 `=` / 带 NUL / 带孤立代理项,值带 NUL / 孤立代理项)在受理口 `400 request.field_invalid`(`field:"settings.env"`),此前 `202`、到 hook 子进程起时才抛(行为收紧;wire 加性一臂;部署零动作)**:
844
+ 判官是引擎合成本体的拒因读口,受理口与合成同问一只;判官放行的形(名字不是标识符、值带 CR LF)照旧受理。续跑重放存量体不过这道门。**出路**:删掉或改写句子点名的变量后原样重发。
845
+
846
+ 88. **「`<坐标> must be a boolean`」一族的 `400 request.field_invalid` 拒体(`promptLean` · `attachments.*` 的布尔键 · `settings.ultracode` / `autoCompactEnabled` · `resilience.*` · 顶层布尔键)多一个键 `field`(= 体内坐标;wire 加性;句子、码、状态不变;部署零动作)**:
847
+ 按整体相等比对这几口拒体的消费方要放宽(按 `errorCode` 分流、按 `field` 定位)。**出路**:无需动作;要定位坏键读 `field`,不要解析句子。
848
+
849
+ 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 加性;部署零动作)**:
850
+ 形对的 `images`(`{ data, mimeType }` 或 `{ url }`)照旧受理,字节与 URL 的准入仍是引擎的;续跑重放存量体不判。按整体相等比对这几口拒体的消费方要放宽(按 `errorCode` 分流、按 `field` / `index` 定位)。**出路**:每张图选一臂、删掉多余键;句子逐字不变。
851
+
852
+ 90. **同步腿零工作的 `config.skill_deny_unreadable`(点名的运维技能,拒侧条目被引擎读成空)答 `409`,此前 `200` + failed 体;零工作的拒不再占提交幂等键(行为修复;新码入册;部署零动作)**:
853
+ 按 `terminal.code` 读同步腿 200 体识别这一失败的消费方改读 4xx 体的 `errorCode`;该码 ⇒ 运维改那只技能的拒侧条目,调用方原样重发即可。`/v1/runs` 与流式腿 HTTP 2xx、同码落终态 run 行,不变。**出路**:无需改请求。
854
+
855
+ 91. **停驻后被批准复活的后台子代:复活那一轮的 fleet 帧照常发 —— 行翻终态、常开流一帧 `bg_notification`(行为修复;wire 零新键、零新码;部署零动作)**:
856
+ 旧形:复活轮零 fleet 帧,行停在首轮的 `running`,直到 60 s 一拍的对账把它摘掉(只有摘除、没有终态帧、没有 `bg_notification`)。
857
+ 新形:复活轮与首轮同一只观察者,收尾时出终态帧并摘行,`bg_notification` 一帧。**谁受伤**:无。**升级前做**:无。
858
+
859
+ 92. **workflow 子代停驻卡在 run 仍在跑时被决:决定交给那条活 run 当场用上,200 体换成 `{ taskId: <workflow run id>, status: "resuming", decision }`;带续跑重述键的决断在活 run 上答 400(行为修复;wire 加性;零新码;部署零动作;多副本已知限制)**:
860
+ 旧形:决定交给宿主会话的新一跑(200 `{ taskId: <宿主新一跑>, sessionId, status: "resuming", bindingEnforced: true }`),模型去调 `Workflow({resumeFromRunId})` 被引擎拒(run 还在跑),`parked: true` 挂到整条 run 结束。
861
+ 新形:持有这张卡的 run 在本进程里跑 ⇒ 引擎在原 run 里驱动停驻的子代,200 `{ taskId: <workflow run id>, status: "resuming", decision }`(无结清证据);同卡同决定再决 ⇒ 同一张回执,另一个决定 ⇒ `409 decide.claim_lost`;
862
+ 卡已离开 pending / run 不在这张卡上等 ⇒ `409 decide.gate_moved`;checkpoint 店读不出 ⇒ `503 decide.store_unreachable`;带 `mcpServers` / `a2aPeers` ⇒ 卡仍待决时 `400 decide.parked_restatement_unsupported`(卡恰在此刻离开 pending ⇒ `409 decide.gate_moved`)。run 已不在本进程里跑 ⇒ 续跑车道照旧。
863
+ **谁受伤**:拿这一形的 `taskId` 轮 `GET /v1/runs/:id` 的客户端(读到 404,改读 `GET /v1/workflows/:id`);多副本部署上决定落在不跑这条 run 的副本 ⇒ 照旧走续跑车道、`parked: true` 可能持续到 run 结束(与上一版同形)。
864
+ **升级前做**:无。
865
+
866
+ 93. **`/health` 世代账的 `configAppliedVersion` / `configAppliedOrdinal`(与心跳 `engineSignal.configAppliedVersion`)在应用那一拍收口时才推进,与该拍的 `restart` 判定同一段写(推进时刻后移;wire 键零变;部署零动作)**
867
+ 旧形:刷新拍(与迟到的起服拉取)一提交新一代,世代账就记「已应用」;之后才采用提示词层、落 LKG(含技能正文预热)、算重启判定 —— 这段时间里 `/health` 读到 applied 已是新一代、`restart` 还是上一拍的。
868
+ 新形:applied 与重启判定(签 / 撤 / 带 `withheld` 扣)同一段写、先于心跳即刻再报;读到 applied 到某一代时,同一次读数里的 `restart` / `restartRequired` 已是那一拍的判定。拍在收口之前失败 ⇒ applied 停在上一代、`configApplyStaleMs` 持续,下一拍重放同一代收口。起服 / 从 LKG 起服 / 凭证换人降档三种拍没有重启判定,收口紧接提交(时刻不变)。已发布的重启信号只在收口改;上一拍扣着的候选在新一代提交那一刻作废,扣着形(`restart.withheld`)那一位可能在收口之前消失(与此前同)。接力账 `configHandoff` 与诊断端点 `configApply.groups[*].appliedVersion` 照旧在提交那一刻记。
869
+ 同批:手动刷新口撞上 env 起服进程正在收口之前的迟到起服拉取时,汇入那一拍、等它收口才返回(修前当场 200,那一拍还没收口);刷新拍与迟到起服拍走同一个车道入口。
870
+ **谁需要**:按 applied 等配置收敛、再按 `restart` 决定是否滚动重启的编排器与运维脚本(不再需要「applied 到版之后再等一会儿」)。
871
+ **谁受伤**:把 applied 推进当作提交时刻计时的读者 —— 推进晚了 LKG 落盘那一段(慢盘、技能正文慢时可到秒级)。
872
+ **补偿**:要提交时刻的读数看诊断端点 `configApply.groups[*].appliedVersion`;要等一拍完整收口也可调 `POST /v1/admin/config/refresh`(返回时该拍已收口)。
873
+ **升级前做**:无。**回滚**:无持久面变更,回到上一版即回到提交即推进。
874
+ 94. **日志面:进程写进 stdout / stderr 的每一行过同一只秘密形筛 —— 凭据形字节换成 `«redacted:<类>»`;五只 `(事件, 字段)` 形缺省落点从散文改成 JSON 行;两只 process warning 改走日志行 / fail-open 兜底臂;`npm_` / `hf_` / `ya29.` 三族在全部脱敏面成记号(安全轴,fail-closed;日志面字节变;部署零动作)**:
875
+ 旧形:结构化日志器原样写字段;各模块自己的 `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 与日志上原样。
876
+ 新形:每行出门前过脱敏器,凭据形字节读作记号(行仍是一条 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 问句不变。
877
+ **谁受伤**:按日志原文匹配凭据片段的排障脚本;按 `[pg-pool] ` / `[session-policy] ` 散文前缀或 `事件名 {` 散文形告警的规则;按 warning 名 `MemoryEmbedderObservabilityWarning` / `SemaRedactionFailClosed` 或 `hardened-vm: un-awaited script rejection contained` 散文告警的规则;把这三族原文当正常输出读的消费方。**出路**:按事件名(`msg`)与同行的非凭据字段读;告警规则改按 JSON 的 `msg` 匹配(两只 warning 分别换成上面的 `msg` 与 fail-open tag)。**升级前做**:无。**滚动升级**:支持。**回滚**:零持久面。
878
+
879
+ 95. **覆盖站上不带标签的请求 PreToolUse 钩子的问照问、只给上下文照收(行为变更;wire 零新键、零新码;部署零动作)**:
880
+ 旧形(7.147.x):任务座之下有部署座链成员(运维 mod 在 `classic.PreToolUse` 上以 `append` 档挂了链成员)的站上,不带托管标签的请求钩子答问或只给上下文 ⇒ 被引擎座位信任律拒,零问零执行;带托管标签的同形照问 / 照收。
881
+ 新形:两条车道同一个结局 —— 问照问(要人批),只给上下文照收、调用落到常规门;放行 / 改写照旧拒。它的问压在下方的问之上时问句先列下方那一句、再列 `(a PreToolUse hook also asks: …)`。
882
+ **谁受伤**:靠「不带标签的问在覆盖站上整次拒」挡住调用的部署 —— 那一形本版要人批之后执行。**出路**:要挡,让运维 handler 自己答否决或问(它的判决恒在请求钩子之前、恒作数)。**回滚**:回到上一版即回到这两形被拒;数据零改动。
883
+
884
+ 96. **e2b 车道:建命令失败而供应商没有答「拒」时,这只环境此后不挂起(行为修复;wire 零新键、零新码;部署零动作)**:
885
+ 旧形:建命令以失败告终(含 SDK 自己的 60 s 握手到点)⇒ 在途保护即撤,挂起(`suspendVM`)照常可成 —— 供应商若其实已起了进程、只是回执丢了,快照里可能有一条在跑的命令(7.129.1 节写明的已知缺口)。
886
+ 新形:只有供应商答了拒(参数错 / 未认证 / 查无 / 限流 —— SDK 的四只具名拒)才撤在途保护;其余失败(握手期限到点、断流、沙箱不可达、别的错)⇒ 保护不撤,这只环境此后挂起恒以 `command_in_flight` 拒,
887
+ 一行 warn `e2b_start_outcome_unknown`(沙箱 id + 错误类名)。**谁受伤**:建命令回执丢了的那只环境不能停驻挂起,VM 计费到任务结束或 `E2B_SANDBOX_MAX_MS`。**升级前做**:无。
888
+
889
+ 97. **k8s 车道工作区快照的上传以 worker 对对象的回读(预签 `HEAD`)判成败;`latest` 写的应答丢了 ⇒ 回读指针定结局(行为修复;wire 零新键、零新码;部署零动作)**:
890
+ 旧形:上传(run 末快照与停驻挂起同一只)以 pod 里 `curl -fsS` 退出 0 判成功 —— 存储答 3xx 或空操作也算存成,`latest` / 停驻快照 id 可以指着存储里没有的对象(下一条 run / 续跑从空目录开始);
891
+ 对象落了而 curl 丢应答 ⇒ 判失败。`latest` PUT 落了而应答丢 ⇒ 报失败而指针已移。
892
+ 新形:上传成没成只看 worker 对刚写的对象发的预签 `HEAD`(2xx = 在),`latest` 在它之后才动、停驻快照 id 在它之后才交给引擎;不在 ⇒ `workspace_snapshot_failed{stage: upload}`(停驻挂起答 `connect_failed`)。
893
+ `latest` 写 / 删的应答没回到 worker ⇒ 回读一次指针定结局。**谁受伤**:不答预签 `HEAD` 的对象存储(或改答非 2xx 的代理)上每次上传判失败。**升级前做**:无(MinIO / S3 都答;所需权限与读 `latest` 同一条 `s3:GetObject`)。
894
+
895
+ 98. **k8s 车道恢复工作区时归档 GET 答 `404 NoSuchBucket` ⇒ 这只执行环境以 `connect_failed` 拒(`snapshot_bucket_missing`),不再在空目录上续跑(行为修复;wire 零新键、零新码;部署零动作)**:
896
+ 旧形:恢复命令把归档 GET 的任何 404 都读成「归档不在」⇒ 悬空恢复点(`workspace_latest_dangling`)、空目录起 —— 快照桶在停驻与续跑之间被删时,续跑的那条腿静默拿到空工作区。
897
+ 新形:pod 原样交回存储的答复,由 worker 用读 `latest` 时的同一只判据读:`NoSuchBucket` ⇒ 与读 `latest` 得同一答案时同拒(句子带 `snapshot_bucket_missing`、桶名与出路)、同一行 `workspace_snapshot_bucket_missing`
898
+ (停驻车道带 `sessionId`)、刚建的 pod 释放;其余 404 仍是悬空恢复点。**谁受伤**:快照桶被删时有停驻 run 的部署 —— 这些 run 续跑失败。**升级前做**:无(桶删了的部署建桶,或把 `WORKSPACE_SNAPSHOT_BUCKET` 指向已有的桶)。
899
+
900
+ 99. **配置根是工作区本身或它的祖先 ⇒ 起服 warn 恰一行 `sema_config_root_encloses_workspace`(日志面,加性;不拒启、不改任何行为;wire 零变化;部署零动作)**:
901
+ 旧形:配置根(`SEMA_CONFIG_DIR`,缺省 `~/.sema`)设成工作区本身或它的祖先(容器里 `SEMA_CONFIG_DIR=/workspace` 而项目在 `/workspace/proj`、直接设成 `HOME`)时,根之内每一次写都过 `write_protection` 一问
902
+ (allow 规则清不掉、`acceptEdits` 不放、无人值守腿拒),而起服与首条任务都零行 —— 第一次知道是第一次写。
903
+ 新形:起服时判一次 —— HTTP 服务在装配第 2 段(执行车道合成)之后,`run-local` 在工作区定下之后。配置根与「工作区」各取一次规范形(符号链接按 realpath 展平,尚不存在的尾巴接在最深既存祖先之后)后,
904
+ 配置根等于工作区或是它的祖先 ⇒ 运维日志 warn 恰一行(`level:"warn"`、`msg:"sema_config_root_encloses_workspace"`,字段 `configRoot` / `workspace` / `workspaceFrom` / `note`);不相交 ⇒ 零行;首条任务之后不再多报。
905
+ 「工作区」只有一条读链:`run-local` 的 `--workspace` ?? `REMOTE_EXEC=host` 的 `HOST_WORKSPACE_BASE` ?? 进程工作目录(`workspaceFrom` = `workspace-flag` / `host-workspace-base` / `process-cwd`);手不在本机盘上的车道(沙箱 / 远程)不判。
906
+ 规范形在盘上竞态里读不出 ⇒ 另报一行 `sema_config_root_workspace_check_unavailable`(类名 + 机器码,不带消息原文),起服照常。规范形对尚不存在的尾巴只比字串、不折大小写:大小写不敏感的盘上,两个只差大小写且尾巴都还不存在的拼写读成两处,这一行会漏报。
907
+ **看不见的一半(如实)**:请求体里按任务给的 `cwd` 起服时不可知,这一行看不见它 —— 项目只靠请求 `cwd` 落在配置根之下的部署,第一次知道仍是第一次写。
908
+ **勘误(7.123.0 节第 4 条「起服不报、首条任务也不报:本服务不拿配置根与工作目录比」;已发节不改字节,本条即订正)**:那一句写的是 7.123.0 的现状,本版起起服会比这一次(只比配置根与起服时的工作区,不比请求里的 `cwd`)。
909
+ **谁受伤**:故意把配置根设在工作区祖先的部署多这一行 warn(包括已用整表替换去掉 `.sema` 行的部署:这一行只说位置关系、不读写保护表,句子里写明它们可忽略),按「warn 行 = 告警」过滤日志的运维会多收到一个事件名。**出路**:行本身就是提示(无旋钮);要消掉它 ⇒ 把配置根指到项目之外的专用目录(不设即缺省 `~/.sema`),
910
+ 确实要保留祖先形配置根的 ⇒ `WRITE_PROTECTED_TABLE_REPLACE` 给一张不含 `.sema` 行的整表(代价见 `USAGE.md` 写保护名表一节)。
911
+
912
+ 100. **补登(引擎 7.62.0 起,7.144.0 已到货;已发节不改字节):审批卡的卡词 `approvalCard` 多两个词 `computer-access` / `computer-control` —— 输出闭集放宽,7.144.0 起两词原样过境却没登进那一版的清单与本文件(文字补全;本版行为零变;部署零动作;消费方有动作)**:
913
+ 事实:引擎 7.62.0 给卡词闭集 `TOOL_APPROVAL_CARDS` 加了这两个词;本服务按这只闭集校验、原样放上 `approval_request` 帧的 `card.approvalCard`(活铸帧 · 落库卡信封 · 断连重放三面同源)与帧活面事实 `approvalCard`。7.144.0 的 wire 变更清单与本文件 7.144.0 节都没写这一条。
914
+ 读法:对卡词写穷举 `switch` 的消费方给这两个词加臂。自本版起,清单把这类逐字过境的 core 词表登在 `coreVocab` 一层,引擎加词那一版清单就有 `added`。
915
+
916
+ 101. **勘误(7.132.0 节第 50 条第一点与 7.134.0 节第 7 条里 `a2aPeers[i].toolAxes` 坏形的处置句;已发节不改字节,本条即订正):新提交上这个形自 7.136.0 起是入口 `400 request.field_invalid`,不是「那一条对端不挂 + 运维 warn `a2a_injection_dropped`」(文书;本版行为零变;部署零动作)**:
917
+ 那两句写的是 7.132.0–7.135.0 的现实(7.135.0 及以前 `a2aPeers` 条目只有 `url` / `cardUrl` 带凭据与个数超界两道入口拒,`toolAxes` 没有入口判官:坏形的对端照常 200 受理,只在运维 warn 里点名)。7.136.0 给 `a2aPeers` 加了条目判官表(与 `mcpServers` 同一副拒绝骨架),`toolAxes` 是表里的一格:
918
+ 新提交(`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs`)的 `a2aPeers[i].toolAxes` 被引擎判官读不出(出词表 · `egress` 非布尔 · 记录里多一个成员 · `__proto__` 键 · 某只 skill 的值不是对象 · 请求侧不收的 `boundaryFlow`)⇒ 入口 `400 request.field_invalid`,
919
+ 拒句点名 `a2aPeers[i].toolAxes` 与 peer 名(形如 `a2aPeers[0].toolAxes (peer "<名>") is not a usable declaration — <判官原因句>`),整份请求不收、零 run,**没有** warn `a2a_injection_dropped`。那两句现在只对**耐久续跑重放存下的旧请求体**成立:
920
+ 重放腿不拒(拒会砖死升级前停驻的任务),坏条目不挂、运维 warn `a2a_injection_dropped` 点名,一次性迁移窗内的重读规则照 7.132.0 节第 50 条与 7.134.0 节第 7 条所述。以码为准。
921
+ **谁受伤**:照已发两节的句子写调用方的人 —— 以为坏形 `toolAxes` 只是「那一条对端没挂、任务照跑」的脚本,在 7.136.0 起拿到的是 400、任务不起。**出路**:改对那个键(或删掉它);完整的拒形与判序见 `USAGE.md` 9.5h。
922
+
923
+ 102. **命令钩子跑完 / 超时 / 被叫停之后整棵进程树被清:脱离进程组的后代不再活过超时;钩子正常退出后留在同组的后台进程也被清;同步与 `async` 条目同一把梯子(安全轴;行为变更;运维日志多一个事件 `hook_command_tree_swept`;零新旋钮;wire 零变化;部署零动作 —— 靠钩子起长命后台进程的壳除外)**:
924
+ 旧形:超时只向钩子的进程组发一枪 SIGKILL 就放手 —— 脱离进程组的后代(自立会话的后代、钩子壳自己起的新会话)活过超时;叫停(预算到 / 任务取消)宽限到点只看「组长还在不在」,组长吃 SIGTERM 就退时组里屏蔽 SIGTERM 的成员被留下;
925
+ 钩子自己跑完(组长正常退出、管道关闭)时留在同组的后台进程(`sleep 300 >/dev/null 2>&1 & exit 0` 这一形)没有任何一拍会去清它。
926
+ 新形:跑完 / 超时 / 叫停三条结局一个 —— 钩子的整棵进程树(进程组 ∪ 往下的后代)被清:跑完 = `close` 之后树里还有后台成员 ⇒ 整组 SIGKILL(树里本来就空 ⇒ 零信号零日志;管道里的输出不被截);
927
+ 超时直接 SIGKILL、立即返回(不等孙进程放开管道,结局仍是非阻断故障);叫停 = SIGTERM → 1 秒 → 树里还有进程则 SIGKILL;SIGKILL 之后 1 秒复核整棵树,
928
+ 清净 ⇒ info `hook_command_tree_swept`(`end` = `exit` / `timeout` / `halt`,`clean: true`),还有 ⇒ 补一枪并 warn(`clean: false`,`shots: 2`)。组长已被收割之后只向「还有原来成员」的进程组发信号(进程号可能已是别人的)。`timedOut` / `aborted` 读数形与 `HOOK_KILL_GRACE_MS`(1 秒)不变。
929
+ 射程如实:钩子壳在被清扫之前就已退出、后代又在新会话里的形(后代被过继给 init、自成一组),与叫停时 SIGTERM 之后组长退了、屏蔽 SIGTERM 的自立会话后代,按进程号 / 进程组 / 父链找不到,不在这一把梯子上。
930
+ **谁受伤**:依赖钩子起一只长命后台进程并让它活过钩子自己(含钩子正常退出后留下的后台进程)的壳 —— 现在那只进程随钩子跑完 / 超时 / 被叫停一起被清。**出路**:长命的活放到钩子之外起(服务单元 / 编排器),钩子只负责触发;钩子本身要跑得更久 ⇒ 条目的 `timeout`(上限 600 秒)与 `HOOKS_TIMEOUT_MS`。
931
+
932
+ 103. **🔴 `loadConfig()` 要求本进程先声明自有凭据:包根导出的 `loadConfig()` 在没调过 `declareServerWithheldEnv()` 的进程里抛(安全轴,fail-closed;嵌入方行为 BREAKING;包根加一个值导出;服务进程部署零动作)**:
933
+ 旧形:嵌入方直接 `loadConfig()` 照返回配置;名单型旋钮点到本服务凭据名照收,宿主子进程在 `inheritEnv:"all"` 下照拿本服务凭据(引擎的自有凭据声明为空)。
934
+ 新形:`loadConfig()` 第一步核本进程的自有凭据名已被引擎扣下,没有 ⇒ 抛,句含 `declareServerWithheldEnv()`。包根新增值导出 `declareServerWithheldEnv`。
935
+ **升级前做**(嵌入方):在 `loadConfig()` 之前、任何执行环境构造与子进程之前调一次 `declareServerWithheldEnv()`(零参)。一个进程只调一次即可;同一进程里多次 `loadConfig()` 不需要再调。
936
+ 之后点到本服务凭据名的名单型旋钮按既有规则拒启 —— 那一形要给沙箱 / 子进程另铸一把凭据(名与值都不同于本服务的)再点名。服务进程(HTTP 服务 / `run-local` / bake-runner)零动作。
937
+
938
+ 104. **运维日志字段的扫描窗改读脱敏器导出的最长识别跨度(日志面;安全;wire 零变化;部署零动作)**:
939
+ 旧形:有界日志字段(hook 输出 / 工具输出预览 / 标题 …)只扫头一段,窗 = `max(4 KiB, 界 × 8)` 读法单元,前半出门区、后半余量(座自定的数)。
940
+ 新形:窗 = 出门区(`max(2048, 界 × 4)` 读法单元,与此前同)+ 余量(脱敏器导出的 `MAX_RECOGNITION_SPAN`,本版 8274 读法单元 —— 识别表里最长的有界结构,SSH2 私钥块的总长上界)。起于出门区、总长不超过余量的有界结构整段落在窗内,与整段脱敏逐字同判。
941
+ **谁受伤**:总长越过余量的结构不保证与整段读法同判(窗读法从起点遮到窗尾:同记号、零明文,遮蔽范围只到窗尾);体长越过识别表上界(8192)的 SSH2 块整段读法本来不认,日志字段上此前被旧窗截断而多遮,现在与整段读法同读;窗变大,每次扫描量毫秒内。
942
+
943
+ 105. **🔴 脱敏器的不可见码点删除集改成一张 Unicode 属性表(`Default_Ignorable_Code_Point` ∪ `Mn` ∪ C1):夹在凭据中段的变体选择符 / 组合符 / C1 控制符 / 蒙古文自由变体选择符 / 谚文填充符 / 高棉固有元音不再让整枚凭据逃过识别(行为面;安全;脱敏产物可能变;wire 零新键;部署零动作)**:
944
+ 旧形:读法格的删除集 = 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` 转义写法),整段读法与出口座的窗读法都原样放过。
945
+ 新形:这些码点(与表里其余成员)按「留着当分隔 / 删掉当不存在」两种读法取并集,拼回完整的值就遮;没有凭据形的文本逐字节不变。读到的面与上一版同(trace 帧 / 终局文本 / 账本 / 审批预览 / 运维日志字段 / MCP 面板 …)。
946
+ **谁受伤**:带这类码点的文本多读一遍(组合符写法的越南语 / 泰语 / 阿拉伯语 / 日语浊点、emoji 的变体选择符):脱敏产物只会多遮不会少遮,计算量随之翻倍(1 MiB 泰语文本实测约 18 ms → 约 47 ms;六类齐在的病态文本读法数上界 16 → 64);**升级前已落库的行**回放读面再过一遍脱敏的那几类面按新读法遮,已落库的原字节不改。
947
+
948
+ 106. **运维日志里嵌在句子里的 http(s) URL 按 URL 的 authority 文法收(日志面;安全;wire 零变化;部署零动作)**:
949
+ 旧形:`a2a_peer_unavailable` / `mcp_server_unavailable` 的 `info` 里,URL 的扫描界到第一个空白或引号 / 括号类界符(含 `[` `]`)为止 —— userinfo 里带括号 / 引号的口令只换到前半段、后半段留句;IPv6 字面地址的 URL(`https://[::1]/x?token=…`)整条不被认作 URL;路径 / query 里的括号处同样截断。
950
+ 新形:`http(s)://` 之后先收 authority(`userinfo@`?、主机或 `[IPv6]`、`:端口`?;最后一枚 `@` 才是 userinfo 的界),再收路径 / query / fragment 到空白为止;展示形仍是 `scheme://host[:port]` + `/…`。句末句读与闭合符(`. , ; : ! ?` 与 `) ] } > ' " \``)留在句里。
951
+ **谁受伤**:URL 后面紧贴(无空白)的非 URL 文字被一并吞进这条 URL;userinfo 里的**裸空白**不是 URL 文法的一部分(第一个空白处结束,余下留句;受理口对该形一律 400)。按这两条日志的 `info` 字面值做匹配 / 告警的运维脚本留意展示形的变化。
952
+
953
+ 107. **🔴 主体长度改按 UTF-8 字节:至多 190 字节(此前 190 个 UTF-16 码元)—— 多字节、超 190 字节的主体名此后 400 `principal_too_long`;同一把尺管收件箱键、记忆退出名单、`?scope=` 查询与规则面的运维目标(行为 BREAKING;wire 句子改;码不变;零 DDL;部署动作:核一遍身份源会不会签出超 190 字节的名字)**:
954
+ 旧形:边界判官数码元 —— 64–190 个 CJK 字(192–570 字节)的主体过判官,随后在按字节计宽的身份键列(收件箱 / 后台子代 / 名册 `VARBINARY(190)`)上写入失败(500);配额三表按码元 × 3 建成 `VARBINARY(570)`;
955
+ 记忆退出名单、`GET /v1/sessions` 与名册读面的 `?scope=`、规则面 `POST` / `DELETE /v1/rules` 体里的 `principal` 各自数 190 个码元(后者连判官都不过)。
956
+ 新形:唯一的尺 = 190 个 UTF-8 字节(`Buffer.byteLength`)。超了 ⇒ 主体头 / SSO 令牌 / bearer / 直连门 JWT 的 sub 同答 `400 principal_too_long`(句子报字节数);`?scope=` 两处 `400 request.query_invalid`;记忆退出路由 `400 request.path_malformed`;
957
+ 规则面运维目标过鉴权边界同一只判官(名字 ∧ 良构、非保留、≤ 190 字节),过不了 ⇒ `400 request.field_invalid` `{ field: "principal" }`(在 operator 判之后;非 operator 照旧先拿 403)。新建库的配额三表列宽 190(两方言);
958
+ 存量库(7.133.0 – 7.147.x 建)保留 `VARBINARY(570)`,不需要 ALTER(更宽、装得下;起服列集对账不比宽度)。主体头按 latin1 一字节一字符读:0x80–0xFF 的字节在 UTF-8 里各占 2 字节,含高位字节的头值上限约减半。
959
+ **谁受伤**:用超过 190 字节的名字认证的身份(长 CJK / 表情名、长 email 形主体)—— 升级后 400,它名下已有的会话 / 审批 / 记忆行留在库里,该名认证不进来。**出路**:升级前让身份源把这类名字映射成 ≤ 190 字节的形(哈希或短 id),映射后的新名是一位新主体(旧行不随迁)。
960
+
961
+ 108. **🔴 含孤立代理项(不是良构 Unicode)的主体是 `principal_not_a_name`(行为收紧;安全轴;wire 零新码;部署零动作)**:
962
+ 旧形:引擎名判不拒孤立代理项,鉴权边界照收;两只 SQL 驱动把它存成 U+FFFD ⇒ `"a\ud800"` 与 `"a\ufffd"` 等落在同一行(会话 / 问账属主、配额、规则桶、记忆 scope、限流键 ……)。
963
+ 新形:SSO 桥 / bearer / 直连门 JWT 的 `sub`、组织投递收件人、A2A `audience` 与组织记忆名单配置、规则面运维目标里的孤立代理项一律按「不是名字」拒(边界 `400 principal_not_a_name`;投递门答 `not_member`;配置拒启)。主体头与 URL 带不进孤立代理项,这些入口零变化。
964
+ **谁受伤**:签出带孤立代理项身份的签发方(坏数据)。**出路**:签发方修正身份编码。
965
+
966
+ 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;部署零动作)**:
967
+ 旧形:删会话不碰两表,挂靠的问(卡上带工具实参字面)留到保留窗(`APPROVAL_ASK_RETENTION_MS`,缺省 30 天)按龄删;店接口的唯一删除动词 `deleteByTask(taskId)` 本服务从不调用。
968
+ 新形:挂靠 = 问的宿主会话格或发问那条腿的会话格是被删的会话(没有会话的 adhoc 腿把 run id 填进会话格,那样的行不算),批随它的问走;已经没有问的空批照旧由保留窗收;审批审计账(`approval-ask-audit/ledger.jsonl`)不随会话删。
969
+ `DB_BACKEND=local`:被删的问的字节离开账本才算删完 —— 账本压实失败 ⇒ 这次删除答 500、会话行留着,重发删除即补压。SQL 后端:存量库起服时补建 `idx_ask_source_session (source_task_id)`(既有的补索引机制;大表上是一次在线建索引)。升级前已删会话留下的问不做一次性清理,照旧由保留窗收。
970
+ **嵌入方**:`ApprovalAskStore` 的 `deleteByTask` 删除、`deleteBySession(sessionId)` 新增(自带实现要补;直调的改调)。**local 账本(一次性迁移 M50,零动作)**:账本里若留着一条 `deleteByTask` 记录(只在嵌入方调过它、且进程停在那一次压实之前时出现),窗内起服按写下它的那一版的读法重放
971
+ (删那条 run 名下的问与批)、起服压实把记录改写掉,stderr 一行点名条数与账本;窗(本版发布日起 30 天)关之后仍有 ⇒ 拒启,拒句点名账本、本条与出路 —— 用早于本版的版本起服一次(它的起服把删行记录压实掉),再升本版。
972
+ **谁受伤**:删会话之后仍想从问账里查这只会话审批历史的运维(本来只保 30 天)。**出路**:要留底就在删会话之前导出;审计痕迹在审计账里照留到它的保留窗。
973
+
974
+ 110. **🔴 会话删除是一只三态(活 → 删除中 → 没了):删除与提交至多各赢一个;删除答 409 时什么都没删;删完之后这只会话名下不留 run 行;同一只会话的删除已在进行 ⇒ `409 conflict.session_deleting`(行为修复;wire 新码;持久面:SQL 后端一句 ALTER + 一次性迁移 M51,停-迁-起,不可滚动;`DB_BACKEND=local` 零动作)**:
975
+ 旧形:`DELETE /v1/sessions/:id` 在 run 账腿判一次「没有在跑的 run」、删行时再判一次,两判之间不挡认领 —— 提交在这一段认领时,删除可能答 409 而会话规则等子数据已删,或删除与提交两边都答成功、这次 run 的 run 行留在已删会话名下。
976
+ 新形:删除先在会话根行的锁里判认领并写下这次删除的令牌(删除中;SQL = `session_ext.deleting_token`,local = 会话元数据那一格),判到认领 ⇒ 409 `conflict.session_active_run`,一个字节没写;写下之后到删完,这只会话对删除门之外的读者与写者读作不在
977
+ (头读 / 列表 / 导出 / 新 run 认领答 404 `resume.session_not_found` / 同 id 登记不新建),删除的每一步之前复核令牌仍是这一次的,删行那一刀在根行锁里判令牌。删除中不回到活:某一步失败 ⇒ 500,同一属主重发接着删完,下一次起服由删除协调器收尾删完。
978
+ 同一只会话的另一次删除仍在进行 ⇒ `409 conflict.session_deleting`(这次请求不等它、自己不删任何东西;那一次已经进了删行的事务 / 锁节 ⇒ 这次等它提交、答 `{ deleted: false }`;删完之后重发答 `{ deleted: false }`;SQL 多副本上别的副本那一次删除开始后 10 分钟内不被接管)。会话同步导入 / 会话规则写 / 附件绑定在门判过之后才撞上删除中 ⇒ 同码,什么都没写。
979
+ **升级前做(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`,拒句给该方言那一句。
980
+ ② 停光全部旧版本副本再起本版:本版第一只副本起服时(一次性迁移 M51)判活窗内还有 `running` run 在心跳 ⇒ 拒启 `config.session_deleting_switch_refused`(一个字节不写;拒句给出可再起的时刻),否则落启用标记,此后不再判。心跳只是探测器 —— 没有在跑 run 的旧副本探测不到,停光旧副本是前提。
981
+ **谁受伤**:按「删除失败之后会话还在」做重试判断的客户端 —— 删除中途失败(500)之后,会话此刻已读作不在;原样重发 `DELETE` 即可删完。**出路**:按码分支:`conflict.session_deleting` 等一会儿再发,`conflict.session_active_run` 先停在跑的 run。
982
+ **回滚(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` 再换旧版。
983
+
984
+ 111. **前台命令超时转后台缺省开:新旋钮 `AUTO_BACKGROUND_ON_TIMEOUT`(缺省 `true`);`/health` 多一键 `autoBackgroundOnTimeout`(行为变更;wire 加性;部署零动作)**:
985
+ 旧形:前台 Bash 命令撞上它自己的超时一律被杀(工具结果 = 超时错误 + 已捕获的输出)。
986
+ 新形:host(单用户、后台 shell 开着)/ k8s / e2b 车道上,合格的命令(引擎判:命令里没有 `git`、首词不是 `sleep`)超时到点转成后台任务继续跑,工具结果是「超时了但仍在跑,已转后台(task_id=…)」;后台 shell 满了照旧杀;同一个开关还让引擎在有人的输入(steer / 排队的消息)等着、而合格命令还在跑时把它转后台,好让输入先送达。其余车道行为不变。`GET /health.autoBackgroundOnTimeout` = `armed` / `off` / `unsupported`(本车道上生不生效)。
987
+ **谁受伤**:依赖「超时即杀」回收资源或判失败的部署与脚本 —— 超时之后命令仍在跑、仍占进程或沙箱算力(受后台 shell 并发上限与后台超时硬上限约束);假定「steer 之后前台命令先跑完」的调用方。**出路**:写 `AUTO_BACKGROUND_ON_TIMEOUT=false` 回到超时即杀、steer 等前台命令跑完(逐字节同旧形)。**回滚**:回到上一版时这根 env 被忽略,`/health` 这一键消失。
988
+
989
+ 112. **订正 7.147.0 节第 5 条的闭集:SQL 起服建 `session_ext` 的「确定拒」两个方向一起收 —— 补齐 MySQL 协议建外键整族;1005 按内层错误号分(盘满等资源类不再当场拒启);拒句按失败类带出路与库答原码(起服拒启面:更多形当场拒、盘满一形改为重试;wire 零新键、零新码;部署零动作)**:
990
+ 旧形:确定拒的闭集只含外键两侧不相容 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`。
991
+ 新形:闭集补 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 协议的墙。
992
+ **谁受伤**:无(前两形本来就起不来,只是更早、出路写对;盘满一形由当场拒启变重试到窗尾再拒,多等至多一个窗,出路不变:清盘 —— 要当场拒就设 `STORE_LOCK_WAIT_MS=0`)。**出路**:按拒句修 `session_meta`(`ALTER TABLE session_meta ENGINE=InnoDB` / 补主键)后重起;盘满清盘;其余部署零动作。
993
+
994
+ 113. **一次性迁移 M10 / M11 退役:local 车道会话属主的窗内认领与 SQL 起服的持久规则坏 scope 行删除删码;`OneTimeMigrationReport` 去三键、起服日志去一条认领行与两种逐行 / 逐桶告警(持久数据面;行为变更〔无主存量会话不再被认领;`conflict.session_ownerless` 的句子只剩一条出路〕;运维日志形变更;嵌入方 BREAKING,类型面)**:
995
+ 7.119.0 / 7.120.0 引入的两条一次性迁移,窗(发布日 2026-10-08 + 30 天)于 2026-11-07 关,本版删了它们的码。M12 / M13 的窗(2026-11-08 / 11-09 关)本版不动,随后续版本窗关即删。逐处删了什么、删后存量形由谁接住:
996
+ - **M10(`DB_BACKEND=local`:会话属主的窗内认领)**:7.119.0 起 local 店把会话属主落盘;7.118.x 及更早写下的会话,边档那一格只有化身、没有属主事实,升级窗内由带 principal 的第一次提交 / 登记认领(一行 info `session_owner_claimed`)。
997
+ 本版删认领臂:`LocalSessionStore.register` 对这种会话只补化身、不记属主;授权口不再为已存在的无主会话调 `register`;窗读口与认领日志行 `session_owner_claimed` 不再有。**认领本身删码零行为变化** —— 窗按日历日判(2026-11-07 关〔含当日〕,UTC 2026-11-08 00:00 起认领就已不生效),与哪个版本在跑无关。**唯一可观测的差在授权口**:它不再为已存在的无主会话调 `register`(那一步的存在性探针会读存档),所以存档读不出(`corrupt_session`)的无主存量会话,带 principal 的提交不再在授权口被这一步拒掉 —— 授权通过,存档的故障改由读存档那一步按腿答(同步 500 / 流式终帧 / 后台行 `corrupt_session`),与认领面其余各口同一条契约(门只判归属、不碰存档)。
998
+ 没有响亮的起服臂。属主从没被记下的存量会话(7.119.0–7.147.x 的窗内从没被带 principal 的提交认领过的)照旧读作无主:它的会话规则这条路由读不了也改不了(`409 conflict.session_ownerless`),已存的规则对写下它们的 principal 的 run 照旧生效;
999
+ 任何 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」(码与状态不变)。
1000
+ 出路 = 删会话(规则随之删)。SQL 后端(`mysql` / `pg`)的属主一直在 `session_meta.owner` 列上,没有这一半。
1001
+ - **M11(`DB_BACKEND=mysql|pg`:持久规则桶里坏 scope 行的起服删除)**:起服不再逐桶扫描 `permission_rule`、不再把 project scope 的 root 不是完整绝对路径的行(7.119.x 及更早的入口按「root 非空」收下的;引擎 7.46.0 起读侧丢它)回写删掉。
1002
+ 存量的那种行留在桶里:引擎读侧继续在有效视图里丢它、每次 run 一条 `permission.rule_row_dropped`(点名规则与 root),那一行不参与任何检查(其中一条 deny / ask 行什么都没保护),撤销口删不动它(引擎的写臂对这种 scope 同样拒)。
1003
+ 出路 = 运维在库里把那只桶的那一行删掉(整桶 OCC 回写,指纹按 `buildRuleBucketChecksum` 重算)。读腿整桶拒的桶照旧整桶拒(出路是人)。店内判官与写法不动(它们是读腿 / 写臂本身)。`DB_BACKEND=local` 的持久规则在引擎自己的 File 分区里,这一半对它本来就是空转。
1004
+ - **运维日志**:起服行 `one_time_migrations_applied` 与被打断时的 `one_time_migrations_interrupted` 去掉 `undurableScopeRuleRowsRemoved` / `undurableScopeRuleBucketsDeferred` / `undurableScopeRuleBucketsUnreadable` 三个读数字段(`removableAfter` 读数去掉 `M10` / `M11` 两个键,`note` 不再叙述它们);
1005
+ 逐行的 `permission_rule_row_removed` 与逐桶的 `permission_rule_bucket_unreadable` 两种告警、认领行 `session_owner_claimed` 不再有。按这些行名或字段做告警 / 看板的规则要改。
1006
+ - **嵌入方(类型面)BREAKING**:`StoreBackend.runOneTimeMigrations()` 的返回型 `OneTimeMigrationReport`(经包根导出的 `StoreBackend` 可达)去掉 `undurableScopeRuleRows` / `undurableScopeRuleBucketsDeferred` / `undurableScopeRuleBucketsUnreadable`;
1007
+ 读它们的代码、把值标成 `OneTimeMigrationReport` 再写这些键的对象字面量 tsc 红;自实现该方法、未标注类型就直接返回含这些键的字面量的代码 tsc 不报(多出的键没有人读),也请一并删掉。`LocalSessionStore` 的构造参数不变(`log` 位还服务其余运维行)。
1008
+ - **谁需要**:所有部署 —— 起服少走一步(SQL 少一次规则表扫描)、日志少几种行。
1009
+ - **谁受伤**:① `DB_BACKEND=local` 上从 < 7.119.0 直接升到本版、或升级窗内从没带 principal 提交过的存量会话(属主仍是「没被记下」,不会再被认领;规则路由 409 句子换了);② 从 ≤ 7.119.x 直接升到本版、中间没在 7.120.0–7.147.x 任一版对这只库起过服的 SQL 部署 —— 桶里仍有坏 scope 的存量行(读侧每次 run 丢一行并通告,删除要运维手工);③ 按被删日志行名 / 字段做告警的运维;④ 按 409 句子里「upgrade window」那半句匹配的客户端。
1010
+ - **补偿 / 做法**:**M11 那一类**:直升的 SQL 库先在 7.120.0–7.147.x 任一版上起服一次(那几版的起服会删掉这些行),再升本版;或升级后在库里手工删那几行。**M10 那一类**:没有按版本补的路 —— 认领按日期判,UTC 2026-11-08 00:00 起任何版本都不认领;不要的无主会话删掉(`DELETE /v1/sessions/:id`)。
1011
+ **升级前做**:常规从 7.147.x 升级的部署无须动作;**回滚**:回到 7.147.x 即恢复旧读法(认领臂按日期已停、M11 的起服删除重新开始跑),本版没有写任何新的存储形。
1012
+
1013
+ 114. **勘误(7.140.0 节第 7 项末句「引擎侧修好之前请别对 cascade 任务开耐久审批」自本版起过期;已发节不改字节;文书,本条零新行为;部署零动作)**:
1014
+ 那一句写的是 7.140.0 当时的已知限制:`cascade:true` 任务的某一级停在审批上时,行 `failed` + `unexpected.suspended`,卡在 `GET /v1/approvals` 里看得见却决不掉(409 `conflict.resume_context_unavailable`)。
1015
+ 这个限制的两半都已收齐:引擎那一半已随 core 7.61.0 到货(引擎在级上的卡上记下它属于哪个宿主会话);本服务那一半即本段第 84 条(`checkpoint.host_session_id` 记下卡归在哪只会话上;cascade 的级上停驻是这条 run 的停驻;决定那张卡 ⇒ 200 带 `taskId`、同一条 run 行接着跑)。
1016
+ 所以 **cascade 任务可以开耐久审批了** —— 「请别开」自本版起不再适用;本版的行为由第 84 条定,本条不引入任何新行为。7.140.0 节第 7 项的原文保持不动(已发节与 tag 逐字一致)。
1017
+
1018
+ 115. **嵌入方:`createHttpServer` 的鉴权桥验签器席(`ServiceDeps.webAdminJwtVerifier`)与配置里的桥必须成对 —— 注入了验签器而配置没声明桥,或配置声明了桥(`authBridgeIssuer`;缺席而接了中心 ⇒ 中心基址回退)而没注入验签器,构造期都拒启(嵌入方装配面 BREAKING;服务入口零变化;wire 零变化;部署零动作)**:
1019
+ 旧形:「这台部署接了哪几个身份来源」读装配(验签器在不在):`/health.auth.kinds` 的 `sso`、属主门的 dev-open 判据、受限技能的身份边界座都看它 —— 配置里有桥而没注入验签器的嵌入读成没有桥,注入了验签器而配置没桥的嵌入读成有桥。
1020
+ 新形:这件事只从配置读(与一次性迁移同一只读法,迁移在验签器建好之前就跑);服务入口起服时按配置里同一个 issuer 建验签器,两者恒一致。嵌入方两者不一致 ⇒ `createHttpServer` 抛,
1021
+ 句子以 `createHttpServer: a webAdminJwtVerifier was injected but the config declares no auth bridge` 或 `createHttpServer: the config declares an auth bridge` 起头。
1022
+ **谁受伤**:自己装配 `createHttpServer`、配了中心或 `authBridgeIssuer` 却不注入验签器(或注入了验签器、配置里却没有桥)的嵌入方。
1023
+ **补偿 / 做法**:两边对齐 —— 配置声明了桥就注入一只验那个 issuer 的验签器;不要 SSO 就把 `authBridgeIssuer` 与中心都从配置里拿掉(接了中心的部署恒有桥)。
1024
+ **升级前做**:嵌入方按上面对齐;服务入口(`sema-server` 进程 / 镜像 / chart)无。**回滚**:无存储形变化。
1025
+
1026
+ ## 7.147.0 —— 1–30 条见下
1027
+
1028
+ 1. **硬断预告 —— 本版兑现:每个部署都要显式声明执行车道,未声明拒启;车道词 `none` 取代词表外的状态名 `in-process`;`REQUIRE_EXECUTION_LANE` 退役(设了即拒启)(行为 BREAKING;wire 值形 BREAKING;部署动作:写明 `REMOTE_EXEC`、去掉 `REQUIRE_EXECUTION_LANE`,有 `in-process` 存量行的部署停机迁移、不可滚动;全部细节与回滚见本节「执行车道恒点名」一条)**:
1029
+ 旧形(7.146.0 及以前):`REMOTE_EXEC` 不设时有两条隐式臂 —— `CONFIG_PROVIDER=local` 隐含 `host`(手带在,宿主真机);其余(`remote` 或不设)落 core 的进程内桩(手带整族不挂,任务照跑、回执 `status=completed`)。
1030
+ 后一条在 `GET /v1/capabilities` 的 `executionLane.provider` 上叫 `in-process` —— 一个不在车道词表里的状态名。想对「没点名」拒启,要自己开 `REQUIRE_EXECUTION_LANE=true`(缺省关;本仓自带的部署产物都写着它)。
1031
+ 新形(自 7.147.0 起,即本版):
1032
+ **硬断(自 7.147.0 起)**:每个部署都要显式声明自己最终生效的执行车道 —— env `REMOTE_EXEC`(`CONFIG_PROVIDER=local` 形下 `config.d/remote-exec.json` 也算);没有声明 ⇒ 拒启,拒句以 `No execution lane is declared` 起、一行给出照旧行为的修法(`CONFIG_PROVIDER=local` 不再隐含 `host`,非 local 未设也不再静默落进「不挂手」的进程内桩)。「不给智能体的工具提供执行环境」写成车道词 `none`,取代词表外的状态名 `in-process`(wire 五处换值,零别名:`GET /v1/capabilities` 的 `executionLane.provider`、`GET /v1/sessions/:id/execution-placement` 的 `lane`、409 `execution_lane.not_served` 与 409 `execution_lane.tree_bound` 的 `boundLane`、403 `execution_lane_not_allowed` 的 `extra.lane`);`REQUIRE_EXECUTION_LANE` 已退役(设了任何非空值 ⇒ 拒启,拒句指向 `REMOTE_EXEC`),自己拼的清单或拷过随包部署产物的 env 里写着它的,升级前要去掉。库里或数据根里记着 `in-process` 的会话 / 审批行由一次性迁移 M40 在起服时改成 `none`:停全部旧副本、再起 7.147.0,不可滚动混跑;SQL 后端上判活窗(`REAP_RUN_STALE_SEC`)内还有 run 在心跳 ⇒ 起服拒 `config.execution_lane_rename_refused`,拒句给出可再起的时刻;守卫只看心跳,没有在跑的 run 的空闲旧副本它看不见 —— 停全部旧副本是运维的动作(细节与回滚见 MIGRATION 7.147.0 节「执行车道恒点名」一条)。web-admin 渲染 env 的中心 worker,须先停渲 `REQUIRE_EXECUTION_LANE`、同时让每个 worker 的 env 带 `REMOTE_EXEC`,再升到 7.147.0。照旧行为的一行修法:7.146.0 里非 local 且未设车道的 ⇒ 7.147.0 写 `REMOTE_EXEC=none`,`CONFIG_PROVIDER=local` 且未设的 ⇒ 写 `REMOTE_EXEC=host`(7.146.0 及以前不认 `none` 这个词,别提前写)。
1033
+ **谁需要**:所有部署方 —— 尤其是 `CONFIG_PROVIDER=local` 的单机形、手写 `.env`、没写 `REMOTE_EXEC` 的托管 worker,以及给 worker 渲染 env 的编排方;读 `executionLane.provider` / 放置读面 `lane` / 409 `boundLane` / 403 `extra.lane` 的壳与客户端(按 `in-process` 字面分支的,要在 7.147.0 同波认 `none`)。
1034
+ **谁受伤**:7.147.0 起 ① 没声明车道的部署拒启;② env 里还写着 `REQUIRE_EXECUTION_LANE` 的(拷过旧版随包部署产物的清单、自己拼的清单、编排方渲染的 worker env)拒启;③ 库里或数据根里有 `in-process` 存量行的部署要停机迁移、不可滚动(旧副本不认 `none`、新副本不认 `in-process`,混跑两头都会拒);④ 按旧词字面读 wire 的消费端。
1035
+ **补偿**:7.146.0 上就能先显式点名 —— 单机用 `REMOTE_EXEC=host`,隔离用 `e2b` / `k8s` / `local-docker`(`none` 是本版才有的车道词,7.146.0 及以前写会被拒,别提前写);要继续「不给手」的部署,本版写 `REMOTE_EXEC=none`(逐字复现 7.146.0 非 local 未设的行为)。
1036
+ 编排方停渲 `REQUIRE_EXECUTION_LANE` 的同时,必须让每个 worker 的 env 带 `REMOTE_EXEC` —— 7.146.0 上只停渲这根旋钮而不点名车道,worker 会静默落进无手的进程内桩。
1037
+ **升级前做**:盘点哪些部署没写 `REMOTE_EXEC`(7.146.0 上非 local 而未设的 ⇒ 写 `REMOTE_EXEC=none`,`CONFIG_PROVIDER=local` 而未设的 ⇒ 写 `REMOTE_EXEC=host`);盘点 env 里的 `REQUIRE_EXECUTION_LANE`(去掉);有 `in-process` 存量行的部署排一次停机窗(停全部旧副本、再起本版,不可滚动)。步骤见本节「执行车道恒点名」一条。**回滚**:见本节「执行车道恒点名」一条(含 M40 改写过的行的回写语句),本条不另给第二份。
1038
+
1039
+ 2. **`task_notification` 帧的会话箱车道上 wire:三只载体 `crossSessionMessage` / `crossSessionNotice` / `inboxNotice` 与侧记 `_sema_provenance` 的三个 lane 词(`cross_session_message` / `cross_session_notice` / `inbox_notice`)及 `peerMeta`(含 typed 通告 `peerMeta.notice`)逐成员投(wire 加性;部署零动作)**:
1040
+ 旧形:接了会话席的部署上,引擎的会话箱 drain 交来的帧(一条对端会话的信 / 本会话发出那条信的投递回执与对端空闲通告 / 一行收件箱计数)在本服务 wire 上只有经典键(`task_id` / `summary` / `result` …);三只载体与它们的侧记恒缺席,消费端只能渲通用通知卡;`inboxNotice.resupplied` 恒缺席。
1041
+ 新形:三条腿(同步 live SSE / bg·resume 两条 durable 账本行 / 空闲态 park → drain 的补投帧)同形加键 ——
1042
+ `crossSessionMessage { from, fromSession?, fromName?, fromMode?, fromScope?, body }`(`from` = 发信方规范编码地址,身份逐字;`fromName` / `body` 过脱敏);
1043
+ `crossSessionNotice { kind: "delivery_notice" | "idle_notice", text }`(`text` 是引擎渲给模型的那一句,过脱敏);
1044
+ `inboxNotice { pending, delivered, urgent?, resupplied? }`(非负整数;`seq` 每个 run 从 1 起);
1045
+ `_sema_provenance.kind` 放行 core 词表四员,两种箱记录 lane 带 `peerMeta { fromSession?, fromRoot?, fromMode?, kind?, fromScope?, notice?, urgent? }`,
1046
+ 回执 / 空闲帧的卡从 `peerMeta.notice { state, refSeq?, recipient?, dropReason?, finishedAt?, detail?, target? }` 渲(`state` 开集串逐字,新词原样过境;`recipient` / `target` / `detail` / `dropReason` 过脱敏)。
1047
+ 仍不投:`peer`、`received`、`peerMeta.senderKey`、`peerMeta.gateReceiptId`、`peerMeta.occupant`、`peerMeta.fromOccupant`(凭据 / 身份令牌类:准入键、投递回执号、会话化身令牌)、`inboxNotice.box`(同帧 `task_id` = `inbox:<box>` 与 `_sema_provenance.from` 已带)。
1048
+ 在场却读不出(容器不是纯数据记录(类实例 / `Date` / `Map` 也算坏)/ 必需成员缺席 / 成员形坏 / 闭集词出词表)⇒ 那一只键整键缺席,运维计数 `server.trace.projection-input-malformed` +1;缺席不计。`_sema_provenance` 词表外 lane 词此前静默丢,现同样计一次。
1049
+ park 补投帧上这些文本位与本服务其余 park 文本位同一个 4000 字界。
1050
+ **谁需要**:接了会话席的多会话部署上的三端渲染 —— 对端信的转录行、投递回执 / 空闲通告的卡、收件箱计数行;按 `inboxNotice.resupplied` 标注补投的壳。
1051
+ **谁受伤**:按「帧上未知键」报错或整帧比对的消费端与金样(要补键);对端信的帧变大(`body` 与经典 `result` 同一串,live 帧上两份);按 `taskId:status:seq` 跨 run 去重收件箱通告的消费端会吞同会话第二个 run 的第一条通告(请把 run 身份并进键)。
1052
+ **补偿**:新键全部可缺席、缺席 = 上一版形,不读这些键的消费端逐字不变;坏形整键缺席并有运维计数;凭据类身份键不上 wire;文本位经与 `summary` / `result` 同一读法的脱敏。
1053
+ **升级前做**:部署零动作。消费端:按载体在场分派渲染(优先序 `agentMessage` → `crossSessionMessage` → `crossSessionNotice` → `inboxNotice`),回执 / 空闲卡读 `_sema_provenance.peerMeta.notice`(不解析 `text`),`notice.state` 按开集读。**回滚**:回到上一版即恢复旧形;零持久面、零 DDL、零一次性迁移(park 已入箱的补投帧带着新键,上一版 drain 原样带出,老消费端忽略)。
1054
+
1055
+ 3. **🔴 单用户部署必须声明「谁是运维」:`REQUIRE_PRINCIPAL` 未开、`OPERATOR_PRINCIPALS` 为空、`OPERATOR_SINGLE_USER` 不是 `true` ⇒ 装配运维面时拒(服务进程起服拒,直接调 `createHttpServer` 的嵌入方同拒;不变量 `operator-declaration-required`);起服日志 `operator_undeclared_single_user` 与 `memory_consolidation_valve_unreachable` 退役(行为 BREAKING;安全轴;没写声明的单用户部署升级前补一行)**:
1056
+ 旧形:单用户部署不写声明照常起服,起服一行 warn `operator_undeclared_single_user`;这台部署上没有运维 —— 审批队列的跨属主列表与决议对谁都不开(每个调用方只看自己的卡),`GET /v1/diagnostics/wiring`、`GET /v1/outcomes`、管理与记忆治理口对谁都答 501 `capability.operator_principals_required`。
1057
+ 新形:多一条跨域不变量 `operator-declaration-required`(服务进程在起服第 1 段判;所有装运维面者在 `createHttpServer` 装路由之前再判同一句,直接调工厂的嵌入方只过这一处):单用户形(`REQUIRE_PRINCIPAL` 不是 `true`)必须二选一 —— `OPERATOR_SINGLE_USER=true`(这台单用户部署的每个调用方都是运维)或 `OPERATOR_PRINCIPALS=<主体,…>`(只有点名的主体是运维);
1058
+ 两样都没有 ⇒ 进程在起服第 1 段退出(先于任何起服日志、店连接与中心拉取;嵌入方:`createHttpServer` 抛同一句),stderr 一行拒句点名这两条出路,并说明不止一个人调用的 worker 是多租、该设 `REQUIRE_PRINCIPAL=true`。`OPERATOR_SINGLE_USER=false` 与没写同判。多租形不归本条(空名单 = 没人是运维,合法;开了 `DURABLE_APPROVAL` 的多租形照旧由 `operator-principals-required` 管)。
1059
+ `operator-single-user`(单用户声明与多租 / 非空名单互斥)与 `operator-principals-required` 两条的拒启集不变。三根键都只在 env、起服冻结;配置热改路径只对「把声明改成被拒形」的候选判本条(三键没动 ⇒ 不判,不装运维面的 `run-local` 的限额照落)。
1060
+ 不装路由的 `run-local` 不判本条(它不跑起服第 1 段、不调 `createHttpServer`,`loadConfig()` 本身不拒)。运维面的 501 `capability.operator_principals_required` 从此只在「多租 + 空名单」上出现。
1061
+ 两条起服日志退役:`operator_undeclared_single_user`(在场条件与本条拒启条件同一);`memory_consolidation_valve_unreachable`(显式开得起来的记忆整理阀门只在单用户 + file 记忆后端上,过了第 1 段就有运维)。`memory_consolidation_run_credential_gated` 不变。
1062
+ 本包的一键部署渲这一行:`sema-up --users=single`(缺省)写 `OPERATOR_SINGLE_USER=true`、`--users=multi` 写 `false`(compose `.env` 每次重跑按租户词重写;cluster 清单同值);chart 两只 worker 从 `server.requirePrincipal` 派生(未开 ⇒ `"true"`,开 ⇒ `"false"`);`server.requirePrincipal` 从此只认 `"true"` / `"false"`(大小写不论),别的词 `helm template` / `helm upgrade` 渲染即拒并点名那个值。具名运维名单这几份模板不渲。
1063
+ **谁需要**:单用户部署的运维 —— 旧形下这些运维面静默对谁都 501,起服只有一行 warn,运维不知道自己丢了它们。
1064
+ **谁受伤**:① 没写声明的单用户 / 本机部署(手写 env、自己的 compose 或编排):升级即拒启;② 读起服日志 `operator_undeclared_single_user` / `memory_consolidation_valve_unreachable` 的告警规则从此读不到这两行;
1065
+ ③ 一台忘设 `REQUIRE_PRINCIPAL` 的团队机器若照出路写 `OPERATOR_SINGLE_USER=true`,每个调用方都成运维 —— 拒句因此把这条出路限定在单用户部署,并点名「不止一个人调用 ⇒ 设 `REQUIRE_PRINCIPAL=true`」;
1066
+ ④ chart 部署把 `server.requirePrincipal` 写成 `yes` / `1` / `on` 之类的:渲染即拒(改写成 `"true"` / `"false"`);⑤ 直接调 `createHttpServer` 的嵌入方:无声明的单用户 config 装配即抛(同一句),此前装得起来、运维口对谁都 501。
1067
+ **补偿**:拒句就是出路 —— 一行声明二选一;没有旋钮、没有宽限、没有缺省。一键部署:重跑 `sema-up`(不带旗即沿用上一次的租户词)或 `helm upgrade` 即落新模板。
1068
+ **升级前做**:单用户部署在 env 里补一行 `OPERATOR_SINGLE_USER=true`(或 `OPERATOR_PRINCIPALS=<主体,…>`);团队机器确认 `REQUIRE_PRINCIPAL=true` 已设。**回滚**:回到上一版 ⇒ 不写声明照常起服(起服 warn 回来);补的那一行上一版照读(同一根键、同一个判法);无持久数据。
1069
+
1070
+ 4. **🔴 `DB_BACKEND=local`:数据根记引擎版本高水位 —— 比记录旧的引擎(本版及以后)开这只根起服拒 `config.schema_mismatch`;marker 读不出同拒;嵌入方类型 `LocalSidecarMismatch` 改名 `LocalDataRootMismatch`(行为变更;持久面;无迁移;部署零动作)**:
1071
+ 旧形:7.144.0 起数据根比代码新只靠**格式**围栏判 —— 会话元数据边档 `session-incarnations.json` 本构建读不出 ⇒ 拒;只盖格形变过的那一跳,格形没变的相邻版本,旧引擎开新引擎服务过的根照常起服(版本降级无人守)。
1072
+ 新形:数据根顶层多一只 `engine-high-water.json`,恰一键 `{"highWater":"x.y.z"}` = 打开过这只根的最高引擎版本(契约见 USAGE「嵌入形契约」同名一条)。local 后端**打开数据根的那一刻**(取锁之后、本仓任何一只店建起之前)先判、后抬:
1073
+ 判 —— 高水位高于本构建 ⇒ 拒;marker 在而读不出(I/O 错 / 悬空符号链接 / 不是 JSON / 缺键 / 多键 / 版本串不是纯 `x.y.z`)⇒ 拒,**不当缺席**;本构建版本按发布线读(`x.y.z`,可带 `-预发布` / `+构建` 后缀,后缀只剥不比:`7.147.0-rc.1` 按 `7.147.0` 判与抬,marker 恒写纯三段),读不出(例 `unknown`)⇒ 拒,先于读 marker;判拒 = 本仓零字节写(店一只没建,收尾不落盘);
1074
+ 拒与格式围栏同一只具名类 `LocalDataRootSchemaMismatchError`、同码、同一张三条出路(本构建版本读不出那一形是确定的拒启族里的一句普通拒),由公开序列的 `ensureSchema()` 交出;`findings` 多一种 `problem: "newer-engine"`(同一段必带 `engineHighWater: { highWater, engine }`),拒句点名 marker、高水位与本构建版本。
1075
+ 抬 —— 判过即抬,先于店构造里的自修、起服对账、一次性迁移与任何服务写:本构建高于记录(或缺席)⇒ 原子替换成本构建(`0600`,目录项证不了落盘也算没写成),相等不写(只证它在盘上);写到一半进程死了,水位已是本构建(比它旧的引擎重开被拒,本构建重开续跑);
1076
+ 对账或迁移在抬之后被拒 ⇒ 水位留在本构建;写不进 ⇒ 不以这只根服务(起服拒;缺省推导的 local 在起服时为空的根上按既有降级臂退内存)。SQL 后端不读不写它。
1077
+ 同一只字节一读也管会话元数据等边档:路径上是一条悬空符号链接 ⇒ 读不出(严格边档拒启、装饰性边档隔离留证后按空表继续),不再当「还没有」。
1078
+ 包根导出的读数类型 `LocalSidecarMismatch` 改名 `LocalDataRootMismatch`(它现在也装 marker 的读数),零别名 —— 按名字 import 它的嵌入方 tsc 红,改名即可;它是以 `problem` 为判别位的联合:`"newer-engine"` 那一支必带 `engineHighWater`,别的种别那一支没有它(字段 `path` / `label` / `unknownFields` 不变)。
1079
+ **无迁移**:marker 由本版第一次打开数据根时写下,升级即生效;升级前不用做任何事。缺席 = 还没有本版及以后的引擎打开过这只根。
1080
+ **谁需要**:`DB_BACKEND=local` 的单机部署与本机壳 —— 新引擎服务过数据根之后,换回旧二进制(或旧壳冷起自己钉的旧引擎)不恢复备份就照起,旧引擎在新引擎写过的数据上跑。
1081
+ **谁受伤**:① 在同一只数据根上交替跑不同版本引擎的开发 / 测试(源码树的 `package.json` 版本落后于代码时同理);② 为躲一个问题降级又没有升级前备份的用户;③ 起服在对账或一次性迁移段被拒之后不恢复备份就换回旧版的部署(水位在打开那一刻已抬),含按跳版拒句的「先过一次带某条迁移的版本」去做、而那一版也是本版及以后的情形 —— 先恢复升级前备份;
1082
+ ④ 按名字 import `LocalSidecarMismatch` 的嵌入方。
1083
+ **补偿**:拒句点名 marker、高水位与出路 —— 部署不低于高水位的 server;回滚 = 恢复升级前的数据根备份(marker 随备份回到旧值);同一台机器要并行跑多个版本 ⇒ 各给一个数据根(`LOCAL_DATA_ROOT`)。不设绕过旋钮;格式围栏照旧在下面兜。
1084
+ **保护起点(如实)**:只有旧的那一端是本版及以后才守得住;更早的引擎不读这只文件,换回它们照旧只有格式围栏。
1085
+ **回滚**:唯一支持形 = 恢复升级前的数据根备份。不恢复备份换回上一版(7.146.x 及更早):上一版不读 marker,照旧起服(格式围栏照旧判);换回本版及以后、但低于记录的版本 ⇒ 拒。不要手删 / 手改 marker 来绕过 —— 删了就是把一只服务过的根当成没人服务过。
1086
+
1087
+ 5. **🔴 SQL 后端:会话上本服务记的十二格搬出引擎座表 `session_meta`,住旁表 `session_ext`;一次性迁移 M41(停-迁-起,不可滚动);外键级联是起服前提(持久面一次性迁移;行为变更;wire 零变化;部署动作:停全部旧副本再起本版)**:
1088
+ ① **表形**:
1089
+ 旧形:`session_meta` 一行同时带引擎的列(身份 / 属主 / 化身 / 叶子 / 时刻 / 委派分区元组)与本服务的十二格 —— `title` · `pinned` · `instruction_source` · `workspace` · `execution_role` · `execution_lane` · `execution_device_id` · `execution_device_owner_tenant` · `execution_device_owner_subject` · `execution_placed_at` · `execution_rev` · `fork_key`。
1090
+ 新形:`session_meta` 只剩引擎的列;十二格住 `session_ext`(主键 `session_id`,外键 `fk_session_ext_session` 引 `session_meta(session_id)` `ON DELETE CASCADE`,各列定义与宽度同前)。一会话一行;行不在 = 每一格缺省(未命名、未置顶、没记过基线 / 位置、没有执行格、非键控 fork)—— 写者锁住会话行之后按需补行。删一只会话(属主删除、委派真删、留存删除)在同一条语句里带走它的旁表行,同一 id 重新登记的新住客从空行起步。
1091
+ ② **一次性迁移 M41(SQL 两方言;local 零动作)**:起服时 ① 把 `session_meta` 上仍在的这几列按会话 id 分页、每一行都搬,upsert 进 `session_ext`(旁表那一行的这几格 = 会话行上的值;上一次没跑完留下的旁表行也改回会话行上的值);② 逐行核对两边相等(有一行不等 ⇒ 起服拒 `config.session_ext_move_refused`(`copy_mismatch`),一列不删,下一次起服重搬);③ 一句 `ALTER TABLE session_meta DROP COLUMN …` 删掉在场的这几列。中断 ⇒ 下一次起服从头重跑,结果相同。窗 = 发布日 + 30 天,窗内每次起服都跑(之后零动作),窗关之后的第一个 minor 删码。起服读数 `sessionExtRowsMoved` / `sessionMetaColumnsDropped`。
1092
+ **停-迁-起**:删列之后,旧副本对这十二格的每一笔读写都撞未知列;搬与删之间旧副本落下的写会丢 ⇒ 停掉全部旧版本副本 → 起本版(起服时迁移)→ 再起其余副本。**守卫**:还有列要搬,而判活窗(`REAP_RUN_STALE_SEC`)内还有 `running` run 在心跳 ⇒ 起服拒 `config.session_ext_move_refused`(`live_runs`),一个字节不写;拒句给出可以再起的时刻。守卫只看心跳 —— 空闲的旧副本它看不见,停全部旧副本是运维的动作。
1093
+ ③ **外键级联是起服前提**:建表之后、一次性迁移之前,起服在一只事务里插一对行、删会话行、读旁表行、回滚(库零写);旁表行还在 ⇒ 拒 `config.session_ext_cascade_absent`。PostgreSQL 恒执行外键;TiDB 要执行外键的版本且会话变量 `foreign_key_checks` 为 `ON`(DSN 或全局设置可能关掉它);MySQL 要 InnoDB。表是在外键不执行时建的(约束没记下)⇒ 删掉那只(空的)`session_ext` 再起。
1094
+ 外键两侧的字符列在 MySQL 协议方言上必须同字符集、同排序规则,而存量库的 `session_meta` 可能随建库时的库缺省(`session_meta` 建表句给表尾写上 `COLLATE utf8mb4_bin` 之前建的库;stock MySQL 8 / 9 的缺省是 `utf8mb4_0900_ai_ci`)⇒ 建 `session_ext` 之前起服读一次 `information_schema.COLUMNS` 里 `session_meta.session_id` 的字符集与排序规则,外键列逐字照写(其余列仍是表级 `utf8mb4_bin`;PostgreSQL 腿照旧 `COLLATE "C"`)。读不出被引列,或库以**确定拒**(闭集:外键两侧列不相容 3780 / 加不上外键 1215 / 被引列缺索引 1822 / 存储引擎拒建表 1005 / 表级权限拒 1142 / 缺表 1146 —— `sql-errors.ts` 的部署错配类一张表)拒了建表句 ⇒ 起服拒 `config.schema_mismatch`,拒句点名 `session_ext`、写下的字符集 / 排序规则与库的原句(不是「库打不开」,开库等待窗不重试它);闭集之外的语句级错(TiDB 8028 / 9005、锁等待 1205 …)原样上抛,等待窗重试;连接类故障(断连、服务端关停、连接被杀)照旧原样上抛,等待窗重试。
1095
+ ④ **整段换装就地改写(行为变更)**:`replaceEntries`(会话同步的整段换装)此前删掉会话行再新建(标题、置顶、换源通告基线、位置与项目随之清空,化身与 fork 键沿用);本版就地改写导入者自己的那一行(属主门 ∧ 不是委派转录;化身与旁表行不动),与暂存提交同一读法 —— 换装之后标题 / 置顶照旧由同步的行重放写,换源通告基线与位置与项目保留服务端上一次记下的值。导入的拒判次序:有 run 认领 ⇒ 409 `session_active`,本处是该会话的写者 ⇒ 409 `conflict.session_writer`,都在写任何字节之前判(两者同在时,整段换装此前先答写者,现与暂存提交同序先答认领)。
1096
+ **谁需要**:SQL 后端的每个部署(引擎的会话行只带引擎的列,本服务的格有自己的表与删除语义)。**谁受伤**:滚动升级的部署(守卫拒,或空闲旧副本漏网后撞未知列);外键不执行的库(起服拒);直接读 `session_meta` 这十二列的运维查询 / 报表(改读 `session_ext`);依赖「整段换装清空标题 / 基线」的脚本。
1097
+ **补偿**:拒句给出可以再起的时刻与库端设置;迁移中断可重跑;读旧列的查询改成 `SELECT … FROM session_meta sm LEFT JOIN session_ext se ON se.session_id = sm.session_id`(行不在 = 缺省)。
1098
+ **升级前做**:① 确认库执行外键(TiDB:`SELECT @@foreign_key_checks` 答 `1`);② 停全部旧副本,再起本版;③ 把直接读这十二列的查询改读 `session_ext`。
1099
+ **回滚**:换回 7.146.x 之前停全部本版副本,把列加回并回写(本版的 `session_ext` 就是数据源):逐列 `ALTER TABLE session_meta ADD COLUMN <7.146.x 建表句里的列定义>`,再 `UPDATE session_meta sm JOIN session_ext se ON se.session_id = sm.session_id SET sm.title = se.title, …`(PostgreSQL:`UPDATE session_meta sm SET title = se.title, … FROM session_ext se WHERE se.session_id = sm.session_id`);`session_ext` 留着不影响 7.146.x(它不读这张表)。
1100
+ 回到 7.146.x 还要撤第 16 条的 M40 改写,次序固定:① 停全部本版副本 → ② 本条的加列与回写(`execution_lane` 由此回到 `session_meta`)→ ③ 第 16 条回滚里的两条反向 `UPDATE`(第二条写的正是 ② 加回来的 `session_meta.execution_lane`;先跑它会撞未知列)→ ④ 起 7.146.x。
1101
+
1102
+ 6. **🔴 pg 记忆向量面:embedder 指纹对不上缺省拒启、一行不清;清列重嵌只经显式确认口令 `MEMORY_EMBEDDER_REEMBED=<model>/<dimensions>`(行为反转;新旋钮;部署动作:换 embedder 时给口令)**:
1103
+ 旧形:配了 `MEMORY_EMBEDDER_*` 的 pg 记忆部署,起服时 `agent_memory_engine_meta` 记下的 `{model, dimensions}` 与配置对不上 —— `changed`(不等)/ `unattributed`(元表无行而库里有向量)/ `unreadable`(那一行读不出)——
1104
+ ⇒ 先把 `agent_memory_engine_entry.embedding` 整列清成 NULL、再写新身份,服务照常起(检索在重嵌之前退词面档)。
1105
+ 新形:这三态缺省**拒启**,一行不清、元表不写;拒句点名所处的态、记下的与配置的身份和出路:① 只有 `changed` 才有 —— 把 `MEMORY_EMBEDDER_MODEL` / `MEMORY_EMBEDDER_DIM` 改回记下的身份;
1106
+ ② 确认重嵌 —— 设 `MEMORY_EMBEDDER_REEMBED=<本次配置的 model>/<dim>`(拒句给出的是 shell 赋值形 `MEMORY_EMBEDDER_REEMBED='<model>/<dim>'`,值带 POSIX 单引号,模型名含空格 / `$` / 引号也能原样粘进 shell;引号只是 shell 的写法,env 里的值不带引号 —— 写进 YAML / `.env` 文件 / 编排器 env 列表时只写引号里那一段),停机后再起:清列一次、记下新身份,`memory_embedder_identity_changed` 照旧响亮;
1107
+ ③ 撤掉 `MEMORY_EMBEDDER_*`,以词面档起、存量向量原样留。口令形:维度在最后一个 `/` 之后(`BAAI/bge-m3/1024`);必须恰好点名本次配置的身份,形不对(`true` / `1` 这类开关形)或对不上 ⇒ 拒启;
1108
+ embedder 三键不全时单独在场 ⇒ 与 `MEMORY_EMBEDDER_TIMEOUT_MS` / `MEMORY_EMBEDDER_API_KEY` 同一条半配拒。口令绑定身份:新身份记下之后下一次起服判「相等」,口令留着无害;再换模型,旧口令对不上新配置 ⇒ 拒启。
1109
+ 相等 / 无记录且零向量两态照旧(零写 / 只记身份)。元表的写改成条件写:多副本同时起服而配置不一致时,判与写之间另一副本抢先记下的身份不再被盖掉 ——
1110
+ 本副本回读看见它、按它重判(未确认 ⇒ 拒启)。`MEMORY_ENGINE_BACKEND=mysql|file` 无向量面,零变化。
1111
+ **谁需要**:任何配了 `MEMORY_EMBEDDER_*` 的 pg 部署 —— 换模型 / 改维度 / 回滚残留 / 手改元表的一次手滑不再在起服时不可逆地丢掉全部向量。
1112
+ **谁受伤**:靠「换模型、下次起服自动清列」的部署 —— 升级后换模型起服即拒;运维脚本里「删 `agent_memory_engine_meta` 那一行让下次起服保守清一次」的做法现在也拒,要带口令起一次。
1113
+ **补偿**:拒句给出口令与三条出路;撤掉 embedder 即可先以词面档起来。
1114
+ **升级前做**:不换 embedder 的部署零动作(记下的身份与配置相等 ⇒ 照常起)。正在换、或升级同一拍要换的:在这一次起服的 env 里加 `MEMORY_EMBEDDER_REEMBED=<新 model>/<新 dim>`,停全部副本后再起(停机纪律不变)。
1115
+ **回滚**:换回上一版无须动作(上一版不读这一键;多出来的 env 键它不认,照旧按自动清列处置)。
1116
+
1117
+ 7. **🔴 场景面:部署接了配置中心而中心答不出这位主体的场景裁定(不可达 / 超时 / 答复读不出 / 指派两键形不对)⇒ 该 run `503 state.scenario_assignment_unavailable`,不再落部署缺省场景、不再放行点名的场景;没接中心 / 匿名运行 / 旧中心照旧(安全轴,fail-closed;wire 新码;行为变更;部署零动作)**:
1118
+ **旧形**:部署接了中心(设了 `SEMA_WEB_ADMIN_URL`、非干跑)、请求带 principal,而中心这一问答不出来(不可达 / 超时 / 非 2xx / 体判坏 / 回声不符)⇒ 这位主体的 run 照跑:请求不点名 ⇒ 部署缺省场景,点名 ⇒ 白名单读成空、照放;
1119
+ 中心答了而指派两键形不对 ⇒ 非串元素逐个丢、非数组折成空、非串指派折成「无指派」,只发一键时另一键补空值,照用。受限主体在这一拍可能被放进比他的指派更宽的工具面。
1120
+ **新形**:同一构造 ⇒ `503 state.scenario_assignment_unavailable`(体 `error` / `errorCode` / `permanence: "transient"`;码族 `transient`;不带 `Retry-After`),拒在一切副作用与计费之前,零 run;点名与不点名同拒。
1121
+ 两键的读法:都缺席 = 旧中心(无治理);都在场且形对 = 裁定;其余一切(形不对、只发一键)= 读不出 ⇒ 同拒。
1122
+ 读面同一只门:`GET /v1/capabilities/mcp`、`GET /v1/sessions/:id/a2a` 整面 503;`GET /v1/sessions/:id/mcp` 答 200,`servers` 缺席,拒因在 `scenarioRefusal`(该码下无 `detail`)。
1123
+ 续跑家族(审批决断后的续跑、`POST /v1/sessions/:id/wake`、`/v1/assistant/tasks/:id/resume` · `/plan_review`)同码同状态 503 + `retriable: true`,**不折** `409 resume_blocked_by_policy`(认领之前,卡仍待决;SLA 到期的自动拒不把这张卡过期,逐拍重试,中心恢复后再决即可)。
1124
+ `/plan_review` 的直连门证明:一次性 nonce 在这一判之前已经用掉 —— 中心恢复后重铸 nonce 重签再发。停驻的后台子代赎回不问场景门,中心答不出时照常赎回。
1125
+ **不变**:没接中心(没设 `SEMA_WEB_ADMIN_URL`,或 `SEMA_WEB_ADMIN_DRY_RUN=true`;`run-local`)、匿名运行(无 principal,中心不被问)、中心答了但两键都不发、中心答了「无指派」—— 照旧走请求名或部署缺省场景;
1126
+ 指派悬空仍是 `503 state.scenario_assignment_unknown`;请求体点名的未知名仍先答 `400 scenario_unknown`。
1127
+ **嵌入方**(自建 `ScenarioGateSources.principalCaps`,包根 `createScenarioGate` 的入参):读数方法的答成三态 —— 裁定 / `undefined`(缺席 = 无治理)/ `"unavailable"`(故障 ⇒ 门拒);中心答不出时要答 `"unavailable"`,仍答 `undefined` 就是放行;读数方法抛错 ⇒ 门不接,读面答 500。
1128
+ **谁需要**:接了配置中心的多租户 / 受限主体部署(中心答不出时受限主体不越界)。
1129
+ **谁受伤**:接了中心的部署在中心答不出期间,每一个带 principal 的新提交与续跑都被拒(此刻分不出谁受限)—— 此前照跑、只拒放大位;单用户而接了中心的部署同受;中心发出形不对的两键 ⇒ 受影响主体全拒,直到中心改好。
1130
+ **补偿**:码族 `transient`,按码重试;取数失败只复用一个短窗(缺省 10 秒),中心恢复后至多这么久即恢复;刚取到的正常裁定在缓存窗(缺省一分钟)内不再问中心;拒句点名出路(恢复本部署到配置中心的链路)。安全轴不设放行旋钮。
1131
+ **升级前做**:壳 / SDK / 控制台:把 `state.scenario_assignment_unavailable` 当可重试的拒渲染(用 `error` 原句;续跑口上同码,不是 `resume_blocked_by_policy`,别给「取消任务」当出路);渲会话 mcp 面板的 `scenarioRefusal` 时不假定 `detail` 在场。
1132
+ 运维:看 `runtime_caps_resolve_failed` 是否常响 —— 常响的部署升级后那些时刻会变成拒,先修本部署到中心的链路;确认中心对 `?principal=` 视图两键要么都发、要么都不发。嵌入方:按上一段改读数方法。
1133
+ **回滚**:无持久面;换回上一版即回到旧形。
1134
+
1135
+ 8. **宿主车道模型 shell「被扣了哪些变量名」只有引擎通告一只读法:`secret_env_scrubbed` 日志行的 `site:"server.remote-env-host.spawn-env"` 一支退役(日志面;wire 零变化;部署零动作)**:
1136
+ 旧形:默认清洗环境(`inheritEnv:"scrub"`)的宿主车道模型 shell,被扣的变量名有两处日志:引擎通告 `inherit_env.names_withheld`(服务日志里的 `engine_notice` 行,`detail.names` / `detail.ownCredentials`;每会话每名字集一次),
1137
+ 与本服务宿主腿 spawn 时写的 `secret_env_scrubbed { site: "server.remote-env-host.spawn-env", keys, … }`(每进程 × 键一次)—— 同一批名字,两种读法。
1138
+ 新形:后一行不再写;名字只读 `engine_notice` 行(日志不封条数;会话流的同码帧每个数组至多 32 项;引擎的去重记录有界,每会话至多 200 份名字集摘要,尽力而为)。通告只在**根腿**调引擎自己的 shell 工具时出:委派子代调 shell 不出 —— 根腿自己从不调 shell、只把活派给子代跑 shell 的会话,服务日志里不再有这批名字(计数器照记)。`secret_env_scrubbed_total{site="server.remote-env-host.spawn-env",kind,confidence}` 计数器照记,读数不变。
1139
+ **不变**:其余九个 `site` 值(project-memory / center-plugins / leader 的 git 腿、语言服务器、bake-runner、local-docker 与 adb 的 CLI 腿、settings hooks 命令腿,以及 git worktree 基环境)的 `secret_env_scrubbed` 行照旧 —— 引擎没有这些腿的读者,那一行仍是它们的唯一读法;git worktree 基环境(`WORKTREE_ISOLATION_ENABLED` 的 host 车道上本服务自己跑 `git worktree add / remove / prune` 的环境,从不交给引擎)此前记在 host shell 的现场名下,本版起记在新现场 `server.remote-env-host.git-base` 名下(行的字节除 `site` 与 `note` 外不变);模型面不变(被扣的变量在模型 shell 里读「未设置」)。
1140
+ **谁需要**:读「这台部署的模型 shell 收不到哪些变量」的运维 —— 一处可读。
1141
+ **谁受伤**:按 `secret_env_scrubbed` 行(`site` 为 `server.remote-env-host.spawn-env`)告警 / 过滤 / 做看板的运维脚本(开了 worktree 隔离的部署:基环境的行改到 `git-base` 名下,计数器标签同改);只靠委派子代跑 shell 的会话(见新形末句);用本包 host 车道适配器、不接 `RunnerDeps.onNotice` 的嵌入方(此前有这一行日志;现在名字只经引擎通告到达,没有通告席时引擎把句子落 `console.warn`,结构化日志行没有)。
1142
+ **补偿**:`engine_notice` 行带同样的名字(并分出自有凭据一半);计数器不变;接 `onNotice` 的嵌入方读同一条通告。
1143
+ **升级前做**:有上述告警 / 过滤规则的,改读 `engine_notice` 行(`code` = `inherit_env.names_withheld`,字段 `detail.names`);按 `site="server.remote-env-host.spawn-env"` 数 worktree 基环境剥除次数的看板,把基环境那份改看 `site="server.remote-env-host.git-base"`;其余零动作。
1144
+ **回滚**:无持久面;换回上一版即恢复这一行。
1145
+
1146
+ 9. **远端车道(ssh / adb / local-docker / k8s / e2b)写文件的「不暂存、直接写目标」退路:取消的读法只看落在哪一段,订正 7.139.0 节第 23 条 ⑧ 的一句;准备 / 提交脚本去掉 `readlink -n` 与 `stat`(行为修复 + 文字订正;wire 零变化;部署零动作)**:
1147
+ 订正(7.139.0 节原文不动):第 23 条 ⑧ 写「写目标那一步因取消中断 ⇒ `unknown`……(那一步自己的通道准备也算在内,保守)」与「核不过 —— ……目标机上没有 `stat` —— 这一次写不暂存」。两处在本版都不成立:
1148
+ ① 一次传输分两段 —— 备件阶段(第一个字节发往目标机之前:adb 在本机落的临时件、ssh 开 sftp 通道含懒重连、k8s 建连、追加退路里 adb / e2b 的读旧 + 拼)与传输阶段(字节真发出的那一段)。取消落在备件阶段 ⇒ `aborted`、目标未碰、一个字节没发(修前读数:`unknown`「目标可能只写了一半」;ssh 另有 `ok:true`,取消落在拿通道的那一刻时 sftp 照样把整份写到目标);
1149
+ 只有传输阶段被取消打断才答 `unknown`;传输阶段不收取消(ssh 的 sftp)⇒ 照样写完、答成功,不变。local-docker 的 `docker exec -i` 起进程与 e2b 的 `files.write` 没有可单列的备件,取消落在其中仍答 `unknown`。
1150
+ ② 脚本只用 POSIX sh 的形:`readlink` 不带 `-n`(读到的一跳核过是同一只文件才信,核不上经链接就地写)、不用 `stat`(模式串与数字属主一律读 `ls -ldn`)。目标机上**没有 `stat` 不再是退回就地写的原因**,权限位照样带到换上去的新件上;
1151
+ 带不过去(目标的模式串读不出 / 读不懂、或目标机拒了那一次 `chmod`)而新件照样换上去 ⇒ 写照样答成功,五条车道同一行运维 warn `remote_env_file_mode_failed`(带车道名、目标路径的显示形与目标原来的模式串;升级前这一形无声,目标的模式位悄悄换成新件落下时的位);
1152
+ `mv` 没成、落到就地拷入时不报(写进原 inode,模式本就不变);
1153
+ 收紧之后读不出模式串(`ls` 不可用 / 输出读不懂)才是 —— 与修前同一出路(直写退路 + `stage-seal-fallback` 计数)。悬空的单跳链接现在经链接就地写建出目标(修前 rename 原子建出;只在写的过程中崩溃时有可见差别)。
1154
+ toybox(Android)上这些形按文档 / 源码**推断**可用,未上真机。
1155
+ ③ adb 的本机备件临时件带 0600(内容可能含凭据);adb push 把本机件的模式带上设备,所以设备目标的模式不再靠本机 umask,而是 push 之后显式 `chmod 0644`(adb 的每次 push 多一次设备命令往返)。设模式是**尽力而为**:字节已经落地,`chmod` 失败(设备文件系统不认改模式,如 Android 共享存储;设备掉线)⇒ 写照样答成功,运维日志一行 warn `remote_env_file_mode_failed`(带 push 目的地的显示形与设备回话首行),文件保留 push 落下的模式。
1156
+ **取消落在这一步上,分两路**:直写退路(push 直落目标)⇒ 字节已在目标上,写答成功 + 同一行 warn;暂存路(push 进私有目录)⇒ 编排在提交之前复核取消 ⇒ `aborted`、目标一个字节没动(从未提交)、暂存件清掉 —— 与其余车道「提交前取消」同一读法。
1157
+ 文件保留 push 落下的模式时 —— 认模式的文件系统上是本机件的 0600,不认模式的文件系统上是它给的固定模式。升级前 push 成功即答成功、不设模式,模式随本机 umask(常见 0644)。
1158
+ **谁需要**:adb 车道(Android)与精简镜像上的远端写;取消后要重试写的调用方(`aborted` 可直接重试)。**谁受伤**:依赖「备件窗口取消也答 `unknown`」的调用方读到更窄的 `unknown` 集合;写进不认改模式的设备路径(如 `/sdcard`)的部署每次写多一行 warn(写本身成功);五条车道上已有目标的权限位带不过去的那一次写多一行 warn(此前无声);`chmod` 失败而文件系统认模式的那一次,设备上的文件是 0600 而不是升级前的 0644(同一用户之外的设备进程读不到)。**补偿**:无需旋钮;传输中途的取消仍答 `unknown`,先重读目标;warn 带路径,模式不对的那只文件可在设备上补一次 `chmod`。
1159
+ **升级前做**:无。**回滚**:无持久面;换回上一版即回到旧形。
1160
+
1161
+ 10. **org scope 键的文法判只有引擎一只:静态目录、中心下发的目录里有引擎文法之外的 org 键 ⇒ 起服拒 / 该代目录不采用;共享记忆店的铸键点同判(行为面收紧;wire 零新键;部署动作:核键)**:
1162
+ 旧形:「这是不是一把 org scope 键」几处各判各的 —— 共享记忆店写侧收 `org:` 加至多 185 个非空白字符,`MEMORY_ORG_DIRECTORY_JSON` 装载收 `org:` 加任意非空白串,中心下发的 `orgMemory` 段只过契约包的类别门(`org:` 加非空白);引擎的记忆准入另按 v2 文法判(`org:` 加一段 `[A-Za-z0-9._-]` 或大写 `%XX` 的名,段至多 64 个编码字符)。名里有 `@` / `/` / `:` / 非 ASCII 的 org 键(例 `org:team@acme`)在目录与店里合法、到引擎的记忆准入里整请求拒(`config.memory_scope_key`),共享库读面却能用。
1163
+ 新形:三处判官都是引擎导出的 `isOrgScopeKey`,本仓不再存任何一份文法。① 静态目录:有键不过 ⇒ 起服拒,拒句点名主体与键(`MEMORY_ORG_DIRECTORY_JSON[…] has an invalid org scope key …`)。② 中心下发的远程目录:一代 `orgMemory` 里只要有一把键不过 ⇒ 这一代整代不采用(不丢单键放行其余;旧授予的时间戳不续、gen 高水位不动,中心改发好的一代即采用),该主体的目录答「坏形」:org 记忆准入判瞬时 `memory.admission_required`(503,带重试提示),共享库读面答连接不可用(可重试);服务日志一条 `org_directory_generation_refused`(`gen` / `badKeyCount` / 至多 5 把净化后的坏键),退避窗内不重复。③ 共享记忆店的铸键点(嵌入方 / 管理面调 `putScopeState` / `putStore`):键不过 ⇒ 在落任何语句之前抛 `shared-memory scope key … is not usable`;店的另三个写方法(`putDocument` / `deleteDocument` / `deleteStore`)的 `scopeKey` 是对登记行属主的围栏 —— 逐字比对(含 MySQL 尾随空格的拼法一律不当同一把键),不判键形,所以**店里已有的存量键行不受影响**:仍可写文档、可删,删后在引擎认的键下重建即可(无迁移代码)。
1164
+ **谁需要**:要「目录 / 店 / 引擎对同一把键答同一个话」的运维 —— 此前用时才响。
1165
+ **谁受伤**:静态目录里、中心目录里或店行里用了引擎文法之外 org 键的部署:静态目录起服拒;中心目录含这类键 ⇒ 该主体的整代目录不采用,所有读目录的面在中心改好键之前一直按「目录不可用」处理(与目录取数失败同映射):org 记忆准入瞬时拒;共享库读面对带 principal 的请求连其部署自证的库也不可读;principal 收件箱投递对收发任一方答不上来答 404 `org_delivery.not_member`(这一口不带重试提示)。此前这一代照常采用。一把陈旧的坏键出现在很多主体的表里时,这些主体同受;店的铸键点拒这类键。这类键本来就过不了引擎的记忆准入。
1166
+ **补偿**:服务日志与拒句点名坏键(净化、有界);把名写成引擎文法的规范形 `org:…%XX`(引擎的 `formatOrgScope(<名>)` 即铸,例 `org:team@acme` → `org:team%40acme`)即恢复;存量店行无需动。
1167
+ **升级前做**:核一遍三处的 org 键 —— 静态目录 JSON 里的 scope 键、中心(web-admin)里各主体的 org 记忆授权键、共享记忆店 `shared_memory_scope` / `shared_memory_store` 两表的 `scope_key` 列(只读 `SELECT`):全是 `org:` 加 `[A-Za-z0-9._-]`(段至多 64 字符)的 ⇒ 零动作;有别的字符的 ⇒ 先把目录与登记里的键改成 `%XX` 形,店里存量行无需动(围栏方法仍按旧键寻址可改可删);要迁到新键的,由导入方按新键重新导入后再用既有删除口逐行删旧键的行,不做任何整库 / 整表操作。中心一侧:同一代里好键坏键并存时整代不采用,改键要一次改齐。
1168
+ **回滚**:无持久面;换回上一版即恢复旧收法。
1169
+
1170
+ 11. **`inheritEnv` 的 `400 request.field_invalid` 机读位 `reason` 闭集四词 → 三词:`no_authorizer_session` 退出(装配器的根会话只剩一个读法 = 执行上下文交进来的根;「没有 authorizer 会话」这一拒因在 HTTP 面上不可达)**:
1171
+ 旧形:`inheritEnv:"all"` 在装配器读不到 `auth.sessionId` 时答 `400 request.field_invalid`、`reason:"no_authorizer_session"`。
1172
+ 新形:装配器只读执行上下文交进的根会话(受理漏斗与续跑腿恒交接),该拒因臂删除;`reason` 闭集 = `unknown_word` · `not_a_string` · `lane_not_host`(其余不变)。
1173
+ **谁受伤**:按 `reason === "no_authorizer_session"` 分支的消费方(已知:sdk `openapi.yaml` / README 词表、client-core `inheritEnvWire.ts` 词表)—— 该词不再出现,分支变死码;改读 = 从词表删它。**补偿**:HTTP 面上两者本就恒等,线上零行为差;只是词表收窄。
1174
+
1175
+ 12. **送话口的正文以用户输入到达模型,与调用方是不是运维无关:steer / interrupt 带 `text` 形 / wake 的正文与它们的停驻条目恒以用户源交给引擎;服务自己铸的 workflow 决定投递文本(宿主仍停驻时)恒以系统源投递(行为修复;授权面零变;wire 零新键;部署零动作)**:
1176
+ 旧形:三口的正文按调用方身份定框架 —— 运维(具名 `OPERATOR_PRINCIPALS`,或 `OPERATOR_SINGLE_USER=true` 下的每个调用方)的话被引擎铸成带 mark 的 `<system-reminder>`;workflow 决定投递文本跟着决定者身份走。
1177
+ 新形:调用方的话恒为用户源(live 腿 = 用户在工作中发来的新消息;停驻 / 唤醒腿续跑首轮 = 引擎的围栏数据段);服务自己铸的决定投递文本在唤醒腿上恒为系统源(与决定者身份无关)。运维身份只管越过属主门,判据不变。
1178
+ **谁受伤**:靠「运维 steer 以系统提醒到模型」的部署(已知消费方零读点);单用户部署里回合停驻期间送达的插话,升级后以引擎的围栏数据段到达(段头「仅为数据」)。**补偿**:要以系统源注入的部署用引擎的 hook 反馈 / 部署提示座。**已知限制**:升级前已停在卡上的运维条目带着冻结的框架续跑;同一把 `Idempotency-Key` 跨升级重发同一句运维 steer ⇒ `409 steering.duplicate_input_id`(`detail.differs` 含 `"trusted"`,别换 key 重发)。
1179
+
1180
+ 13. **应答口命中停驻行时点的「本会话放行」(`allow_session`)与 `/decide` 的 `remember:"session"` 同一只请求、同一个铸点:可记的停驻行由不记变记,`POST /v1/tool-approvals/:id/respond` 的 `parked_redeemed` 体上 `rememberApplied` 由恒 `false` 变真答;同口两条幂等回放(`idempotent:true`)不再挂 `rememberApplied`(行为修复;wire 值变化;部署零动作)**:
1181
+ 按 `rememberApplied === false` 断言「停驻支恒不记」或回放体带该键的消费方改读:`true` = 记住了,`false` = 只放行这一次,缺席(回放)= 本次没有授予判定(看首次回执或 `GET /v1/approvals/:sessionId/exemptions`)。workflow 出身 / 无会话锚的停驻行上 `allow_session` 不新增 400(与 `/decide` 的 `remember` 400 是唯一允许的两口差)。已知限制:耐久 ask 决定口 `POST /v1/tasks/:taskId/asks/:askId/decision` 的体不收 `remember`(只答未转停驻的活问;活问的「本会话放行」走 live 应答口的 `allow_session`)。
1182
+
1183
+ 14. **`POST /v1/tasks/stream` 的账本落 `prompt_assembled` / `config_assembled` / `cross_boundary_taint` 三种既有行(此前这条腿恒缺,`POST /v1/runs` 与续跑腿一直有;wire 加性:零新键、零新事件名;部署零动作)**:
1184
+ 按事件序号逐字比对这条腿账本的消费方多见三种行(清单行先于首帧、污染行先于它被发出之后的下一帧,都先于终局行);按事件名分派的消费方零改动。非流式 `POST /v1/tasks` 结构上没有账本,不变。
1185
+
1186
+ 15. **执行车道的声明座只有 `REMOTE_EXEC`:`REQUIRE_EXECUTION_LANE` 退役(设了任何非空值 ⇒ 起服拒,`config.env_key_retired`,拒句点名替代名 `REMOTE_EXEC`;随包部署产物不再渲它;部署面 BREAKING;7.146.0 已预告),车道词 `none` 落地(`REMOTE_EXEC=none` / `config.d/remote-exec.json` 的 `{"provider":"none"}`;`executionLane.provider` 的 `in-process` 换成 `none`(wire 值形 BREAKING,见第 16 条);部署零动作)**:
1187
+ ① **`REQUIRE_EXECUTION_LANE` 退役**:
1188
+ 旧形:`REQUIRE_EXECUTION_LANE=true` 让「没点名车道」拒启,随包部署产物(车道表 · 两份根 compose · 栈 compose · 两份 chart · 集群清单)一律写着这一键。
1189
+ 新形:它在契约包的退役 env 表里(替代名 `REMOTE_EXEC`),在场即拒启,写 `false` 也拒;空串 = 未设。随包产物不再渲该键;配置目录的退役投影 `retired[]` 列它。
1190
+ ② **车道词 `none`**:
1191
+ 旧形:`none` 不是车道词(写了拒启);「无手」只有 `REMOTE_EXEC` 未设一种写法,`executionLane.provider` 答 `in-process`。车道表(逗号串)遇第一处坏段即停、拒句列一份手抄的词表。
1192
+ 新形:声明了 `none` ⇒ 与 7.146.0 上非 local 形(`CONFIG_PROVIDER` 不是 `local`)的未设同一个运行期状态(无手、能力行同、执行环境块同;本版未设本身拒启,见第 16 条),`executionLane` 答 `{ provider: "none", toolsOnThisHost: false }`。车道表的拒因全部交回(坏词与重复同表两条都报),
1193
+ `none` 与别的车道同表 ⇒ 拒(`must be the only entry`),只含空白的段报空段,拒句以契约规则句收尾;结论(拒启)与多车道「一进程一条」拒启不变。
1194
+ **硬断预告的另两件本版同样兑现**:本文件「硬断预告」一条(7.146.0 期登记,见上)里的「未声明车道即拒启」与「`in-process` 改写成 `none`(含一次性迁移)」见本节「执行车道恒点名」一条 —— 预告的四件在 7.147.0 全部落地。
1195
+ **谁需要**:每个部署(车道只有一个声明座 `REMOTE_EXEC`);要把「不给工具执行环境」写成声明的部署。**谁受伤**:自己写的 env、自己拼的清单、或从 7.146.x 及以前的随包产物拷过 env 的部署 —— 起服拒;对 `executionLane.provider` 八词穷举的客户端;按车道表旧拒句措辞匹配的脚本;
1196
+ 记着 `in-process` 的存量会话 / 审批行 —— 由一次性迁移 M40 改写成 `none`(见本节「执行车道恒点名」一条)。
1197
+ **补偿**:自写 env 删一行(随包 compose 不带 `env_file`,旧 `.env` 里的残行不进容器);要表态「不给工具执行环境」写 `REMOTE_EXEC=none`。
1198
+ **升级前做**:在部署的 env / 清单 / `.env` 里查 `REQUIRE_EXECUTION_LANE`,删掉;由中心(web-admin)编排器起的 worker,先把编排器换成已停渲该键的发行、再升 worker(DEPLOY-PREREQS 本版节)。
1199
+ **回滚**:回到 7.146.x 时 `REQUIRE_EXECUTION_LANE` 缺席 = 旧缺省(不拒),无需加回;回到 7.146.x 之前先把 `REMOTE_EXEC=none` 撤掉(旧版拒启这一词)。
1200
+
1201
+ 16. **🔴 执行车道恒点名:每个部署都要声明自己最终生效的执行车道(env `REMOTE_EXEC`;`CONFIG_PROVIDER=local` 形下 `config.d/remote-exec.json` 也算),未声明 ⇒ 拒启;状态名 `in-process` 改名车道词 `none`(wire 五处换值,零别名);存量 `in-process` 行由一次性迁移 M40 改写(停-迁-起,不可滚动);起服行 `exec_lane_selected` 只带 `{lane}`(行为 BREAKING;wire 值形 BREAKING;嵌入方类型面 BREAKING;持久面一次性迁移;部署动作:写明 `REMOTE_EXEC`,有存量行的部署停全部旧副本)**:
1202
+ ① **未声明即拒启**:
1203
+ 旧形:`REMOTE_EXEC` 未设 / 空串时,`CONFIG_PROVIDER=local` 隐含 `host`(工具直接跑在这台机器上,无 OS 沙箱),其余形静默落进不挂手的进程内桩(手带整族不挂、任务照跑、回执 `completed`)—— 同一个「没写」,两种结局靠第三个变量分。
1204
+ 新形:判点在执行车道合成步的尾部(本地配置文件覆写之后、中心拉取之前):最终车道不来自显式声明 ⇒ 拒启,拒句以 `No execution lane is declared — every deployment names its execution lane: set REMOTE_EXEC (with CONFIG_PROVIDER=local, config.d/remote-exec.json also declares it). To keep what this deployment did before 7.147.0: REMOTE_EXEC=none when CONFIG_PROVIDER is not "local" (…), REMOTE_EXEC=host when CONFIG_PROVIDER=local (…). …` 起,一行给出照旧行为的两条修法;`CONFIG_PROVIDER` 只回答「配置从哪来」,不选车道。
1205
+ `REMOTE_EXEC=""`(空串)与未设同判。`run-local` 入口自身声明 `host` 车道(入口 = 部署者;声明的先后 = `config.d/remote-exec.json` > `REMOTE_EXEC` > 入口,在场的最高者终结选择,入口只填缺席位,不写进程 env)。`config.d/remote-exec.json` 点了隔离车道(`e2b` / `k8s` / `ssh` / `adb`:坐标此版只从 env 取)而 `REMOTE_EXEC` 没有声明同一条 ⇒ 拒启(修前:一行 `remote_exec_file_isolated_lane_unwired` 告警后照跑 env 的车道,或判点拒);出路是 `REMOTE_EXEC=<同一条>` 带齐坐标 env,或把文件改成要的车道;它只跑 `host` / `none`,部署声明了别的车道 ⇒ 起任何任务之前拒(换跑 HTTP 服务,或声明 `host` / `none`)。自建装配的嵌入方:`composeExecutionLane` 的 `ctx.drivesFromFile` 换成必填的 `ctx.entry`(HTTP 形递包根导出的 `HTTP_SERVICE_LANE_ENTRY`)。
1206
+ ② **`none` 两座皆无**:`REMOTE_EXEC=none`(或文件 `{"provider":"none"}`)⇒ 执行环境工厂与执行环境座都不给,每个 run 的 `wiring_manifest.hands = {mounted:false, reason:"no_execution_env"}`;手带之外的工具照常执行;请求体 hooks 与 stdio MCP 不归车道管(各自的开关照旧)。
1207
+ ③ **wire 五处换值(对象形不变,`in-process` → `none`)**:`GET /v1/capabilities` 的 `executionLane.provider` · `GET /v1/sessions/:id/execution-placement` 的 `lane` · 409 `execution_lane.not_served` 的 `boundLane` · 409 `execution_lane.tree_bound` 的 `boundLane` · 403 `execution_lane_not_allowed` 的 `extra.lane`。
1208
+ 车道全集仍是八个词(`host` `e2b` `k8s` `ssh` `adb` `local-docker` `device` `none`),`in-process` 不在其中;`REMOTE_EXEC=in-process` 起服拒(拒句列合法词)。嵌入方类型 `ExecutionLane` / `ALL_EXECUTION_LANES` 删旧词,零别名。
1209
+ ④ **起服行**:`exec_lane_selected` 由合成步在判点与不变量都过了之后发恰一行,字段只有 `{ lane }`(最终车道);此前多带的 `source` 退役;`remote_exec_real_system` 的「单机缺省落了 host」那一形随隐式 `host` 退役(显式 `host` / 非隔离车道照旧有这一行)。
1210
+ ⑤ **一次性迁移 M40(SQL 两方言 + local)**:`approval_ask.execution_lane` 与 `session_meta.execution_lane` 里的 `in-process` 改写成 `none`;local 数据根里会话元数据边档与审批问账日志里的同一词同改。改值不丢信息;窗 = 发布日 + 30 天,窗内每次起服都跑(之后无行可改即零动作),窗关之后的第一个 minor 删码。
1211
+ **停-迁-起**:有 `in-process` 存量行的部署,停掉全部旧版本副本 → 起本版(起服时迁移)→ 再起其余副本;两版副本不可混跑(旧副本会在改写之后接着写旧词)。
1212
+ **守卫**:SQL 后端上若库里有带旧词的行,而判活窗(`REAP_RUN_STALE_SEC`,收割器判「持有者还活着」用的同一个窗)内还有 `running` run 在心跳 ⇒ 起服拒 `config.execution_lane_rename_refused`,一行不改;拒句给出可以再起的时刻(最新心跳 + 判活窗,ISO 时刻与「N 秒之后」两种写法)—— 旧副本确已全停时,那些心跳是它们留下的 run,过了那个时刻收割谓词也判它们为死,再起即过。
1213
+ **守卫看不见的一形(如实)**:守卫只看心跳,**空闲的旧副本**(没有在跑的 run)不留心跳 ⇒ 守卫放行;改写之后它若接新活,会再写下旧词,本版读到旧词的行时按「这一词已改名」响亮拒(不静默当作别的车道)。出路:停掉它,再起一次本版(窗内每次起服都跑 M40,漏网的旧词再改一遍)。所以「停全部旧副本」是运维的动作,守卫只兜住有 run 在跑的那一种。
1214
+ local 数据根由数据根锁保证同一时刻只有一个进程,无需守卫。local 两腿读得出旧词而改写落不了盘(不可变文件 / 只读挂载 / 盘满)⇒ 起服拒 `config.execution_lane_rename_refused`,拒句点名文件与原错码,文件一个字节不动;恢复那只文件与所在目录的写权限再起,改名在下一次起服重跑。
1215
+ **谁需要**:每个部署(车道只有一个声明座,「没写」不再有两种结局);按 `executionLane.provider` 判无手的面板与客户端(词表内的词,不再是表外状态名)。
1216
+ **谁受伤**:没写 `REMOTE_EXEC` 的部署 —— 起服拒;按 `in-process` 字面分支的客户端(读到 `none`);有存量行又想滚动升级的部署(守卫拒,或空闲旧副本漏网后的响亮拒);依赖 `exec_lane_selected.source` 的日志规则。
1217
+ **补偿**:拒句里就是一行修法;`none` 逐字复现 7.146.0 非 local 未设的运行期行为,`host` 逐字复现 local 未设的行为;守卫的拒句给出可以再起的时刻;M40 窗内每次起服都跑。
1218
+ **升级前做**:① 在 env / 清单 / `.env` 里写明 `REMOTE_EXEC`:7.146.0 上非 local 而未设的 ⇒ `REMOTE_EXEC=none`,`CONFIG_PROVIDER=local` 而未设的 ⇒ `REMOTE_EXEC=host`(或在 `config.d/remote-exec.json` 里写);② 跑过未点名车道的部署(库里或数据根里可能有 `in-process` 行):停全部旧副本,再起本版;③ 客户端把 `executionLane.provider` / 放置读面 `lane` / `boundLane` / `extra.lane` 的 `in-process` 分支改读 `none`;④ 中心按 `allowedLanes` 写的车道准入策略里列 `none`(过渡期两个词都列,升级完删旧词 —— 那是策略数据,不是代码里的双读)。
1219
+ **回滚**:回到 7.146.x 之前停全部本版副本,并把 `REMOTE_EXEC=none` 撤掉(7.146.x 不认这一词);M40 改写过的 SQL 行要回写才能被 7.146.x 读成它认得的词 —— **前提**:`session_meta.execution_lane` 在本版已被 M41 搬进 `session_ext`(第 5 条),先按第 5 条回滚把列加回 `session_meta` 并从 `session_ext` 回写,再跑下面两条(次序见第 5 条回滚):`UPDATE approval_ask SET execution_lane = 'in-process' WHERE execution_lane = 'none';` 与 `UPDATE session_meta SET execution_lane = 'in-process' WHERE execution_lane = 'none';`(在本版上声明过 `none` 之后新建的行同样会被改回,这正是 7.146.x 对「无手」的叫法);local 数据根没有反向工具 —— 升级前备份数据根,回滚 = 用备份。
1220
+
1221
+ 17. **🔴 缺省推导的 local 只在数据根不存在 / 为空时退回内存;数据根上已有东西而开不了 ⇒ 拒启,与显式 `DB_BACKEND=local` 同形(行为变更)**
1222
+ 旧形:没写 `DB_BACKEND` 的部署开数据根失败 ⇒ 退回内存 + 一行 `store_db_unreachable_fallback_memory`(adoption 在飞与店的确定拒启除外),数据根里已有会话 / run 账本的那一形也一样;另一实例持锁时,第二只裸 boot 等满 `STORE_LOCK_WAIT_MS` 窗后退内存。
1223
+ 新形:开店之前读一次数据根:不存在 / 空目录 ⇒ 照旧退内存(`/health.storeDegraded`、gauge `store_backend_degraded` = 1、`store.degradedReason: "local_unwritable"`);有任何条目或列不出 ⇒ 开它时的任何失败原样拒启;持锁那一形等满窗后拒,拒句点名持锁 pid。
1224
+ **升级前做**:`store_backend_degraded` 现为 1 的副本升级后可能拒启 —— 先读启动日志里 `store_db_unreachable_fallback_memory` 的 `error`,修好数据根的权限 / 挂载;本来就要内存形的写 `DB_BACKEND=memory`;要另起一个空根就把 `LOCAL_DATA_ROOT` 指到空目录。同机两只裸 boot 共用一个数据根的,给第二只单独的 `LOCAL_DATA_ROOT`。
1225
+ **回滚**:回到上一版即回到按错误种类判的降级臂;数据零改动。
1226
+
1227
+ 18. **引擎 7.64.0 → 7.65.0(`@sema-agent/core` 精确钉;`@sema-agent/primitives` 随 core 的同版精确依赖到 7.65.0):① 🔴 记忆控制面要在能建硬链接的卷上 —— 不能 ⇒ File 记忆后端起服拒 `memory.control_plane_links_unsupported`;② 兑付与导入的引擎拒按「可不可重试」一读,兑付后被撤的放行读 `refused` / `dot_removed`;③ 规则导入 prepare 的审批记录建不成 ⇒ `503 state.rule_write_failed`;④ 住客比较一读律;⑤ 起服日志 `session_box_mount` 取代 `mailbox_store_enabled` 上两格;⑥ 一次性迁移 local 腿报叫不出名字的桶数;⑦ 限制表上退役且没有后继的工具名 = 这一行跳过 + 说一句(会话流多一码 `config.legacy_tool_name`;请求体 / 部署名单 / 中心下发的审批名单不再拒)(行为变更 + 硬破坏一条;部署动作只在 ①)**:
1228
+ 换钉:`@sema-agent/core` 7.64.0 → 7.65.0 精确(`package.json` 只钉 core),`@sema-agent/primitives` 随 core 的精确依赖到 7.65.0。下列各项按「谁看得见」排。
1229
+ ① **记忆控制面的硬链接(硬破坏)**:
1230
+ 旧形:File 记忆店在任何文件系统上都打开;控制面所在的卷不能建硬链接时,每个控制对象写失败 —— 一次收留把可疑文件从模型可见面拿下、副本却一份都没存下(报告 `quarantine copy FAILED`)。
1231
+ 新形:引擎每次开店先在控制面顶层试建一枚硬链接(`.link-probe-<uuid>`,试完即删);不能 ⇒ 店在打开处被拒,码 `memory.control_plane_links_unsupported`(店形拒一族的第三码;拒句点名 errno、不带路径),店里的文件一个字节不动。
1232
+ 本服务:`MEMORY_ENGINE_BACKEND=file`(缺省)的 File 记忆后端构造期抛 ⇒ **起服拒**;`MEMORY_ENGINE_BACKEND=pg|mysql` 的引擎 mount 时在自己的控制面上开 File 店被拒 ⇒ 这一跑没有记忆、会话照跑
1233
+ (`effectiveMemoryScopes` = `{ state: "memoryless", reason: "mount-failed" }`;运维行 `memory_engine_incident` 带码,fail-open 计数 `server.memory.store-form-refused-step-skipped`);运维面经引擎开店撞上它 ⇒ `409` 原码。
1234
+ **谁需要**:每一次收留都要真存下副本的部署(上一版在这种卷上静默丢副本)。**谁受伤**:记忆控制面(记忆根 —— `MEMORY_ENGINE_DIR`,缺席时数据根 —— 下面那只 `<slug>/.engine` 目录;目录钉住的部署另有个人平面的 `personal/.engine`,运维面第一次用到个人平面时开)在不能建硬链接的卷上 —— 有的网络共享、FAT / exFAT 卷、有的容器 overlay 配置。
1235
+ **补偿**:把控制面挪到支持硬链接的卷上;店的文件不受拒动,无需迁移。支持形:docker `-v` 绑定挂载、k8s PVC 块存储、`hostPath`、`emptyDir`(本地文件系统)都能建硬链接;NFS 不可靠(见 DEPLOY-PREREQS 的 `DB_BACKEND=local` 数据目录一节);SMB / Azure Files / FUSE 类卷不在支持形(不能建硬链接 ⇒ File 记忆后端起服拒)。本服务的工具结果、文件历史与邮箱锁本来就要硬链接,但那是数据根所在的卷;记忆根在另一只卷上时,那只卷要自己试。进程崩在试建与删除之间会留一枚 `.link-probe-*`(不当记录读,可手删)。
1236
+ ② **兑付 / 导入的引擎拒**:赎回拒臂与批成员拒臂多一位 `retriable`。卡道:`retriable` 真且是店故障 ⇒ 可重试的 `rule_store_error`(批:全员被拒且全员可重试才重兑);其余 `redeem-refused`。
1237
+ 导入两只 redeem 口:成员可重试或引擎说不知落没落 ⇒ `503 state.rule_import_retry` 同票重走;其余拒是确定结局(200 回执里 `refused`)。相对上一条(7.146.0 节第 23 条「引擎 7.63.0 → 7.64.0」⑥):
1238
+ 记 dot 的 CAS / dot 分配失败卡道改回可重试;同票重走时其间被属主撤掉的放行在回执里读 `refused` + `reason: "dot_removed"`(此前仍读 `persisted`;那一条的已知限制只对引擎 ≤ 7.64.0 成立)。
1239
+ ③ **规则导入 prepare**:引擎的审批记录店建不成这次导入的记录 ⇒ `POST /v1/rules/cc-import/prepare` / `POST /v1/rules/local-import/prepare` 答 `503 state.rule_write_failed`(带 `committed: "no"`;没有票、没有放行落店;
1240
+ local-import 这一批收下的 deny / ask 可能已落店)—— 原样重发即重铸。此前两口落未分类 500。确认口的记录店故障:卡道可重试、导入道同票重走。
1241
+ ④ **住客比较**:两侧都没有化身令牌的住客比较由「说不准」改答「同一位」,一侧有一侧没有答「不是同一位」。本服务会话缓存的新鲜判随之命中两侧都没戳的会话头(本服务的店建行即铸化身;写面照旧拒)。
1242
+ ⑤ **起服日志**:`session_box_mount { peerLaneMountable, peerLaneRefusal?, reason? }`(邮箱店 × 会话店一只判;不拒起服);`mailbox_store_enabled` 去掉 `peerLaneMountable` / `peerLaneRefusal` 两格。
1243
+ ⑥ **一次性迁移(导入层根的全局放行退役)local 腿**:引擎一次答出桶在场的属主(导入记录点名的身份交给它)与叫不出名字的桶数;报告新键 `importedLayerRootBucketsUnnamed`(SQL 恒 0),
1244
+ 非零每次起服 warn `imported_layer_root_buckets_unnamed`(带个数)—— 那几只桶本步没读,其中这种放行照旧生效,按属主列规则(`GET /v1/rules`)处置。
1245
+ ⑦ **限制表上退役且没有后继的工具名**(引擎退役表里那一行是 `removed` / `folded into`:`TeamCreate` · `TaskOutput` · `MultiEdit` …)—— 这一行跳过 + 说一句(不审、不拒),整表不拒(只在有人说那一句的三道门,见下);改名了的旧名(有后继:`Task` ⇒ `Agent`、`KillShell` ⇒ `TaskStop`)照旧拒。
1246
+ 行原样留着(表谁都不改;嵌入方自挂同名工具时它照管那只工具)。谁读这张表,谁说:
1247
+ 请求体 `settings.permissions.deny` / `ask` 与会话存下 / 祖先交下来的规则 —— 引擎读:请求照收(此前 `422 request.unprocessable`、`reason: "retired"`;存量会话规则上此前整跑被拒),会话流通告 `config.legacy_tool_name`(受众 user);
1248
+ 部署 `APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO` —— 本服务读:照常起服(此前拒启),起服 warn `approval_list_legacy_tool_name`(一张表一行,点名 env 与条目);只剩这种行的表仍算审批意图(没有 checkpoint 店的部署照「名单在场要 durable 门」拒启,与写任何名字同一判 —— 删掉那一行即可);
1249
+ 中心下发 `governance.approvalRequire` —— 本服务读:整组照落(此前整组拒、保前值),组受理之后 warn `web_admin_approval_require_legacy_tool_name`。
1250
+ 放行只在有人说那一句的这三道门;没有人说话的面照拒(不拒就是静默受理),候引擎下一版在选择器表 / 技能表发退役名通告、并导出通告句源后同形放行:请求体 `settings.permissions.neverAuto`(`422`,与上一版同码同句)·
1251
+ 请求的 `excludeTools`(`400 config.tool_face_control`)/ 子代 `denyTools`(`400 config.agent.unknown_tool`)/ 技能 `disallowedTools`(`400 request.field_invalid`)。
1252
+ **谁需要**:写着这种名字的限制表(壳从 CC 用户 settings 转投的 deny 表常带)—— 不再因一行死项整份被拒。**谁受伤**:按 422 `reason: "retired"` / 拒启 / 整组拒找这种名字的调用方与运维 —— 改读通告与两条 warn。**补偿**:按通告 / warn 点名的条目把它从表里删掉。
1253
+ **引擎已知限度(随版发)**:多只副本共一只记忆控制面时,扣留账的对账与收留写可能交错、把行记成 `capture_lost` 而保管字节成孤(KL-3485-a,引擎下一版收);
1254
+ 采集退出记录与污染标记对同一只坏槽两读(KL-3466-b,过渡双读);引擎面百分号只解一层(KL-3487-a)—— 本服务出口脱敏器解到定点,覆盖它。
1255
+ **谁需要 / 谁受伤 / 补偿**:见各项。**升级前做**:① 核记忆控制面所在的卷能建硬链接(在那个目录里 `ln a b` 试一次);不能就先挪;② 按 `mailbox_store_enabled.peerLaneMountable` 告警的规则改读 `session_box_mount`;
1256
+ 其余零动作。**回滚**:回到上一版 ⇒ 不能建硬链接的卷上 File 记忆店照旧打开(并照旧丢收留副本);其余各项无持久面(零 DDL、零一次性迁移)。
1257
+
1258
+ 19. **本服务自己要的目录一律 `0700`:新建的目录创建即 `0700`,升级前由裸 `mkdir` 铸成 `0755` 的 `DB_BACKEND=local` 数据根下 `runs/<taskId>` · `space-commits` · `checkpoint-ctx` · `.tmp` · `attachments` · 会话 scratchpad · 中心 plugin 缓存 · 记忆同步游标目录起服时一次性收紧(一次性迁移 M39);本服务自己落的文件一律 `0600`、原子写的 tmp 每次独占新建(安全面;持久面;日志面加性;部署零动作,外部读者见「升级前做」)**:
1259
+ 旧形:本服务自己铸的目录有几种做法 —— 一部分店走 core 的 `ensureDir`(`0700`),run 店(`runs/<taskId>` · `space-commits`)· checkpoint 店(`checkpoint-ctx` · `.tmp`)· 附件店(`attachments`)· 会话 scratchpad · 中心 plugin 缓存 · 记忆同步游标目录 · 配置根下的 LKG 父目录与技能正文缓存直接 `mkdir -p`(进程 umask 之下的 `0755`)。
1260
+ 目录 `0755` 而里面的文件多半 `0600`:组 / 他人读不了文件,但列得出文件名(run 的 taskId、附件 id、checkpoint token 文件名);附件店的文件与会话边档(`session-titles.json` 等)是默认的 `0644`,`0755` 的 `attachments` 目录连附件字节都对别的本机用户开着。
1261
+ 新形:这些写口也走 `ensureDir`,新建的目录一律 `0700`(`src/**` 没有第二种建目录的写法、没有手写的 `0o700`,有普查钉);本服务自己落的文件(附件 · 会话边档 · 记忆同步游标 · LKG · 技能正文缓存 · 凭证续签 · 钥匙文件 · 完成收件箱 · spool · 数据根顶层的 `exit-last.json` / `crash-last.json`)只读一个模式值 `0600`;
1262
+ 原子写的 tmp 每次独占新建(pid + 随机名、`O_EXCL`;同步写口 —— 完成收件箱账本的压实、续租被拒的粘性位 —— 也一样,它们原先经引擎的原子写,那一只以截断方式打开 tmp):此前固定 / 可复用的 tmp 名(附件的 `<id>.bin.tmp` / `<id>.json.tmp`、最近活动边档的 `<path>.<pid>.<n>.tmp`)在崩溃后留下的升级前 `0644` tmp 会被下一次写截断后原样改名上位、把 `0644` 带上正式文件,现在不会。升级前已有的 `0755` 目录,`ensureDir` 对已存在的目录什么也不做 —— 所以起服时(`DB_BACKEND=local`,任何读者之前)一次性收紧:
1263
+ 对 `runs` 与它下面的每一只子目录 · `tmp` · `space-commits` · `checkpoint-ctx` · `.tmp` · `attachments` · `scratchpad`(与每个会话段)· `plugin-cache`(往下三层)· `<记忆引擎根>/sync-cursors`(缺省 = `<数据根>/sync-cursors`;引擎根在数据根之外则不在其内)从数据根(持锁的那只物理路径;起服途中它自身被换成链接 ⇒ 一行 warn 点名数据根(`.`),整步不走)逐段往下看:
1264
+ 路径上任一段是符号链接 ⇒ 这一条整条不走、进 warn(码 `SYMLINK_IN_PATH`,链接指向根内根外一样);是真目录且带组 / 他人位的 ⇒ 先以 `O_NOFOLLOW` 打开取 fd,再核这只 fd 就是根内那条路径上的目录
1265
+ (物理路径按段在数据根之下、那条路径此刻的 inode 等于 fd 的、路上每一段此刻仍不是链接),三者皆过才对这只 fd 收紧成 `0700`(已有文件的模式一字不动;普通文件不碰;不在的不建;数据根自身与名册外的目录不碰)。
1266
+ 收紧了至少一只 ⇒ 一行起服提示 `local_data_dir_modes_tightened`(`count` + 至多五个 `examples`,相对数据根);第二次起服零命中零写、不再有这一行。win32 没有 POSIX 模式位,整段不动。
1267
+ **收紧失败不拒启,但响亮**:目录不属于服务进程的用户(只能写、不能改模式)、路径上有符号链接、检查之后被换走(`ESTALE`)等 ⇒ 逐目录点名(路径 + 码)进 warn `local_data_dir_mode_refused`(`entries` 至多十条,带出路),窗内每次起服再报,其余目录照收,服务照起。
1268
+ 把店目录链到别的盘的部署:链接那头的真目录不被跟、不被改,由属主自己 `chmod 700`(这一行窗内每次起服都在 —— 迁移看不见链接那头是否已改)。
1269
+ 新写下的文件在这样的目录里仍是 `0600`(含附件店与会话边档);留着的缺口只有一格:升级前写下的附件字节(`0644`)在一只收不紧的 `attachments` 目录里仍可被他人读到 —— 看到这一行 warn 点名 `attachments` 的部署要当天处理。
1270
+ **不在迁移里的(披露)**:SQL 后端的 host 车道在同一个数据根下铸的 `scratchpad` / `plugin-cache`、配置根(`SEMA_CONFIG_DIR`,缺省 `~/.sema`)下的 LKG 父目录与 `skill-cache`、`MEMORY_ENGINE_DIR` 指到数据根之外的 `sync-cursors`,升级前若是 `0755` 原样留着(新建的一律 `0700`);升级前已落盘的边档文件(`session-*.json`)与记忆同步游标不扫 —— 下一次重写即换成 `0600`;崩溃留下的旧固定名 tmp(`attachments/<id>.bin.tmp` 等)不再被复用、也不清扫;数据根顶层的 `exit-last.json` / `crash-last.json` 是原地覆盖,升级前已在的那两只模式不动(新建的是 `0600`)。
1271
+ 要收这些:`chmod 700` 它们(目录),或 `chmod -R go-rwx <配置根>`。工作树类目录(宿主执行环境替工具建的目录)、spool、壳 / 请求 / 运维点名的目录不在其内,模式不变。
1272
+ **谁需要**:每个 `DB_BACKEND=local` 部署(自动,无配置);配置根与缓存目录的收紧只对新建生效。**谁受伤**:靠组 / 他人读权限读数据根的外部进程 —— 另一个用户身份的备份 / 监控 / 同步任务升级后列不出、读不进这些目录;数据根的目录属主不是服务进程用户的部署,收紧被拒、每次起服一行 warn。
1273
+ **补偿**:外部读者换成服务进程的用户身份,或给数据根加 ACL(`setfacl`);被拒的目录由属主 `chmod 700 <目录>`(或 `chown` 给服务用户)后重启,那一行 warn 即消失。无放宽旋钮(只收不放)。
1274
+ **升级前做**:`find <数据根> -maxdepth 3 -type d -perm /077` 看一眼会被收紧的目录(信息性);有别的用户身份在读数据根的部署(备份 / 监控),升级前把读者换成服务身份或配 ACL。
1275
+ **将来变化**:这一步是一次性迁移,窗内(发布日 + 30 天,日期见 `plugins/one-time-migrations.ts` 登记表 M39 行)每次起服都跑,窗关之后的第一个 minor 删码 —— 此后从更早的版本直升的数据根,升级前铸成的 `0755` 目录原样留着(新建的一律 `0700`,不受影响),本服务不再点名;
1276
+ 出路 = 运维一次 `chmod 700` 数据根下 `runs`(及其子目录)· `space-commits` · `checkpoint-ctx` · `.tmp` · `attachments` · `scratchpad`(及其子目录)· `plugin-cache`(及其子目录)· `<记忆引擎根>/sync-cursors`,或升级时先过一次带本条的版本并起服。**回滚**:回到 7.146.x 时已收紧的目录保持 `0700`(旧版对已存在的目录不 chmod),旧版新建的目录又是 `0755`。
1277
+
1278
+ 20. **hook 条目的 `onFailure: "block"` 自本版起执行:同步的 command / http 条目被选中却没给出裁决 ⇒ 按退出码 2 算,它守的动作被拦下;续跑重放读出存量请求里的 `onFailure`(安全轴,失效关闭;行为变更;部署零动作);同批:续跑存量体里有本版读者读不出、而本部署本会采纳的成员 ⇒ `409 resume_blocked_by_policy`(安全轴,不再去掉照跑);新提交 `settings.env` 有成员不是串 ⇒ `400 request.field_invalid`(采纳 env 的车道);坏 `args` 的 400 判决改由契约分类器出(`detail.reason` 由 `wire_key_invalid` 变为 `entry-invalid` / `guard-entry-invalid`;wire 值变,BREAKING)**:
1279
+ 旧形:7.135.0–7.146.x 新提交里 command / http 条目上的 `onFailure` ⇒ `400 request.body_shape`(读者不携带);续跑重放的存量请求里它被读者剥掉 —— 写了 `"block"` 的守卫起不来时照放行。
1280
+ 新形:读者携带它(契约包 19.0.0),本服务执行 `block`:起不来 / 超时 / 退出码非 0 非 2(http 非 2xx)/ 输出读不成判词 / `PreToolUse` 判词在闭集外,以及本服务自己的门让它没跑成(URL 名单拦下、
1281
+ shell 形 powershell、`if` 评不出、组的 matcher 编不过、事件墙钟耗尽)⇒ 交给事件的是一次退出码 2(`PreToolUse` deny · `UserPromptSubmit` / `PreCompact` block · Post* 三站一段反馈上下文),
1282
+ 句子 `<事件> hook did not reach a verdict (<成因>); blocking because onFailure is "block"`。`async` / `asyncRewake`、`Stop`、`StopFailure` / `PostCompact` 上不生效;`continue` 与缺席同 7.146.0。
1283
+ `onFailure` 写在 prompt / agent / mcp_tool 条目上照旧是读者不携带的键(新提交 400)。7.135.0 节第 13 条「投影前剥掉 `onFailure`」的建议对 command / http 条目不再适用。
1284
+ **谁需要**:要守卫起不来时拦下的调用方。**谁受伤**:① 写了 `block` 的条目因本服务自己的门没跑成 —— 此前放行,现在拦下;② 升级前停驻的任务:存量请求(只可能来自 7.134.x 及更早:7.135.0 起新提交带这个键就 400)
1285
+ 里写了 `block` 的守卫续跑时开始按 block 执行;存量里写的是两词之外的值 ⇒ 读者判坏块,续跑**拒**:这条车道本会采纳请求体 hooks(单用户车道)⇒ `409 resume_blocked_by_policy`(`blockedBy: "request.field_invalid"`,`field: "settings.hooks"`;句子只点名成员键,不回显值),卡 / 任务仍待决、行不动;不采纳请求体 hooks 的车道(多租户)零变化 —— 续跑重读的一次性迁移不接这一形(坏值没有可猜的正确值)。
1286
+ 同一条律覆盖存量体里本版读者读不出、而这条车道本会采纳的每一个成员:`settings` 的其它键(如 `env` —— 有成员不是帽内的串;空记录 `{}` 不算 —— 车道采纳调用方 cwd,或采纳请求体 hooks 且请求带着 hooks 时)、`mcpServers[i]` 的传输成员(部署注入请求 MCP、条目名不被部署占住时)、`a2aPeers[i].headers` 的成员(部署注入请求 A2A 时)——
1287
+ 升级前这些成员被去掉、任务照跑(运维日志 `task_settings_deferred` / `mcp_transport_members_dropped` / `a2a_peer_headers_members_dropped`,外加 hooks 的 fail-open 计数 `server.hooks.resume-reader-refused`),这三行日志与该计数本版一并退役;新提交带同样的成员 ⇒ `400 request.field_invalid`(同一只判;新提交面唯一的新拒是 `settings.env` 里值不是串的成员 —— 受理门收下了它们,此前装配静默不交;只在采纳 env 的车道上拒:单用户 host / device,或采纳请求体 hooks 的车道上请求带着 hooks,其余车道 env 没有读者、零变)。
1288
+ 判的是**续跑将要跑的那一份体**:续跑请求带了重述键 `mcpServers` / `a2aPeers`(四道续跑门都收)⇒ 按盖过重述之后的体判,读不出的 MCP / A2A 成员可由一张合形的整表(空表也算)换掉、照常续跑;不带 ⇒ 存量体原样判。
1289
+ 拒体形(如实):复用 `409 resume_blocked_by_policy` + `blockedBy: "request.field_invalid"`(不铸新码);句子只列成员键路径(不回显值、不带会话坐标 —— 会话坐标在运维行 `resume_refused_stored_body` 上);A2A 对端不看场景同名占位(存体预判在认领之前答、不知道场景)⇒ 会输给同场景部署同名对端的那条请求对端照样算,方向是多拒一次。
1290
+ **补偿**:拦下的那句点名成因,故障帧点名是哪一条;改条目 / 改 URL 名单,或改回 `continue`。不加窗、不加旋钮。续跑被拒的停驻任务:拒句点名哪些成员读不出;出路 = 读不出的是 MCP / A2A 成员 ⇒ 续跑请求带这一键的合形整表;其余 ⇒ 取消那只任务、按本版的形重提(一次性迁移 M20 窗内,两类此前受理的 hooks 存量形照旧由剥键重读接住,不拒)。新提交的 `settings.env` 值写成串即过。
1291
+ **同批:坏 `args` 的 400 判决改由契约分类器出**:
1292
+ 旧形:7.133.0 起本服务在契约分类器装上的同一坐标上读原值 `args`,形错 ⇒ `400 request.field_invalid`,`detail: { reason: "wire_key_invalid", key: "args", path: [..., "args"] }`。
1293
+ 新形:契约包 19.0.0 承运 `args`(串数组、元素无 NUL;`[]` 与空串元素合法 —— 与本服务旧读法同形),坏值是分类器的坏块;本服务不再读第二遍原值:`detail.reason` 变为 `entry-invalid`(非守卫事件)/ `guard-entry-invalid`(守卫事件),
1294
+ `key` 仍是 `"args"`,`path` 指那一条而不是那只键;句子换成块码释义。受理与执行的形不变。
1295
+ **谁受伤**:按 `reason === "wire_key_invalid"` ∧ `key === "args"` 匹配的客户端 / 脚本。**补偿**:按 `detail.key === "args"` 读。
1296
+ **升级前做**:原样投影宿主设置文件的调用方,确认守卫条目上 `block` 是本意;有 7.134.x 及更早停驻、hooks 里写着 `onFailure` 的任务,升级前把它们跑完或取消。**回滚**:回到 7.146.x 即回到「新提交 400、续跑剥掉」,`args` 的 400 判决回到旧坐标与旧 `reason`。
1297
+
1298
+ 21. **日志脱敏认复合凭据名(`DB_PASSWORD` / `PGPASSWORD` / `SECRET_KEY` / `AWS_SECRET_ACCESS_KEY` …,名字末尾收在强档词上);请求面 URL 凭据判官随包认同一批名字(行为变更:遮得更多、新提交拒得更多;部署零动作)**:
1299
+ 旧形:脱敏器只认整名表上的名字,复合名后面的值原样出门;请求面 URL 只拒整名在表上的参数。
1300
+ 新形:名字判定读契约包的判官(整名在表上,或末段尾部是 `password` / `passwd` / `pwd` / `secret` / `apikey`,或末尾是 `secret_key` / `secret_access_key` / `api_key` / `access_token`;只看末尾,`password_hash` / `tokens` 不算);日志四个名字读者同读,名长不封顶。
1301
+ 请求面 URL 带这类参数(`?db_password=…`)⇒ 新提交 `400 request.field_invalid`(`reason: "url_credential_param"`);续跑重放存量体照旧不判。
1302
+ **谁需要**:日志 / trace 里出现复合凭据名的部署。**谁受伤**:读日志的人(末尾收在强档词上的非凭据名也被遮,如 `show_password=1`;单行出门形里凭据值后紧贴的下一行首词随值遮);URL 里带复合凭据名参数的调用方。
1303
+ **补偿**:无放宽旋钮(脱敏只收不放);非凭据的名字改名让末段不落在强档词上;URL 凭据改走同一条目的头位(MCP `transport.headers` · A2A `headers` · hook `headers` · 搜索 `apiKey`)。**升级前做**:无。**回滚**:回到 7.146.x 即回到整名判定。
1304
+
1305
+ 22. **本地配置源开始读 `config.d/a2a.json`(行为变更);中心发的 `a2a` 域过契约读口(坏条目点名丢);内部型 `EffectiveConfig.a2a` 改契约型 `A2aConfig`、`CenterA2aPeer` 删(包导出面零变化);同批披露:对端 `allowSkills: []` 的读法将变(本版零行为变化)**:
1306
+ 旧形:`EffectiveConfig.a2a?: { peers: CenterA2aPeer[] }`(本仓自持的对端型,`enabled` / `scenarios` 可缺席);本地腿不读 `config.d/a2a.json`(读腿点名为没人读的文件);中心 `/effective.a2a` 原样透传给解析器。
1307
+ 新形:`EffectiveConfig.a2a?: A2aConfig`(`@sema-agent/settings-schema` 的型;条目 `A2aPeerSpec`,`enabled` / `scenarios` 由读口补缺省、型上必填),`CenterA2aPeer` 删去(两者都不在包根 / 子路径的导出面上);两腿读成同一个声明;
1308
+ 本地腿没写 = `{ peers: [] }`,中心没发这一域 = 缺席(契约包 20.0.0 起线上读口不替中心编造它没发的域),两者与空名册是同一个运行期状态(不拨对端)。写法见 USAGE 9.5i-bis。
1309
+ **谁需要**:本地配置源要声明常驻 A2A 对端的部署。
1310
+ **谁受伤**:① 越过包的 `exports` 深引 `dist/web-admin-client/*` 的代码(不受支持的面):`CenterA2aPeer` 不在了、`EffectiveConfig.a2a` 的条目要带 `enabled` / `scenarios`;② 本地配置根里早就有 `config.d/a2a.json` 的部署,升级后这些对端在首次被用到时被拨号(任务准备取卡 / 会话 A2A 面板读缓存缺失或过期;起服本身只解析配置、不取卡);③ 中心发的对端 url 带 userinfo / fragment / 像密钥的 query 值、名字越界、`headerRefs` 有坏成员 ⇒ 这一条不再拨(此前原样交给引擎)。
1311
+ **补偿**:① 改从 `@sema-agent/settings-schema` 取 `A2aConfig` / `A2aPeerSpec`;② 不要的文件删掉;③ 按读口告警改对那一条,凭据走 `headerRefs`。
1312
+ **披露:对端 `allowSkills: []` 的读法将变(本版零行为变化、零 wire)**:今天配置腿(`config.d/a2a.json` / 配置中心)上 `allowSkills` 写空表与不写同读 = 挂对端发布的**全部**技能(契约包 20.0.0 的字段定义,本服务照它读);请求腿 `a2aPeers[].allowSkills: []` 原样交引擎 = 零技能。
1313
+ 契约包下一个 major 起配置腿上空表 = **零技能**(与请求腿同读),本服务随那一版提货。**谁受伤**:配置腿上写了 `allowSkills: []` 本意是「全部」的部署 —— 提货那一版起这个对端一只技能都不挂。**升级前做**:要全部就删掉这个键,要不拨这个对端就写 `enabled: false`;本版无需动作。
1314
+ **披露:对端拨号面今天没有主机底线(已知限制)**:启用的对端按 `url` / `cardUrl` 取卡、按卡里写的服务端点发送,不过任何部署主机底线(本服务今天不给引擎接它);`url` / `cardUrl` 是运维写的,可指向任意主机(含内网与回环),不带头的对端(这次发送不带任何声明的头)的服务端点由它的卡写、可指向任意主机、遇重定向照跟(带头的对端另受引擎的端点绑定:服务端点须落在声明的 `url` / `cardUrl` 所在的源上,且不跟重定向);取卡发生在每次任务准备与会话 A2A 面板缓存缺失 / 过期时,起服本身不取卡;多租户部署同样挂(多租户闸只关请求体自带的 `a2aPeers`,部署基线照挂)。**谁受伤**:在多租户 / 公共部署里写了 `config.d/a2a.json` 对端的运维 —— 不带头的对端,它的卡能让引擎去敲内网地址。**补偿**:只写可信对端、自审 `config.d/a2a.json`;出路 = 部署主机底线接线(尚未到货)。
1315
+ **升级前做**:本地配置根 `ls config.d/a2a.json`;留下的对端逐个确认可信(见上一条披露)。**回滚**:回到 7.146.x 后 `config.d/a2a.json` 又不被读(读腿点名),中心腿回到透传。
1316
+
1317
+ 23. **目录条目的 `thinkingLevelMap` 开始生效(坏形整条丢);anthropic 条目的 `compat` 按线路生效;`GET /v1/models` 行加 `thinkingLevelMap`(行为变更 + wire 加性;部署零动作,升级前自查目录)**:
1318
+ 旧形(7.146.x):条目带 `thinkingLevelMap`(合形也算)⇒ 契约包读腿把它当未知键剥掉并告警(`unknown-keys-dropped`),**本服务把该告警判成域失败 ⇒ 整份候选拒**(本地 `config.d` 起服回落 env,env 也没配模型即零模型 `config_local_no_models`;中心腿停在上一份好配置),声明到不了引擎;anthropic-messages 条目的 `compat` 一律整只丢 + 一条 `model_compat_dropped`。
1319
+ 新形:契约包 20.0.0 判 `thinkingLevelMap` 的形(键 `off` / `minimal` / `low` / `medium` / `high` / `xhigh` / `max`,值非空串或 `null`),合形原样交引擎(串 = 那一档发的值,`null` = 那一档不支持;当前引擎只在 openai-completions / responses 条目上读它,anthropic-messages 条目上原样带、零效果),
1320
+ 坏形(未知键 / 非对象 / 空串 / 非串非 `null`)⇒ 那一条被读腿丢(`entry-dropped`);被 `roles` / `atMention.only` / `tierGroups` 引用的条目坏了 ⇒ 契约包把整个 `models` 域读成缺省(`domain-defaulted`),本服务把它判成域失败 ⇒ 整份候选拒(本地 `config.d` 起服回落 env、中心腿停在上一份好配置)。env 腿没有这一席。
1321
+ 条目里写了本契约版本不认识的键(`thinkingLevelMap` 自己的键是闭集,那是上一句的坏形,不是这里):7.147.0 仍整份候选拒(读腿剥键告警,本服务判成域失败);自 7.148.0 随 settings-schema 22.0.0 起,允许逐条丢弃的域里持键层为数组元素的未知键 ⇒ 该条目丢弃(点名),其余域不变。
1322
+ anthropic-messages 条目的 `compat` 读 `thinkingMode`(`budget` | `adaptive`)/ `effortLevels` / `supportsTemperature` / `contextManagement` / `interleavedThinking`;写了 openai 线路的键(`thinkingFormat` 等)照旧整只丢 + warn。
1323
+ `GET /v1/models` 行加可选键 `thinkingLevelMap`,anthropic 行可带 `compat`;声明了的行上 `supportsThinkingOff` / `supportedEffortLevels` 随声明变。
1324
+ **谁需要**:端点某档关不掉 / 换名的部署,adaptive / effort 族 anthropic 端点。**谁受伤**:① 目录里写过 `thinkingLevelMap` 的(此前整份候选被拒、没有装上,见旧形)—— 坏形的那一条升级后被丢,被引用时整份候选被拒(停在上一份好配置 / env);合形的见 ②;
1325
+ ② 写过合形的 / anthropic 条目写过 anthropic 键 `compat` 的 —— 升级后请求形变(该档的值换成声明的拼写、`adaptive` 不再带 `budget_tokens`、`supportsTemperature: false` 丢调用方 temperature);
1326
+ ③ 按封闭 schema 严格校验 `/v1/models` 行的消费方。**补偿**:读腿告警 / `model_compat_dropped` 点名条目;删掉那个键即回到 7.146.x 的读数。
1327
+ **升级前做**:在 `config.d/models.json` 与配置中心目录里查 `thinkingLevelMap` 与 anthropic 条目的 `compat`;坏形改合形或删掉,不想升级后生效的删掉。**回滚**:回到 7.146.x ⇒ 带 `thinkingLevelMap` 的目录整份候选被拒(本地 `config.d` 回落 env、中心腿停在上一份好配置),回滚前先删这个键;anthropic 条目的 `compat` 回到「整只丢」。
1328
+
1329
+ 24. **hook 条目的 `rewakeMessage` / `rewakeSummary` / `cloud`(command;`cloud` 也在 http)与 `continueOnBlock`(prompt)由新提交 400 变受理,本服务如实带、不执行;续跑重放读出存量里的这几键(行为变更;部署零动作)**:
1330
+ 旧形:7.135.0–7.146.x 新提交带这几键 ⇒ `400 request.body_shape`(`unknownKeys` 点名);续跑重放的存量请求里它们被读者剥掉。
1331
+ 新形:契约包 20.0.0 承运并判形(`rewakeMessage` / `rewakeSummary` 非空串、`continueOnBlock` 布尔、`cloud` 任意值),在各自的归属型上受理;本服务的执行器不读它们(唤醒文本不加前缀、`cloud` 写什么都照跑、`continueOnBlock` 不改阻断结局)。
1332
+ 写在别的条目类型上照旧 400。能力位 `settingsContract.hookEntryFields` 的列随之多这四键。
1333
+ **谁需要**:原样投影宿主设置文件的调用方。**谁受伤**:① 以为写了就生效的调用方;② 升级前停驻的任务:存量请求(只可能来自 7.134.x 及更早)里三键写了坏值(空串 / 非串 / 非布尔)⇒ 读者判坏块,
1334
+ 续跑**拒**:这条车道本会采纳请求体 hooks(单用户车道)⇒ `409 resume_blocked_by_policy`(`blockedBy: "request.field_invalid"`,`field: "settings.hooks"`;句子只点名成员键,不回显值),卡 / 任务仍待决、行不动;不采纳请求体 hooks 的车道(多租户)零变化(同第 20 条)—— 续跑重读的一次性迁移不接这一形。
1335
+ `cloud` 不同:它没有坏值,读者不读它的值;存量里 `cloud` 的值藏着守卫迹象(契约包分类器的判法:以 `PreToolUse` / `PermissionRequest` 为键的成员、匹配器形的对象,嵌多深都算)时读者整份拒,
1336
+ 续跑重读的一次性迁移在窗内把这只 `cloud` 剥掉、同一份 hooks 照采纳(运维日志 `hooks_read_as_before_upgrade` 点名被剥坐标)—— 与升级前同读。
1337
+ **补偿**:能力位与契约附录明写不执行;不加窗、不加旋钮。
1338
+ **升级前做**:有 7.134.x 及更早停驻、hooks 里写着这几键的任务,升级前把它们跑完或取消(否则续跑被拒,见上)。**回滚**:回到 7.146.x 即回到「新提交 400、续跑剥掉」。
1339
+
1340
+ 25. **`DB_BACKEND=local`:会话同步干跑 `POST /v1/sessions/:id/sync/plan` 对仍带属主戳的存档,按 id 分类出 fork / stale 时直接答 `409 conflict.session_archive_stamped` + 固定句,不再答 `200` + `relation`(wire 加性:干跑多一口答该码;行为修复;部署零动作)**:
1341
+ 旧形:干跑只读两边的 id 集合并分类、不问存档带不带戳 —— 带戳存档上 fork / stale 答 `200` + `relation`,而同一份 id 集合的真推送在第一阶段就被 `409 conflict.session_archive_stamped` 早拒(7.145.0 节第 1 条):干跑说「分叉了,可带同意去推」,推送说「删掉会话再推」。
1342
+ 新形:干跑问第一阶段同一只早拒判官(按没带同意问;体里没有「同意」位),带戳 ⇒ 同码同体(体只有 `error` / `errorCode`,不带 `relation`);不开暂存、不拿租约、不写存档。`fast_forward` / `identical` / `fresh`、匿名存档与 SQL 后端上的 fork / stale、分区会话(委派子代的转录),干跑照旧 `200` + 关系体。
1343
+ 干跑这一读是「此刻读」(不持锁):提交里持锁的那一问仍是权威。带同意的同一推送第一阶段受理、提交里被同一只带戳判以同码拒,所以带戳存档上干跑答这个码对两种推法都是实话。
1344
+ **谁需要**:先调干跑再决定推不推的壳 / SDK 在 local 部署的带戳存档上(起服 warn `local_archive_kept_stamped` 点名过的会话):当场读到出路,不再先问用户保留哪边。
1345
+ **谁受伤**:把干跑当「永不 409 的纯读分类」的客户端(已装 SDK 24.0.0 的 spec 与注释这样写)—— 这两形它们读到 409 而不是 `200` 关系体;把非 2xx 一律当「服务不可用」重试的逻辑会白重试(确定性拒,重发同答)。
1346
+ **补偿**:按码 `conflict.session_archive_stamped` 分支,体的 `error` 即出路(`DELETE /v1/sessions/:id` 后重推);按状态 409 分支的不受影响。
1347
+ **SDK 锁步前的读法**:已装 SDK 的 spec 与注释仍写「plan 永不 409」(锁步版本改注与 spec);在 SDK 锁步版本之前,`pushSessionBundle` 的第一步是干跑 —— 对 local 部署上带戳的目标,它第一步就读到这个 409(SDK 映射为抛错,此前返回 conflict 结果,用户当时拿到的是「保留哪边」的问题,带同意重推后才在提交里读到同一个码)。
1348
+ **升级前做**:无。**回滚**:回到 7.146.x 即回到「干跑只读 id 集合」。
1349
+
1350
+ 26. **停驻补投帧的整条字节预算:收件条目的扩展键按 UTF-8 字节量,越过最窄后端的 `payload` 列宽(65,535 字节)⇒ 补投帧是最小形并带 `payloadTruncated { droppedKeys, bytes }`(行为修复 + wire 加性;部署零动作)**:
1351
+ 旧形:停驻收件条目(下一次开流 drain 出的 `task_notification` / `workflow_complete` 补投帧)的扩展键只有逐成员的界;多枚满界文本位、多字节文字或控制字符转义一放大,MySQL 协议后端上那一条入箱失败(通知丢,只剩一行服务端日志),PostgreSQL / File 照存全形。
1352
+ 新形:三种后端同一个预算(最窄后端的 `payload` 列容量;按 UTF-8 字节量)。装得下 ⇒ 帧形逐字同上一版;装不下 ⇒ 补投帧只带去重键位(`task_id` / `task_type` / `status` / `seq` / `attempt` 里带着的那几位)、归因侧记 `_sema_provenance`(带着且装得下就留)、`summary`、
1353
+ `payloadTruncated { droppedKeys(被丢的键名,全形键序), bytes(全形扩展键的 UTF-8 字节数) }`,其余键缺席(`workflow_complete` 的去重键是 `runId`,只多 `payloadTruncated`)。
1354
+ 侧记自身也装不下 ⇒ 侧记也丢,且全形带归因成员(`_sema_provenance` / `agentMessage` / `crossSessionMessage`)时 `summary` 换成 `[payload over budget: summary withheld; see payloadTruncated]`、`droppedKeys` 末尾多一个 `summary`。live 腿(活流帧 / bg·resume 账本行)不变。
1355
+ **谁需要**:park 的耐久投递 —— 停驻的完成在任何后端上都在下一次开流时到达。**谁受伤**:越界的停驻通知在所有后端上收最小形(侧记也越界的那一形连摘要原句也扣下);PostgreSQL / File 部署在这一尺寸段此前收全形。按帧上未知键报错的消费端要认这一键。
1356
+ **补偿**:帧上点名丢了什么;去重键位全在;同一次完成的活腿帧照旧全形;运维计数 `server.workflow-completion-inbox.payload-over-budget`。
1357
+ **升级前做**:部署零动作。消费端:`payloadTruncated` 在场 ⇒ 按「这一帧的扩展键被裁」渲(`summary` 照渲、点名缺了哪些)。**回滚**:回到上一版即回到「无整条预算」;已入箱的最小形条目两个家族不同:
1358
+ `task_notification` —— 上一版 drain 把 payload 整只铺回帧上,`payloadTruncated` 与侧记照带(老消费端忽略未知键;已换成受信句的 `summary` 在列里,照出);
1359
+ `workflow_complete` —— 上一版 drain 只读 `completionId` / `diagnostics` 两键,`payloadTruncated` 回滚即消失,帧上只剩 `runId` / `status` / `summary`,披露丢失(通知本身照到)。零 DDL、零一次性迁移。
1360
+
1361
+ 27. **缺省模型检查的拒启句(`MODEL_ID is required when no catalog default resolves [config.default_model_missing] …`)在「本地候选整份被判官拒、回落 env、又没有 `MODEL_ID`」时,同一行多一段回落原因:被拒的文档名、拒码、原因类词与文档路径;句首的 grep 锚不变(拒启句 / 日志加性;部署零动作)**:
1362
+ 旧形:这一句只说「这张表没有缺省模型」+ 二选一的出路,不说这次为什么走的是 env 腿 —— 点名被拒文档与悬空符号链接的只有先出的 `config_candidate_rejected` warn 行。
1363
+ 新形:判官整拒了候选(`config.d` 里某份文档悬空链接 / 坏 JSON / 空 / 不是对象 / 太深 / 读不出,或某个域判形失败,或退役域文件)时,句子在 `(every enabled catalog entry …)` 那一段之后多 `(the config candidate was rejected whole … — rejected: "<文档名>" [<拒码>] <原因类词>: <文档路径> | …)`。
1364
+ 只带机读字段:原因类词是闭集常量(`dangling symbolic link` · `unreadable` · `parse error` · `empty file` · `not a JSON object` · `nested too deep` · `retired domain file` · `the domain failed its schema`),文档路径是 `<配置根>/config.d/<域>.json`(本地配置源才有)。
1365
+ **不带**链接指向的目标路径、不带配置值、不抄契约 / 读腿的原句 —— 那些只留在 `config_candidate_rejected` 行。`config_candidate_rejected` 行的 `errors` 每条多一个键 `kind`(闭集词 `schema_invalid` · `empty` · `parse_error` · `not_object` · `too_deep` · `retired_domain` · `dangling_symlink` · `unreadable`,即上面各短语的机读形;日志加性)。没有被拒候选的拒启(纯 env、候选被收下)整句逐字不变。
1366
+ **谁需要**:模型只配在 `config.d/models.json`、没设 `MODEL_ID` 的部署碰上候选被整拒,和只渲引擎原句的壳。**谁受伤**:对拒启句整句做精确相等匹配的脚本(只在候选被整拒这一形上变长)。
1367
+ **补偿**:按句首锚 `MODEL_ID is required when no catalog default resolves [config.default_model_missing]` 前缀匹配,或读 `config_candidate_rejected` 行。**升级前做**:无。**回滚**:回到 7.146.x 即回到不带回落原因的句子。
1368
+
1369
+ 28. **嵌入方类型面:`StoreBackend.retention` 改形 —— 入参 `{ taskAttachmentTable, taskListTables, logger? }` 不变,返回从 SQL 留存店类改为执行器面(破坏性三方法的 `audit` 必填);服务内的字节口 `BlobBackend` 四方法收成三只字节方法(包根不导出;零 wire、零表、零存储格式;部署零动作)**:
1370
+ 旧形:`retention?(opts): SqlRetentionStore` —— 三只破坏性方法收 `{ domain, cutoffMs, audit? }`,`audit` 类型上可选、缺席时运行期抛;`BlobBackend` = `putBlob` / `getBlob` / `hasBlobs` / `deleteBlobs`,后两只带索引语义。
1371
+ 新形:`retention?(opts): RetentionExecutor` —— `listRetentionDomains()` / `previewRetention({ domain, cutoffMs })` / `expireCheckpoints` · `deleteExpiredSessions` · `deleteOrphanToolResults`(各收 `{ domain, cutoffMs, audit }`,`audit` 必填,
1372
+ `{ mode, policyDays, fencingToken }`)/ `retention`;`deleteExpiredSessions` 的回执照旧在有结束了的空间时多 `endedSpaces`。`BlobBackend` = `put(key, bytes)` / `get(key)` / `delete(keys)`(只搬字节;在不在、孤儿、宽限窗、内容寻址校验在索引的属主)。
1373
+ **谁需要**:把 SQL 店目录逐字搬进引擎侧包的那一步(执行器入参与引擎的 `{ domain, cutoffMs }` 同形;部署的表经事务内钩参与)。**谁受伤**:自己实现 `StoreBackend`(带 `retention`)或直接调 `backend.retention(opts)` 的嵌入方 ——
1374
+ 返回型与入参型的名字变了,经执行器类型漏传 `audit` 是编译错;经引擎契约类型调用照旧在运行期当场拒(与修前同);改本仓源码、自带 `BlobBackend` 实现的人。
1375
+ **补偿**:实现方让 `retention` 返回一只带上面六个成员的对象(与本仓 SQL 后端的组合同形);调用方每次破坏性调用带上本轮的 `audit`。字节口实现只剩三只方法:`hasBlobs` / `deleteBlobs` 的索引语义交给索引属主。
1376
+ **升级前做**:无(零表、零存储格式、零 wire)。**回滚**:回到上一版即回到旧形(代码面,无数据面)。
1377
+
1378
+ 29. **决断类续跑入口上这一行自己的拒答行上 `rowVerdict.code`:任何门同一个码 `checkpoint.invalid_outcome`;`approval_binding_mismatch` / `resume_outcome_invalid` 只给真有成因的拒;订正 7.124.0 节第 14 条「没有 `field` 的拒逐字维持 `approval_binding_mismatch`」半句(wire 码变;按码分支的客户端改读法;部署零动作)**:
1379
+ 旧形:一张停驻行被引擎的行判官判续不了(例 `reason: "requirements_damaged"`)时,运维队列 / 收件箱行上 `rowVerdict.code` 是 `checkpoint.invalid_outcome`,决断类入口却按门借码 ——
1380
+ `POST /v1/approvals/:id/decide` 上答 `409 approval_binding_mismatch`(没有 `field`)、`/v1/assistant/tasks/:id/plan_review` 与 `/resume` / `/v1/sessions/:id/wake` 上答 `409 resume_outcome_invalid`;
1381
+ 决断口上存储体读不成检查点答 `409 conflict.checkpoint_unreadable`,存储体 `{}` 等门类读不出 / 别的门上的坏行答 `409 gate_not_tool_approval`。引擎在 `policy_ask` 门上不带判别位的拒也借 `approval_binding_mismatch`。
1382
+ 新形:有决断成因的拒照旧(引擎点名绑定席 ⇒ `approval_binding_mismatch`;点名决定体的别的格、或审阅门上不带判别位的内容拒 ⇒ `resume_outcome_invalid`);其余一律 `409 checkpoint.invalid_outcome` ——
1383
+ 这一行自己的拒(体顶层 `reason` 在场,码与行上 `rowVerdict.code` 同一只判官、同一个判决,`error` 以行上 `rowVerdict.sentence` 开头)与引擎不带判别位 / 带本服务不认得的 `field` 的拒。决断口在门型守卫之前先问这一行:行坏了就答行的拒,行好才指门;
1384
+ 存储体读不成检查点的那一形同答行的拒(店的别的失败仍 `conflict.checkpoint_unreadable`)。更新引擎停驻、门类本版不认的行在决断口答 `409 checkpoint.unsupported_version` + 两版本键(此前 `gate_not_tool_approval` 指错门)。
1385
+ `retriable: true`(卡仍 pending、行字节不动)、`reason` / `thrownName` / `field` 原样:续跑腿上与修前同;决断口两早退臂此前不带 `reason` / `retriable`,本版带上。
1386
+ **订正 7.124.0 节第 14 条**:那一条「决断口的 409 不再借名」子条里的「没有 `field` 的拒(含 core 的行完整性拒,例 `read_face_damaged`)逐字维持 `approval_binding_mismatch`」自本版起不成立 —— 那些拒答 `checkpoint.invalid_outcome`;
1387
+ 同一子条前半句「`approval_binding_mismatch` 只说绑定变了(重取坐标再决)」自本版起才名副其实。已发段原样留着。
1388
+ **谁需要**:按码分支的客户端 —— 「这一行续不了」与「绑定变了 / 改那一格」按码就分得开。**谁受伤**:对 `approval_binding_mismatch` 一律重取坐标再决、对 `resume_outcome_invalid` 一律提示改那一格、按 `gate_not_tool_approval` / `conflict.checkpoint_unreadable` 处置坏卡的客户端:坏行上拿到新码。已把 `checkpoint.invalid_outcome` 与 `approval_binding_mismatch` 并成一臂的客户端码面零变化、行为照旧 —— 本版的分因要它们拆开那一臂才看得见。
1389
+ **补偿 / 升级前做**:客户端加一臂 `checkpoint.invalid_outcome`(已与 `approval_binding_mismatch` 并成一臂的拆出来),按体顶层 `reason` 在不在分两形 —— 在场 = 这一行自己的拒:按 `reason` 与 `error`(= 行上 `rowVerdict.sentence`,出路是作为新任务重提;停它的那一版 worker 也许还能续)呈「这张卡续不了」,不再重取坐标;
1390
+ 缺席 = 引擎没点名哪一格的拒(带本服务不认得的 `field`〔原样上 wire,引擎新加的格〕,或与决定体无关的引擎内部拒):卡仍待决,出路读 `error` 句,同样不重取坐标;
1391
+ 行上 `rowVerdict` 非 `ok` 的卡本就不该呈批准。按前缀 `checkpoint.*` 兜底的客户端零改。**回滚**:回到上一版即回到按门借码;数据零改动。
1392
+
1393
+ 30. **一次性迁移 M9 退役:park 指针索引改主键的启动期迁移连同它的读侧半场删码;随包排空判据 `workflow-park-holder` 少一条(持久数据面;行为变更;同一批存量卡的 409 码换了;运维日志形变更;嵌入方 BREAKING,类型面)**:
1394
+ 7.118.0 引入的一条一次性迁移,窗(发布日 2026-10-07 + 30 天)于 2026-11-06 关,本版删了它的码 —— 写半场与读侧半场(同一件事「引擎 7.43 及以前写下的 workflow 子代停驻记录」)同窗同删。M10–M12 的窗 2026-11-07 … 11-08 关,本版不动,随后续版本窗关即删。逐处删了什么、删后存量形由谁接住:
1395
+ - **写半场**:SQL 起服不再把 `workflow_agent_session`(workflow park 指针索引,派生投影)的主键由 `(session_id)` 改成 `(session_id, run_id)`(暂存表复制 + 原子换名那一整套连同暂存表 `workflow_agent_session_m9` / 待删旧表 `workflow_agent_session_m9_old` 的收尾删除)。
1396
+ 删后仍是旧主键的库(从 ≤ 7.117.x 直接升到本版、中间没在 7.118.0–7.146.x 任一版起过服),指针写口(冲突目标 `(session_id, run_id)`)两方言各自落败:TiDB / MySQL 的 `REPLACE INTO` 按单列主键整行替换 —— 同一个子会话只剩后写的一枚指针,续跑链 / 分叉里后写的记录覆盖先写的,判决只看得到一条记录(分叉判不出、链尾可能被更早的记录盖掉);
1397
+ PostgreSQL 的冲突目标没有可仲裁的唯一约束 ⇒ 指针写失败(响亮)。没有响亮的起服臂。
1398
+ 出路:运维手工照中央 DDL 重建这张表(派生投影,丢了只丢升级那一刻还停驻着的旧卡的指针),或先在一只 7.118.0–7.146.x 的版本上起服一次再升本版。`DB_BACKEND=local` 的索引是账本、没有主键,这一半对它本来就是空转。
1399
+ - **读侧半场**:路由里「点名子会话的条目没有持有者位(引擎 7.43 及以前写下)」的专读臂删除。删后这样的存量卡路由判 `none`、落 legacy 腿,答 `409 conflict.resume_context_unavailable`(响亮;成因是子会话没有续跑上下文)—— 不再答 `409 decide.workflow_parks_unreadable`、句子里「更早的引擎版本」那一说随之没了;出路不变:续跑发起它的那条 workflow run。
1400
+ `decide.workflow_parks_unreadable` 自此只有一种成因:某一条点名这张卡的记录的停驻列表读不出(条目形坏 / 这一份在场却不是列表),一句拒文,体键不变(`runId`、在场才带的 `readableHolderRunId`)。`DB_BACKEND=local` 同样适用(路由是同一只)。
1401
+ - **随包排空判据**:两份 SQL 与 `drain-check-local.mjs` 去掉 `workflow-park-holder`(local 脚本的判据表少一条,末行 `WORKFLOW-PARK-HOLDER` 与命中行 `WORKFLOW-PARK-ROW` 不再出)。要在 7.118.0 那条边界上数这些卡,用 7.118.0–7.146.x 任一版包里的同名判据。
1402
+ - **运维日志**:起服行 `one_time_migrations_applied` 与被打断时的 `one_time_migrations_interrupted` 去掉 `workflowParkIndexKey` / `workflowParkIndexRowsCarried` 两个读数字段(`removableAfter` 读数去掉 `M9` 一个键,`note` 不再叙述它)。按这些字段做告警或看板的规则要改。
1403
+ - **嵌入方(类型面)BREAKING**:`StoreBackend.runOneTimeMigrations()` 的返回型 `OneTimeMigrationReport`(经包根导出的 `StoreBackend` 可达)去掉 `workflowParkIndexKey` / `workflowParkIndexRowsCarried`;读它们的代码、把值标成 `OneTimeMigrationReport` 再写这些键的对象字面量 tsc 红;
1404
+ 自实现该方法、未标注类型就直接返回含这些键的字面量的代码 tsc 不报(多出的键没有人读),也请一并删掉。
1405
+ - **谁需要**:所有部署 —— 起服少走一步、排空判据少一条。
1406
+ - **谁受伤**:① **跳版升级**:从 ≤ 7.117.x 直接跳到本版的 SQL 库 —— 仍是旧主键(TiDB / MySQL 上指针被整行替换、PostgreSQL 上指针写失败;上面写半场一条);② **升级那一刻还停驻着、由引擎 7.43 及以前写下的 workflow 子代卡**(7.118.0 起新写的记录恒带持有者位;`APPROVAL_TERMINAL_BACKSTOP_MS` 调长的部署或从 ≤ 7.117.x 直跳的部署才可能还有)——
1407
+ 决定口的 409 码由 `decide.workflow_parks_unreadable` 换成 `conflict.resume_context_unavailable`,按那一码做分支或按「更早的引擎版本」那句话匹配的客户端 / 告警要改;两者都是响亮的 409、卡仍 pending、什么都没投递;③ 按上面日志字段做告警的运维。
1408
+ - **补偿 / 做法**:**表形**(① 那一类):跳版升级的库先在 7.118.0–7.146.x 任一版上起服一次再升本版,或升级后运维手工照中央 DDL 重建 `workflow_agent_session`(排空卡改不了主键)。**存量卡**(② 那一类):升级前把它们决掉或取消(数法见旧包判据 `workflow-park-holder`),或升级后续跑发起它的那条 workflow run 再决。**升级前做**:常规从 7.146.x 升级、没有 ② 那批卡的部署无须动作;**回滚**:回到 7.146.x 即恢复旧读法与旧判据,本版没有写任何新的存储形。
9
1409
 
10
1410
  ## 7.146.0 —— ① 引擎首次附着前的宽限 `ENGINE_FIRST_ATTACH_MS`(缺省 180 s):从没被非探针请求碰过的引擎要等 `max(ENGINE_LINGER_MS, 本值)` 才自退;`/health.engineLease` 多一格 `firstAttach`(行为变更 + wire 加性;部署零动作) ② 设备 WS 未鉴权握手的 per-remote 帽可按真实对端计:新旋钮 `DEVICE_TRUSTED_PROXY_CIDRS`(可信代理名单,缺省空 = 今日行为);帽键统一为地址规范形;提货 settings-schema 17.1.0(安全轴,fail-closed;新旋钮 + 日志 / 指标加性;部署零动作) ③ SQL 记忆腿(`MEMORY_ENGINE_BACKEND=pg|mysql`)兑现 core 的落点问询协议(`admitsLandings` / `opts.admit` / `opts.confirm`):在这两条腿上驱动 core 记忆整合时,写闸判的是真正落下的拼写,此前传进来的第二参被静默丢掉(行为变更;部署零动作) ④ TiDB 记忆腿(`MEMORY_ENGINE_BACKEND=mysql`)上 stale `baseRev` 的 update 改按契约报冲突:对手恰好把行写成与本次 update 逐字节相同的目标态时,此前报 applied,现与 PG 腿同答冲突并带 `currentRev`(行为修复;部署零动作) ⑤ 随包文书补全与订正:停机上界契约句、`blocked` 终局的用户面是 `terminal.detail`(点名 cli · web-admin · client-core 渲染层)、hooks 托管标签由调用方自报且失败方向只收紧、server-as-peer 启动日志行、场景面收窄写法、坏行降级形的键集(文字订正;零行为变更;部署零动作) ⑥ `local_roots_split` 起服告警只报「一声不响的分家」:显式给了 `CONFIG_LOCAL_DIR`(等于数据根 = 合一,不等 = 有意分家)即视作运维已表态,不再每次起服响;推导的配置根 ≠ 数据根照报(行为修复;日志面;部署零动作) ⑦ 在飞 run 并发帽:新旋钮 `RUN_MAX_CONCURRENT`(本副本全局)与 `RUN_MAX_CONCURRENT_PER_PRINCIPAL`(同一已验提交主体),缺省 `0` = 关;新提交超帽 ⇒ 429 `limit.rate_exceeded` + `reason: "run_concurrency_cap"` + `Retry-After: 5`(行为加性,缺省关;wire 加性;部署零动作) ⑧ 硬断预告:自 7.147.0 起每个部署都要显式声明执行车道(`REMOTE_EXEC`;`CONFIG_PROVIDER=local` 形下 `config.d/remote-exec.json` 也算),未声明拒启;车道词 `none` 取代词表外的状态名 `in-process`;`REQUIRE_EXECUTION_LANE` 退役(预告;本版零行为变化、零 wire 变化;部署零动作,但 7.147.0 的升级路径上有三件事要提前排) ⑨ 更正 7.144.0 节第 1 条与 7.137.0 节第 15 条的出路句:`corrupt_session` / `invalid_session` 的出路里没有「从断点之上的条目分叉」—— `POST /v1/sessions/:id/fork` 不选条目,对结构坏的会话也不是出路(文字订正;零行为变化;部署零动作) ⑩ 起服告警 `memory_engine_dir_defaulted` 改名 `memory_engine_dir_outside_data_root` 并改按路径包含判:file 形记忆引擎的已解析根不在本机数据根(`config.localDataRoot`)之下才报,句子带两条真路径;`MEMORY_ENGINE_DIR` 缺席不再是判据(行为修复;日志面,日志事件改名(旧名退役;壳 / 编排脚本按新名读)) ⑪ 单用户部署上 `GET /v1/diagnostics/wiring` 与 `GET /v1/outcomes` 也先问运维名册:名单为空且没写 `OPERATOR_SINGLE_USER=true` ⇒ 两口答 501;单用户部署的具名名单对 `GET /v1/outcomes` 也生效(安全轴,fail-closed;行为变更;名单为空的单用户部署要这两口写一行 `OPERATOR_SINGLE_USER=true`) ⑫ 后台子代状态 `agentState` 过 wire 的读法成文并钉死,订正 7.116.0 节「未核」一句:哪些应答带它、哪些不带(缺席是引擎的选择);持久子代行读口的状态是 core 同一只读器的产物,停驻行的审批卡读作 `unreadable`(文字订正;零行为变更;wire 零变化;部署零动作) ⑬ 收编批量导入:源主体把本机会话导进收编目的地 `POST /v1/adoption/:id/sessions`,能力位 `adoptionImport`(按调用方 present-iff)给出 `:id` 与两只帽;两根新旋钮 `ADOPTION_IMPORT_MAX_SESSIONS` / `ADOPTION_IMPORT_MAX_SESSION_BYTES`(新面;wire 加性;部署零动作) ⑭ hooks 托管车道成为任务座上自己的一张引擎注册 `settings.hooks.managed`:引擎 handler 预算(`HOOKS_TIMEOUT_MS`)每车道一份,非托管钩子吃光自己那份挤不掉托管钩子;托管车道被自己的预算叫停记 `hook_managed_unrun{budget_exhausted}`;`Stop` 上 `continue:false` 只撤本车道的推回(安全轴,失效关闭;行为修复 + wire 加性:新注册名;部署零动作,按注册名字面读的读者见本条「升级前做」) ⑮ 请求面压缩开关:`settings.autoCompactEnabled`(布尔)逐字交给引擎的自动压缩座 `compaction.autoCompact`,能力位 `taskSettings.autoCompactEnabled`;键缺席时与旧形逐字相同(wire 加性;部署零动作) ⑯ 请求的 `settings.env` 不收凭据:名字是本引擎的凭据变量或值是秘密形 ⇒ 新提交 400 `request.env_credential_refused`;升级前停驻的任务窗内续跑时剥掉照续(安全轴,fail-closed;wire 新码;调用方动作:凭据挪进引擎进程的环境;部署零动作) ⑰ 错误码目录加「码族」列:契约附录 A 每个码恰属五族之一,消费端按列读、不再各抄码表;`wire-changes` 清单多一集 `errorCodeFamily`(契约列加性;应答体零变化;部署零动作) ⑱ 会话记忆状态报出引擎记忆写家:带层座(`?scope=`)时多一个可选键 `writeHome`(那只店的引擎答案,绝对目录,字节原样),不带层座时多一个可选键 `planes`(逐店明细里引擎答的 `writeHome` 原样透出),单用户 `host` 车道在场、其余车道缺席,与能力位 `projectContext` 同一只射程谓词(wire 加性;部署零动作) ⑲ 🔴 引擎 7.62.0 → 7.63.0:升级前停驻的工具审批行在本版上续跑不了(`409 approval_binding_mismatch` + `reason: "requirements_damaged"`,升级前先排空;混跑期两版互拒对方停驻的行)· 规则导入回执的引擎拒成员按落没落分 `refused` / `indeterminate`、`reason` = 引擎拒因码(`store_refused` 退出)· 记忆收紧(`userlocal:` 族不复制、v2 下保留前缀的折叠拼写拒、hipaa / zdr 否决记忆整理、店集只算写过的个人店、公告队列文件坏了响亮拒)· 停驻行成员形不对即判坏、`DB_BACKEND=local` 的审批列表不再因一行坏字节整张 503 · 后台 fork 子代进委派分区 · 本进程停驻的赎回完成回停驻车道 · 用户面通告加两码(行为变更 + 硬破坏两条;wire:两通告码加性、一回执词退出;升级前先排空待决工具审批卡) ⑳ 🔴 本进程删过的会话 id 只再执行给删前的属主:另一位属主在本进程用同一个 id 起执行(新提交、续跑、唤醒、停驻赎回)⇒ `409 conflict.session_id_retired`(续跑家族 `409 resume_blocked_by_policy`),什么都不跑(安全轴,fail-closed;wire 新码;行为变更;部署零动作) ㉑ 嵌入方类型面:服务型 `ServiceWorkflowJournalStore` 的可选成员 `deleteByRun?` 删(journal 只剩按龄清扫一条删路);`ServiceConfig` 多七个必填席(各由 `loadConfig` 从本版新旋钮铸出);检查点店与 workflow journal 店的源文件换了目录,包外本来就 import 不到(嵌入方类型面 BREAKING 两处;零 wire、零表、零存储格式;部署零动作) ㉒ k8s 沙箱 Role 的 `persistentvolumeclaims` 四动词与 `secrets` `create` 改按特性开关授:随包 chart 缺省不再渲这两条规则,设了 `WORKSPACE_CACHE=volume` / `K8S_SANDBOX_ENV` 的存量部署要在 values 里开对应开关(或手写 RBAC 补规则)(部署面;行为收紧;两个旋钮都没设的部署零动作) ㉓ 🔴 引擎 7.63.0 → 7.64.0:会话帧与会话盒按住客投 —— 删后同 id 重建的后任不再收前任后台工作的完成、信与回执(弃一条在运维席说一次 `delegation.delivery_discarded`),升级前让旧副本排空会话盒、混版副本共一只信箱时旧副本领不动装着本版记录的盒、本版副本弃掉旧副本写下的记录 · File 记忆店的「绑定之前」账本形退役(先用上一版引擎开一次)· 共用一只记忆控制面的副本一起升级 · 停驻行三处判坏 · 规则提议里无 kind 的批成员整批丢 · 兑付腿店故障只在店没变时可重试 · 规则导入成员结局不知 ⇒ 503 同票重走 · 一次性迁移 local 腿读得更全 · 拒绝回显上帧(行为变更 + 硬破坏三条;wire:一帧键加性;升级前先排空会话盒) ㉔ 不报主体的 service 凭据可声明为无身份调用方:新旋钮 `SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT`(缺省 `true` = 授权判定不变;`false` ⇒ fleet 读面 / 运维聚合口 / 写档对它收窄);`GET /health` 的 `auth` 加一键、运维口 401 operator 句改写(安全轴,opt-in;wire 加性 + 一句改写;零迁移;缺省部署零动作) ㉕ 🔴 自由文本脱敏:行首键形(YAML / INI / compose 的配置行 `password: <值>` / `PASSWORD = <值>`)是声明形的第四种 —— 值成记号;值是类型名(`str` / `string` / `SecretStr` …)时不是值(行为面;安全;脱敏产物变;部署零动作) ㉖ 引擎交接车道:壳退出的「Move to background and exit」—— 新口 `POST /v1/engine/handover` / `POST /v1/engine/attach`、能力位 `engine.handover`、新旋钮 `ENGINE_HANDOVER_LINGER_MS`(缺省 30 min);`/health.engineLease` 多 `lane` / `handover`;`exit-last.json` 用格式 3(`lane` 取代上一版的 `orphan`;第 1 条的首附着窗到期同由 `lane` 说)(新面 + wire 加性;留痕文件与日志键 BREAKING;部署零动作) ㉗ 一次性迁移 M6–M8 退役;M7 的拒臂留为按写者版本的永久门(持久数据面;行为变更;运维日志形变更;随包排空判据少一条;嵌入方 `OneTimeMigrationReport` 去三键〔BREAKING,类型面〕;没在 7.117.0–7.145.x 任一版起过服的 SQL 库先在其中一版起服一次)
11
1411
 
@@ -367,14 +1767,14 @@
367
1767
  没开缓存卷的部署也持有 `deletecollection persistentvolumeclaims`,没转发 env 的部署也持有 `secrets create`。
368
1768
  新形:这两条规则只在对应开关开着时授 —— `WORKSPACE_CACHE=volume` ↔ chart 值 `sandbox.workspaceCacheVolume`(布尔,缺省 `false`;`--set-string …=false` 这类字符串渲染即拒)、
369
1769
  `K8S_SANDBOX_ENV` 非空 ↔ chart 值 `sandbox.sandboxEnv`(`NAME,NAME` 名单字符串,缺省空)。同一个 chart 值**同时写引擎 env**(主 worker 与 v4pro 变体)与 Role 规则,开关与引擎旋钮只有一个写者;
370
- cluster 静态清单里这两条规则是注释块,给 server 设了对应 env 时取消注释。规则表只写在源码的一张表里,chart / 静态清单 / 随包 `deploy/facts/sandbox-rbac.json` 与部署前置文档(仓库 docs 目录下 DEPLOY-PREREQS)的规则表都从它生成。pod / exec / log 与出网自检的两只只读照旧恒授。
1770
+ cluster 静态清单里这两条规则是注释块,给 server 设了对应 env 时取消注释。规则表只写在源码的一张表里,chart / 静态清单 / 随包 `deploy/facts/sandbox-rbac.json` 与源码仓里的部署前置文档(内部记录)的规则表都从它生成。pod / exec / log 与出网自检的两只只读照旧恒授。
371
1771
  **谁需要**:按最小权限部署 k8s 沙箱车道的 owner(没开缓存卷 / 没设沙箱 env 的部署不再持有这两条规则),以及整份拷走 chart 沙箱 RBAC 模板的取用方(规则与开关同表驱动)。
372
1772
  **谁受伤**:用随包 chart 或静态清单、引擎旋钮是**手补在 Deployment 上**(chart 之外)的存量部署 —— 升级后 Role 里没有对应规则:
373
1773
  `K8S_SANDBOX_ENV` 点到了本进程环境里有的键而 `secrets` 缺 `create` ⇒ **起服拒**,拒句带 `[sandbox-secret-rbac]`、点名缺的动词与要加的 Role 规则原文;
374
1774
  `WORKSPACE_CACHE=volume` 而 `persistentvolumeclaims` 缺动词 ⇒ 服务起得来,但每条 run 拿不到缓存卷(run 照起、不挂卷),fail-open 计数 `server.workspace-cache.unavailable` 涨。
375
1775
  **补偿 / 怎么改**:用 chart 的 —— 在 values 里开对应开关(`sandbox.workspaceCacheVolume: true` / `sandbox.sandboxEnv: "NAME,NAME"`),chart 同时写引擎 env,之前在 Deployment 上手补的同名 env 可以去掉;
376
1776
  用静态清单的 —— 取消对应规则注释块的注释;自维护 chart / 手写 RBAC 的 —— 照随包 `deploy/facts/sandbox-rbac.json`(`when` 列 = 开关)补那一行规则。把 `templates/sandbox-rbac.yaml` 整份拷进别的 chart 的取用方,只需在自己的 values 里补这两个键(模板自带开关判官;键缺席渲染即拒)。
377
- **升级前做**:两个旋钮都没设 ⇒ 零动作(升级后 Role 少了两条多余权限);设了的部署按上一条在升级前开好开关。语句与读法同部署前置文档(仓库 docs 目录下 DEPLOY-PREREQS)7.146.0 节。**回滚**:回到 7.145.x 即恢复无条件渲(零持久形变化)。
1777
+ **升级前做**:两个旋钮都没设 ⇒ 零动作(升级后 Role 少了两条多余权限);设了的部署按上一条在升级前开好开关。语句与读法以上一条为准。**回滚**:回到 7.145.x 即恢复无条件渲(零持久形变化)。
378
1778
 
379
1779
  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:一帧键加性;升级前做见本条)**:
380
1780
  换钉:`@sema-agent/core` 7.63.0 → 7.64.0 精确,`@sema-agent/primitives` 随之 7.64.0。下列各项按「谁看得见」排。
@@ -522,7 +1922,7 @@
522
1922
  **补偿**:老 server 不带这个键 ⇒ 按原读法(本端提交的 run / 行的会话 = 当前会话)。**升级前做**:无。**回滚**:回到上一版即不带这个键;落盘数据不受影响(本版不写任何新形)。
523
1923
 
524
1924
  3. **订正 7.144.0 节第 12 条「远端五车道不变」一句:k8s / local-docker / ssh / adb / e2b 上家目录主张证不了时,第一句拒是哪一形按命令形、执行面与会话分(文字订正;零行为变更)**:
525
- 7.144.0 节第 12 条(与契约附录 A 的 `env.home_unconfirmed` 行、USAGE §9 的同一行、DEPLOY-PREREQS 的 `REMOTE_EXEC_HOME_DIR` 节)写这些车道「照旧在开环境那一拍拒、拒句落在工具结果里;递归读形与 adb 上连带路径的普通读先被读边界拦下」。
1925
+ 7.144.0 节第 12 条(与契约附录 A 的 `env.home_unconfirmed` 行、USAGE §9 的同一行)写这些车道「照旧在开环境那一拍拒、拒句落在工具结果里;递归读形与 adb 上连带路径的普通读先被读边界拦下」。
526
1926
  7.144.0 发出后的复跑(真引擎 Runner,五条车道的供方换成假的;每格另跑一遍主张 = 实测的负控,只记两遍不同的形)读到的形比这句多,读法以本条为准(已发节原文不改):
527
1927
  ① **环境在开跑前就被打开**:新提交腿上,引擎拿到执行环境后的第一件事是把任务根读成规范路径,这一读就让车道建连、问 `$HOME`、判出拒;引擎把这次失败读作「任务根读不成规范形」,照样开跑(模型照常被调),拒句要等模型的第一条工具调用才再被答出来。模型要跑的命令一条都没进环境(车道自己建根、探 shell、问 `$HOME` 的命令照跑)。
528
1928
  ② **全 shell 面**:不带路径的命令(`echo hi`、`ls`)⇒ 工具结果 `shell_unavailable` + 判官的拒句(点名声明值、实测值与改法)。带路径的命令(路径不在读拒表上 —— 读拒表命中的路径照旧先答读拒表的拒)先撞引擎的读边界(要人批,句子「could not establish what is read」,不点名家目录)的范围:
@@ -1135,7 +2535,7 @@
1135
2535
  ② 两端同版后的第一轮:每一层带基线的游标(升级前写下的,没有化身)被中心拒 `absent`,本机那一层停驻(`GET /v1/sessions/:id/memory-status` 的 `memorySync.parked[]`、运维行 `memory_sync_layer_parked { axis: "incarnation", found: "absent" }`),停驻层每一轮仍发一次请求、被中心在写之前拒掉;
1136
2536
  ③ 中心从备份恢复:恢复回来的化身就是备份时那一只,读作同一份状态 —— 备份之后设备上的新条目照旧会被删掉或回滚(引擎的已知限制)。
1137
2537
  **补偿**:① 两端都升到本版,先后不限(升级期只是不同步,不丢数据);② 删掉停驻层的游标文件(运维行 `cursorPath` 逐字;`<记忆引擎根>/sync-cursors/<scope 的 sha256 前 32 位>.json`),下一轮从空基线重收敛:
1138
- 两边都改过的条目按冲突报,上一轮之后一侧删掉的条目会从另一侧回来;③ 中心从备份恢复之后、起服之前删掉 `agent_memory_engine_sync_partition` 的全部行(轮换化身):每个客户端下一轮被拒 `other`、按 ② 处置(DEPLOY-PREREQS)。
2538
+ 两边都改过的条目按冲突报,上一轮之后一侧删掉的条目会从另一侧回来;③ 中心从备份恢复之后、起服之前删掉 `agent_memory_engine_sync_partition` 的全部行(轮换化身):每个客户端下一轮被拒 `other`、按 ② 处置。
1139
2539
  **升级前做**:无(新表起服时 `CREATE TABLE IF NOT EXISTS` 自建;库账号已有建表权限)。**回滚**:旧中心不认 `/v2` ⇒ 同步再停;本版写下的游标带 `peerIncarnation`,旧二进制按名挑员时丢掉它 —— 回到旧版即回到旧语义;新表留着无读者。
1140
2540
  **嵌入方**(自建 `ServiceDeps`):`memorySync` 的答型改为 `MemorySyncAnswer`(结果或拒答);自建 `MemorySyncStore` 多一口 `partitionIncarnation(scope)`(TypeScript 编译红即通知)。
1141
2541
 
@@ -2630,7 +4030,7 @@
2630
4030
  **升级序**:先把读同一只会话规则店的**全部**副本升到本版,再放会话规则的写(`PUT /v1/sessions/:id/policy`、2c 同步导入);做不到就先排空旧副本。单进程部署零动作。
2631
4031
  **回滚**:本版写下的行旧版读不了(同上的整行拒),而且在本版上重写一遍没有用 —— 本版的写口判官照样盖戳 `4`;旧版的 `PUT` 也改不了它(写前先读那一行,读不出 ⇒ `500 corrupt`)。
2632
4032
  要回滚,这些会话在旧版上只有两种结局:每一次工具调用都拒(失效关闭),或删会话(规则随之删)。**不要**在库里把戳改回 `2`:同一条目在文法 2 里意思不同
2633
- (`toolDeny` 的 `mcp__*` 在文法 2 里什么也不拒),改戳 = 静默放宽。混版实测读数与部署前置写在仓库的部署前置清单(不随包)7.135.0 节。
4033
+ (`toolDeny` 的 `mcp__*` 在文法 2 里什么也不拒),改戳 = 静默放宽。混版实测读数是内部记录。
2634
4034
  **人的持久规则(同一件事的另一只店)**:引擎 7.55.0 起持久规则桶带文法戳,新文法写下的 deny(Bash 中段 `*` 的模式形、`Agent(<类型>)`)在 7.54.x 上**什么也不拒**
2635
4035
  (旧引擎不读戳,把模式形读成「无形」)—— 同一份规则目录(`DB_BACKEND=local`)或同一只库不要混跑两版,先升全部进程;**降级到 7.55.0 之前**:先把这类 deny 改写成覆盖它的前缀 deny
2636
4036
  或整工具 deny,或不降。SQL 持久规则店自本版起也写 / 读这只戳(`permission_rule` 加一列,见第 16 条),且**戳算进桶的完整性指纹**:本版副本读到更晚文法写下的桶整桶拒、每次调用问人;7.134.x 副本(引擎 7.54.1)不读戳,
@@ -2942,7 +4342,7 @@
2942
4342
  adb 仍照单全收。**升级前对 k8s 部署核一遍**:在镜像里跑 `printf %s "$HOME"`,与声明值比;对不上的按拒句改声明(或让镜像以声明的用户运行)。**谁受影响**:① 此前为了消掉起服 warn 而手填了 `REMOTE_EXEC_HOME_DIR` 的部署 —— 不必改,声明仍胜;想让车道自己测就删掉它,**但**用了 `~/` 形权限规则的部署必须保留声明:
2943
4343
  `~/` 形规则的下单门与规则基仍只认声明(提交任务那一刻执行环境还没开),没声明 ⇒ 照旧 `422`;② 按起服行 `execution_lane_home_undeclared` 配了告警的运维 —— 这一行现在只在 device 车道起服时响;k8s / local-docker / ssh / adb 没声明时起服不再响,
2944
4344
  改成**某只环境实测缺席时**响同一只事件码(字段仍是 `provider` + `note`,note 点名读到了什么;同一部署同一句只响一次),把告警条件从「起服出现」改成「运行期出现」;③ 没声明的部署上引擎对这四条车道的家锚拒读行落位变了
2945
- (由「没有家目录时在任何位置按路径段判」落到实测的家目录下,并另锚引擎宿主的账户家、每条 run 的落位多一次经该车道 `canonicalPath` 的账户家探针,上限 2 s —— 引擎对「声明了家」的远端车道的既有口径,见部署前置文档(仓库 docs 目录下 DEPLOY-PREREQS)该节;本版未在真集群上实测)。
4345
+ (由「没有家目录时在任何位置按路径段判」落到实测的家目录下,并另锚引擎宿主的账户家、每条 run 的落位多一次经该车道 `canonicalPath` 的账户家探针,上限 2 s —— 引擎对「声明了家」的远端车道的既有口径;本版未在真集群上实测)。
2946
4346
  **做法**:k8s 部署核声明与镜像用户的 `$HOME`(上一段);其余无需动手;想看到实测值是否生效,看运行期是否出现 `execution_lane_home_undeclared`(出现 = 那只环境的 `$HOME` 读不出绝对路径:修环境的 `HOME`,adb 上也可以声明;k8s / local-docker / ssh 上声明替代不了一个读不出的 `$HOME`,会被拒)。
2947
4347
  12. **SQL 后端(`DB_BACKEND=mysql` / `pg`):workflow 续跑日志(journal)的属主 scope 搬进新表 `workflow_journal_owner`,`workflow_journal` 起服一次性按新主键重建(持久数据;🔴 先停旧副本再起新)**:
2948
4348
  7.132.x 及以前 scope 是 journal **每一行**上的一列,读面按它判、写面不判(别的 scope 能往一条 run 里写)。本版起一条 run 的属主 scope 只记在 `workflow_journal_owner` 一行(主键 `run_id`,
@@ -4795,7 +6195,7 @@
4795
6195
  - **🔴 回滚到 7.115.x 之前排空停驻行**:7.116.0 停驻的行可能带 7.115.x(引擎 7.40)不读的技能授予节 / 卡绑定,或续跑上下文里某只技能声明的非空 `disallowedTools`(那只技能停驻时还没被激活、没有授予行可冻 —— 回滚后模型再激活它,上一版什么也不拒)—— 在 7.115.x 上续跑这种行,这一 run 的技能禁止行会丢。
4796
6196
  回滚前在 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 才回滚;
4797
6197
  `DB_BACKEND=local` 用随包 `node scripts/drain-check-local.mjs [<数据根>]`,首行 `SKILL-GRANTS rows=0 …` 才回滚)。本脚本的末行从两行变四行(含下面的升级前判据):`SKILL-GRANTS …` 排第一,倒数第二行仍是 `PERMISSIONS-ALLOW-LIST …`、最后一行仍是 `RETIRED-MODE-SEED …`。
4798
- - **🔴 排空配方现在在包里(7.116.0 起)**:此前排空 SQL 只写在不随 npm 包出的 `docs/DEPLOY-PREREQS.md` 里,只装 npm 包的部署读不到。现在两只可直接执行的 SQL 文件随包出(`scripts/drain-check.mysql.sql` / `scripts/drain-check.pg.sql`,与本地脚本同一目录、
6198
+ - **🔴 排空配方现在在包里(7.116.0 起)**:此前排空 SQL 只写在不随 npm 包出的部署文档里(内部记录),只装 npm 包的部署读不到。现在两只可直接执行的 SQL 文件随包出(`scripts/drain-check.mysql.sql` / `scripts/drain-check.pg.sql`,与本地脚本同一目录、
4799
6199
  每条判据一段、整只文件一次跑完出一行读数 `criterion | hit_rows | sessions`),文档里不再持有 SQL。**还没升到 7.115.0 的部署**(要在升级前数):不必先升级服务 ——
4800
6200
  `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`)去跑;
4801
6201
  四条判据各自该在哪个版本边界跑看该条所在的那一节(`permissions-allow-list` 见 7.115.0 节、`retired-mode-seed` 见 7.113.0 节、`skill-grants-rollback` 与 `retired-skill-manifest` 见本节)。判据与读数不变,只是搬了家并多一条。
@@ -5079,7 +6479,7 @@
5079
6479
 
5080
6480
  ### 运维日志事件名退役一族(车 UQ / 车 UR)—— 按事件名配告警 / 数行的运维要改配
5081
6481
  - **退役(不再逐记录发 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 八座)。
5082
- - **替代读法(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 行与其余既有行)。
6482
+ - **替代读法(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` 形与其余既有项)。
5083
6483
  - **保持逐命中响亮(安全轴混座,不退役)**:`file_store_corrupt_read`;其 session-policy 脸的坏读今天仍 fail-open(引擎修后改拒),server 7.113.0 起同时计 `server.session-policy.corrupt-read-fail-open`(P-DEBT)。
5084
6484
  - **run-local 车道**(前台 CLI 进程)的会话 repo 仍走混座逐命中 warn,不降。
5085
6485
 
@@ -5101,7 +6501,7 @@
5101
6501
  - **会话删除 / 托管留存级联接上用户输入受理账本(车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 红即通知。
5102
6502
  - **同步子代的 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 读得懂这些行,照常收敛 / 告知)。
5103
6503
  - **用户输入受理账本收敛判词合一 / 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 无数据动作(账本行形不变)。
5104
- - **`@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 会把「只缺换行」的末行截掉(只在崩溃留下的那一形上;盘上格式不变,零数据动作)。
6504
+ - **`@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 会把「只缺换行」的末行截掉(只在崩溃留下的那一形上;盘上格式不变,零数据动作)。
5105
6505
 
5106
6506
  ## 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 告知(用户输入受理账本)
5107
6507
 
@@ -5242,8 +6642,7 @@
5242
6642
  - **wire:`READ_FACE=roots` 面上 Read / Grep / Glob 读工作区外 = 一张卡**(`default` / `acceptEdits` / `plan`;`auto` 先交分类器、`bypassPermissions` 释放)(修前当场拒);新 `tool_end.errorCode` `read_unestablished`;`permission_denied_total`
5243
6643
  的 `deniedBy` 标签 `plan_mode` → `mode`。
5244
6644
  - **🔴 安全面(部署):git 的 env 配置族(`GIT_CONFIG_*` / `GIT_CONFIG_PARAMETERS`)与代理变量现在**连同凭据**原样到达宿主子进程(含模型可驱动的 host shell)。**
5245
- **迁移**:把凭据挪出服务进程 env 的这两族 —— git 走 credential helper 的配置文件、ssh key 文件或 `durableRemote` URL,代理按来源免密(`docs/DEPLOY-PREREQS.md`
5246
- 「宿主子进程拿到的 env 改成参照实现的剥除形」节)。`SSH_AUTH_SOCK` 与 `OTEL_*` 自本版起不到宿主子进程:经 ssh-agent 推送的 leader 部署改 key 文件;
6645
+ **迁移**:把凭据挪出服务进程 env 的这两族 —— git 走 credential helper 的配置文件、ssh key 文件或 `durableRemote` URL,代理按来源免密(或 git 侧只带用户名的 `http.proxy` + credential helper 供口令)。`SSH_AUTH_SOCK` 与 `OTEL_*` 自本版起不到宿主子进程:经 ssh-agent 推送的 leader 部署改 key 文件;
5247
6646
  语言服务器 / bake-runner 要 OTel 用 `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。`secret_env_scrubbed_total` 的 `kind` 标签换成 core 五词,按
5248
6647
  `suffix-rule` / `family-rule` 写的告警规则改标签。
5249
6648
  - **升级窗**:升级前把**耐久子代 park**(父链经过部署治理层的子代审批)答完或取消 —— 7.105.0 上 park 的这类行在 7.106.0 上可能拒 `resume.parent_constraint_mismatch`
@@ -5446,7 +6845,7 @@
5446
6845
  #### `401 auth.unauthorized` 的 message 换成出路句
5447
6846
 
5448
6847
  - **`401 auth.unauthorized` 的 `error` 换句(wire 文案,码不变)**:此前恒为 `unauthorized` 一个词,现在按这道门收什么给三句出路句之一(凭据门 /
5449
- 运维口 / 要调用方身份,逐字见 `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 A.1)。按 `error == "unauthorized"` 字面判的调用方改按 `errorCode`
6848
+ 运维口 / 要调用方身份,句子就在应答的 `error` 字段里)。按 `error == "unauthorized"` 字面判的调用方改按 `errorCode`
5450
6849
  (`auth.unauthorized`)判 —— 状态码与码都没变。
5451
6850
 
5452
6851
  #### `GET /v1/capabilities` 多一段 `sealedKey`(模型钥匙 sealed 形的公钥发现面;additive,零迁移)
@@ -5662,7 +7061,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
5662
7061
  #### 内部构造面(对包消费方零影响)
5663
7062
 
5664
7063
  - 内部面(非公开导出):三家 run 店的 `setSuspended` / `setNeedsReview` 收第二个必填参数 `result`(结果或 `null`),`result` 列经同一只入口
5665
- `sealRunRowResult`(封口 + 脱敏)落列。契约全文见 `docs/ASSISTANT-WIRE-CONTRACT.md` §5.0c。(正文见「wire」小节与「存储与一次性迁移」小节)
7064
+ `sealRunRowResult`(封口 + 脱敏)落列。(正文见「wire」小节与「存储与一次性迁移」小节)
5666
7065
  - **内部构造面(对包消费方零影响)**:`observability/corrupt-read-seat.ts` 的 `createCorruptReadSeat` 多一个可选第 4 位 `leg`;`plugins/session-event-payload.ts`
5667
7066
  的 `decodeSessionEventPayload` 对坏体抛 `SessionError("corrupt_session")`(此前是 `StoreCorruptError`)。都不在包的导出面上。(正文见「wire」小节)
5668
7067
  - **内部构造面(对包消费方零影响)**:`createFilePermissionRuleStores` 的 opts 多一个 `warn`(两份日志的腐读座;`onError` 只接 core 规则文件);
@@ -5677,7 +7076,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
5677
7076
  ⇒ 整只不交(7.103.1 上第 4 条起放行;鉴权头 / URL userinfo / 口令旗等其它凭据形任何位置早就整只扣),同一只里无害的 `-c` 一起没了。
5678
7077
  **迁移**:凭据别写进 `GIT_CONFIG_PARAMETERS`;无害设置按腿分 —— project-memory / center-plugins 两条 git 腿隔离宿主全局配置(`GIT_CONFIG_GLOBAL` / `GIT_CONFIG_SYSTEM`
5679
7078
  = `/dev/null`),只能留在 env 里:从 `GIT_CONFIG_PARAMETERS` 删掉凭据条目只留无害设置,或改用 `GIT_CONFIG_COUNT` 组(一条一判、被扣的一条原位占位、其余照到);
5680
- host shell / leader 推送 / 语言服务器 / bake-runner 四条腿另可写进宿主 `~/.gitconfig` / `GIT_CONFIG_GLOBAL`(`docs/DEPLOY-PREREQS.md` 同段)。
7079
+ host shell / leader 推送 / 语言服务器 / bake-runner 四条腿另可写进宿主 `~/.gitconfig` / `GIT_CONFIG_GLOBAL`。
5681
7080
  - `OTEL_EXPORTER_OTLP_{TRACES,METRICS,LOGS,PROFILES}_HEADERS` 与旧拼法 `_SPAN_` / `_METRIC_HEADERS` 不再交给宿主子进程(`OTEL_EXPORTER_OTLP_HEADERS` 此前已由本服务
5682
7081
  按名剥)。**迁移**:语言服务器 / 构建里要用 ⇒ `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 点名放回。**观测面**:`OTEL_EXPORTER_OTLP_HEADERS` 被剥时计数改记
5683
7082
  `secret_env_scrubbed_total{kind="exact-name"}`(core 的桶),不再记 `kind="config-catalog"`(本服务目录臂的桶)—— 按 `config-catalog` 桶数它的看板改看 `exact-name`;
@@ -5750,7 +7149,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
5750
7149
  KL-1129a)**:`GIT_CONFIG_VALUE_<i>` **不在** core 的凭据形状判据里 —— 组里 KEY 是 `http.extraHeader`、VALUE 是 `Authorization: Bearer …`
5751
7150
  这一形会**原样**进宿主子进程(含模型能驱动的 host shell),并在 `isolateConfig` 的 git 腿上作为命令级配置**生效**(`GIT_CONFIG_GLOBAL /
5752
7151
  SYSTEM=/dev/null` 挡不住 env 这一层)。**迁移**:不要把凭据放进服务进程 env 的 git 配置组;要给 git 带凭据,走 credential helper / ssh key /
5753
- 写在 `durableRemote` 里(见 DEPLOY-PREREQS)。⤷ **7.103.0 已随 core 7.33.2 修掉**(车PA 提货):core 给凭据侧加了**值族表**,
7152
+ 写在 `durableRemote` 里。⤷ **7.103.0 已随 core 7.33.2 修掉**(车PA 提货):core 给凭据侧加了**值族表**,
5754
7153
  `GIT_CONFIG_VALUE_<i>` 的值是 `Authorization:` / `Proxy-Authorization:` / `Cookie:` 头(任一行、含折行续写)、带 userinfo 的 URL
5755
7154
  (`<scheme>:/+<user>[:<secret>]@…`),或 proxy 地址键(`http.proxy` / `http.<url>.proxy` / `remote.<name>.proxy`)下的 `user[:secret]@host`
5756
7155
  ⇒ 按凭据剥(遥测 `secret_env_scrubbed_total{kind="family-rule"}`),被剥的那一条不到子进程(7.103.0 是本仓**整组**扣、该组里别的配置
@@ -5788,12 +7187,12 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
5788
7187
  由展开给出的程序名)core 读不到、照原样交出;③ `http.extraHeader` 下的**非凭据**头(trace / 路由头)照样按键扣,要它到达写进 git 配置文件。
5789
7188
  **带口令的代理(core 7.33.5 / 7.33.6)**:`http_proxy` / `https_proxy` / `all_proxy` 与 `npm_config_https_proxy` / `npm_config_proxy` /
5790
7189
  `ftp_proxy`(大小写两形)值里带 userinfo / `%40` ⇒ 宿主子进程拿不到它(`family-rule`);只有地址的代理与 `NO_PROXY` 照到;写死口令的 `GIT_SSH_COMMAND` /
5791
- `GIT_PROXY_COMMAND`(`sshpass -p <口令>` …)同样不到。出路见 `docs/DEPLOY-PREREQS.md`(服务进程自己的出网不受影响)。
7190
+ `GIT_PROXY_COMMAND`(`sshpass -p <口令>` …)同样不到。出路:代理按来源免密,或 git 侧 `http.proxy=http://<user>@<proxy>:<port>`(只带用户名)+ credential helper 供口令(服务进程自己的出网不受影响)。
5792
7191
  ⤷ **`GIT_CONFIG_PARAMETERS`随 core 7.33.5 收口**:git 的命令级配置 env(`git -c` 传给子进程的那一份)按 git 自己的引号语法读,
5793
7192
  任一条带凭据(或 git 会拒的写法)⇒ 整只不到宿主子进程;干净的列表逐字节原样。7.103.0 此处「不在剥密族表里」的披露降级为「core 扣它」。
5794
7193
  ⤷ 7.103.2(core 7.33.8)起按判、不论第几条(7.103.1 / core 7.33.6 上第 4 条起的嵌套命令凭据助手 `!sh -c '…'` 读不到、整只原样到;其它凭据形任何位置
5795
7194
  都整只扣);任一条带凭据 ⇒ 整只变量不交,同一只里无害的 `-c` 一起没了。凭据别写进它;无害设置按腿分(隔离配置的 project-memory / center-plugins 两腿只能留在 env:
5796
- 删掉凭据条目或改用 `GIT_CONFIG_COUNT` 组;其余四腿另可写进宿主 git 配置文件)—— 出路见 `docs/DEPLOY-PREREQS.md` 同段。
7195
+ 删掉凭据条目或改用 `GIT_CONFIG_COUNT` 组;其余四腿另可写进宿主 git 配置文件)。
5797
7196
 
5798
7197
  ## 7.103.0(车OW 部分)—— `/health.modelRefusals` 是**免鉴权面**上的新键(7.103.0 验收 G2 格补披露)
5799
7198
 
@@ -5832,7 +7231,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
5832
7231
  - **被拒条目的名字撞档位词 / 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`)。
5833
7232
  - **`MODEL_ID` 不再是 loadConfig 期的硬要求**:目录有可用条目即可省;目录应用之后仍没有缺省模型 ⇒ 拒启(`config.default_model_missing`,句首保留 `MODEL_ID is required`)。中心超出 `CONFIG_BOOT_FETCH_BUDGET_MS` 且无 LKG 时 boot 那一刻没有目录:没写 `MODEL_ID` 就拒启 —— 写一个 `MODEL_ID` 兜底或调大预算。
5834
7233
  - **类型面**:`ServiceConfig.modelRefusals`(新必填席;手铸 `ServiceConfig` 的消费方 tsc 即红 —— env 形写 `{}`)与 `ServiceConfig.lspEnvAllow`(新必填席 `readonly string[]`,同样 tsc 即红 —— 缺省形写 `[]`);`SealedKeyPoisonReason` 删 `unsupported_alg`(形错的 sealed 密文现在让整条不可用,到不了毒丸臂);`FoldedReadWarning` 带 `scope` 判别位、`FetchEffectiveResult` 新键 `droppedEntries`。
5835
- - **记忆抹除面的 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 错误码目录)删掉那一臂。
7234
+ - **记忆抹除面的 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 错误码目录)删掉那一臂。
5836
7235
  - **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`。
5837
7236
  - **子进程剥名收窄(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 起文档写明)。
5838
7237
  - **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」表。
@@ -5850,12 +7249,12 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
5850
7249
  - **`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` / 墙钟兜顶。
5851
7250
  - **记忆抹除面:三个既有端点新答 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提货版撤销本预检与这个码。
5852
7251
  - **审批名单热应用(行为面)**:`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」的部署核对名单。
5853
- - **回滚到 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 原样读得动。
5854
- - **子进程按名剥凭据形变量(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`。
7252
+ - **回滚到 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 原样读得动。
7253
+ - **子进程按名剥凭据形变量(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`)。
5855
7254
 
5856
7255
  ## 7.99.0 —— 三条 BREAKING(行为面 / 类型面 / 运行时下限)
5857
7256
 
5858
- - **显式签发方不再算托管证据(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` 托管形前置。
7257
+ - **显式签发方不再算托管证据(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`)。
5859
7258
  - **`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 活动状态目录暂不迁移。
5860
7259
  - **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+。
5861
7260
 
@@ -5875,7 +7274,7 @@ schema **拒启并打印要执行的 `ALTER TABLE … ADD COLUMN …`**,不会
5875
7274
  | **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 产物是可恢复窗缓存,转录内联预览不受影响) |
5876
7275
  | **7.101.0** | `session_meta` 新列 `instruction_source VARCHAR(64) NULL`(PG `COLLATE "C"`;项目指令换源通告的基线) | 两方言按拒启句里给出的 `ALTER TABLE session_meta ADD COLUMN …` 由部署者自己加列;**先升库、再升副本**(加列后旧副本重启见幽灵列拒启) |
5877
7276
 
5878
- > 列增批此前只记在 CHANGELOG / `docs/DEPLOY-PREREQS.md`(7.92.0 `session_policy`、7.93.4 `approval_ask.settled_by` 各加过一列),自 7.101.0 起同样入本表。7.101.0 这一列的拒启句自带可粘贴的 `ALTER`,本仓仍不替你执行。
7277
+ > 列增批此前只记在 CHANGELOG 与内部部署记录里(7.92.0 `session_policy`、7.93.4 `approval_ask.settled_by` 各加过一列),自 7.101.0 起同样入本表。7.101.0 这一列的拒启句自带可粘贴的 `ALTER`,本仓仍不替你执行。
5879
7278
 
5880
7279
  ## server 3.0.0 —— BREAKING 四条(2026-07-31)
5881
7280
 
@@ -5900,7 +7299,7 @@ schema **拒启并打印要执行的 `ALTER TABLE … ADD COLUMN …`**,不会
5900
7299
  | `HOST_EXEC_SPOOL_DISABLED` | `HOST_EXEC_SPOOL_ENABLED=false` | 开 | host lane exec 的 spool 形 stdio |
5901
7300
  | `LSP_ENABLED=false`(拆分前用来关 host 腿) | `LSP_HOST_ENABLED=false` | 开 | host lane 本地 LSP。⚠️ `LSP_ENABLED=true` **不受影响**——那是沙箱腿自己的 opt-in |
5902
7301
 
5903
- **② 的完整码表**见 `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 A;机器执行面是 `test/error-code-key-gate.test.ts`
7302
+ **② 的完整码表**是服务端 wire 契约的附录 A(内部记录,不随包);机器执行面是 `test/error-code-key-gate.test.ts`
5904
7303
  (`src/` 全树的 error 帧 + `src/http/` 全树的 4xx/5xx 错误体,两面都不许漏码)。
5905
7304
 
5906
7305
  ## core 引擎侧 BREAKING(经 `@sema-agent/core` 依赖传入)