@sema-agent/server 7.137.0 → 7.139.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 (328) hide show
  1. package/MIGRATION.md +600 -142
  2. package/README.md +7 -3
  3. package/README.zh-CN.md +6 -3
  4. package/USAGE.md +132 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/wire.d.ts +3 -3
  8. package/dist/approval-card.d.ts +23 -16
  9. package/dist/approval-card.js +1 -0
  10. package/dist/audit.js +1 -0
  11. package/dist/background-agent-name.d.ts +5 -0
  12. package/dist/background-agent-name.js +5 -0
  13. package/dist/bench/s1/arms.d.ts +1 -1
  14. package/dist/bench/s1/arms.js +1 -3
  15. package/dist/bench/s1/run-firm.js +2 -2
  16. package/dist/boot/budget-tracing.d.ts +1 -12
  17. package/dist/boot/deployment-mods.d.ts +46 -16
  18. package/dist/boot/deployment-mods.js +82 -6
  19. package/dist/boot/device-lane.d.ts +8 -3
  20. package/dist/boot/device-lane.js +7 -2
  21. package/dist/boot/execution-env.d.ts +4 -2
  22. package/dist/boot/execution-env.js +16 -24
  23. package/dist/boot/execution-lane.d.ts +1 -1
  24. package/dist/boot/governance-seams.d.ts +12 -18
  25. package/dist/boot/governance-seams.js +10 -24
  26. package/dist/boot/leader.d.ts +3 -0
  27. package/dist/boot/leader.js +1 -0
  28. package/dist/boot/memory-consolidation.js +2 -2
  29. package/dist/boot/org-delivery.js +15 -2
  30. package/dist/boot/resolve-spec.d.ts +4 -1
  31. package/dist/boot/resolve-spec.js +29 -19
  32. package/dist/boot/retention-lane.d.ts +14 -8
  33. package/dist/boot/retention-lane.js +2 -8
  34. package/dist/boot/runner-deps.d.ts +10 -4
  35. package/dist/boot/runner-deps.js +2 -0
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-04-stores.d.ts +1 -12
  40. package/dist/boot/stage-05-execution-env.d.ts +3 -12
  41. package/dist/boot/stage-05-execution-env.js +8 -5
  42. package/dist/boot/stage-06-runners.d.ts +3 -12
  43. package/dist/boot/stage-06-runners.js +5 -3
  44. package/dist/boot/stage-07-capability-layer.d.ts +3 -12
  45. package/dist/boot/stage-07-capability-layer.js +2 -2
  46. package/dist/boot/stage-08-reapers.d.ts +3 -12
  47. package/dist/boot/stage-09-leader.d.ts +3 -12
  48. package/dist/boot/stage-09-leader.js +2 -3
  49. package/dist/boot/stage-10-http-server.d.ts +3 -12
  50. package/dist/boot/stage-10-http-server.js +5 -3
  51. package/dist/boot/stores.js +4 -4
  52. package/dist/boot/web-admin.d.ts +5 -2
  53. package/dist/boot/web-admin.js +5 -5
  54. package/dist/brain.js +5 -5
  55. package/dist/budget.d.ts +17 -15
  56. package/dist/budget.js +2 -2
  57. package/dist/capabilities/mcp-probe.d.ts +36 -11
  58. package/dist/capabilities/mcp-probe.js +44 -5
  59. package/dist/capabilities/scenarios.d.ts +1 -1
  60. package/dist/capability-facts.d.ts +21 -7
  61. package/dist/capability-facts.js +13 -3
  62. package/dist/checkpoint-identity.d.ts +13 -6
  63. package/dist/config-catalog.js +14 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +19 -24
  67. package/dist/config-provider.js +27 -12
  68. package/dist/config-types.d.ts +25 -12
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +52 -20
  71. package/dist/delegated-session-owner.d.ts +2 -2
  72. package/dist/deployment-shape.d.ts +7 -7
  73. package/dist/device-enrollment.d.ts +41 -2
  74. package/dist/device-enrollment.js +27 -12
  75. package/dist/device-store.d.ts +58 -85
  76. package/dist/device-store.js +19 -49
  77. package/dist/device-ws-hub.js +2 -1
  78. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  79. package/dist/exec-cut.d.ts +60 -0
  80. package/dist/exec-cut.js +36 -0
  81. package/dist/execution-lane-caps.d.ts +19 -0
  82. package/dist/execution-lane-caps.js +10 -0
  83. package/dist/execution-placement.d.ts +259 -0
  84. package/dist/execution-placement.js +199 -0
  85. package/dist/field-conflict.d.ts +3 -2
  86. package/dist/field-conflict.js +1 -0
  87. package/dist/gate-settlement.d.ts +71 -0
  88. package/dist/gate-settlement.js +40 -0
  89. package/dist/hooks/classic-stations.d.ts +1 -0
  90. package/dist/hooks/classic-stations.js +1 -0
  91. package/dist/hooks/command-spawn.d.ts +2 -2
  92. package/dist/hooks/hook-runner.js +14 -14
  93. package/dist/hosted-posture.d.ts +2 -2
  94. package/dist/http/admission.js +10 -19
  95. package/dist/http/checkpoint-ctx.d.ts +21 -12
  96. package/dist/http/checkpoint-ctx.js +4 -2
  97. package/dist/http/claimed-run.d.ts +1 -1
  98. package/dist/http/dispatch.d.ts +4 -0
  99. package/dist/http/dispatch.js +3 -0
  100. package/dist/http/durable-run-leg.js +12 -6
  101. package/dist/http/execution-context.d.ts +218 -0
  102. package/dist/http/execution-context.js +330 -0
  103. package/dist/http/memory-compliance-failure-reply.js +3 -0
  104. package/dist/http/resume-legs.d.ts +5 -11
  105. package/dist/http/resume-legs.js +179 -104
  106. package/dist/http/route-ctx.d.ts +44 -59
  107. package/dist/http/route-ctx.js +2 -5
  108. package/dist/http/routes/a2a-serve.js +10 -4
  109. package/dist/http/routes/agents-roster.d.ts +1 -1
  110. package/dist/http/routes/agents-roster.js +5 -1
  111. package/dist/http/routes/approvals-assistant.js +6 -6
  112. package/dist/http/routes/background.d.ts +29 -1
  113. package/dist/http/routes/background.js +29 -2
  114. package/dist/http/routes/capabilities.js +12 -10
  115. package/dist/http/routes/devices.d.ts +13 -19
  116. package/dist/http/routes/devices.js +21 -26
  117. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  118. package/dist/http/routes/mcp-reconnect.js +7 -5
  119. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  120. package/dist/http/routes/memory-origin.d.ts +1 -1
  121. package/dist/http/routes/rules.js +3 -3
  122. package/dist/http/routes/runs.js +11 -7
  123. package/dist/http/routes/session-sync.js +110 -15
  124. package/dist/http/routes/sessions.d.ts +6 -0
  125. package/dist/http/routes/sessions.js +119 -13
  126. package/dist/http/routes/side-query.d.ts +12 -4
  127. package/dist/http/routes/side-query.js +6 -8
  128. package/dist/http/routes/tasks.js +800 -782
  129. package/dist/http/server.d.ts +61 -39
  130. package/dist/http/server.js +11 -0
  131. package/dist/http/session-inherit-env.d.ts +3 -4
  132. package/dist/http/session-inherit-env.js +1 -1
  133. package/dist/http/wire-types.d.ts +22 -18
  134. package/dist/identity-source.d.ts +1 -1
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.js +1 -0
  137. package/dist/leader/wire.d.ts +7 -0
  138. package/dist/leader/wire.js +5 -4
  139. package/dist/mcp-assertion-header.d.ts +51 -40
  140. package/dist/mcp-assertion-header.js +10 -11
  141. package/dist/mcp-authorization-face.d.ts +27 -0
  142. package/dist/mcp-authorization-face.js +15 -0
  143. package/dist/memory-operator-faces.d.ts +13 -4
  144. package/dist/memory-operator-faces.js +1 -17
  145. package/dist/memory-sync-client.d.ts +53 -14
  146. package/dist/memory-sync-client.js +187 -92
  147. package/dist/memory-sync.d.ts +1 -1
  148. package/dist/memory-sync.js +3 -2
  149. package/dist/model-route-gap.d.ts +6 -22
  150. package/dist/model-route-gap.js +7 -5
  151. package/dist/mods-declaration.d.ts +110 -0
  152. package/dist/mods-declaration.js +109 -0
  153. package/dist/observability/cost-taxonomy.d.ts +2 -2
  154. package/dist/observability/err-text.d.ts +5 -0
  155. package/dist/observability/err-text.js +9 -0
  156. package/dist/observability/fail-open.d.ts +17 -1
  157. package/dist/observability/fail-open.js +17 -1
  158. package/dist/observability/run-terminal.js +0 -1
  159. package/dist/observability/secret-env-scrub.d.ts +1 -1
  160. package/dist/observability/secret-env-scrub.js +1 -1
  161. package/dist/orchestration/workflow-notify-journal.js +4 -4
  162. package/dist/org-memory-admission.d.ts +4 -3
  163. package/dist/org-memory-admission.js +6 -6
  164. package/dist/parked-decide.d.ts +49 -11
  165. package/dist/parked-decide.js +25 -26
  166. package/dist/parked-revive-surface.d.ts +12 -15
  167. package/dist/parked-revive-surface.js +3 -6
  168. package/dist/peer-seat.d.ts +156 -0
  169. package/dist/peer-seat.js +273 -0
  170. package/dist/permission-rule-vocab.d.ts +7 -7
  171. package/dist/permission-rule-vocab.js +3 -3
  172. package/dist/plain-string-record.d.ts +38 -0
  173. package/dist/plain-string-record.js +38 -0
  174. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  175. package/dist/plugins/approval-ask-store-file.js +11 -0
  176. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  177. package/dist/plugins/approval-ask-store-memory.js +12 -0
  178. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  179. package/dist/plugins/approval-ask-store-sql.js +30 -12
  180. package/dist/plugins/background-agent-store-sql.js +6 -3
  181. package/dist/plugins/caching-session-store.d.ts +11 -2
  182. package/dist/plugins/caching-session-store.js +15 -3
  183. package/dist/plugins/checkpoint-store-sql.d.ts +21 -25
  184. package/dist/plugins/checkpoint-store-sql.js +13 -15
  185. package/dist/plugins/device-store-sql.d.ts +25 -51
  186. package/dist/plugins/device-store-sql.js +49 -103
  187. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  188. package/dist/plugins/execution-placement-sql.js +223 -0
  189. package/dist/plugins/file-history-store-sql.d.ts +7 -6
  190. package/dist/plugins/file-history-store-sql.js +8 -7
  191. package/dist/plugins/file-run-store.d.ts +6 -1
  192. package/dist/plugins/file-run-store.js +4 -0
  193. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  194. package/dist/plugins/fork-routing-session-store.js +16 -0
  195. package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
  196. package/dist/plugins/k8s-pod-reaper.js +3 -3
  197. package/dist/plugins/local-checkpoint-store.d.ts +1 -11
  198. package/dist/plugins/local-checkpoint-store.js +0 -1
  199. package/dist/plugins/local-session-store.d.ts +183 -45
  200. package/dist/plugins/local-session-store.js +412 -105
  201. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  202. package/dist/plugins/mailbox-store-sql.js +103 -15
  203. package/dist/plugins/memory-key-guards.d.ts +4 -0
  204. package/dist/plugins/memory-key-guards.js +1 -0
  205. package/dist/plugins/memory-run-store.d.ts +1 -1
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +117 -6
  209. package/dist/plugins/one-time-migrations.js +383 -14
  210. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +13 -15
  212. package/dist/plugins/permission-rule-store-sql.js +34 -29
  213. package/dist/plugins/pg-pool.d.ts +7 -3
  214. package/dist/plugins/pg-session-storage.d.ts +41 -22
  215. package/dist/plugins/pg-session-storage.js +136 -55
  216. package/dist/plugins/remote-env-adb.d.ts +22 -4
  217. package/dist/plugins/remote-env-adb.js +70 -62
  218. package/dist/plugins/remote-env-device.d.ts +32 -12
  219. package/dist/plugins/remote-env-device.js +18 -17
  220. package/dist/plugins/remote-env-e2b.d.ts +19 -3
  221. package/dist/plugins/remote-env-e2b.js +41 -42
  222. package/dist/plugins/remote-env-file-error.d.ts +2 -0
  223. package/dist/plugins/remote-env-file-error.js +1 -1
  224. package/dist/plugins/remote-env-host.d.ts +23 -8
  225. package/dist/plugins/remote-env-host.js +66 -70
  226. package/dist/plugins/remote-env-k8s.d.ts +13 -16
  227. package/dist/plugins/remote-env-k8s.js +61 -54
  228. package/dist/plugins/remote-env-local-docker.d.ts +30 -5
  229. package/dist/plugins/remote-env-local-docker.js +46 -59
  230. package/dist/plugins/remote-env-ssh.d.ts +18 -4
  231. package/dist/plugins/remote-env-ssh.js +72 -56
  232. package/dist/plugins/remote-shell.d.ts +100 -3
  233. package/dist/plugins/remote-shell.js +166 -2
  234. package/dist/plugins/retention-store-sql.d.ts +23 -8
  235. package/dist/plugins/retention-store-sql.js +13 -1
  236. package/dist/plugins/run-store-sql.d.ts +13 -3
  237. package/dist/plugins/run-store-sql.js +5 -0
  238. package/dist/plugins/schema-consistency.d.ts +15 -5
  239. package/dist/plugins/schema-consistency.js +14 -8
  240. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  241. package/dist/plugins/schema-drift-sentence.js +38 -0
  242. package/dist/plugins/session-fork.d.ts +63 -12
  243. package/dist/plugins/session-fork.js +38 -21
  244. package/dist/plugins/session-ownership.d.ts +7 -0
  245. package/dist/plugins/session-ownership.js +5 -0
  246. package/dist/plugins/session-row-sql.d.ts +22 -0
  247. package/dist/plugins/session-row-sql.js +81 -0
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  250. package/dist/plugins/session-workspace-cell.js +38 -0
  251. package/dist/plugins/store-backend.d.ts +1 -1
  252. package/dist/plugins/store-backend.js +26 -14
  253. package/dist/plugins/store-contracts.d.ts +25 -5
  254. package/dist/plugins/tidb-pool.d.ts +12 -7
  255. package/dist/plugins/tidb-pool.js +15 -3
  256. package/dist/plugins/tidb-session-store.d.ts +74 -28
  257. package/dist/plugins/tidb-session-store.js +132 -53
  258. package/dist/plugins/tool-result-store-sql.d.ts +16 -8
  259. package/dist/plugins/tool-result-store-sql.js +26 -17
  260. package/dist/plugins/worktree-isolation.d.ts +3 -2
  261. package/dist/plugins/worktree-isolation.js +1 -7
  262. package/dist/project-identity.d.ts +1 -14
  263. package/dist/project-identity.js +0 -4
  264. package/dist/project-memory.d.ts +9 -15
  265. package/dist/project-memory.js +5 -4
  266. package/dist/request-key-closure.js +1 -1
  267. package/dist/request-value-closure.d.ts +6 -7
  268. package/dist/request-value-closure.js +1 -3
  269. package/dist/rules-consent.js +6 -4
  270. package/dist/run-local.d.ts +6 -0
  271. package/dist/run-local.js +36 -26
  272. package/dist/runs.d.ts +9 -2
  273. package/dist/runs.js +9 -2
  274. package/dist/sandbox-git-plane.d.ts +2 -2
  275. package/dist/security.d.ts +38 -12
  276. package/dist/security.js +8 -2
  277. package/dist/server-secret-env.d.ts +15 -8
  278. package/dist/server-secret-env.js +4 -2
  279. package/dist/session-children-retire.d.ts +27 -9
  280. package/dist/session-children-retire.js +9 -5
  281. package/dist/session-incarnation.d.ts +19 -10
  282. package/dist/session-incarnation.js +5 -3
  283. package/dist/session-row.d.ts +114 -5
  284. package/dist/session-row.js +55 -5
  285. package/dist/session-titler.d.ts +2 -2
  286. package/dist/session-workspace.d.ts +130 -0
  287. package/dist/session-workspace.js +83 -0
  288. package/dist/spec-fields.d.ts +1 -1
  289. package/dist/standing-answer-grant.d.ts +2 -13
  290. package/dist/standing-answer-grant.js +0 -7
  291. package/dist/task-a2a.d.ts +44 -14
  292. package/dist/task-a2a.js +46 -20
  293. package/dist/task-cwd.d.ts +6 -1
  294. package/dist/task-mcp.d.ts +33 -20
  295. package/dist/task-mcp.js +46 -22
  296. package/dist/tool-approval.d.ts +38 -8
  297. package/dist/tool-approval.js +57 -13
  298. package/dist/trace/core-keyset-guard.d.ts +33 -18
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +2 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +3 -0
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/project.d.ts +26 -7
  306. package/dist/trace/project.js +30 -3
  307. package/dist/trace/redact.js +42 -13
  308. package/dist/trace/self-minted-wire.d.ts +240 -12
  309. package/dist/trace/self-minted-wire.js +100 -4
  310. package/dist/trace/wire-projection-faces.d.ts +6 -6
  311. package/dist/trace/wire-projection-faces.js +6 -5
  312. package/dist/url-refusal.d.ts +1 -1
  313. package/dist/user-authored-text.d.ts +2 -2
  314. package/dist/user-authored-text.js +16 -1
  315. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  316. package/dist/web-admin-client/apply-effective.js +20 -10
  317. package/dist/web-admin-client/center-request.d.ts +3 -2
  318. package/dist/web-admin-client/center-request.js +2 -3
  319. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  320. package/dist/web-admin-client/skills-mcp.js +32 -18
  321. package/dist/web-admin-client/types.d.ts +11 -0
  322. package/package.json +3 -3
  323. package/wire-changes/server@7.138.0.json +446 -0
  324. package/wire-changes/server@7.139.0.json +348 -0
  325. package/dist/http/device-placement.d.ts +0 -175
  326. package/dist/http/device-placement.js +0 -145
  327. package/dist/http/mcp-remote-text.d.ts +0 -5
  328. package/dist/http/mcp-remote-text.js +0 -7
package/MIGRATION.md CHANGED
@@ -7,6 +7,461 @@
7
7
  > ⚠️ 完整清单在仓库根 `CHANGELOG.md`——它**不随 npm tarball 出包**(本文件随包)。看完整迁移窗的
8
8
  > 权威姿势是源码 tag diff:`git diff v<旧>..v<新>`(每版都推 `v<版本>` tag);npm 包页也镜像 CHANGELOG。
9
9
 
10
+ ## 7.139.0 —— 执行放置成为根会话行上的一格:🔴 SQL 后端 `session_meta` 加八列、`device_session` 表退役、`approval_ask` 加一列 `execution_lane`(本服务起服时自己改表;升级前备份、先停光全部旧副本再起本版;回滚只有恢复备份)· 路由 `GET /v1/devices/sessions/:id` 删除(BREAKING,wire;换读 `GET /v1/sessions/:id/execution-placement`)· 新口 `POST /v1/sessions/:id/children/retire` · fork 可带键重试 `{forkId, forkNonce}`(wire additive)· 四只新 409(`conflict.session_mirror` / `conflict.session_writer` / `conflict.fork_*` / 活子代)与拒体新顶层键 `forkPath` / `boundLane` / `children` / `retirePath`(行为面)· 会话行条件写 `expectedRowTag` ⇒ `409 conflict.session_row_changed`(wire 加性)· 🔴 记忆同步:升级后每一层停同步直到运维对该层游标做一步 · 请求键 `rewindFiles` 退役(wire BREAKING;新提交 400)· `POST /v1/rules/cc-import/prepare` 的 200 体少键 `translated`(wire BREAKING,读侧)· 后台行多可选键 `sessionId`(wire 加性)· 旁问路由 400 只给 `config.unknown_role`(行为变更)· 声明判官的拒句不再回显调用方写的名(运维面)· 部署 mod 包内核契约号 6(`contract: 5` 起服拒)· 四只新运维通告码不上用户流 · 沙箱带外 env 名单点到本服务自有凭据名 ⇒ 起服拒(`E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` / `K8S_SANDBOX_ENV`;安全,行为收紧)· k8s 车道 `K8S_NAMESPACE` 必设(部署面,行为收紧)· 模型目录 `apiKeyEnv` 点到名单型旋钮正在交出的名 ⇒ 该候选整拒(安全)· `CONFIG_PROVIDER=remote` 无中心地址 / `RETENTION_MODE=enforce` 缺天数或节律 ⇒ 起服拒(行为收紧,fail-closed)· 会话规则 / 持久规则桶文法戳 7(升级序:先升全部读者再放写)· 执行环境写入改「暂存 → 一次提交」(七条车道一条规则;行为面)· 本机宿主车道 workflow 子代 `isolation: "worktree"` 的已知变化(E10,引擎 7.61.0 收)· 嵌入方类型面 BREAKING 多处(`RunnerDeps.peerSeat` 三员对象 · `createHttpServer` 的 `authorize` 席必填 · `resolveSpec` 不再写 `sessionId` · 设备店绑定四法换两只放置写 · 停驻赎回腿的会话店必须带执行席、`root` → `rootOccupant` · `StoreBackend` 问店行与迁移报告多键)· 契约包 settings-schema 15.0.0 · 引擎 7.60.0
11
+
12
+ 1. **🔴 记忆同步(`MEMORY_SYNC_URL` 设了的 file 记忆部署):升级后每一层都停同步,直到运维对那一层的游标做一步**:
13
+ 本版起同步对端 = `MEMORY_SYNC_URL` 的规范化形(协议与主机小写、缺省端口省掉、路径去尾斜杠;起服日志 `memory_sync_enabled` 的 `peer` 就是它,该行不再带 `url`),
14
+ 每层一只游标 `<记忆根>/sync-cursors/<scope 摘要>.json`,游标的对端 / scope / 店绑定只由引擎判。第一轮会把上一版的分区游标(`sync-cursors/central/…`)与更早的根下游标
15
+ (`sync-cursor-central.json`)搬到各自那一层的路径(只搬、字节不变;日志 `memory_sync_cursor_relocated`,目标路径已有游标或读不出它属于哪一层 ⇒ 原地不动、一行 `memory_sync_cursor_not_relocated`)。
16
+ 搬过来的游标绑的对端名是 `central`,与新身份不符 ⇒ 引擎在对端轴上拒、这一层零请求,`memory_sync_layer_failed` 带引擎的拒句(两条出路)与游标路径;其余层照跑,下一轮同样拒,直到处置。
17
+ **处置(每一层一次,二选一)**:① 中心没换(同一只中心,只是换了身份写法)⇒ 把那只游标文件里的 `"peer"` 改成 `memory_sync_enabled` 日志里的 `peer` 值,其余字节不动,下一轮照常增量同步 —— 例外:游标里没有 `"store"` 键的(7.138.0 之前写下的 `sync-cursors/central/…` 与更早根下的 `sync-cursor-central.json` 都没有),改完 `peer` 后下一轮引擎在店轴再拒一次
18
+ (三轴按 scope → peer → store 的顺序判,peer 过了才轮到 store),`memory_sync_layer_failed` 的拒句点名这一轮的店身份:把它作为 `"store"` 键写进那只游标,再下一轮照常增量同步(或走处置 ②);
19
+ ② 删掉那只游标 = 接受空基线重收敛:两边都改过的条目按冲突上报,自上一轮以来一侧删掉的条目会从另一侧回来。中心换过了只能走 ②。执行器不替运维选:读不了 / 读不成 / 被拒的游标一律原地不动。
20
+ **起服判 `MEMORY_SYNC_URL`**(引擎关着也判):不是层级式 http(s)、带 userinfo / query / fragment(含空的 `?` / `#`)、路径段里带令牌形、或规范化后超过中心 `peer` 列宽 ⇒ 拒启(拒句值只到 origin,不回显地址其余部分);
21
+ 令牌只走 `MEMORY_SYNC_TOKEN`。上一版照收的这些形升级当天起服即拒 —— 升级前把地址写成基址本身。
22
+ 两道判各有属主,本服务不另抄:地址的形归「后面要拼路径的基址」座位的判官 `pathBaseUrlRefusal`;身份里有没有凭据(路径段的令牌形、任何 userinfo)归引擎包根导出的 `carriesCredential` ——
23
+ 引擎同步客户端判对端身份的同一只,起服对规范化后的身份调它,所以引擎在第一轮会拒的地址起服就拒,一个请求都不发。
24
+
25
+ 2. **请求键 `rewindFiles` 退役(wire BREAKING;零别名)**:新提交(`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs`)带它 ⇒ `400 request.body_shape`、`unknownKeys: ["rewindFiles"]`,不建 run;
26
+ 续跑重放盘上旧体里的它零读者(不进引擎 —— 引擎本版对它按名拒,带它存过的任务因此照常续跑)。客户端改用 `restoreFiles` 或 `rewindFilesTo`。
27
+
28
+ 3. **旁问路由(`POST /v1/side-query`)的 400 只给引擎的 `config.unknown_role`(行为变更)**:角色族四臂(角色词不在词表 / 不是模型引用 / 指到目录外 / 角色缺模型)带码 400;
29
+ 没有引擎码的错误一律 500(上一版按英文前缀表把同形句子判 400)。调用方按 `errorCode` 判,不按句子。续跑侧:停驻卡因角色缺模型(`no_model_for_role`)被拒时与目录缺条目同判可兑 —— 配好角色表后同一张卡可续。
30
+
31
+ 4. **声明判官的拒句不再回显调用方写的名(行为变更;运维面)**:请求面 `mcpServers[].toolAxes` / `toolFaces` / `sessionMetaKey` 与 A2A `toolAxes` 的 400 拒句里,调用方写的工具名 / 键 / 词换成
32
+ `[redacted] (N characters)`(N = 码位数)。部署腿(`config.d` / 中心下发)的 `web_admin_mcp_tool_axes_invalid` / `web_admin_mcp_tool_faces_invalid` 的 `problem` 同样只给码位数 —— server 名照点,
33
+ 哪只工具坏了要按 server 名去配置里逐个查。码与状态码不变。
34
+
35
+ 5. **部署 mod 包的内核契约号是 6**:`contract: 5` 的包起服拒 `config.mods_invalid`(拒句点名两号;不静默装、不跳过)。6 = 四个新扩展事件开站(`agent.offer` / `agent.spawn` / `turn.complete` / `session.end`)
36
+ + `tool.call` 失败列 `refuse`(调用跑过之后扩展失败 ⇒ 结果扣下)。升级前把包的 `contract` 改成 6 并核处理器对新列的假设。
37
+
38
+ 6. **`POST /v1/rules/cc-import/prepare` 的 200 体少一个键 `translated`(wire BREAKING,读侧)**:引擎删了这个恒空数组,本服务原样投。读它的客户端改为不读(它从来是空的)。
39
+
40
+ 7. **`GET /v1/sessions/:id/background` 的行多可选键 `sessionId`(wire 加性)**:后台 agent 行在子会话绑定之后带它(跳到子会话用;那只会话照常过会话面的属主门)。键缺席 = 没有 / 还没绑定。
41
+
42
+ 8. **运维面:四只新通告码受众是运维,不上用户流**:`mcp.credential_echoed`(对端把连接凭据回显进它的自述 —— 点名对端与位置,不带值)、`config.read_deny_floor_unkept`
43
+ (执行车道不守读拒表的字节地板 —— 本服务七只车道都声明不守,读拒表非空的每条带车道的 run 都会有一行)、`classifier.seat_rate_limited`(自动模式分类座的模型连续被限流,
44
+ 这条 run 余下的门改由主模型判;引擎缺省连续 3 次,本服务不接这只引擎旋钮 —— 要一直问分类座就设 `AUTO_MODE_CLASSIFIER_FALLBACK=none`,那时它答不出整条拒、从不退到主模型)与 `config.image_processor_unavailable`(这条 run 没有图片处理器、一张超软目标的图原样发出;
45
+ 本服务把 sharp 列为可选依赖,装上即到达不了)。看板 / 告警按 `audience` 过滤。
46
+ `/metrics` 的 `peer_registry_holders` 本版起 = 宿主租约 + 引擎持有之和(run 在飞时读数会高于名册条目数,落定后回到租约数)。
47
+
48
+ 9. **嵌入方(类型面 BREAKING;部署零动作)**:`RunnerDeps.peerSeat` 是 `{ answer, hold, release }` 三员对象(函数形构造即拒 `config.invalid_argument`;本服务的 desk 已是对象;
49
+ desk 对它没铸过的引用 —— `env` / `vault` / `assertion` 或闭集外的种类 —— `hold` / `release` 抛,引擎报一次运维面 `peer-seat-hold`、不记持有);
50
+ 自写执行车道的 `capabilities` 必须声明引擎八键(`hostLocalPaths` / `externalContentTarget` / `io` / `keepsReadFloor` 新必填,设备车道顶层两只散布尔已并入块);
51
+ `loadProjectMemory` 只答 `{ content, instructionSources? }`(无可注入 = `{ content: null }`;裸串 / `null` 引擎不读)。
52
+
53
+ 10. **沙箱带外 env 名单点到本服务自有凭据名 ⇒ 起服拒(`E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` / `K8S_SANDBOX_ENV`;安全,行为收紧)**:
54
+ 三只名单点到的变量从服务进程环境原样装进沙箱(e2b VM env / `docker exec -e` / k8s pod 自己的 Secret),沙箱里模型驱动的命令读得到。本版起它们与
55
+ `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW` 同一条律:点到本服务自有凭据名 —— 配置目录里全部 secret 型变量(如 `SERVICE_AUTH_TOKEN(S)` / `APPROVAL_HMAC_KEYS` /
56
+ `MODEL_API_KEY` / `E2B_API_KEY` / `K8S_TOKEN` / `GIT_API_TOKEN`)与名单型旋钮名本身 —— ⇒ 起服拒,拒句点名旋钮与第几段
57
+ (`env E2B_SANDBOX_ENV: entry #2 of 2 is this deployment's own credential — a sandbox list puts the named variable, as written, into a sandbox the model can read; …`),
58
+ 不回显值;多租户姿态(`REQUIRE_PRINCIPAL=true`)下同样拒。
59
+ **谁受伤**:靠这三只名单把本服务自有凭据交进沙箱过活的部署(典型:`E2B_SANDBOX_ENV=MODEL_API_KEY` 让沙箱里的工具直调模型网关、`K8S_SANDBOX_ENV=GIT_API_TOKEN`
60
+ 让沙箱里的 git 用本服务的 Git host 凭据)—— 升级后起服失败。
61
+ **升级前做(出路)**:给沙箱铸一把独立凭据 —— 名与值都不同于本服务的任何凭据(例如在网关 / Git host 上为沙箱另发一把限权、可单独吊销的 key)—— 放进服务进程环境,
62
+ 名单改点那个名:`SANDBOX_GIT_TOKEN=<另一把令牌>`、`K8S_SANDBOX_ENV=SANDBOX_GIT_TOKEN`,沙箱里的工具改读新名。别把同一个值换个名字再点
63
+ (`SANDBOX_GIT_TOKEN=$GIT_API_TOKEN`):那仍是本服务的凭据进了模型可读的沙箱,只是换了名字。
64
+ 名单只点部署方给沙箱的令牌(`GIT_TOKEN`、`NPM_TOKEN` 这类不在配置目录里的名)的部署零动作。**回滚**:回到上一版即恢复旧行为(名单照装),无数据面改动。
65
+
66
+ 11. **k8s 车道:`K8S_NAMESPACE` 必须设,缺席 / 空白起服拒(部署面,行为收紧;嵌入方类型面 BREAKING)**:
67
+ 沙箱 pod 所在的命名空间是部署事实(沙箱 Role / RoleBinding / NetworkPolicy 与回收器都认部署声明的那一个),服务不再带内置缺省。
68
+ `REMOTE_EXEC=k8s` 而 `K8S_NAMESPACE` 缺席、空串或只含空白 ⇒ 起服拒,拒句点名旋钮与出路:它是 k8s 车道的必需件,拒的是所有车道共用的那道必需 env 门
69
+ (`REMOTE_EXEC=k8s but required env K8S_NAMESPACE is unset, empty or whitespace-only — it counts as absent: …`;门的判法见第 18 条)。其它车道不读这根旋钮,缺席照常起。
70
+ **谁受伤**:`REMOTE_EXEC=k8s` 且没设 `K8S_NAMESPACE` 的部署 —— 升级前沙箱 pod 落在 `sandboxes`;典型是不走随包 chart 的自管集群与本地联调。
71
+ 嵌入方:`ServiceConfig` 的 k8s 车道臂里 `namespace` 由可选改必填(类型面,编译红即消费点清单,没有别名)。
72
+ **升级前做(出路)**:在服务进程环境里设 `K8S_NAMESPACE=<沙箱 pod 所在的命名空间>`;原来没设的部署设成 `K8S_NAMESPACE=sandboxes`,即与升级前逐字同。
73
+ 随包 chart(`deploy/sema-up`,取 `sandbox.namespace`)与单文件栈清单已显式设,零动作。**回滚**:回到上一版即恢复旧缺省,无数据面改动。
74
+
75
+ 12. **模型目录条目的 `apiKeyEnv` 点到名单型旋钮正在交出去的名 ⇒ 该候选整拒(安全,行为收紧)**:
76
+ 中心 / config.d 模型目录条目的 `apiKeyEnv` 在模型目录换代时并进本服务自有凭据名。本版起这一刻对活配置里的名单(`E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` /
77
+ `K8S_SANDBOX_ENV` / `LSP_ENV_ALLOW`)此刻交出去的名重判一次:新并进的名正被某只名单交给沙箱 / 语言服务器 ⇒ 这份候选整拒、上一代照常服务(起服时落 LKG / env;
78
+ 刷新拍 `web_admin_refresh_failed` 每拍重判,`/health` 目标 ≠ 已应用),拒句点名旋钮、名与条目
79
+ (`env K8S_SANDBOX_ENV hands on GATEWAY_KEY, which this candidate makes this deployment's own credential — …`),不回显值。
80
+ **谁受伤**:worker 的名单点着某个变量、中心又把同一个变量写成某条模型条目的 `apiKeyEnv`(典型:`K8S_SANDBOX_ENV=GATEWAY_KEY` 让沙箱里的工具直调网关,中心又给一条模型配
81
+ `apiKeyEnv: GATEWAY_KEY`)—— 升级后中心那份发布在这台 worker 上整份不生效;修前同一个值既是本服务的模型凭据,又在每只沙箱里。
82
+ **升级前做(出路,二选一)**:给沙箱 / 语言服务器另铸一把凭据(名与值都不同),名单改点新名并重启 worker;或在中心把那条模型条目的 `apiKeyEnv` 改指另一个变量(下一拍自愈,不用重启)。
83
+ 名单与模型条目 `apiKeyEnv` 不相交的部署零动作。**回滚**:回到上一版即恢复旧行为,无数据面改动。
84
+
85
+ 13. **嵌入方(类型面 + 构造期,BREAKING):`createHttpServer` 的 `authorize` 席必填;`resolveSpec` 不再写 `sessionId`**:
86
+ 标准起服零动作 —— 它恒装 authorizer(`run-local` 不起 HTTP 面,同样零动作)。自建 `createHttpServer(deps)` 的嵌入方:
87
+ ① deps 加一行 `authorize: createAuthorizer(config, runner.sessions)`(包根导出;店没有属主读时退化为只派 principal 与会话 id,单用户嵌入与升级前同义);
88
+ 这一键从 `governance` 组移到顶层必填席,写在 `governance: { authorize }` 里的改写到顶层。省掉 ⇒ 编译错;JS 嵌入方省掉 ⇒ `createHttpServer` 构造期抛,拒句点名这一行。
89
+ ② 自建 `resolveSpec` 删掉返回值里的 `sessionId`(返回型 `ResolvedTaskSpec` 上它是 `never`);要用这条腿的根会话就读必填的 `opts.execution.root`。
90
+ 根由 server 在装配之后盖进 spec;JS 形装配器返回另一只会话 ⇒ 提交腿 `400 request.precondition_unmet`、零 run 行(续跑腿折成 `409 resume_blocked_by_policy`,`blockedBy` 同码)。
91
+ 要续已有会话,让请求体带它的 id(过 authorizer 的属主门)。
92
+ ③ 注入了 `runStore` 而解析器不写 `sessionId` 的嵌入:同步 / 流式提交从此起认领 + run 行(与 durable 腿同形)。不想记 run 账就不注入 `runStore`(`/v1/runs` 501)。
93
+ ④ SQL run 店的认领事务先锁根会话行:根会话行不在(受理之后会话被删)⇒ 四个建行点答 `404 resume.session_not_found`。自建 deps 把 SQL run 店与非 SQL 会话店配在一起的装配(生产起服不会这样配)认领永远读到零行 —— 两只店要同一个 SQL 后端。
94
+
95
+ 14. **SQL 后端:执行放置切换 —— `session_meta` 加八列、`device_session` 表退役、`approval_ask` 加一列 `execution_lane`(🔴 本服务起服时自己改表;升级前备份、先停光全部旧副本再起本版;回滚只有恢复备份一条路)**:
96
+ 「这只会话在本部署上由谁写」成了根会话行上的一格(`absent` / `writer` / `mirror`,`DB_BACKEND=local` 另有 `forking`);device 车道的设备绑定就是 `writer` 那一格里的设备。
97
+ 本条**不用手跑 `ALTER`**:起服时先只读探一次库形,再在一次性迁移锁内依次 —— 加列(`execution_role` · `execution_lane` · `execution_device_id` · `execution_device_owner_tenant` ·
98
+ `execution_device_owner_subject` · `execution_placed_at` · `execution_rev` · `fork_key`,全部可空;`approval_ask.execution_lane` `NOT NULL DEFAULT ''`)→ `device_session` 的绑定整行搬进根会话行
99
+ (`rev` 原值)→ 有 run 行而还没有放置的会话回填成本处写者(本部署的车道)→ 问行回填车道 → 删掉旧表。中途被打断,下次起服从断点续;新副本在迁移走完之前不服务。库账号要有 DDL 权限(起服建表本就要求)。
100
+ **升级步**:
101
+ ① **备份**整个库(回滚的唯一前提)。`DB_BACKEND=local`:备份整个数据根(会话元数据边档 `session-incarnations.json` 与问账日志 `approval-asks/asks.jsonl` 会被改写)。
102
+ ② **先停光全部旧副本,再起第一个本版副本** —— 滚动升级在本版不成立:切换开始之后仍在跑的旧副本还会往 `device_session` 写首绑,那些行会让下一次起服撞围栏(见 ④)。
103
+ 多副本 k8s 本次按 `Recreate` 做:先把副本数缩到 0、等旧 pod 退光,再升级、再放回副本数(各安装路径的缩容做法与 7.137.0 节第 4 条「升级前先缩光副本」三段相同)。
104
+ ③ 首启时 `REMOTE_EXEC` 照旧取一个值(回填按这一条车道写)。起服日志行 `one_time_migrations_applied` 的七个读数键说这次做了什么:`executionPlacementColumnsAdded`(补了几列)·
105
+ `deviceBindingsMoved`(搬了几条绑定)· `deviceBindingsOrphaned`(指向已不在的会话、被丢弃的绑定数;非零另有一行 warn `device_bindings_orphaned`)· `deviceBindingTablesDropped`(删了几张绑定表)·
106
+ `executionPlacementsBackfilled`(回填了几只会话)· `askExecutionLanesBackfilled`(回填了几只问)· `executionPlacementSessionsUnreadable`(只 `DB_BACKEND=local`:被回填跳过的读不出的旧会话数)。
107
+ `DB_BACKEND=local` 数据根里「有 run、会话元数据格缺、存档读不出」的老会话被回填**跳过并告警**、起服不挡:每只一行 warn `execution_placement_session_unreadable`(`sessionId` 与 `fault`:`corrupt_session` / `invalid_session` / `storage`;
108
+ `storage` = 读存档文件时抛了别的故障〔I/O 级:权限不够、磁盘 I/O 错、存档大到读不进内存〕,此时多一个字段 `errno` 带系统码 `EACCES` / `EIO` / `ERR_STRING_TOO_LONG` ……),**I/O 级读故障同样跳过并点名**(fork 创建的格而存档读不出的会话同样);
109
+ 每次起服都再报;该会话的请求照旧答存档的故障。出路 = 把它的存档文件(数据根 `sessions/` 目录下)从留存副本恢复(`storage`:修好文件权限 / 磁盘),重起后补它的放置;移走存档文件则不再告警、也不补放置(这只会话在本服务上不再存在,它的 run 行留着;fork 创建的会话例外:它的格还在,读作 fork 未落定,出路是同键重试那次 fork 或删除该会话)。
110
+ device 车道上升级前有 run、绑定表里却没有它的会话回填成「本处写者、device 车道、设备未知」:不带 `deviceId` 的提交答 `409 device.not_bound`,带 `deviceId` 即首绑。
111
+ ④ **围栏**:切换已开始(`session_meta.execution_role` 列在,或中途表 `device_session_retired` 在)而 `device_session` 里又有行 ⇒ 起服拒 `config.execution_placement_switch_refused`
112
+ (`reason: fence`),拒在任何 DDL 之前、库零写,拒句列出这些行的根会话(至多 20 只)。先停光旧副本,再二选一,然后重起本版:
113
+ **采旧**(这些行在下一次起服时覆盖它们根会话行上的设备放置)—— 中途表不在时,(MySQL 协议)`RENAME TABLE device_session TO device_session_retired;`
114
+ (PostgreSQL)`ALTER TABLE device_session RENAME TO device_session_retired;`;中途表已在时(两方言同一串):
115
+ `DELETE FROM device_session_retired WHERE root_session_id IN (SELECT root_session_id FROM device_session); INSERT INTO device_session_retired (root_session_id, device_id, owner_tenant, owner_subject, bound_at, rev) SELECT root_session_id, device_id, owner_tenant, owner_subject, bound_at, rev FROM device_session; DELETE FROM device_session;`
116
+ **弃旧**(会话行保留现有的放置):`DELETE FROM device_session;`(只清空旧绑定表;这张空表由本版自己的迁移在下一次起服删掉,不用你动手)。
117
+ 另一拒因 `backfill_ambiguous`(声明的车道不止一条而还有要回填的会话 / 问行)在 `REMOTE_EXEC` 只取一个值的本版不可达;拒句给的出路是「先以单一车道起一次服,让切换走完」。
118
+ ⑤ **回滚**:唯一支持的形 = 恢复 ① 的备份(代价:切换之后的写全丢)。上一版起在已切换的库上会建回一张空 `device_session`,随后起服列册对账把执行列看成未知列而拒启
119
+ (`config.schema_mismatch`),不写行;再起本版,迁移删掉那张空表。`DB_BACKEND=local` 上,上一版读到带执行位的会话元数据格时整份拒那一只边档(首次触及时,不是起服时)—— 同样恢复备份。
120
+ ⑥ **窗**:这段迁移窗内每次起服都跑(切换走完之后零动作),窗 = 本版发布日起 30 天;窗关之后的版本删掉它,并让还带 `device_session` / `device_session_retired` 的库起服拒启 ——
121
+ 跳过本版直升的库,先在本版上起一次服。
122
+ `DB_BACKEND=memory`(引擎缺省的内存会话店)零动作:那种部署不记执行放置。
123
+
124
+ 15. **路由:`GET /v1/devices/sessions/:id` 删除(BREAKING,wire;零转发),换读 `GET /v1/sessions/:id/execution-placement`;新口 `POST /v1/sessions/:id/children/retire`;`POST /v1/sessions/:id/fork` 收可选体 `{forkId, forkNonce}`(wire additive)**:
125
+ ① 旧读面答全局 `404 not_found.route`。新读面 200 体 = `{role:"absent"}` | `{role:"writer", lane, device?:{deviceId, rev}}` | `{role:"mirror"}` | `{role:"forking"}`(`lane` = 执行车道词,
126
+ `REMOTE_EXEC` 的取值,未设 = `in-process`)。换绑的材料:旧体 `boundDevice.deviceId` / `boundDevice.rev` ⇒ 新体 `device.deviceId` / `device.rev`(`rev` 仍是换绑口 `expectedRev` 要回显的前态);
127
+ `boundAt` 没有了;旧体的 `rootSessionId` 就是路径里的 id。「没有绑定」此前答 `404 not_found.device`,现在是 200 —— 格不是 `writer`,或没有 `device` 键;他人会话与不在的会话同答
128
+ `404 not_found.session`(此前 `not_found.device`)。**可见性的门换了**:旧读面按设备域判(要有 tenant claim,且是该设备绑定的同属主,否则 403 / 404;operator 不受此限),新读面按会话判 ——
129
+ 会话面的同一只属主谓词(有主的会话行 = 会话属主;没有身份边界的开发部署与无主的普通会话行对调用方开放,与会话面同读)∨ explicit operator。对**非 operator** 的调用方,在带身份边界的部署、有主会话上:
130
+ 会话属主没有 tenant claim 时,旧读面答 403,现在读得到自己会话的 `device`(绑定);会话属主带的 tenant claim 与该设备绑定的属主不同时,旧读面答 404,现在读得到;
131
+ 设备属主既不是会话属主、也不是 operator 时,旧读面读得到,现在答 `404 not_found.session`。operator 两边都读得到,无变化。非 device 部署上它也在(旧读面在那里整族 `501 capability.device_lane_required`);
132
+ 会话店不带执行席 ⇒ `501 capability.session_store_required`。没有能力位:老 server 对新路径答 `404 not_found.route`。
133
+ ② 结清口(无体)⇒ `200 {children: string[]}`(首轮观察到、且已全部结清的后台子代,每项与 `GET /v1/agents/roster` 行上的 id 同串)/ `409 conflict.session_children_alive`
134
+ (体 `remaining`,有本副本结束不了的子代,一只都没动)/ `404 not_found.session`;鉴权、限流、无凭据写门与 `POST /v1/sessions/:id/background/stop` 同。停止口本身语义不变
135
+ (停驻子代与它的待决卡照留);要「停一切」= 停止口 + 结清口两次调用。
136
+ ③ fork 口:`forkId`(调用方铸的规范 uuid,= 新会话的 id)+ `forkNonce`(1–255 个字符,重试送同一个),同在同缺。首次 `200 {sessionId}`;同键重试 `200 {sessionId, replayed: true}`;
137
+ `forkId` 已是你的另一只会话 ⇒ `409 conflict.fork_id_taken`(终局,换一组新键);已是别人的会话 ⇒ `404 not_found.session`;缺一键 ⇒ `400 request.field_conflict`(`detail.kind: "fork_target"`);
138
+ `forkId` 不是规范 uuid ⇒ `400 request.id_invalid`;`forkId` 等于源 ⇒ `400 request.field_invalid`;`forkNonce` 不合形 ⇒ `400 request.field_invalid`;
139
+ 两次撞上同一目标的别的写者 ⇒ `503 state.fork_target_unsettled`(`permanence: "transient"`,原样重试)。不带体 ⇒ 与上一版同(现铸 id);零字节体与字面 `null` 同义于不带体。
140
+ **体现在被解析了**(上一版这个口忽略体,任何体都照常现铸一只):畸形 JSON ⇒ `400 request.invalid_json`;超过体帽(8 MiB)⇒ `413 request.payload_too_large`;
141
+ JSON 数组或标量(`[]`、`"x"`、`7`)⇒ `400 request.field_invalid`。三种都拒在 fork 之前(什么都没建)。
142
+ 对账读新读面:`GET /v1/sessions/<forkId>/execution-placement` 答 `absent` / `writer` ⇒ 已 fork;`forking` ⇒ 没拷完,同键重试补齐;404 ⇒ 没 fork。
143
+
144
+ 16. **壳 / 客户端的读法:四只新 409 与拒体新顶层键 `forkPath` / `boundLane` / `children` / `retirePath`;同一份日志重推到本处执行过的会话从 200 变 409(行为面)**:
145
+ · `409 conflict.session_mirror`(体 `forkPath`):会话是从别处导入的只读副本 —— 要在本处继续,`POST <forkPath>`(带 `{forkId, forkNonce}` 可重试)后在新会话上执行。
146
+ · `409 conflict.session_writer`:推送(`POST /v1/sessions/:id/sync/import` 与 `…/sync/import/:stagingId/entries`)打到本处写者 —— 本处执行过的会话,升级时有 run 行的会话都被回填成写者。
147
+ **内容完全相同的重推也是 409**(此前 `200 relation:"identical"`)。改为拉取(`GET …/sync/manifest` + `…/sync/entries`),或 fork 后推自己的副本;推之前可读一次执行放置读面(`writer` ⇒ 别推)。
148
+ · `409 conflict.fork_in_progress`(只 `DB_BACKEND=local`):目标是一次没拷完的 fork —— 用同一组 `forkId` / `forkNonce` 重试那次 fork,或删掉这只会话。
149
+ · `409 execution_lane.not_served`(体 `boundLane`):会话放在本部署已不再运行的车道上(升级之后运维换了 `REMOTE_EXEC`)—— fork 出新会话,新会话首跑落在当前车道。
150
+ · 子代半:换绑 `409 device.rebind_active_run`、推送 `409 session_active` 的体可以是 `{children, retirePath}`(根下有活后台子代)而不是 `{activeTaskId}`(根 run 在跑)—— 按键分支;
151
+ `POST <retirePath>` 结清后重试。
152
+ · 续跑家族(`/decide` · `/answer` · `/plan_review` · `/wake` 等)上,这些拒在认领之前一律折成 `409 resume_blocked_by_policy`,`blockedBy` = 原码,原拒体的键随行。
153
+ · 会话在受理与执行之间被删、或删后同 id 重登记:提交腿 `404 resume.session_not_found`(零 run 行);续跑腿认领前 `409 resume_blocked_by_policy`(`blockedBy: "resume.session_not_found"`)、
154
+ 认领后 `404 resume.session_not_found`(那条停驻的 run 以 `failed` 收尾);停驻赎回仍答 `409 decide.not_parked`。
155
+ · device 车道:带 `resumeAt` 的提交,设备准入的拒(`device.*`)先于解锚的拒(`resume_at.*`)—— 锚错又点错设备答 `403 device.identity_mismatch`(此前 `404 resume_at.unknown_event`);
156
+ 提交时读根会话行出故障答 500(此前 `409 device.not_bound`;设备注册簿读故障仍是 `409 device.not_bound`)。
157
+
158
+ 17. **嵌入方(类型面,BREAKING;零别名):设备店的绑定四法换成两只放置写;自建 `StoreBackend` 的问店行与迁移报告多键;会话店、authorizer、`ServiceDeps` 各多可选位**:
159
+ 标准起服零动作。自建装配的嵌入方:
160
+ ① 经 `ServiceDeps.deviceStore` / `StoreBackend.device()` 交出的设备店:删 `getSessionBinding` / `bindSession` / `rebindSession` / `deleteByRootSession`,实现 `placeDeviceExecution`
161
+ (首绑:锁设备行 → 根会话行那一格的条件写)与 `rebindDeviceExecution`(换绑:锁设备行 → 同一事务锁根会话行、读认领,有认领答 `active_run` → 按住客 + 格上属主 + `rev` 的 CAS → 审计行)。
162
+ 绑定不再住在设备店里:执行放置的唯一载体是会话店的执行席。经 `ServiceDeps.deviceEnrollment` 交出的准入链实现 `readPlacement`,`admitSession` 判调用方交来的那一读。
163
+ ② 自建 `StoreBackend`:`approvalAsk()` 的问店铸行时写 `executionLane`、读回带它(必填;幂等命中别人插的行不改);`runOneTimeMigrations()` 的报告多七键
164
+ `executionPlacementColumnsAdded` / `deviceBindingsMoved` / `deviceBindingsOrphaned` / `deviceBindingTablesDropped` / `executionPlacementsBackfilled` / `askExecutionLanesBackfilled` /
165
+ `executionPlacementSessionsUnreadable`(点名行数组 `{ sessionId, fault, errno? }`,`fault` 是闭集 `corrupt_session` / `invalid_session` / `storage`,`errno` 只在 `storage` 时在场;只 local 非空;不跑这段迁移的后端答 0 / 空数组)。
166
+ ③ `OwnerAwareSessionStore` 多两只可选席:`executionPlacement`(`read` / `place` / `markMirror`)与 `forkTo(sourceId, owner, { id, key? })`。不带执行席 ⇒ 不记放置(执行放置读面 501,
167
+ 不判 mirror / writer);不带 `forkTo` ⇒ 带键的 fork 501。包根的 `createStoreBackend()` 造出的会话店都带。
168
+ ④ 自建 authorizer:`AuthContext` 多可选 `head`(门判过的那一读);交了它,执行起点拿它与行上的住客比,不交就不比。包根的 `createAuthorizer` 交它。
169
+ ⑤ `ServiceDeps.executionRuling`(可选,治理组):主体的执行车道裁定,执行起点的唯一输入;缺席 = 不判。
170
+ ⑥ 包根导出型 `ExecutionContext` 的带根两形多 `occupant` / `placement` / `lane` / `device?`,服务形多 `lane` / `placement`;自建 `resolveSpec` 收的 `opts.execution` 仍只有 `{ kind, root }`(第 13 条)。
171
+ ⑦ 直调 `DB_BACKEND=local` 会话店(`createStoreBackend(...).session()`)的 `importEntries` 只建新会话(与两只 SQL 后端同判):id 上已有行或格缺而存档在 ⇒ `SessionError("conflict")`、
172
+ 一个字节不写(上一版 local 店在属主本人的既有行上原地换了日志;SQL 后端一直只建新行,撞已有行答 `storage`,不变)。改写既有会话用 `replaceEntries` 或暂存提交;HTTP 会话同步只走暂存提交,零动作。
173
+
174
+ 18. **契约包 settings-schema 15.0.0 提货(部署面,行为收紧;零数据面改动,回滚 = 回上一版)**:
175
+ ① **车道必需 env 的「缺」判法统一:未设、空串、只含空白一律按缺(所有车道、所有必需键同判)**。此前起服门只判真值,`SSH_HOST=" "` / `E2B_API_KEY=" "` 这类纯空白被当成写了、起服放行、到第一次用才失败;
176
+ 现在 `REMOTE_EXEC=<车道>` 点了名而该车道的任一必需键(`E2B_API_KEY` / `K8S_SANDBOX_IMAGE` / `K8S_NAMESPACE` / `SSH_HOST` / `SSH_USER` / `SSH_PRIVATE_KEY` / `ADB_SERIAL` / `DOCKER_IMAGE`)是这三形之一 ⇒ 起服拒,
177
+ 拒句点名缺的键并说 `unset, empty or whitespace-only — it counts as absent`(与契约包写闸对同一件事的拒句同一句话)。前后带空白但有内容的值原样放行(不 trim)。
178
+ **谁受伤**:必需键写成纯空白的部署(病态输入;典型是模板渲染留下的 `" "`、或只有换行的 secret 文件内容)—— 升级后起服拒;**出路**:填真值,或不点名该车道(`unset REMOTE_EXEC`)。
179
+ ② **compose 用户:`K8S_NAMESPACE` 随根 `docker-compose.yml` / `docker-compose.review.yml` 透传,空串透传 = 按缺**。车道表把 `K8S_NAMESPACE` 列进 k8s 车道的必需栏,两份根 compose 的必需键透传区跟着多一行 `K8S_NAMESPACE: ${K8S_NAMESPACE:-}`;
180
+ `REMOTE_EXEC=k8s` 的 compose 用户必须在宿主环境或 `.env` 里填它(此前 compose 只透传镜像,命名空间要在 override 里自己加;本版起标准透传)。原来没设的部署设成 `sandboxes` 即与升级前逐字同(第 11 条)。
181
+ 其它车道的 compose 用户零动作;随包 chart 与单文件栈清单本来就显式设了,零动作。`deploy/sema-up/lanes.json` 的 k8s 行 `env` 多一键 `K8S_NAMESPACE`(值恒 `null`;读这张表的 cli / web-admin 随表重算)。
182
+ ③ **单机形 `config.d/remote-exec.json` 的 k8s 臂 `namespace` 必填(`CONFIG_PROVIDER=local`)**:契约包读侧对缺它的文件抛,起服沿既有「文件存在而坏 ⇒ 响亮拒」(不静默退回 host),拒句点名 `namespace`。
183
+ **谁受伤**:文件里写了 `"provider":"k8s"` 而没写 `namespace` 的单机部署;**出路**:补 `"namespace": "<沙箱 pod 所在的命名空间>"`(此前靠内置缺省的写 `sandboxes` 即与升级前同)。
184
+ ④ **MCP 条目的 `sessionMetaKey` / `startupTimeoutMs` 从 `config.d/mcp.json` 与中心下发一路承运到引擎(行为面)**:此前这两把键在契约包读腿被剥掉并报 `unknown-keys-dropped`(没有效果),现在原样交给引擎。
185
+ 存量里已经写着它们的条目:合格的值自此生效(引擎在发给这台服务器的每个 `tools/call` 的 `_meta` 里放会话 id / 这台服务器的握手与首次工具列举各带这个启动界);
186
+ 不合格的:`sessionMetaKey` 坏形 ⇒ 这一条 server 整条不挂 + 一行 `web_admin_mcp_session_meta_key_invalid` 点名(兄弟照挂);`startupTimeoutMs` 坏值 ⇒ 引擎在拨号时只拒这一台、点名 `config.mcp_startup_timeout_invalid`(兄弟照挂)。
187
+ **出路**:删掉这把键,或改成引擎收的值(键名格式 / 整数毫秒的判官在引擎,本服务不另判)。
188
+ ⑤ **中心形部署:升级本服务前,中心里存量 workers 文档的 k8s 行先补 `K8S_NAMESPACE`(契约包的部署序:先补键、后升级)**。本服务不消费 workers 域,但拉取腿的契约读法会解析线上载荷里带的 workers 域(整域读不进即抛);
189
+ 中心给 worker 的 `/effective` 视图是否带这个域取决于中心,带的话缺命名空间的 k8s 行让拉取失败、本服务回落 LKG / env。**出路**:中心侧给每个 k8s 行补 `coords.K8S_NAMESPACE`(值 = 沙箱 pod 所在的命名空间)。
190
+ 嵌入方(类型面,加性):`CenterMcpServer` 多可选键 `startupTimeoutMs`(`unknown` 承载形);自建装配零动作。
191
+ 随 15.1.0 判官改 import,行为不变:① 里「空串 / 只含空白」的判法改调契约包根导出的 `isBlankCoordinate`,本仓只留「未设 = 缺」一臂;拒句、放行形、可选键同前,部署者零动作。
192
+
193
+ 19. **嵌入方(构造期 + 类型面,BREAKING;零别名):接了停驻赎回腿的会话店必须带执行席;自写赎回面工厂的入参 `root` → `rootOccupant`**:
194
+ 标准起服零动作 —— 接这条腿的部署(停驻底座在场)用的会话店一律带执行席。自建 `createHttpServer(deps)` 的嵌入方:
195
+ ① 交了 `parkedReviveSurface` 的,`sessionStorage` 必须带执行席 `executionPlacement`:用包根 `createStoreBackend()` 交出的会话店(`backend.session()`;缓存 / 分叉路由包装原样转发)。
196
+ 缺 ⇒ `createHttpServer` 构造期抛,拒句点名这一席。不接停驻赎回腿的,不交 `parkedReviveSurface`,会话店带不带席照旧。
197
+ ② 自写赎回面工厂(`ServiceDeps.parkedReviveSurface`)的第二参从 `{ principal, root?: { before, after } }` 改成 `{ principal, rootOccupant }`:`rootOccupant`(`{ owner, incarnation }`,恒在)
198
+ = 认领之后写口放行的那一位根住客。根住客换没换已由写口判过(换了 ⇒ 决定答 `409 decide.not_parked`,工厂不被调用),工厂只判属主是不是卡的 principal。读旧名 ⇒ tsc 红。
199
+ ③ 删一只有后台子代的根会话走服务端删除路径 `DELETE /v1/sessions/:id`(它先作废 / 停掉以该会话为根的子代,做完才删会话行)。直调会话店的 `deleteSession` 只删行、不结清子代:
200
+ 子代的待决卡仍挂着,同一个 id 再登记之后,对旧卡的决定会复活到新住客的会话上。
201
+
202
+ 20. **会话行条件写(wire 加性;行为变更两处;嵌入方类型面 BREAKING,零别名)**:
203
+ 列表行(`GET /v1/sessions` 每一行、`PATCH /v1/sessions/:id` 的 200 行)多键 `rowTag`(不透明串,只原样回传);`PATCH` 体可带 `expectedRowTag: <读到的 rowTag>` ——
204
+ 行仍是读到的那一份才写,否则 `409 conflict.session_row_changed`、一个字节不写,体 `currentRow` = 此刻的列表行(含新 `rowTag`)。不中一律 409:`currentRow` 的可写位已等于要写的值 ⇒ 视为已同步;
205
+ 否则按它重新决定,再带它的 `rowTag` 发,**不要原样重发**。键形不对 ⇒ `400 request.field_invalid`;只带它、没有 `title` / `pinned` ⇒ `400 request.body_shape`。
206
+ **行为变更**:① 只读镜像会话(从别处导入、写者在别处)上的 `PATCH` 由 200 变 `409 conflict.session_mirror`(体 `forkPath`,与执行面同码同体;带不带键都一样)—— 要在本处改名,先 fork;
207
+ ② 不带键的 `PATCH` 在处理中这只会话的属主被改(同一会话被认领 / 同步重戳)⇒ 404、不写(上一发布版照写)。
208
+ **自动重放的客户端**:带上 `expectedRowTag`;滚动升级窗里落到老副本 ⇒ `400 request.body_shape`(什么都没写)—— 待同步项留着稍后再发,不要去掉键重发。交互式「此刻改名」可以不带(仍是无条件写)。
209
+ **嵌入方**:会话店的行写口 `patchSessionMeta(id, patch, occupant)` 删除,换成 `writeSessionRowCells(id, cells, how)`:`how = { writer: "client", row: <core 行期望>, rowTag? }` 的结局是
210
+ `written`(带行)/ `changed`(带此刻的行)/ `mirror` / `absent`;`{ writer: "replay", row }`(会话同步的行重放)只有 `written` / `absent`。自实现会话店按新签名实现(判序:行期望 → 写者身份 → 标签 → 写,
211
+ 判与写同锁);列表行型 `SessionListItem` / `SessionSummary` 多可选键 `rowTag`。用包根 `createStoreBackend()` 造的三种会话店都已带。没有数据面改动、没有迁移;回滚到上一发布版即恢复无条件写。
212
+
213
+ 21. **配置源与留存扫车道的两条起服拒(行为收紧,fail-closed;零数据面改动;回滚 = 回上一版)**:
214
+ ① `CONFIG_PROVIDER=remote` 而没设 `SEMA_WEB_ADMIN_URL` ⇒ 起服拒,拒句点名两键与出路
215
+ (`CONFIG_PROVIDER=remote names the web-admin center as this worker's config source, but SEMA_WEB_ADMIN_URL is not set — …`)。上一发布版这一形照起:HTTP 服务不建配置源、按纯 env 跑,
216
+ `run-local` 读本地 `config.d`,两处都零句。**升级前自查**:写了 `CONFIG_PROVIDER=remote` 的部署(含按多租 profile 渲出来的)确认 `SEMA_WEB_ADMIN_URL` 在场 —— 要中心就补地址;
217
+ 本就靠 env / 本地 `config.d` 跑的,改成不设 `CONFIG_PROVIDER`(纯 env)或 `CONFIG_PROVIDER=local`。`run-local`(`sema` CLI)只装本地配置源:写了 `CONFIG_PROVIDER=remote`(配没配中心地址都一样)
218
+ ⇒ 一行拒句、退 2;共享 `.env` 里带这个词的,给 CLI 去掉它或写 `local`(没写词时 CLI 自己写 `local`)。
219
+ ② 被要的留存扫车道必须齐:`RETENTION_MODE=enforce` 或 `RETENTION_SWEEP_INTERVAL_SEC > 0` 都是在要车道,要了就得有 `RETENTION_MAX_AGE_DAYS` 且节律 `> 0`;缺一 ⇒ 起服拒,拒句点名缺的键与出路。
220
+ 上一发布版:enforce 而节律缺 / 为 0 照起、什么都不删、`capabilities.retention` 为 `null`(给了天数的只有一行 warn —— 7.138.0 节第 13 条「关着、配了没锁的策略」那一形,enforce 档下改为拒);
221
+ 节律在而天数缺在装配第 6 段(一次性迁移之后)拒,本版在第 1 段拒、拒句换成本条的句子,拒的那一次起服不碰库。**升级前自查**:写了 `RETENTION_MODE=enforce` 的部署确认天数与 `> 0` 的节律都在
222
+ (车道跑在 SQL 后端上);本就不删的改 `RETENTION_MODE=audit-only` 或不设(节律 `> 0` 而没给天数的,同时把节律设 0)。`audit-only` 下给了天数而车道关着照起,warn `retention_policy_not_executed` 多两个字段 `mode` / `retentionSweepIntervalSec`,
223
+ 说明句只说「节律缺或为 0」这个真因 —— 按旧说明句匹配告警的改读字段。
224
+ 运营目录 `GET /v1/config/catalog` 的 `CONFIG_PROVIDER` / `RETENTION_MODE` / `RETENTION_SWEEP_INTERVAL_SEC` 三行 `semantics` 写出这两条拒启条件。
225
+
226
+ 22. **会话规则 / 持久规则桶的文法戳 7(升级序:先升全部读者,再放写;回滚前见下)**:本版写下的会话规则行、SQL 后端 `permission_rule` 的规则桶与规则同步状态都盖文法戳 `7`
227
+ (零 DDL:`grammar` 列早已在)。意思动在拒绝 / 询问桶里身上带 `__` 的 MCP 名:`mcp__a__b` 同时拒 server `a` 的工具 `b` 与 server `a__b` 的每一只工具(限制只会变宽,放行不变;
228
+ 放行表里的条目:本轮工具名单里没有这只精确名、却有另一种 server 拼法下的工具时,按引擎的句子点名、不放任何一只 —— 写成铸出的拼法 `mcp__a_b__<工具>`;名单里有这只精确名的工具则照放这一只)。戳 6 及更早的**会话规则行**保留写者的意思(精确名只拒那一只工具),
229
+ 每层通告一次 `config.session_rules_earlier_grammar`;**持久规则桶**不留旧读法:戳 6 的桶里的整工具 `mcp__a__b` 按文法 7 读(更宽)。7.138.x 及更早的副本读不了戳 7 的行 / 桶 ——
230
+ 整只拒,不按旧文法逐条读(会话行:那条会话每一次调用都拒;规则桶:载零条、拒每一次写,报 `permission_rules.later_grammar`;规则同步:整轮拒)。本版本就要求先停光旧副本再起(SQL 执行放置切换),
231
+ 所以混跑窗口不出现;回滚到 7.138.x 只有恢复备份一条路(第 14 条),**不要**在库里把戳改小。
232
+
233
+ 23. **执行环境的写入改成「暂存 → 一次提交」(行为面;七条车道一条规则;零配置)**:`writeFile` 是整文件替换 —— 整旧或整新,取消 ⇒ 目标未碰;
234
+ host 车道委托引擎的整文件替换,ssh / adb / local-docker / k8s / e2b 先在目标目录下建一只生来 0700 的私有目录 `.<名>.stage-<12 位十六进制>/`、
235
+ 把整份传进去,再在目标机上一次 `mv -f`;`appendFile` 只暂存要加的字节、提交是一次 `cat >>`(inode 不换)。
236
+ **暂存自创建起不比目标更可读**:替换一只 0600 的文件时,新内容在传输期间只有写入方(与 root)读得到(私有目录别的用户进不去;
237
+ 本机侧 adb 推送前落的临时件同样在私有目录里);host 车道的这一保证在引擎原语里:引擎 7.60.0 起目标存在时暂存件以 0600 打开。
238
+ 准备目录、上传、提交、清理是同一个身份:**local-docker 的上传改由容器内以镜像的用户经 stdin 收字节**,不再由守护进程的 `docker cp` 以 root 落盘
239
+ —— 镜像用户 ≠ root 时,写文件与代理的 shell 同一套权限:镜像用户写不了的路径照实拒 `permission_denied`(7.138.x 的 `docker cp` 以 root 写得进)。
240
+ 部署零动作;以下几处语义变了,依赖它们的先核:
241
+ ① **硬链接被断开**:替换之后另一条硬链接留旧内容(与引擎 / 参照实现同形);
242
+ ② **没有写权限位的文件在可写目录里会被替换**(权限位保留;修前就地写被拒 `permission_denied`)—— 防代理改文件靠写门 / 写保护规则,不靠权限位;
243
+ ③ 替换后的文件**属于写入方**(属主不随原件);
244
+ ④ **host 车道上名字超过约 230 字节(随服务进程号的位数浮动)的文件写不进**(引擎的暂存名超出 255 字节上限 ⇒ `unknown` / `ENAMETOOLONG`;远端五车道不受影响)—— 已知缺口,修在引擎;
245
+ ⑤ 目标目录里可能见到一只没清掉的隐藏目录 `.<名>.stage-…/`,可以直接删:一是中断之后清理那一次往返也失败(失败的写的错误句会点名它);二是写已经成功、
246
+ 却因文件系统为仍打开着的文件留了隐藏项(NFS 的 `.nfsXXXX`、FUSE 的 `.fuse_hidden*`、SMB 的待删)而删不掉目录 —— 写照常成功,只在服务的遥测里记一条
247
+ `server.remote-write.staging-dir-left`(不进错误句);
248
+ ⑥ 远端车道的写多一次往返(提交;e2b 多两次:建私有目录 + 提交);
249
+ ⑦ local-docker:镜像用户 ≠ root 的部署,代理以前靠 `docker cp` 的 root 身份写得进、镜像用户自己写不了的路径(例如 root 的目录里不归镜像用户写的文件)
250
+ 现在答 `permission_denied` —— 要写那些路径,让镜像用户有权限(或镜像就以 root 跑);local-docker 新建的文件属镜像用户、权限位按容器内的 umask(以前属 root)。
251
+ **最常见的一处是工作区根本身**:镜像里没有这只目录时,容器启动(`docker run -w <工作区>`)以 root 建出它(root 所有、0755)——
252
+ 镜像用户 ≠ root 的部署,写工作区里的文件从本版起答 `permission_denied`(代理的 shell 在 7.138.x 就写不进那里,只有写文件经 `docker cp` 写得进)。
253
+ **升级前做**:镜像里预建工作区目录并归镜像用户(例如 `RUN mkdir /workspace && chown <镜像用户> /workspace`;已有的目录启动时不改属主),或让镜像以 root 跑。
254
+ ⑧ **私有暂存目录收不成私有时退回就地写,不再静默暂存**:准备那一步把刚建的目录收成 0700 并读回核实(模式、属主);核不过 —— `chmod` 被拒、文件系统不认权限位、
255
+ 父目录的缺省 ACL 掩码收不下来、目标机上没有 `stat` —— 这一次写**不暂存**,退回就地写目标(与「目录不收新名字」同一条退路:非原子;取消落在写目标那一步开始之前(读旧也在这之前)⇒ `aborted`、目标未碰;写目标那一步因取消中断 ⇒ `unknown`、目标可能只写了一半(那一步自己的通道准备也算在内,保守);那一步不收取消(ssh 的 sftp)⇒ 照样写完、答成功;
256
+ ssh / local-docker / k8s 写进原 inode、权限位不变,e2b 的 `files.write` 与 adb 的 `adb push` 整份写目标、inode / 权限位由对端定),并在遥测里记 `server.remote-write.stage-seal-fallback`(计数非零 = 这个目录上的写都在走非原子退路,去看那个目录)。
257
+ **adb 两面在私有目录收不成私有时退回 7.138.x 的形**(写 = 整份 push 到目标;追加 = 读旧 + 拼 + 整份 push;非原子,中途断目标可能没了或只剩半份;`adb push` 不保 inode / 权限位,与 7.138.x 同形)
258
+ 并计 `stage-seal-fallback`。Android 共享存储(`/sdcard` 一类:权限位由挂载派生、不认 `chmod`)上 adb 的写按 sdcardfs / MediaProvider FUSE 的权限语义**推断**每一次都走这一形(未上真机,真机读数候 test)—— 把 adb 的工作区放在 `/data/local/tmp` 一类认权限位的目录即照常暂存。
259
+ 以前这一步的失败被吞掉、字节照样放进一只没核成私有的目录。
260
+ 已知缺口:目标机是 macOS、且工作区父目录带继承的**原生 ACL 允许条目**时,模式位挡不住那个条目(读回 `700` 也一样);FreeBSD / illumos ZFS 的 NFSv4 ACL(`aclmode=passthrough`)同类 ——
261
+ 这类目录上暂存件对那个条目可见,替换之后目标带的是继承来的条目、不是原件自己的 ACL(比 7.138.x 的就地直写宽:就地写不换 inode,原件的 ACL 不变);本版不另造探测臂。
262
+ 回滚到 7.138.x:零数据面动作(暂存名是瞬时的)。
263
+
264
+ 24. **本机宿主车道(`REMOTE_EXEC=host`)上 workflow 子代的 `isolation: "worktree"`(已知变化;行为面)**:本版的引擎(7.60.0)在这条车道上按宿主读,worktree 子代按物理路径比对、「它自己的目录」即收;
265
+ 上一发布版这条车道上这一形一律拒(`isolation.unavailable`)。本版的读法:
266
+ ① **配了包装**(`WORKTREE_ISOLATION_ENABLED=true` 且 `WORKTREE_REPO_ROOT` 指向一个 git 仓):包装铸的 worktree 被收,workflow 子代 `agent(spec, { isolation: "worktree" })` 照跑
267
+ (读已提交副本、调用方检出零写)—— 上一发布版这一形仍拒;
268
+ ② **没配包装**(或仓根不存在 / 里面没有 `.git`、包装被起服关掉 —— 起服日志 `worktree_isolation_disabled_bad_repo_root`;`.git` 在而仓坏的,包装照开、铸树时 git 自己报错):本服务的 host 工厂在铸环境之前拒,码 `isolation.unavailable`,句子点名两只开关,子代零轮 ——
269
+ **与上一发布版同码同句形**。不拒的话引擎的新读法会收下一只本服务新铸的空临时目录:子代读不到项目里任何文件,照烧 token,结果照交回。要在这条车道上用 workflow 的 worktree 隔离,配包装;
270
+ ③ 引擎 7.61.0 起这一形由引擎自己拒,本服务的这一臂到那一版随提货删,届时码与句子随引擎。
271
+ 委派工具形(`Agent({ isolation: "worktree" })` / `agents[].isolation`)不受这一拒影响:worktree 由引擎自己铸,子代的根经 `parentCwd` 交给工厂,工厂收不到 `isolation` 提示。部署零动作。
272
+
273
+ ## 7.138.0 —— MCP / A2A 的凭据件改由部署的对端座在发送时作答(行为面;件的形更严;嵌入方 `ServiceCoreDeps.peerDesk` 必填,BREAKING)· 🔴 SQL 后端 `session_meta` 加 `workspace` 列、`mailbox_message` 加 `record_id` 列(升级前先加列)· 请求 `projectId` 与检出记号不等 ⇒ 409 · 记忆同步:升级前写的旧游标 ⇒ 该层停同步直到运维一步(两条出路)· settings hook 子环境维持十二名边界 · 抹除授权集与收执 v2 · 已知缺口:会话级子代在父腿作用域结束后首拨 / 再问被座拒 · 引擎 7.59.0
274
+
275
+ 1. **SQL 后端:`mailbox_message` 表加一列 `decision`(🔴 升级前先加列;持久数据,不能删表重建;引擎 7.57.0 的邮箱留置决定)**:
276
+ 收件人设置把一条消息留置(held)之后,对它的决定(放行 / 拒绝 / 过期 / 已投递……)从本版起是这条记录自己的字段,每个读这只箱的进程读同一个决定;
277
+ 本服务不发 `ALTER`:存量库缺这一列 ⇒ 起服列册对账拒启(`config.schema_mismatch`),拒句带可直接粘贴执行的语句。
278
+ **升级前做**(MySQL 协议):`ALTER TABLE mailbox_message ADD COLUMN decision VARCHAR(16) NULL;`
279
+ (PostgreSQL)`ALTER TABLE mailbox_message ADD COLUMN decision VARCHAR(16) COLLATE "C";`
280
+ 存量行这一列是 NULL = 从未留置,零回填。**顺序**:先升库(加列)、再升副本 —— 加完列之后,仍是 7.137.x 的副本**再启动**会把 `decision` 读成幽灵列而拒启
281
+ (`config.schema_mismatch`,拒句点名 `UNKNOWN column(s) decision`、不给 ALTER;列册对账缺列多列两个方向都拒)—— 只挡重启:已在跑的旧副本写消息时带列名清单、不写这一列。
282
+ 滚动窗里仍在跑的 7.137.x 副本不读这一列,会照旧投递别的副本已留置或已拒绝的记录 —— 不想要这个窗就先停光旧副本再起本版。**回滚**:先停光本版副本,`ALTER TABLE mailbox_message DROP COLUMN decision;`(两方言同一句),再起 7.137.x;丢掉的是留置决定(还在箱里的留置记录回到「从未决定」,下一次读箱重新判)。
283
+ `DB_BACKEND=local` 与内存后端零动作(引擎自带的文件箱)。**嵌入方**经 `RunnerDeps.principalInboxConsumer` 声明 `"terminals"`(这个 scope 的终端会话在自己的箱旁边一起读 principal 收件箱)之前,
284
+ 先把每一个读这只箱的副本 / 终端都升到本版 —— 更早的引擎读不到决定、可能投递已被拒的信。运维旋钮 `PRINCIPAL_INBOX_ASSISTANT` 只声明 `{ assistant }` 一形,不变。
285
+
286
+ 2. **引擎 7.57.0 的部署序:先升读者与续跑者,再升写者与停驻者(两处)**:
287
+ ① **停驻的 shell 审批行多一个成员 `targetReads`**(停驻时 shell 读站判出的读落点;续跑时读落到别处 ⇒ 这次调用被否决 `resume.target_moved`,模型重发会拿到新卡):
288
+ 7.137.x 及更早的副本遇到这种行拒 `version_newer`、行留 pending(不会不绑定地重放)—— 混跑的舰队里 shell 停驻行要等升过的副本来接。SQL 店把 `pendingAction` 整只存成 JSON,零迁移。
289
+ ② **会话规则 / 持久规则桶的文法戳 6**(裸工具名 `Tool` / `Tool()` / `Tool(*)` 成为整工具规则):7.137.x 及更早的引擎读不了戳 6 的桶 / 行 —— 整只拒,那位的规则读成「读不出」、
290
+ 按 fail-closed 多问 / 多拒,不会少问,直到升级。回滚前确认没有写过戳 6 的行,或接受回滚窗内这种 fail-closed。
291
+
292
+ 3. **本机宿主车道(`REMOTE_EXEC=host`)上,选中本服务或其上层进程的模式杀被 Bash 工具拒(行为变更;安全收紧)**:
293
+ `pkill -f <词>`(词出现在本服务或其祖先的命令行里)、`killall <名>`、`kill $(pgrep …)` 这类按模式选进程的命令,本版起在这条车道上照本进程的进程表问一遍,选中本服务自己或其上层进程 ⇒ 不跑、
294
+ 工具结果是带句子的错误(此前在这条车道上不问,会结束发起它的会话)。`pkill -P $$`(只杀本 shell 的子进程)与按字面 pid 杀照常。容器 / k8s / e2b / ssh / 设备 / adb 车道不变(命令跑在别的进程表,不问)。
295
+ ssh 车道的目标恰是本机(或本服务所在容器的宿主)的部署,这一问今天不覆盖 —— 那种车道不要拿 `pkill -f` 清理与本服务同名的进程。
296
+
297
+ 4. **未起名的后台子代停驻的审批可决(行为变更;wire 句子退出)**:Agent 调用省略可选 `name` 的后台子代停驻之后,`POST /v1/approvals/:sessionId/decide` 的 approve 照常复活它、动作执行,
298
+ deny 照常复活它、子代收到拒绝(此前 approve 答 `409 decide.row_unrevivable` 的「parked row carries no agent name …」、deny 作废这张卡)。这句拒退出 wire;
299
+ `409 decide.row_unrevivable` 只剩「行上没有根会话锚」一句(出路照旧:deny 作废)。升级前停驻的无名行同样可决(读作引擎派生名 `agent-<12 位十六进制>`)。
300
+ 名册 `GET /v1/agents/roster` 的行从本版起恒带 `name`(未起名的子代是派生名,此前键缺席),未起名的行另带 `anonymous: true`(`name` 就是引擎派生名时在场,起过名的行缺席这一键;调用方恰好起了与派生名同一个串的,引擎读不出区别,同样在场)—— 据此区分「起的名 / 派生名」,不必自算派生式。
301
+ **滚动窗的反方向 —— 决卡面先升**:本版写下的未起名子代行带着派生名;仍是 7.137.x 的副本决这样一张停驻卡,会把它复活成一只**具名**子代(名字就是那个派生名,
302
+ 以具名子代的身份出现),本版副本决同一张卡,复活的子代仍是匿名的。要避开:先把接 `POST /v1/approvals/:sessionId/decide` 的副本全部升到本版,再让本版副本接会停驻后台子代的任务;
303
+ 或接受滚动窗里少数复活的子代带着派生名。
304
+
305
+ 5. **文件历史导入:来源给出的字节对不上它的地址 ⇒ `adopt_failed`(wire 码变更)**:会话同步重放把店的答原样上 wire;这一臂此前答 `422 unsupported_format`,本版起 `422 adopt_failed`
306
+ (`unsupported_format` 只留给导入门对信封本身的拒)。来源读抛的那一臂多带判得出的 `permanence`。按 `unsupported_format` 判「信封坏、别重试」的调用方零改;按码分支重试的,把这一臂当作来源问题。
307
+
308
+ 6. **无规则文法的工具的审批卡给「这只工具不再问」(行为变更;wire 值加性)**:本服务自带的宿主工具(`Now` / `SendUserFile` / `SelectEnvironment` / `repo_*` 等)与 MCP 工具的问卡,
309
+ `ruleOffers` 多一只整工具候选 `{ kind: "single", rule: "<工具名>", match: "tool", command: "" }`,选中即落一条整工具规则(这只工具的每一次调用)。壳按 `match: "tool"` 渲染「不再询问这只工具」;
310
+ 不认得 `tool` 这个匹配词的壳不渲这一只即可(读者对集外词丢该候选)。卡的编辑面不铸整工具规则。
311
+
312
+ 7. **嵌入方(类型面,BREAKING;引擎 7.57.0)**:手写 `CheckpointStore` 必须实现 `reopen`(缺它的店在店席被拒),删掉 `redecision`;根导出 `checkpointStoreExecutionUndeclared` 改名 `checkpointStoreIncomplete`
313
+ (全齐答 `undefined`);手写 `BackgroundAgentStore` 的记录 / 摘要 `name` 必填(旧行读作 `row.name ?? engineAgentName(row.handle)`);手写 `MailboxStore` 必须实现 `moveDecision`;
314
+ 手写远端执行适配器的 `capabilities` 必须声明 `sharesProcessTable`(命令跑在本进程的进程表上 ⇒ `true`)。只读这些型的代码零动作。
315
+
316
+ 8. **回决门族的 200 体多两个可选键 `decisionCommitted` / `checkpointId`(wire additive;另收紧一处停驻子代的竞态)**:`POST /v1/approvals/:id/decide`(受理 / 终局 / 幂等回放 /
317
+ 停驻子代复活成功 / 复活不了的停驻子代被 deny 作废)、`POST /v1/assistant/tasks/:id/resume`、`POST /v1/assistant/tasks/:id/plan_review` 的 200 体,在「这道门已以
318
+ 这次决定结清过」能被证明时带 `decisionCommitted: true`,并带执行之前选中那一行的门身份 `checkpointId`(与运维队列 / 收件行 / park 账本行同名同值;读不出就缺席)。
319
+ `POST /v1/sessions/:id/wake` 与 `/decide` 交给宿主的回执(workflow 子代的审批)不带。**读法**:「已提交」只读 `decisionCommitted === true`,缺席按「没提交」读;
320
+ 它与 `errorCode:"cancelled"`、`retriable:true` 并存时照样成立,不说明卡的当前状态;`retriable:true` 只说「这一跑已重新停驻,请重读待决列表」。
321
+ 经 `POST /v1/tool-approvals/:id/respond` 迟到兑现的停驻卡:同向重试的回放带两键,反向重试的回放(回放首次那一向)不带。
322
+ **同一张卡同向的并发 / 重发请求**:拿到 200 回放体(`idempotent: true`)的,是受理者之后到、而回执(或在飞的赎回)还在的那些 —— 迟到兑现的卡上回执只在受理它的那一副本上、有界(换副本 / 重启 / 被逐 / 过期之后再来的是新一次赎回,答 `409`,终局不变、不会双兑);
323
+ `POST /v1/approvals/:id/decide` 上,首决已落行之后到的同向重发答回放体,与首决真正重叠的输家答 `409`(`conflict.not_resumable` 或 `checkpoint.already_resolved`)。拿到回放体时:迟到兑现的卡上它带着受理体的成员(`status: "resuming"`、`taskId`、两键),
324
+ 所以分清受理者**只看 `idempotent` 是否在场**(缺席 = 受理者),别拿 `status` / `taskId` 数「起了几跑」(回放不起续跑);`/decide` 的幂等回放体则不带 `taskId` / `status` / `checkpointId`(带 `decisionCommitted: true`),要结果面读 `GET /v1/runs/:id`。
325
+ **竞态收紧**:决一张后台子代的停驻卡时,若这只子代在你决断的同一刻被别处续过、又在新的卡上停驻,本版答 `409 decide.gate_moved`(此前把决定交给了那张新卡)
326
+ —— 重拉待决列表、对新卡再决。
327
+ **升级前做**:用封闭 schema 校验这些 200 体的调用方(多余键即拒)把两键加进可选键;其余零动作。**升级后看**:选中那一行的门身份读不出时,既有计数
328
+ `server.approvals.durable-row-checkpoint-id-missing` 多一种 detail `face=decision-receipt`(老行 / 坏行在被决断;体照常,只是不带身份)。
329
+
330
+ 9. **令牌声明 `sub_inc`(化身号)在场而畸形 ⇒ 整张中心登录令牌验证不过(行为面;契约包 settings-schema 14.7.0 的令牌判官新读这个声明)**:
331
+ 此前令牌里的 `sub_inc` 被忽略;现在它**在场**时必须是非空字符串 —— 数字(含 0)/ 空串 / `null` / 布尔 / 对象 / 数组 ⇒ 这张令牌按 `malformed` 拒(401 通用体不变;
332
+ 计数 `auth_bridge_verify_total{outcome="malformed"}` 加一、一行 `auth_bridge_rejected{error:"malformed"}`;`malformed` 是这条验证腿既有的通用拒因,不专指 `sub_inc`),与 `sub` / `iat` 畸形同律(声明形是垃圾不降级成「缺席」)。
333
+ 合形的(非空串)随验证出的身份带出 `principalInc` 原样,本版**没有读者**;不带 `sub_inc` 的令牌读数与升级前逐字相同。
334
+ **升级前做**:零动作 —— 已知没有铸畸形 `sub_inc` 的签发方,存量令牌不带该声明。**顺序**:签发方(web-admin)开始铸 `sub_inc` 的时点与本服务升级先后无关:旧版忽略该声明,本版对合形的原样带出、对畸形的拒。
335
+ **升级后看**:上面的 `malformed` 计数与拒行只在签发方铸了畸形 `sub_inc` 时因它增长(其它畸形令牌也走这一因,要确认是不是 `sub_inc`,看签发方铸出的令牌声明);**补偿**:签发方把 `sub_inc` 改成非空串或不铸。**回滚**:回到上一版即回到「忽略该声明」。
336
+
337
+ 10. **`POST /v1/runs/:id/steer` 不带 `Idempotency-Key` 的停放腿:条目的 `inputId` 变成 202 回执上的 `messageId`(wire 值变更;键集 / 状态码 / 回执体逐字不变)**:
338
+ `202 delivery:"queued"`(run 停在检查点上)与 `202 delivery:"parked_for_wake"`(终态 run 铸唤醒卡)两条停放腿,不带 key 时,条目上的 `inputId` 此前是引擎在把条目写进停放队列时自铸的 uuidv7,
339
+ 续跑(或 wake)首轮引擎铸的 `human_input{delivery:"applied"}` 帧带的就是那一个(部署的 `userPromptSubmit` 屏拦下它时,`human_input{delivery:"blocked"}` 帧与 `steering.parked_input_blocked` 通告带的也是它)—— 与回执上的 `messageId` 不是同一个值,按回执找不到那些帧。本版起停放两腿与 live 腿(`200 applied`,早已如此)同形:
340
+ **回执 `messageId` ≡ 引擎收到的 `inputId`**,不带 key 时是本服务对每个请求现铸的 uuidv7,带 key 时是由 key 派生的确定性值(带 key 的形不变)。
341
+ **谁需要**:按回执 `messageId` 去对 `human_input{delivery:"applied"}` 帧(或被拦时的 `blocked` 帧 / `steering.parked_input_blocked` 通告)的消费方(壳 / cli / sdk 的回执账);**谁受伤**:无 —— 每请求现铸的值互不相同,不会撞引擎的 `inputId` 去重,停放队列的容量与顺序不变;**补偿**:不适用。
342
+ **升级前做**:零动作。**升级后看**:升级前已停放、升级后才续跑的条目带的仍是引擎当时自铸的值(不改写),那一批的回执对不上 applied 帧 —— 按「消费与否关账时再定」读。**回滚**:回到上一版即回到引擎自铸值。
343
+
344
+ 11. **部署座可装运维声明的 mod 包:新旋钮 `MODS_ROOT` / `MODS_PACKAGES`(没声明的部署零动作;起服拒句换形)**:部署座(每一只 Runner 共用的那一份扩展注册)在本服务自铸的注册之后,
345
+ 装 `MODS_PACKAGES` 声明的包(JSON 数组,每项 `{ name, dir, tier, options? }`;`dir` 的真实路径须严格在 `MODS_ROOT` 的真实路径之下 —— 根本身不算,`tier` 宿主必填)。包里的文件只有引擎的读包者读;
346
+ 起服整张声明先判完、再逐只装、再整列交引擎准入,任一失败即拒启,拒句一行 `deployment mods refused: <词>(<主语>)[: <细节>]`(词表与读法见契约 §0.9)。
347
+ **不声明的部署**:零动作 —— 部署座与此前同三张,`/health` 与 `/v1/capabilities` 逐字节不变(配置目录多这两根旋钮的两行)。开了 leader 的部署:leader 车道派出的腿(路由 / worker / 修复)
348
+ 此后也挂部署座 —— 拒绝计量计入这些腿上的拒绝(拒绝计数的看板会多出 leader 腿的那一份);`TOOL_TRACE=true` 时它们的工具调用也写追踪行、系统提示多出引擎的钩子段
349
+ (与主车道同配置的腿同读;此前这条车道漏挂)。
350
+ **要装包的部署**:① 把包放进只读物料树(镜像层 / 只读挂载),`MODS_ROOT` 指它;② 包是**受信的部署代码**,在本进程里跑、可触全部租户与进程凭据 —— 多租户部署上声明的包对全体租户生效,
351
+ 准入不是沙箱,只装你审过的包;包若在 `PreToolUse` 上答 `allow`(可带 `updatedInput`),引擎仍按最终参数裁决,运维旋钮要问或要拒的(`APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` / `MANUAL_MODE_SHELL_GATE=always` / `governance.commandPolicy` 的问档与拒档等)与引擎强制的问句不因它改变,但**未被强制的**缺省审批问句它能清掉 —— 装包就是把这一类问句的决定权交给包作者;要某类调用无论包怎么答都问人,用这些旋钮声明;③ 包按「自包含」构建(执行代码全在 `hooks/register.mjs`,不另 import 包内文件、不读运行时资源),`register` 确定、可重复、不留进程副作用(引擎在每条腿再调它);
352
+ ④ 改声明或换包要重启(配置刷新不重载,也没有自动重启信号);滚动升级期间新旧副本可以并存 —— 声明只在设了它的新副本上生效,停驻的任务在哪只副本续跑就按那只副本当下的部署座再准入。
353
+ **升级后看**:起服日志每包一行 `mods_package_loaded { name, tier, contract, digest }`(`digest` 是引擎读包者读的三件文件的字节摘要,认得出装的是哪几份字节,不是代码完整性凭据);`/health.mods.deploymentPackages` 与能力位 `modsDeploymentPackages`;每条腿 `wiring_manifest.mods[]` 有那只包一行(`seat: "deployment"`、`provenance: "operator"`;本服务自铸的注册那几行带 `provenance: "server"`)。
354
+ **起服拒句换形(运维面,非 wire)**:部署座准入被拒此前是 `deployment extension registration refused: <引擎句>`,现在是 `deployment mods refused: admission_refused[(<引擎码>)]: <引擎句>` ——
355
+ 按旧句匹配起服失败的告警改读新前缀。回滚:删掉两根旋钮(或回到上一版)即回到只有自铸注册的部署座。
356
+
357
+ 12. **`tool_start` / `tool_end` 与审批开卡帧多可选键 `requestedBy` / `answeredBy`(wire additive;零动作)**:扩展经 `$.tool.call` 自己发起的调用,`tool_start` / `tool_end` 与开卡帧
358
+ (旧族 `tool_approval`、呈卡族 `approval_request` 顶层)带 `requestedBy: { kind: "extension", name }`;扩展在 `tool.call` 站上代替工具体作答的调用,`tool_end` 带 `answeredBy: <注册名>`(旁边恒有 `notExecuted: true`)。
359
+ 只在部署座装了能这样做的包时出现;其余帧逐字节不变。按闭集读帧键的消费方:未知键忽略(开集律),要渲染归因的读这两位(契约 §4.0b)。
360
+
361
+ 13. **SQL 后端:三只会话 / 检查点 / 工具结果店的留存声明随扫车道走(扫车道关着的部署不再被引擎拒启;锁着留存策略的那一形拒句换形)**:引擎这一版起,店说自己的行由托管留存按期删(`managed`)而部署不跑执行器 ⇒ 起服拒(锁不锁都拒)。
362
+ 本服务据此把声明改成部署的事实:`RETENTION_SWEEP_INTERVAL_SEC > 0`(扫车道开)⇒ 三只 SQL 店声明 `managed`、执行器交给引擎;关着(缺省)⇒ 声明 `none`、执行器 `null`。
363
+ **扫车道开着的部署**:零动作。**关着、没配留存策略的部署**:零动作(此前也不删;不升级到这一版的同一套店在新引擎上会被拒启,本版正是为此)。
364
+ **关着、配了没锁的策略**:照起;起服 warn `retention_policy_not_executed` 的说明句换成点名扫车道关着。**关着、策略被锁**:照旧拒启,拒句换成引擎的 `config.retention_capability` 句(此前是本服务的「WIRES NO RETENTION EXECUTOR」句)——
365
+ 按旧句匹配告警的改读码;要能起服就开扫车道或解锁 / 删策略。**回滚**:回到上一版即回到旧声明(店恒声明 `managed`)。
366
+
367
+ 14. **wire 加性四处(零动作)**:每条腿 `wiring_manifest.mods[]` 每行多 `provenance`(本服务自铸的注册 `"server"`,每个部署至少拒绝计量那一行;运维声明的包 `"operator"` —— 出处词与同一行上 `seat` 的座词 `deployment` / `task` 不共用词)· `tool_end` 多可选 `rewrite: { by, input }`(门放行时交给工具体的参数被改过才在场;
368
+ `input` 是放行的那份参数、与 `tool_start.args` 同一只脱敏,`by` 每项是 `{ kind: "extension", name }` / `{ kind: "policy" }` / `{ kind: "approver" }`)· 请求面 MCP 条目受理 `sessionMetaKey`(声明了它的服务器在每次 `tools/call` 的 `_meta` 下收这条腿的会话 id;
369
+ 写坏 ⇒ `400 request.field_invalid`)· 名册 `GET /v1/agents/roster` 行的可选键 `anonymous`(`name` 是引擎派生名才在场,恒为 `true`)。按闭集读键的消费方:未知键忽略(开集律)。部署侧在中心 / `config.d` 写的 `sessionMetaKey`,在契约包补这把键之前于读配置那一道被剥(带未知键告警)。
370
+
371
+ 15. **`workspace_changed` 帧的节律随引擎变了(成员不变)**:引擎在每条腿准备好之后、第一次模型 / 工具交互之前先发一帧,其后每变一帧 —— 同一个 `cwd` 可能连着来两帧。本服务只投 `cwd`(与上一版同形)。
372
+ 把每一帧都当作「目录搬了」来渲染的消费方:按帧替换本地副本,只在 `cwd` 与持有值不同时渲染搬迁。
373
+
374
+ 16. **SQL 后端:`session_meta` 表加一列 `workspace`(🔴 升级前先加列;持久数据,不能删表重建;会话的位置与项目)**:
375
+ 这一格存这只会话上一条腿自己的最后一帧 `workspace_changed`(`cwd` / `root` / `entered` / `project` / `remote`),下一条不带 `projectId` 的提交把它的 `project.id` 声明给引擎 —— 只当那是调用方声明过的项目(`project.source` 为 `declared`;见下一条)。
376
+ 持流的腿(同步 / 活流 / 后台 / 续跑)记;只回结果的腿(`verify` / `cascade`)不记(引擎在组合入口里自己排空内层腿的流,宿主看不到这一帧)。
377
+ 本服务不发 `ALTER`:存量库缺这一列 ⇒ 起服列册对账拒启(`config.schema_mismatch`),拒句带可直接粘贴执行的语句。
378
+ **升级前做**(MySQL 协议):`ALTER TABLE session_meta ADD COLUMN workspace JSON NULL;`
379
+ (PostgreSQL)`ALTER TABLE session_meta ADD COLUMN workspace JSONB;`
380
+ 存量行这一列是 NULL = 没有记录,零回填(下一条腿记下)。**顺序**:先升库(加列)、再升副本 —— 加完列之后仍是 7.137.x 的副本**再启动**会把 `workspace` 读成幽灵列而拒启
381
+ (只挡重启:已在跑的旧副本建行时带列名清单、不写这一列)。滚动窗里旧副本上跑的腿不记这一格(下一条提交读到的是更早一条腿的记录,或没有记录)。
382
+ **回滚**:先停光升级后的副本,`ALTER TABLE session_meta DROP COLUMN workspace;`(两方言同一句),再起 7.137.x;丢掉的是各会话记下的位置与项目(没有记号的检出里,会话不再续声明它的项目)。
383
+ `DB_BACKEND=local` 零动作(数据根里多一只 `session-workspaces.json`,随会话删除一起删);内存会话店不记(没有行可读,只交提交带的 `projectId`)。
384
+
385
+ 17. **请求 `projectId` 交给引擎:与检出的 `.sema/project` 记号不等 ⇒ 开跑前拒,同步 409(行为面收窄;BREAKING)**:
386
+ 7.137.x 及更早,提交体的 `projectId` 只挑记忆分区(`proj:<租户>/<projectId>`)与项目登记簿的默认读层,引擎从不知道它。升级后它同时是这条腿交给引擎的项目声明:
387
+ 每条腿声明 = 这次提交带的 `projectId`(续跑重放存下的同一个体)?? 这只会话上一条腿声明过的项目(上一条;引擎从记号判出的项目不续声明);都没有不声明。引擎每条腿判一次 ——
388
+ 检出带记号 ⇒ 声明必须等于记号,否则 `config.project_identity_mismatch`(**409**,零工作、不计费);检出没有记号 ⇒ 声明就是身份;声明了而记号读不出 ⇒ `config.memory_project_marker` /
389
+ `config.memory_project_marker_nested`(**409**)。异步 / 活流腿 HTTP 2xx,同码落在终态 run 行。
390
+ **谁撞上**:① 提交带的 `projectId` 与它跑的检出里的记号不是同一个项目;② 同一只会话在没有记号的检出里声明过项目,之后换到带另一个记号的检出、不带 `projectId` 续跑(声明过的项目被续声明);
391
+ ③ 声明了项目(提交带的或会话声明过的)而检出的记号坏了 / 嵌在仓根之下。不带 `projectId` 的部署零变化(检出带不带记号都一样:记号判出的项目不续声明,记号改写 / 换检出之后续跑照跑)。
392
+ **出路**:声明记号里的那个 id(提交带它就胜过会话声明过的)、改或修记号,或换一只会话(新会话没有记录)。记忆分区、登记簿默认读层与单用户记忆的项目层(按 git 检出)不变。
393
+
394
+ 18. **SQL 后端:`mailbox_message` 表加一列 `record_id`(🔴 升级前先加列;持久数据,不能删表重建;邮箱记录的身份)**:
395
+ 引擎这一版起邮箱记录带生产者铸的身份,店在写锁之内判:同一身份同一条记录 ⇒ 答原来的序号、什么都不写;同一身份不同记录 ⇒ 拒。停驻座写失败时会用同一条记录再问一次,
396
+ 没有这一列的店会把那一问写成第二条记录(同一条消息被读两遍)。本服务不发 `ALTER`:存量库缺这一列 ⇒ 起服列册对账拒启(`config.schema_mismatch`),拒句带可直接粘贴执行的语句。
397
+ **升级前做**(MySQL 协议):`ALTER TABLE mailbox_message ADD COLUMN record_id VARCHAR(1024) NULL;`
398
+ (PostgreSQL)`ALTER TABLE mailbox_message ADD COLUMN record_id VARCHAR(1024) COLLATE "C";`
399
+ 存量行这一列是 NULL = 没说身份(照旧按序号读),零回填。**顺序**:先升库、再升副本(加完列后仍是 7.137.x 的副本再启动会把它读成幽灵列而拒启;已在跑的旧副本不写这一列)。
400
+ **回滚**:先停光升级后的副本,`ALTER TABLE mailbox_message DROP COLUMN record_id;`(两方言同一句),再起旧版。`DB_BACKEND=local` 零动作。
401
+
402
+ 19. **跨升级的在飞件(引擎 7.59.0;行为收窄)**:
403
+ ① **后台子代**:升级前生下的后台子代,行上没有「出生时的限制」(`policyFloor`)⇒ 新引擎跨进程复活它时拒 `revive.policy_floor_unreadable`(SendMessage 回执与 Agent 未起结果的 `details.error`;行不动、不计费)。
404
+ 出路:让它在旧版副本上跑完,或新起一只子代。升级后生下的子代都带这一员(没有任何限制时是空对象)。
405
+ ② **待决的工具审批**:升级前停驻、还没决的工具审批行不带工具声明的摘要 ⇒ 放行它在认领之前被拒(`checkpoint.unsupported_version`,`detail.reason: "tool_identity_missing"`,行仍待决)。
406
+ 三条出路:**拒掉**(模型重发那一次调用,新卡照常问)· 在停驻它的那一版副本上决 · 让它过期。拒不受影响(7.5.x 之前停驻的行连拒也拒,与上一版同)。
407
+ 反方向:旧版副本读到本版写下的审批行 ⇒ 拒 `version_newer`(认领前、可在新副本上重试)—— 滚动升级期间先把会决卡的副本升完。
408
+ ③ **记忆同步游标**:升级前落盘的游标没有本地店绑定(`store`)⇒ 那一层升级后**不同步**(零请求;每轮一条 warn `memory_sync_cursor_predates_store` 点名那只文件与两条出路,该层按失败层报 `memory_sync_layer_failed`,
409
+ 别层照跑),直到运维处置那只文件;本版不以空基线替它跑(空基线会把上一轮之后在一侧删掉的条目从另一侧拉回来,且不报冲突)。文件 = 每层一只 `sync-cursors/<peer>/<scope 摘要>.json`;
410
+ 同步层的新路径上没有文件时,只按 peer 分区的旧文件 `sync-cursor-<peer>.json` 是同步层的基线。**谁受伤**:开着记忆同步的部署(每一层都停到处置为止),上一轮之后有还没同步出去的删除的部署选错出路会丢删除。
411
+ **两条出路**:① 升级前在旧版上跑完一轮同步(删除落到对端),升级后删掉这些文件(可整只删 `sync-cursors/` 目录与旧文件)—— 第一轮两边已一致,没有条目被拉回;
412
+ ② 直接删掉文件 = 接受空基线重收敛:两边都改过的条目按冲突上报,上一轮之后在一侧删掉的条目从另一侧回来。
413
+
414
+ 20. **settings hook 的子进程环境维持十二名边界(零动作为主;授予形更严,随引擎 7.59.0)**:
415
+ command hook 子进程与 http 条目的 `$NAME` 插值只继承一张十二名的名单(`PATH` / `HOME` / `SHELL` / `USER` / `LOGNAME` / `TERM` / `TZ` / `LANG` / `LC_*` / `TMPDIR`)
416
+ 加请求 `settings.env` 与 hook 自己的变量,与上一发布版同;本服务自有凭据任何情况都不交。引擎的 hook 继承词本部署不采:请求的 `inheritEnv` 只给模型的工具 shell,对 hook 不作用。
417
+ 这一版起组合经引擎的宿主子进程环境组合:请求 `settings.env` 里名字带 `=` / NUL、值带 NUL 的项让 hook 起不来(此前子进程会读成另一对名 / 值;http 条目此前剥掉 NUL 照发,现在一个字节都不发)。
418
+ **谁要动**:hook 要用的变量写进请求 `settings.env`,名字不带 `=` / NUL、值不带 NUL。
419
+ 同一版里 hook 不再筛委派子代收到的那段任务文本(子代的开头改到 `SubagentStart` 站):靠 `UserPromptSubmit` 钩子筛子代提示的部署,把规则挪到 `PreToolUse` 且工具是 `Agent` 的那一站。
420
+
421
+ 21. **抹除的授权集与收执 v2(wire;引擎 7.59.0)**:
422
+ `POST /v1/memory/erase` 的请求体可带 `expectedScopes`(授权集,判官是引擎):选择子的 scope 与每个解析出的 id 的绑定 scope 都得在集里,否则 `400 config.memory_erasure_scope`(什么都没删、什么都没记;
423
+ 会话自助面同码同状态)。收执是 v2:`residuals` 换成八类载体表与两计数、`replay`;`erased[].binding` 不带 slug;`erasedPreviously[]` 为 `{ id, ev, at }`。**谁要动**:按 v1 读
424
+ `residuals.quarantineHits` / `binding.slug` 的消费方改读载体表、按自己的 `requestId` 定位被抹条目;读到 `v > 2` 拒读。`memory.erasure_selector_mismatch` 的原句不再带选择子哈希。
425
+
426
+ 22. **几处读法随引擎(零动作为主)**:只含空白的 `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 读作没有凭据(此前算有,与另一把同设会拒启);
427
+ 部署 mod 包的 `hooks.json` 契约号是 `5`(写 `4` 的包起服拒,拒句点名两个号);MCP 要用户授权的那台在清单行、重拨回执与 `//mcp` 面板带 `authorization: { reason }`(加性);
428
+ 写下 `a2a` 锁或合规禁 `a2a_peers` 的部署,能力位 `a2aInjection` 为 false —— 锁了 `a2a` 而请求仍带 `a2aPeers` ⇒ 同步 `400 config.locked_key`(锁先判,与是否多租户 / 合规禁项无关;与 `mcpServers` 的锁同形;续跑重放腿折成 `409 resume_blocked_by_policy`),没锁而合规禁了 `a2a_peers` 时请求自带的 `a2aPeers` 被忽略(留痕);卡编辑落盘不再出 `wildcard` 一词(更早存下的行照读)。
429
+
430
+ 23. **MCP / A2A 的凭据件改由部署的对端座在发送时作答(行为面;件的形比此前严;新提交的 `principalHeader` 撞属主名 ⇒ 400)**:
431
+ **What changed** —— 本服务交给引擎的 MCP / A2A 声明不再带任何件值(http MCP 的凭据头、stdio MCP 子进程的环境变量、A2A 发送的头):件登记在服务进程内存里,声明只带一只不透明引用,
432
+ 引擎在起子进程(stdio)/ 发请求(http · A2A)之前问部署的对端座,座按原字节作答,引擎的读器判件的形。请求面的形不变(仍收 `headers` / `env`,不收引用位)、名册声明的写法不变(`envRefs` / `headerRefs`)。
433
+ **Who is hurt**(对上一发布版;① ② ③ ⑤ ⑧ 是「那一台不再连上、兄弟照挂、提交照收、运行期才见」:连接期 `wiring_manifest.mcp[].errorCode` / 调用期 `tool_end.errorCode` = `credential_unavailable`,A2A 一侧只有文本;因件的形被引擎读器拒的那一台,服务端没有对应的拒行,看这些码 / 文本;`peer_seat_refused` 只在本服务的座自己拒时才有 —— 引用不在表里 / 绑定不符 / 引用种类座不答):
434
+ ① stdio 件值含 CR / LF / NUL(多行 PEM、尾换行的 Secret);② stdio 件名不是标识符形(`ODD.NAME`、`MY-VAR`);③ MCP http 的件头名是传输自己写的头(`content-type` · `accept` · `mcp-session-id` · `mcp-protocol-version` · `last-event-id`);
435
+ ④ MCP 或 A2A 条目的 `principalHeader` 取引擎的断言头名 `connector-assertion`(任何大小写)—— **新提交 `400 request.field_invalid`**(此前受理:上一发布版的引擎只查身份头名与静态头重名);⑤ stdio 的秘密形件(变量名被引擎认作凭据名)的值恰等于一只每个子进程都会继承的变量的值;
436
+ ⑥ 嵌入方(下一条);⑦ MCP 条目的 `principalHeader` 取传输自己写的头名(`mcp-session-id` · `mcp-protocol-version` · `content-type` · `accept` · `last-event-id`,任何大小写)—— **入口 400**,与 ④ 同一道门、同一个码,点名 `mcpServers[i].transport.principalHeader`,拒句里的头名是引擎固定表里的规范化(小写)名,不回显调用方写的原串 / 大小写形(调用方写的恰是小写时,句里的名与所写相同)
437
+ (A2A 没有传输自有头名表,A2A 只中 ④);⑧ http 件值首尾带 CR / LF(Secret 文件的尾换行;此前由发送时的头规范化吞掉,现在读器拒)。④ ⑦ 的耐久 resume 重放存量体不 4xx:MCP 照挂(引擎拨号时拒那一台),A2A 那一条对端整条不进(warn `a2a_injection_dropped` 点名)。
438
+ 另:⑨ 会话级子代(http / stdio)的已知缺口见第 25 条;⑩ **扣留次序**:引擎把座答里认作凭据的 http 头值与 stdio 秘密形件值记为自己持有的凭据值(服务进程环境里同值的变量不再交给模型可驱动的 host shell 子进程;MCP stdio 子进程只继承 MCP SDK 的少数默认变量〔`HOME` · `LOGNAME` · `PATH` · `SHELL` · `TERM` · `USER`〕与座给的件,拿不到服务进程环境的其余变量),
439
+ 次序是先过读器、放行了才记 —— 被读器拒的形(件值含 CR / LF / NUL、头名不是 HTTP token、两个头名只差大小写、变量名不是标识符形)的值不进扣留表:那一台失败,环境里同值的变量仍交给 host shell 子进程(上一发布版先记后判,同样的形值已在表里);MCP 传输自己写的头名(③)在读器之后的协议层才拒,值此时已在表里。补偿:名册 `headerRefs` 指向的变量值去掉尾换行;件值别与长期留在服务进程环境里的变量同值而又带读器拒的形。
440
+ **How to migrate**(补偿)—— ① 多行值改 base64 或改传文件路径;⑧ 去掉 Secret 文件的尾换行;② 变量名改标识符形;③ 件头名改非协议名;④ ⑦ `principalHeader` 换成非协议、非引擎自有的名(例 `x-agent-principal`);⑤ 换一个与继承变量不同的值;
441
+ ⑥ 见下一条。零数据迁移:名册只存引用名(不存值),停驻任务的续跑上下文形不变(请求体仍只以封签存,每一腿从封签体重铸引用),引用不跨进程、不跨副本 —— 滚动升级期间新旧副本互不依赖。
442
+ **升级后看**:`/metrics` 的 `peer_registry_entries` / `peer_registry_holders`(在飞腿全落定后回名册基线);`wiring_manifest.mcp[]` 里 `credential_unavailable` 的行(点名那一台的 `name`)与座自己拒时的 `peer_seat_refused` 行(`protocol` / `peer` / `reason`,不带件值)。**回滚**:回到上一版即回到件随声明交引擎。
443
+
444
+ 24. **嵌入方(类型面,BREAKING):`ServiceCoreDeps.peerDesk` 必填、`resolveSpec` 的 `opts` 必填且带 `lease`、Runner 要接座**:自建 `createHttpServer` 的嵌入方(不用任何 MCP / A2A 凭据的也一样)用包根导出的 `createPeerDesk()`(零 IO)铸一只 desk:
445
+ `RunnerDeps.peerSeat` 给 `desk.seat.answer`(函数形 `(question) => Promise<PeerAnswer>`,可赋给引擎 7.59.0 的座型 `(question, signal) => Promise<PeerAnswer>`),`ServiceCoreDeps.peerDesk` 给整只 desk;同一只既给 HTTP 服务也给每只 Runner。tsc 红即通知。
446
+ `ServiceDeps.resolveSpec` 的第四参 `opts` 由可选改必填,带 `lease: PeerLease`(这一腿的宿主租约:受理 / 续跑两只漏斗在调用之前开、由漏斗的失败出口或拿到产物的那段作用域放;装配只借用、不放不留;实现方自铸的声明归自己的 desk 时可以不理它),
447
+ 第三参 `auth` 随之写成 `RequestAuth | undefined`(必填 `opts` 不能跟在可选位后);**直调** `resolveSpec` 的代码要递租约。自己手铸 `McpServerSpec` / `A2aServerSpec` 交给 Runner 的嵌入方:引擎不再收带字面 `transport.headers` / `transport.env` / 顶层 `headers` 的声明
448
+ (整任务 prepare 拒 `config.credential_in_declaration`),带引用而 Runner 没有座整任务拒 `config.peer_seat_missing`(一个坏兄弟也拒整单;Runner 之外的面板 / A2A 物化 / 探测则按对端拒、兄弟照挂)—— 把值改走名册引用或请求面条目,经 desk 铸引用。`RunnerDeps.peerSeat` 的型随引擎 7.59.0 是函数形。
449
+
450
+ 25. **已知缺口(行为面,本版披露不修):会话级子代在父腿作用域结束之后首拨 http / stdio、或再发 http 会被对端座拒**:引擎持有引用的计数那一半本版不在,座只认宿主租约。一个会话级(后台)子代继承父的、**请求体自带**的 http / stdio MCP 声明(引用随声明继承),在**父腿作用域结束之后**再问座 ⇒
451
+ 那次发送 / 那一台的挂载 `credential_unavailable`(`delivered:"no"`,一行不带值的 warn `peer_seat_refused`,`reason: handle_not_held`):http 在首次连接与每次发送时问座,stdio 在起子进程时问座 —— 父腿作用域结束之后才首拨的 stdio 子代同样被拒;父腿很快收尾时,子代连自己的挂载都会被座拒(子代的挂载被跳过)。**谁受伤**:请求体带件的 http / stdio MCP + 后台子代的部署(单用户壳的 `.mcp.json` 带头 / 带环境)—— 上一发布版声明里直接带件,子代在父腿之后仍能连;名册(`headerRefs` / `envRefs`)的服务器不受影响:名册件由进程寿命的名册租约持有,父腿结束不动它;
452
+ 同一腿内(含 cascade 各级、同步腿)与父腿作用域之内已起的 stdio 子进程不受影响,A2A 没有这个形(委派子代不继承父的 A2A 对端)。**补偿**:让父腿等子代收尾(父腿作用域内子代的发送照答);或把这类服务器改成名册声明,或让这类子代只用不带件的 MCP;缺口在引擎持有那一半到货后翻绿。
453
+
454
+ 26. **订正 7.133.0 节第 17 条「同步腿的旧游标文件第一轮自动收编(info `memory_sync_cursor_adopted`)」:收编臂已删,这句不再成立(动作见第 19 条 ③)**:
455
+ 同步腿旧游标文件 `sync-cursor-<peer>.json` 不再被收编,日志行 `memory_sync_cursor_adopted` 随之不再存在。升级前落盘的旧文件都没有引擎 7.59.0 起必带的店绑定,收编的形判从不认它,这条臂对任何存量文件都不可达;
456
+ 旧文件不再被当游标、不改名不删:同步层的新路径上没有文件而它是同步层的无绑定基线 ⇒ 同步层不同步、通告点名它,出路与第 19 条 ③ 同。此后每层一只 `sync-cursors/<peer>/<scope 摘要>.json` 的写法不变。
457
+
458
+ 27. **嵌入方直调 local 店的换装三条腿(`importEntries` / `replaceEntries` / 暂存提交)时属主传 `undefined` ⇒ `TypeError`(行为变更;安全收紧;部署与 HTTP 路径零动作)**:
459
+ 经包根导出的 `createStoreBackend(...).session()` 拿到 `DB_BACKEND=local` 的会话店、再直调这三条腿且属主给 `undefined` 的嵌入方(参数的声明型是 `string | null`,JS 或收窄类型才到得了):上一发布版把它宽读成匿名 —— 不存在的 id 建出无主行,既有属主行被静默改写成无主;
460
+ 本版与 `register` 首写同一只判官 ⇒ `TypeError`、一个字节不写。**补偿**:要匿名显式传 `null`,要某位主体传主体名;按整句匹配拒句的调用方改按类 / 开头(`session owner must be a principal name`)匹配 —— 拒句的类与开头同上一发布版,其后不同。
461
+
462
+ 28. **已知缺口(行为面,本版披露不修;引擎侧缺陷已由引擎认领):换了同步目标之后,本机未改的记忆条目会被当成「中心已删」而删除**:同步腿的游标按对端名(`central`,本版恒为缺省)与层各存一只,**不随 `MEMORY_SYNC_URL` / 中心的引擎声明变化**;把 `MEMORY_SYNC_URL` 指向另一台中心(或同地址换了中心的引擎声明 / 店)后,旧游标里的基线对新中心成立「基线有、中心无」,新中心按协议答删除,本机侧照做 —— 本机未改过的条目被删,零冲突上报。
463
+ **升级前做**:零动作(不换中心不触发)。**换中心前做(本版与之前各版同)**:二选一 —— ① 先在旧中心跑完一轮同步使两边收敛,再删该层的游标文件 `sync-cursors/central/<scope 摘要>.json`(同步根下;层目录见第 19 条 ③);② 直接删该游标文件 = 接受以空基线对新中心重收敛(两边都改过的条目按冲突上报)。**升级后看**:换中心后的首轮日志 `memory_sync_round` 里 `localApplied`(本机被应用的变更数,含删除)非零而 `conflicts` 为零、且本机近期没改过记忆 ⇒ 即此症(日志不单列删除数;对账看本机记忆目录条目数)。**回滚**:回到上一版行为相同,不是修复。真修 = 游标绑对端身份、目标不符整轮零请求拒,随引擎的对端身份件在下一版到达。
464
+
10
465
  ## 7.137.0 —— 对 web-admin 中心的请求不再跟随重定向(安全收紧;行为面;反代会回 3xx 的部署升级前把两席写成最终地址) · k8s 车道 `K8S_SANDBOX_ENV` 的值改经每只 pod 自己的 Secret(部署面 BREAKING;沙箱 Role 要 secrets 的 `create`,名单非空而 Role 不许 ⇒ 起服拒;共用沙箱命名空间的两套部署升级前各给一个命名空间) · SQL 后端 `task_run` 表加三列 `identity_source` / `identity_scope` / `identity_principal_inc`(🔴 升级前先 `ALTER TABLE` 加列;持久数据,不能删表重建;嵌入方 `RunRecord` 多必填键 `identity`〔BREAKING,类型面〕) · 请求键 `promptProfile` 退役、换成布尔 `promptLean`(BREAKING,wire;零别名;升级前停驻的任务存体起服原地改写〔一次性迁移 M30,窗 30 天〕,没改写到的续跑 409) · 模型目录条目带 `promptGuidance` 的不服务、fable 系模型 id 不再带 fable 提示段(行为变更) · 带图预检的计量 `images_omitted_total` 与日志行 `images_omitted_no_vision_model` 退役(运维面;行为变更;看板 / 告警改读会话流的 `model.capability_downgraded`) · 引擎 7.56.0 的部署序:先升全部读者、回滚前先决完停驻行(三处:停驻审批行 `mount_site`、技能座 `skill_scopes`、会话规则文法 5) · 规则名里的 `*`:限制侧整名 glob、授予侧一条孤 `*` 不再让整张放行表作废(行为变更;升级前先审放行表) · 规则名外缘的空白被拒(行为变更;人敲的规则编辑文本修剪后再提交) · 嵌入方 hook / mod 的 handler 答案按数据收、非普通记录一律拒(行为变更,fail-closed) · 不是名字的主体在鉴权边界被拒:`400 principal_not_a_name`(行为变更;反代把 UTF-8 用户名原样塞进主体头的部署升级前核) · 计划审阅的决断体可带 `checkpointId`:门换了 ⇒ `409 approval_stale`、不落决断(wire additive;决断方先读能力位 `planReviewCheckpointId` 再带键) · `delegation.ask_unresolvable` 通告的 `detail` 多可选键 `remedies`(wire 加性;宿主按 `kind` 渲染出路,闭集外的 `kind` 忽略) · 引擎 7.56.0 的五个新键本版刻意不投(`requestedBy`、`answeredBy`、`hostFloor`;登记披露,无消费方动作) · 本版其余 wire 面变化的消费方动作逐面表态(多数零动作;设备执行器的修订 3、`attachments.mcpUnavailable`、`resultEntryIds` 各有一句真动作) · 7.136.x 停下、技能请求项带 `mods` 的任务续跑失败(行为变更;新提交早已 400) · 订正 7.136.0 节第 4 条:没有返回任务目标全文的读口(`GET /v1/runs/:id` 不带目标)
11
466
 
12
467
  1. **对 web-admin 中心的请求不再跟随重定向(安全收紧;行为面)**:此前只有令牌续签不跟重定向,其余对中心的请求(拉配置、principal 视图、skill 正文、prompt 产物、配额租约、
@@ -2620,7 +3075,7 @@
2620
3075
  - **用户可见(引擎 7.40.0,零配置动作)**:`settings.permissions.ask` 里的 `Read(<path>)` 规则现在也管 Grep / Glob 在该路径下的搜索(各出一张 Read 卡;无审批面 ⇒ 拒),`Edit(<path>)` ask 规则也管 Write / NotebookEdit;
2621
3076
  Read 工具结果不再带常驻的内容安全提醒(依赖那句约束弱模型的部署,把同一句放进自己的 `appendSystemPrompt`)。
2622
3077
 
2623
- ## 7.114.0(车UW,S-995;车UY)—— `settings.hooks` 工具事件 matcher:别名写成正则形的同一个错误,提交当场 400(7.112.0 只拒字面形) · `@sema-agent/settings-schema` 7.0.1 + `@sema-agent/core` 7.39.2:车道 / 存储词表改读正本 · 写了 `remote-docker` 的 `config.d/remote-exec.json` 拒启 · local 车道坏会话规则文件改拒 · 被拒的 `resumeAt` 不再挪会话叶
3078
+ ## 7.114.0(车UW;车UY)—— `settings.hooks` 工具事件 matcher:别名写成正则形的同一个错误,提交当场 400(7.112.0 只拒字面形) · `@sema-agent/settings-schema` 7.0.1 + `@sema-agent/core` 7.39.2:车道 / 存储词表改读正本 · 写了 `remote-docker` 的 `config.d/remote-exec.json` 拒启 · local 车道坏会话规则文件改拒 · 被拒的 `resumeAt` 不再挪会话叶
2624
3079
 
2625
3080
  - **🔴 settings 面硬破坏(响亮拒,无迁移代码、无兼容形)**。① *谁受影响*:提交体 `settings.hooks` 里 PreToolUse / PostToolUse / PostToolUseFailure 的 `matcher` **选中引擎工具别名、却选不中它的正名**的 —— 7.112.0 只拒字面的 `ListPeers` / `Read|ListPeers`,
2626
3081
  `^ListPeers$` / `ListPeers.*` / `(ListPeers)` 这类正则写法当时 200、钩子永不命中(core 按 wire 名匹配,别名不是 wire 名)。判据现在是对 core 工具目录、按 hook-runner 运行期**同一只**匹配函数求值(字面 / 名字表读法:`|` 与 `,` 分隔、逐段 trim,与 CC 2.1.280 同形;区分大小写)。
@@ -2707,17 +3162,17 @@
2707
3162
  旧二进制的收敛只扫 `state = 'open'`,不受影响。
2708
3163
  - **嵌入方(类型面)**:包根导出的 `SettleHow` 多一个词 `consumed`(对它穷举的 switch tsc 红即通知);`TaskSpec.outputStyle`(core 7.39.0 新席)本服务不接、请求面不收。
2709
3164
 
2710
- ### 运维日志事件名退役一族(车 UQ S-990 / 车 UR S-1000 / S-569)—— 按事件名配告警 / 数行的运维要改配
2711
- - **退役(不再逐记录发 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`(S-990 六座);`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`(S-1000 八座)。
2712
- - **替代读法(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 行与 S-582 / S-928 / S-967 / S-977 既有行)。
2713
- - **保持逐命中响亮(安全轴混座,不退役)**:`file_store_corrupt_read`;其 session-policy 脸的坏读今天仍 fail-open(core #1299 修后改拒),server 7.113.0 起同时计 `server.session-policy.corrupt-read-fail-open`(P-DEBT)。
3165
+ ### 运维日志事件名退役一族(车 UQ / 车 UR)—— 按事件名配告警 / 数行的运维要改配
3166
+ - **退役(不再逐记录发 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 八座)。
3167
+ - **替代读法(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 行与其余既有行)。
3168
+ - **保持逐命中响亮(安全轴混座,不退役)**:`file_store_corrupt_read`;其 session-policy 脸的坏读今天仍 fail-open(引擎修后改拒),server 7.113.0 起同时计 `server.session-policy.corrupt-read-fail-open`(P-DEBT)。
2714
3169
  - **run-local 车道**(前台 CLI 进程)的会话 repo 仍走混座逐命中 warn,不降。
2715
3170
 
2716
- ### 会话读三口的非属主 404(车 UQ S-989;**安全修复:存在性探测口闭合**;wire 值变更)
3171
+ ### 会话读三口的非属主 404(车 UQ;**安全修复:存在性探测口闭合**;wire 值变更)
2717
3172
  - **修前(7.112.0 及更早;7.103.x 的 detail 口读码已是此形,head / events 两口与更早版本未逐版核)**:`GET /v1/sessions/:id`(detail / head / events)对**非属主**调用方答 `not_found.run` + run 长文,对**不存在**的会话答 `not_found.session` + `session not found` —— 同一端点两臂的码与句子都不同,多租户部署里任何持有效凭据的调用方可以据此判断「别人的某个会话 id 存不存在」(读不到内容,只能探存在性;7.112.0 发布字节黑盒实测可区分)。**7.113.0 起两臂逐字节相同**(`not_found.session` + `session not found`)。多租户部署(`REQUIRE_PRINCIPAL=true`)建议升到 7.113.0 及以上;单用户部署没有「非属主」这一臂,不受影响。
2718
3173
  - **兼容面**:读 `not_found.run` 判「会话读被拒」的旧端要改读 `not_found.session`;属主 200 不变;run 面(`/v1/runs/:id`)不变。
2719
3174
 
2720
- ## 7.112.0(车UG,S-924)—— `settings.hooks` 里按工具别名写的 matcher 提交当场 400(此前静默不命中)
3175
+ ## 7.112.0(车UG)—— `settings.hooks` 里按工具别名写的 matcher 提交当场 400(此前静默不命中)
2721
3176
 
2722
3177
  - **🔴 settings 面硬破坏(响亮拒,无迁移代码、无兼容形)**。① *谁受影响*:提交体 `settings.hooks` 里 PreToolUse / PostToolUse / PostToolUseFailure 的 `matcher`
2723
3178
  是**引擎工具别名**的(今天只有 `ListPeers` → `ListAgents`;别名表读 core 静态工具目录)—— 它们**早就不命中**(post 两事件自 7.107.0 / core 7.36.0,PreToolUse 一直),只是没人告诉写的人。
@@ -2725,38 +3180,38 @@
2725
3180
  不再是「接受、hook 永不跑」。耐久 resume 重放**不判**(会砖 parked 任务):升级前就 parked 的任务,其存量 body 里的别名 matcher 在续跑腿照旧永不命中、同一份 hooks 里其余钩子照常生效(与 7.111.0 逐字同)。
2726
3181
  嵌入方经 `resolveSpec` 席挂的工具别名在受理面看不见,不在本门射程。
2727
3182
 
2728
- ## 7.111.0(车TA,S-961 / S-972)—— `wiring_manifest` 帧 +`instructions` 段(additive,零动作)
3183
+ ## 7.111.0(车TA)—— `wiring_manifest` 帧 +`instructions` 段(additive,零动作)
2729
3184
 
2730
- - **wire(additive,零动作)**:`wiring_manifest` 帧(四条腿:流式 SSE / 账本行 / 非流式 `wiringManifest` 回执 / 续跑腿)多一段本服务自铸的 `instructions: { selected: string[] }` = 这条腿选中的项目指令文件(相对 cwd 的链成员);`[]` = 没有,缺席 = 无陈述(契约附录 G.21)。按封闭 schema 校验该帧的消费方加这一可选键;不要它的部署 `PROJECT_MEMORY_ENABLED=false`(连同项目记忆注入一起关)。`task.user_steer_undrained{cause:"crashed"}` 的 `message` 改句序(行动句在前、< 400 字符),`detail` 不变 —— 按文本匹配的脚本改读 `detail.cause`(S-972)。
2731
- - **会话删除 / 托管留存级联接上用户输入受理账本(车TC,S-965;零 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 红即通知。
2732
- - **同步子代的 steer 入用户输入受理账本(车TF,S-966;零 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 读得懂这些行,照常收敛 / 告知)。
2733
- - **用户输入受理账本收敛判词合一 / SQL 坏行逐行跳过(车TD,S-969;零 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 无数据动作(账本行形不变)。
2734
- - **`@sema-agent/core` 7.38.0 → 7.38.2(车TG;两只 patch,core 硬破坏 0、wire 键 / 码 / 闭集零变化,零动作)**:① 内建读拒表的家锚定行(`~/.sema/settings.json` 等)另落**账户家**(core 7.38.1 #1244,S-941)—— 引擎进程的 `HOME` 被改指时,账户真实家下的同名文件由「读得到」变为 `read_path_denied`;真要读的部署用 `READ_DENY_BUILTIN_EXCLUDE` 删那一行。S-941 时期按 DEPLOY-PREREQS 加的 `READ_DENY_PATTERNS` 不锚家同名行可撤(不撤无害)。账户查询无答的主机上这些行在任何位置判(项目自己的 `.sema/settings.json` 也拒,一次 `console.warn`,下一条 run 重问)。② local 车道 File 店族的 JSONL 末段整条记录缺换行 ⇒ 认下并在下次打开补换行(core 7.38.2 #1278,S-975);末段非对象 ⇒ 截 + 多一条 `corrupt-record-skipped` 计数。**回滚**到 ≤7.110.x:回退版本的 core 会把「只缺换行」的末行截掉(只在崩溃留下的那一形上;盘上格式不变,零数据动作)。
3185
+ - **wire(additive,零动作)**:`wiring_manifest` 帧(四条腿:流式 SSE / 账本行 / 非流式 `wiringManifest` 回执 / 续跑腿)多一段本服务自铸的 `instructions: { selected: string[] }` = 这条腿选中的项目指令文件(相对 cwd 的链成员);`[]` = 没有,缺席 = 无陈述(契约附录 G.21)。按封闭 schema 校验该帧的消费方加这一可选键;不要它的部署 `PROJECT_MEMORY_ENABLED=false`(连同项目记忆注入一起关)。`task.user_steer_undrained{cause:"crashed"}` 的 `message` 改句序(行动句在前、< 400 字符),`detail` 不变 —— 按文本匹配的脚本改读 `detail.cause`。
3186
+ - **会话删除 / 托管留存级联接上用户输入受理账本(车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 红即通知。
3187
+ - **同步子代的 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 读得懂这些行,照常收敛 / 告知)。
3188
+ - **用户输入受理账本收敛判词合一 / 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 无数据动作(账本行形不变)。
3189
+ - **`@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 会把「只缺换行」的末行截掉(只在崩溃留下的那一形上;盘上格式不变,零数据动作)。
2735
3190
 
2736
- ## 7.110.0(车ST,S-955;小车 SV,S-956;车SX,S-958 / S-959;小车 SA,S-962 / S-963;主会话 S-964;车SW,S-928)—— `@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 告知(用户输入受理账本)
3191
+ ## 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 告知(用户输入受理账本)
2737
3192
 
2738
- - **🔴 记忆同步 env(S-964,配置面硬破坏)**:单用户 file 引擎上设了 `MEMORY_SYNC_URL` / `MEMORY_SYNC_TOKEN`、**没设** `MEMORY_SYNC_SCOPE`、且 `MEMORY_SCOPE` 不是 typed 键(`user:` / `org:` / `proj:` / `userproj:`;含缺省 `local`)的部署**升级后拒启**。此前这一形派生同步层 `user:<MEMORY_SCOPE>` —— 一个本部署从不写的层(写家是裸 `MEMORY_SCOPE`,core 同步按同一个名字取条目)⇒ 同步腿自 142-S2.5-W1 起每轮推 0 条。出路二选一(错误句原文点名):`MEMORY_SYNC_SCOPE=<要复制的层>`,或把 `MEMORY_SCOPE` 设成中心期待的 typed 键(如 `user:<tenant>`,缺省同步层随之同名)。显式 `MEMORY_SYNC_SCOPE` 的部署零变化。
3193
+ - **🔴 记忆同步 env(配置面硬破坏)**:单用户 file 引擎上设了 `MEMORY_SYNC_URL` / `MEMORY_SYNC_TOKEN`、**没设** `MEMORY_SYNC_SCOPE`、且 `MEMORY_SCOPE` 不是 typed 键(`user:` / `org:` / `proj:` / `userproj:`;含缺省 `local`)的部署**升级后拒启**。此前这一形派生同步层 `user:<MEMORY_SCOPE>` —— 一个本部署从不写的层(写家是裸 `MEMORY_SCOPE`,core 同步按同一个名字取条目)⇒ 同步腿自 142-S2.5-W1 起每轮推 0 条。出路二选一(错误句原文点名):`MEMORY_SYNC_SCOPE=<要复制的层>`,或把 `MEMORY_SCOPE` 设成中心期待的 typed 键(如 `user:<tenant>`,缺省同步层随之同名)。显式 `MEMORY_SYNC_SCOPE` 的部署零变化。
2739
3194
 
2740
- - **hook 作者(stdin 载荷契约)**:`permission_mode` 的值源从「请求上的模式词」改为**腿的实时模式**(core 回调上下文 `permissionMode`,plan 腿续跑 / 模式释放后的真实值);PreCompact / PostCompact / StopFailure 三事件与上下文缺席时**不带**该键(此前恒带请求词)。按旧值做分支的 hook 改读实时词、对缺席作「无模式语义」处理。**接手屏**(core 7.38.0):PreToolUse hook 结果越界 `action` / 字串布尔 / `null` 成员 / 不可克隆改写 ⇒ 引擎拒(工具不跑、模型读接手句、`permissionDenied` 观察者响);无 `action` 仍是无异议 —— 本服务映射核在约内,部署自写 hook 自查。经本服务 hooks 复合体(部署基线恒挂,挂了 hooks 的 run 都经过它)的结果同判:读不出词的结果(集外 `action`、非对象 —— 含 `0` / `""` / `NaN`;无异议只认 `undefined` / `null` / `false`)原样交引擎屏 ⇒ 引擎拒(S-959;修前复合体把它读作无异议、照跑,带 `additionalContext` 的还被译成 allow)。
3195
+ - **hook 作者(stdin 载荷契约)**:`permission_mode` 的值源从「请求上的模式词」改为**腿的实时模式**(core 回调上下文 `permissionMode`,plan 腿续跑 / 模式释放后的真实值);PreCompact / PostCompact / StopFailure 三事件与上下文缺席时**不带**该键(此前恒带请求词)。按旧值做分支的 hook 改读实时词、对缺席作「无模式语义」处理。**接手屏**(core 7.38.0):PreToolUse hook 结果越界 `action` / 字串布尔 / `null` 成员 / 不可克隆改写 ⇒ 引擎拒(工具不跑、模型读接手句、`permissionDenied` 观察者响);无 `action` 仍是无异议 —— 本服务映射核在约内,部署自写 hook 自查。经本服务 hooks 复合体(部署基线恒挂,挂了 hooks 的 run 都经过它)的结果同判:读不出词的结果(集外 `action`、非对象 —— 含 `0` / `""` / `NaN`;无异议只认 `undefined` / `null` / `false`)原样交引擎屏 ⇒ 引擎拒(修前复合体把它读作无异议、照跑,带 `additionalContext` 的还被译成 allow)。
2741
3196
  - **嵌入方(类型面,不在包导出面)**:`SERVER_NOTICE_AUDIENCE` / `ServerNoticeCode` / `isServerNoticeCode` / `HookRunnerContext.permissionMode` / `ENGINE_ABSENT_PERMISSION_MODE` 仓内硬删 —— 四枚本服务铸码的受众 / 铸者改读 core `NOTICE_AUDIENCE` / `NOTICE_MINTER`;client-core 镜像行可退役(core 包已含四码)。
2742
3197
  - **结果面(additive)**:`terminal.failed.detail? { kind:"provider_rejected", status, code? }` 过境(同步 200 体 / `done.result` / `GET /v1/runs/:id` / `done` 账本行);判「可改重发」看 `status`(401 / 403 / 429 也带)。`engine_notice` D.3 白名单 +`task.tool_turn_incomplete`(user);`memory.layer_locked_legacy` 明拒(operator)。`/metrics` `brain_echo_dropped_total{field}` 可出现 `field="apiErrorCode"`。
2743
3198
  - **审批面(值层,键不变)**:`askClass` / `classes` 读写两面统一走 core `screenAskClassMembers`:投规范序副本;重复员 / 非规范序首员不符形改判(只在 core 自己不写出的形上);`card_json` 存量卡零影响。
2744
- - **🔴 迁移窗口(core #1213)**:本版提货 core 7.38.0 **仍迁移旧模式键检查点行、不拒**;排空窗到提货 core 7.39.0 的 server 版前(7.109.0 段原句)。
2745
- - **run-local(S-956)**:无 TTY 被拒的 run 不再带 `haltedOnUserRejection`。退出码仍为 1;非 `--json` 停因行从 `task stopped (haltedOnUserRejection) …` 改为 `task incomplete (approval unanswered) …`;门记录 `settlement.kind` `human_refused` → `policy_refused`、`who.party` `person` → `none`;模型读 core 策略句 + 拒因。按 7.101.0 迁移建议读 `--json` 的 `haltedOnUserRejection` 判拒的脚本,改看退出码 / stderr 停因行。同一拍的兄弟调用不再被 `gate.batch_halted` 连坐,各自过门。委派子代里无 TTY 的拒也计数 ⇒ CLI 退 1(更严;TTY 下子代人答 N 仍退 0)。
2746
- - **嵌入方(类型面硬破坏,S-928)**:`StoreBackend`(包根导出型)新增**必选** `userInputLedger(): UserInputLedgerStore`;自建 StoreBackend 的嵌入方 tsc 红即通知(7.109.0 `listByCall` 同形);返回型 `UserInputLedgerStore` 及行型 `UserInputAcceptance` / `NewUserInputAcceptance` / `SettleHow` / `OpenScanCursor` / `WriterGoneEvidence` 自本版从包根导出。
2747
- - **用户输入受理账本(S-928;零动作)**:live 腿 steer 在回 200 之前先落一行受理(local:`<数据根>/user-input-ledger/ledger.jsonl`;SQL:新表 `user_input_acceptance`,
3199
+ - **🔴 迁移窗口**:本版提货 core 7.38.0 **仍迁移旧模式键检查点行、不拒**;排空窗到提货 core 7.39.0 的 server 版前(7.109.0 段原句)。
3200
+ - **run-local**:无 TTY 被拒的 run 不再带 `haltedOnUserRejection`。退出码仍为 1;非 `--json` 停因行从 `task stopped (haltedOnUserRejection) …` 改为 `task incomplete (approval unanswered) …`;门记录 `settlement.kind` `human_refused` → `policy_refused`、`who.party` `person` → `none`;模型读 core 策略句 + 拒因。按 7.101.0 迁移建议读 `--json` 的 `haltedOnUserRejection` 判拒的脚本,改看退出码 / stderr 停因行。同一拍的兄弟调用不再被 `gate.batch_halted` 连坐,各自过门。委派子代里无 TTY 的拒也计数 ⇒ CLI 退 1(更严;TTY 下子代人答 N 仍退 0)。
3201
+ - **嵌入方(类型面硬破坏)**:`StoreBackend`(包根导出型)新增**必选** `userInputLedger(): UserInputLedgerStore`;自建 StoreBackend 的嵌入方 tsc 红即通知(7.109.0 `listByCall` 同形);返回型 `UserInputLedgerStore` 及行型 `UserInputAcceptance` / `NewUserInputAcceptance` / `SettleHow` / `OpenScanCursor` / `WriterGoneEvidence` 自本版从包根导出。
3202
+ - **用户输入受理账本(零动作)**:live 腿 steer 在回 200 之前先落一行受理(local:`<数据根>/user-input-ledger/ledger.jsonl`;SQL:新表 `user_input_acceptance`,
2748
3203
  中央 `ensureSchema` 以 `CREATE TABLE IF NOT EXISTS` 自建,两方言 + 两条索引,无 ALTER、无回填)。账本写不进 ⇒ steer 回 **503 `steering.ledger_unavailable`**(此前 200;引擎零字节)——
2749
3204
  local 车道数据根只读 / 盘满、SQL 车道库不可达时出现,其余路由不受影响。进程崩溃时丢掉的受理在该会话下一条 run 首拍告知 `task.user_steer_undrained{cause:"crashed"}`,
2750
3205
  `GET /v1/sessions/:id` 多一个可选键 `userInputUndrained`(缺席 = 零条)。**回滚**:回到 ≤7.109.x 时账本文件 / 表留着无害(旧二进制不读);滚回之后的崩溃丢失恢复修前的静默。
2751
3206
  - **零数据迁移**;DDL 只有上一条的新表(自建)。
2752
3207
 
2753
- ## 7.109.0(车SK,S-934)—— `@sema-agent/core` 7.37.1(7.37.0 的全部变更 + #1224 工具回合律请求修复,运维通告 `context.tool_turn_repaired` 不上会话流):无人值守腿按类作答(`UNATTENDED_PERMISSION_MODE` 退役,设了即拒启)· ask 类对 `askClass` / `classes` 上 wire · 策略决定对象的普通对象律 · 迁移窗口
3208
+ ## 7.109.0(车SK)—— `@sema-agent/core` 7.37.1(7.37.0 的全部变更 + 工具回合律请求修复,运维通告 `context.tool_turn_repaired` 不上会话流):无人值守腿按类作答(`UNATTENDED_PERMISSION_MODE` 退役,设了即拒启)· ask 类对 `askClass` / `classes` 上 wire · 策略决定对象的普通对象律 · 迁移窗口
2754
3209
 
2755
3210
  - **🔴 env:`UNATTENDED_PERMISSION_MODE` 设了即拒启**(任何值,含 7.106.0 的缺省 `bypassPermissions`;拒因带 `config.env_key_retired` 并点名键)。
2756
3211
  **迁移**:从 `.env` / 编排清单里删掉它。leader worker / leader 修复腿 / `sema` 一次性 CLI(run-local)及 leader worker park 的 `/decide` 续跑,
2757
3212
  自本版起恒按 `default` 跑,审批席**按类作答**:机器只答引擎盖了 `ordinary` 类的问(普通写、非只读 shell 的形状层问 —— 照常落地)。
2758
3213
  **写面与 `ordinary` 的边界**:`roots` 只约束 Write / Edit 这类结构化文件工具;shell 的根外写与 Read 工具的根外读属 core `ordinary`,无人值守腿上由机器答(与 ≤7.108.0 的 bypass 放行同一落地结果,记法不同)。
2759
- **审计读者**:机器按类放行在 core 门记录里写成 `settlement.kind:"human_allowed"` / `who.party:"person"`(core 没有「机器放行」归属词,S-953 转 core)—— 无人值守腿上读作机器放行;无席且无 durable 块的 leader 腿被拒的问(run-local 有本地席,不走这一词)结算词 `no_approver` → `approver_unavailable`,按词告警的运维改比码。
3214
+ **审计读者**:机器按类放行在 core 门记录里写成 `settlement.kind:"human_allowed"` / `who.party:"person"`(core 没有「机器放行」归属词,已转 core)—— 无人值守腿上读作机器放行;无席且无 durable 块的 leader 腿被拒的问(run-local 有本地席,不走这一词)结算词 `no_approver` → `approver_unavailable`,按词告警的运维改比码。
2760
3215
  - **🔴 行为面(安全轴收紧)**:这些腿上此前被缺省 `bypassPermissions` 放掉的六类问 —— shell 读会话目录外(`probe`)、MCP / A2A 工具标记、
2761
3216
  transcript 写、规则店读不出(`rule_unreadable`)、共享制品读(`artifact_shared_read`)—— 改为**不答**:run-local 有终端时问你 y/N、无终端当场拒;
2762
3217
  leader 各腿配了 durable 审批块 ⇒ park 到 `/v1/approvals/:id/decide`,没配 ⇒ 当场拒。写保护表目标从「策略层路径拒行拒(人在场也答不了)」改成一问
@@ -2770,8 +3225,8 @@
2770
3225
  `allow` / `deny` / `ask` 之一;契约成员必须是对象**自有可枚举**成员(不放原型上、不靠 getter、不靠 Proxy);改写(`updatedInput` 等)只放可克隆纯数据。
2771
3226
  不合 ⇒ 接手即拒(工具不执行)。本服务自身的策略 / hook 全是字面对象或展开(亲核),部署自写的 `ToolPolicy`(嵌入方)按此自查。
2772
3227
  **委派**:祖先层一次「是」只覆盖它答过的类 —— 子代门查到更严的类(写保护、根外读)会再出一张卡;带出网 / 不可逆标记的工具在委派下首卡即
2773
- `operator_forced`(`bypassPermissions` 不放它)。持久 ask 店车道(流内审批协议上场的部署)上第二张卡同样出卡(S-944,见下一条)。
2774
- - **🔴 安全轴(S-944):持久 ask 店车道上的 askId 身份含这一问的类集**。委派下同一调用的第二张卡(类集不同)自本版是**新问**:新行、出自己的卡、
3228
+ `operator_forced`(`bypassPermissions` 不放它)。持久 ask 店车道(流内审批协议上场的部署)上第二张卡同样出卡(见下一条)。
3229
+ - **🔴 安全轴:持久 ask 店车道上的 askId 身份含这一问的类集**。委派下同一调用的第二张卡(类集不同)自本版是**新问**:新行、出自己的卡、
2775
3230
  等人答这一问 —— 此前它与首卡同 askId,被首卡的「是」回放。同一调用同类集的重试照旧幂等。**行为面(收紧)**:会话授权(`allow_session` /
2776
3231
  耐久 `remember:"session"`)不再代答「这次调用在这条腿上已出过卡」的后续问(同一调用的另一类集问)—— 出卡,人答。**wire 值变更**:不透明 `askId`(呈卡帧、
2777
3232
  `POST /v1/tasks/:taskId/asks/:askId/decision`)对同一调用的取值与 ≤7.108.0 不同(形不变,64 位 hex);持久 `approval_ask.ask_id` 主键的派生同变,
@@ -2781,25 +3236,25 @@
2781
3236
  会话授权(live `allow_session` / 耐久 `remember:"session"`)**不会**替它代答 —— 一揽子放行的复核按**调用**读(这次调用在这条腿上有任何行,
2782
3237
  含旧派生写的人拒 / 挂着的卡 ⇒ 不短路),与 ask 身份无关。**迁移**:自建 `StoreBackend`(不走 `createStoreBackend`)的嵌入方须实现 `ApprovalAskStore.listByCall`(类型面硬破坏,tsc 红即通知);部署零 DDL、零数据迁移。**滚动升级**:混版窗内旧版副本接管本版写过的腿读不到新派生行(反向),
2783
3238
  与 7.107.0 段「持久面反向不兼容边界」同一处置:同一存储上不要让旧版实例接管本版在跑的腿。
2784
- - **leader worker 的增量上传循环随 env 收尾(S-949,P1;嵌入方 / 夹具可见)**:worker `executionEnvFactory` 交出的 env 若**没有 `destroy()`**,工厂当场拒收(与集成沙箱 / grader 同一道闸;生产三车道 e2b / k8s / host 都有);stage 末步起循环、finalize 首步停循环(先于 belt 与真 destroy,等每一代退出 ≤30 s),循环的每次上传带 `curl --max-time 25`;工作区多出 `.leader-upload-loop.sh` / `.gen` / `.seq` / `.pid.<代>`(无凭据)。**迁移**:自建 worker env 的嵌入方补 `destroy()`;依赖「循环与 belt 并跑」时序的无;收尾每 worker 常态多 ≤1–2 s(等循环下一拍退出),上界 = stop 等待 30 s(循环正卡在一次上传上时)。已知边界:S-950(e2b 车道循环是否真活着未核)/ S-951(stop 超界残余窗)。
2785
- - **目录条目 `headers` 两条读腿打通(S-935,settings-schema 6.4.0)**:`config.d/models.json` 与配置中心写的 `models[].headers` 自本版起到达目录(7.108.0 被读腿剥掉)。
3239
+ - **leader worker 的增量上传循环随 env 收尾(P1;嵌入方 / 夹具可见)**:worker `executionEnvFactory` 交出的 env 若**没有 `destroy()`**,工厂当场拒收(与集成沙箱 / grader 同一道闸;生产三车道 e2b / k8s / host 都有);stage 末步起循环、finalize 首步停循环(先于 belt 与真 destroy,等每一代退出 ≤30 s),循环的每次上传带 `curl --max-time 25`;工作区多出 `.leader-upload-loop.sh` / `.gen` / `.seq` / `.pid.<代>`(无凭据)。**迁移**:自建 worker env 的嵌入方补 `destroy()`;依赖「循环与 belt 并跑」时序的无;收尾每 worker 常态多 ≤1–2 s(等循环下一拍退出),上界 = stop 等待 30 s(循环正卡在一次上传上时)。已知边界:e2b 车道循环是否真活着未核 / stop 超界残余窗。
3240
+ - **目录条目 `headers` 两条读腿打通(settings-schema 6.4.0)**:`config.d/models.json` 与配置中心写的 `models[].headers` 自本版起到达目录(7.108.0 被读腿剥掉)。
2786
3241
  **行为面**:秘密形的头值(形似令牌 / 密钥)在 schema 自由形安全闸即让条目不可用(拒因字段整键 `headers`)。**迁移**:零动作。
2787
- - **🔴 迁移窗口(core #1213;core 7.38.0 发车帖把它改期到 **7.39.0**)**:core 7.39.0 删掉旧检查点行的一次性迁移、并**拒续跑**仍带旧模式键(`autoModeRequested` / `approverPosture` /
3242
+ - **🔴 迁移窗口(core 7.38.0 发车帖把它改期到 **7.39.0**)**:core 7.39.0 删掉旧检查点行的一次性迁移、并**拒续跑**仍带旧模式键(`autoModeRequested` / `approverPosture` /
2788
3243
  doctrine `shellGate`)的行。这类行只可能是 **server ≤7.105.0(core ≤7.33.8)时期停放、至今仍 pending** 的行 —— server 7.106.0(core 7.35.2)起写的行
2789
3244
  与在 7.106.0+ 上续跑过一次的行都已是新形。**在升到提货 core 7.39.0 的 server 版本之前**(7.110.0 提货 core 7.38.0 仍迁移、不拒),把这些行答完或放弃:
2790
3245
  列表 = `GET /v1/approvals`(运维队列;`createdAt` 早于本部署升到 server 7.106.0 那一刻的行)与 `GET /v1/assistant/inbox`;
2791
3246
  决定口 = 工具审批 `POST /v1/approvals/:id/decide`(`:id` = sessionId,体 `{ "decision": "approve" | "deny" }`)、计划审阅
2792
3247
  `POST /v1/assistant/tasks/:id/plan_review`、资源停车续跑 `POST /v1/assistant/tasks/:id/resume`。本版(core 7.37.x)上续跑这类行仍会迁移一次再继续。
2793
3248
  本服务不读、也不判这几个旧键(那是 core 的私有迁移面),只按停放时间给出区间。
2794
- ## 7.108.0(车SI,S-919 / S-929 / S-930 / S-920;车SJ,S-931 / S-925 / S-922 / S-921)—— `@sema-agent/core` 7.36.0 不变:按名策略臂读 core 名字全集 · 有序关停 settle 活卡 · 自助抹除口码表补齐 · 目录条目 `headers` · 出站建连失败通告 · side-query `errorMessage` 脱敏
3249
+ ## 7.108.0(车SI;车SJ)—— `@sema-agent/core` 7.36.0 不变:按名策略臂读 core 名字全集 · 有序关停 settle 活卡 · 自助抹除口码表补齐 · 目录条目 `headers` · 出站建连失败通告 · side-query `errorMessage` 脱敏
2795
3250
 
2796
- - **🔴 安全轴(S-919):本仓收紧方向的按名策略臂(`APPROVAL_DENY` / `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` / commandPolicy ask 表 / 治理 shell 标 / durable 问题门 /
3251
+ - **🔴 安全轴:本仓收紧方向的按名策略臂(`APPROVAL_DENY` / `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` / commandPolicy ask 表 / 治理 shell 标 / durable 问题门 /
2797
3252
  supervisor 危险门 / workflow 问与 plan 拒)读 core `ruleNamesOf(req)` 全集,任一名命中即算命中。**只影响**经 `resolveSpec` 席挂引擎名别名的嵌入方工具(`MyShell{aliases:["Bash"]}`):
2798
3253
  修前模型按别名调它一个门都不拦,修后照拦照问。**迁移**:要让某只工具不被某条名单够到,别给它挂那条名单里的引擎名作别名;规则归因 `matchedAskRule` 写命中的那个名。
2799
- - **wire 值(S-929):`GET /v1/approvals` 的 `crashConverged[].cause` 从单值 `"crashed_before_park"` 变闭集 `"crashed_before_park" | "shutdown_before_park"`**(有序关停宽限窗满仍未闭的已批腿;
3254
+ - **wire 值:`GET /v1/approvals` 的 `crashConverged[].cause` 从单值 `"crashed_before_park"` 变闭集 `"crashed_before_park" | "shutdown_before_park"`**(有序关停宽限窗满仍未闭的已批腿;
2800
3255
  `orphanState` / `resumeSafe` 判据同形,`shutdown_before_park` 常态 `decided`、`pending` 形只在故障下出现 —— 持久 ask 店 claim 挂住,或 park 路由的停车行到宽限窗满仍未提交)。
2801
3256
  **迁移**:消费方按 `orphanState` / `resumeSafe` 分桶,不按 `cause` 单值判。**消费方版本约束**:client-core ≤0.82.7 的行校验 `cause !== 'crashed_before_park'` 把新词行计进
2802
- `dropped`(cli 渲「could not be read」,fail-safe、不自动续跑);配套 = client-core 认领 CC-218 的那一版(放宽为两值)。审计账本 settle 行 additive `cause:"shutdown_before_park"` + 第六个记录种类 `interrupted_by_shutdown`。
3257
+ `dropped`(cli 渲「could not be read」,fail-safe、不自动续跑);配套 = client-core 认领这一变化的那一版(放宽为两值)。审计账本 settle 行 additive `cause:"shutdown_before_park"` + 第六个记录种类 `interrupted_by_shutdown`。
2803
3258
  **回滚约束**:回滚到 ≤7.107.0 后,本版写下的 `interrupted_by_shutdown` 行在旧二进制上计 `corruptLines`、boot 那一行 `approval_ask_audit_crash_converged` warn 会响
2804
3259
  (无害:旧读者跳过坏行,settle 行多出的 `cause` 键被忽略)。**park 政策下**:有序关停时握着未决卡的 run 落 `done(suspended)`(修前进程退出把它截断在 running,
2805
3260
  由下一次 boot 收成崩溃孤儿)—— 轮询 run 终态的消费方会看到 suspended,可经 `/v1/approvals/:sessionId/decide` 事后决议。
@@ -2808,19 +3263,19 @@
2808
3263
  下一次 boot 照样列成 pending 孤儿(与崩溃同路;子代(未被追踪腿)卡的腿闭证据不由宿主腿提供 —— 重放的腿证据只对 `legTracked` 行作数;`backend.close()` 排在店的在飞 `put` 静默之后)。
2809
3264
  **`UNATTENDED_APPROVAL_POLICY=deny` 的部署**:有序重启时未决卡当场按部署政策拒、腿带着拒绝再跑至多 10s(模型可能把 run 收成 `completed`),该卡不再出现在
2810
3265
  `crashConverged`(修前是 `crashed_before_park` / pending / `resumeSafe:true`)—— 要事后决议就改 `park` 政策,或在排空窗内答完。
2811
- - **wire 值(S-930):`POST /v1/sessions/:id/memory/erase` 的四种 core 失败形从 500 `internal.error` 改为与 operator 面同码同状态**(409 `memory.erasure_selector_mismatch` /
3266
+ - **wire 值:`POST /v1/sessions/:id/memory/erase` 的四种 core 失败形从 500 `internal.error` 改为与 operator 面同码同状态**(409 `memory.erasure_selector_mismatch` /
2812
3267
  `memory.erasure_evidence_unavailable` / `memory.erasure_census_incomplete`;500 `internal.memory_control_plane_corrupt` 固定句)。**迁移**:按「自助抹除失败恒 500」写死的调用方改按 `errorCode` 分支;
2813
3268
  sdk 15.0.0 的 🚧 live 表征钉随 15.0.1 翻 409。
2814
- - **目录条目 +1 键(S-931):`models[].headers`**(闭集白名单,今天只 `anthropic-beta`、只在 `api: "anthropic-messages"` 条目;表外 / 线路不读 / 值不合形 ⇒ 条目不可用
3269
+ - **目录条目 +1 键:`models[].headers`**(闭集白名单,今天只 `anthropic-beta`、只在 `api: "anthropic-messages"` 条目;表外 / 线路不读 / 值不合形 ⇒ 条目不可用
2815
3270
  `[config.model_entry_invalid]` fields `headers.<名>`)。**⚠️ 本版半场**:settings-schema 6.3.0 读腿剥未知键 ⇒ 经生产配置通道写的 `headers` 到不了目录(只有 LKG / 手写 effective 到得了),
2816
- settings-schema 6.4.0 + server 7.109.0 打通(S-935)。**迁移**:零动作;要今天就用,走 effective 直写通道并接受读腿告警。
2817
- - **通告码 +1(S-925):user 受众 `server.model_unreachable`**(`engine_notice` 帧 / 账本行,先于 `done`;`detail = { code, targetHost, proxyInUse?, remedy, sessionId }`;每腿每目标一次;
2818
- 腿里的辅助模型调用同判 —— 帧说的是端点够不着,不是 run 失败)。**迁移**:按 `code` 渲染的消费方零动作;经 client-core 按受众分发的端在 client-core 镜像 +1 行(0.86.x)前看不到它(S-933,core 7.38.0 入册后两边镜像退役)。
3271
+ settings-schema 6.4.0 + server 7.109.0 打通。**迁移**:零动作;要今天就用,走 effective 直写通道并接受读腿告警。
3272
+ - **通告码 +1:user 受众 `server.model_unreachable`**(`engine_notice` 帧 / 账本行,先于 `done`;`detail = { code, targetHost, proxyInUse?, remedy, sessionId }`;每腿每目标一次;
3273
+ 腿里的辅助模型调用同判 —— 帧说的是端点够不着,不是 run 失败)。**迁移**:按 `code` 渲染的消费方零动作;经 client-core 按受众分发的端在 client-core 镜像 +1 行(0.86.x)前看不到它(core 7.38.0 入册后两边镜像退役)。
2819
3274
  运维面另 +1 日志行 `outbound_connect_failed`(代理只报变量名)与 `GET /v1/diagnostics/wiring` 的 `outbound` 段。
2820
- - **wire 值(S-922):`POST /v1/side-query` 200 体 `errorMessage` 过 `redactErrorMessage`**(键不变;服务商错误体里的密钥形换 `«redacted»`)。**迁移**:按原样错误体做字符串匹配的调用方改比错误码。
2821
- - **零动作(S-921 / S-920)**:披露改真与明拒行保鲜钉,无行为变化。
3275
+ - **wire 值:`POST /v1/side-query` 200 体 `errorMessage` 过 `redactErrorMessage`**(键不变;服务商错误体里的密钥形换 `«redacted»`)。**迁移**:按原样错误体做字符串匹配的调用方改比错误码。
3276
+ - **零动作**:披露改真与明拒行保鲜钉,无行为变化。
2822
3277
 
2823
- ## 7.107.0(车SE,S-907 / S-890;车SF)—— `@sema-agent/core` 7.36.0:post 钩子收 wire 名 · 双引擎名声明拒 · 工具调用 id 越界折叠(服务商拿回原串)· 两只恒真能力位删
3278
+ ## 7.107.0(车SE;车SF)—— `@sema-agent/core` 7.36.0:post 钩子收 wire 名 · 双引擎名声明拒 · 工具调用 id 越界折叠(服务商拿回原串)· 两只恒真能力位删
2824
3279
 
2825
3280
  - **🔴 hooks:PostToolUse / PostToolUseFailure 的 matcher 与 payload `tool_name` 改为调用派发到的工具的 wire 名**(此前是模型拼写;PreToolUse 本来就是 wire 名)。
2826
3281
  按工具**别名**写的 post matcher(及条目 `if` 条件的名部)不再命中(只影响执行后面,不放宽任何决定)。**迁移**:matcher 写 wire 名;滚动升级期两名都写(本服务不做双读)。
@@ -2834,16 +3289,16 @@
2834
3289
  **零动作**(join 照旧成立);与服务商日志对账的运维读 `wireId`,或服务端结构化日志 `engine_notice` `route.tool_call_id_folded`(每 run 一行,operator 受众,不上会话流)。
2835
3290
  升级前已 park 的行以原串为键,新版 resume 不再折叠(askId 不变、卡照旧可答)。
2836
3291
  - **耐久停车行 `pendingAction.names` 的序改「拼写先」**(门判定那张脸)。本服务任何 wire 面都不投 `names`;只影响直读店行(SQL `checkpoint` 列 / local 检查点文件)的工具 —— 按 `names[0]` 猜 wire 名的改读 `toolName`。
2837
- - **🔴 wire(能力面,车SF S-899):`GET /v1/capabilities` 的 `modeShellGateTranslation` 与 `permissionModeAuto.intentArming` 删**(两位 7.106.0 起恒 `true`,零信息)。
3292
+ - **🔴 wire(能力面,车SF):`GET /v1/capabilities` 的 `modeShellGateTranslation` 与 `permissionModeAuto.intentArming` 删**(两位 7.106.0 起恒 `true`,零信息)。
2838
3293
  **迁移**:壳不再按 `modeShellGateTranslation` 决定是否注 `MANUAL_MODE_SHELL_GATE`(缺席不是「老 server」;直接不注);`intentArming` 的读者改读 `armed` / `reason`。**真实后果**:已发布 cli ≤1.0.139 的引擎附着门把缺席读成旧引擎 ⇒ 同机多安装下 headless `-p` 拒复用 ≥7.107.0 引擎、交互车道误报一行(fail-closed 有出路:停那台引擎或升级较旧的 cli 安装 ≥1.0.140);sdk 14.0.0 仍把 `intentArming` 写成必填(门 6 红在围栏头校准 7.106.0),随 sdk 14.1.0 删两位 + 抬围栏头。
2839
- - **请求面模式词表(S-902)**:五词受理集不变、`dontAsk` 仍 400 `request.field_invalid`;三处 400 拒句里的词序改随 core `PERMISSION_MODES` 序(文案值变、码不变)—— 按字节比对拒句的测试改比码。
3294
+ - **请求面模式词表**:五词受理集不变、`dontAsk` 仍 400 `request.field_invalid`;三处 400 拒句里的词序改随 core `PERMISSION_MODES` 序(文案值变、码不变)—— 按字节比对拒句的测试改比码。
2840
3295
 
2841
- ### 升级须知补三条(S-923 + 合并复审)
3296
+ ### 升级须知补三条(含合并复审)
2842
3297
  - **工具名帧的拼写**:fresh 腿 `tool_start` / `tool_end.toolName` 是模型拼写(与 7.106.0 同);升级前 park 的行续跑仍给 wire 名(`names` wire 名在先);**只有 7.107.0 起按别名 park 的调用**续跑帧改给拼写。壳按 `toolCallId` join,不按帧的 `toolName` 归一;要 wire 名读 PreToolUse / post 钩子上下文的 `toolName`、`wiring_manifest.tools` 名册或停车行 `pendingAction.toolName`(帧不能反推)。
2843
3298
  - **把引擎手工具名挂成别名的嵌入方**(`aliases:["Read"]` 一类):中断调用按较不安全效应判、效应面按较不安全效应记(只在该名挂载不重登效应时)、结果预算不再豁免、微压缩清理不再达它(上下文可能变大)—— 升级前排空这类声明下的 park,或接受更保守判定;一只名字属于两只引擎工具的声明在 prepare 被拒(`config.tool_face_invalid`),已 park 的调用续跑不动,改声明后重试。
2844
- - **持久面反向不兼容边界(回滚 / 共享存储混版)**:7.107.0(core 7.36.0 #1207)起,服务商给的**越界** tool-call id(字符集外或 >128)在转录 / 检查点里落**折叠形**,原串只在同行 `wireId`;≤7.106.0 的实例(core 7.35.2)不读 `wireId`,续跑这类会话时会把折叠 id 发回网关 ⇒ 要求回传原 id 的网关拒绝后续请求(在形 id 零差异,不受影响;7.35.2 的 pre-CAS 复核按 `names` 先读拼写、取座可能不同)。**约束**:同一存储上不要让 ≤7.106.0 实例接管 7.107.0 已写过折叠 id 的会话;回滚前排空这类会话(会话 `messages[]` 里出现 `wireId` 的行即受影响),或接受重开。
3299
+ - **持久面反向不兼容边界(回滚 / 共享存储混版)**:7.107.0(core 7.36.0)起,服务商给的**越界** tool-call id(字符集外或 >128)在转录 / 检查点里落**折叠形**,原串只在同行 `wireId`;≤7.106.0 的实例(core 7.35.2)不读 `wireId`,续跑这类会话时会把折叠 id 发回网关 ⇒ 要求回传原 id 的网关拒绝后续请求(在形 id 零差异,不受影响;7.35.2 的 pre-CAS 复核按 `names` 先读拼写、取座可能不同)。**约束**:同一存储上不要让 ≤7.106.0 实例接管 7.107.0 已写过折叠 id 的会话;回滚前排空这类会话(会话 `messages[]` 里出现 `wireId` 的行即受影响),或接受重开。
2845
3300
 
2846
- ## 7.106.0(车QY,S-877 / S-881)—— `@sema-agent/core` 7.35.2(7.35.0 的全部变更 + #1206 新会话锁 + 看门狗 30s 等待披露):一只权限模式 · `approverPosture` / `taskApproverPosture` 删 · `MANUAL_MODE_SHELL_GATE=classify` 拒启 · 宿主子进程 env 按 CC 形剥(git 配置族与代理族原样到达)
3301
+ ## 7.106.0(车QY)—— `@sema-agent/core` 7.35.2(7.35.0 的全部变更 + 新会话锁 + 看门狗 30s 等待披露):一只权限模式 · `approverPosture` / `taskApproverPosture` 删 · `MANUAL_MODE_SHELL_GATE=classify` 拒启 · 宿主子进程 env 按 CC 形剥(git 配置族与代理族原样到达)
2847
3302
 
2848
3303
  - **🔴 wire:提交体 `approverPosture` 删,零别名。** 仍带它 ⇒ 400 `request.body_shape`(`unknownKeys:["approverPosture"]`)。**迁移**:删掉这个键;要「宿主自动答卡」的效果用
2849
3304
  `permissionMode`(`acceptEdits` / `bypassPermissions`,后者在托管部署上 422 `request.host_posture_refused`)。能力位 `taskApproverPosture` 同删 —— 读它的探测改读 `taskWriteFaceOpen`
@@ -2858,7 +3313,7 @@
2858
3313
  也被拒(core 路径拒座把 `cp` 的源也按写目标判,与 CC 同形),升级前照跑 —— 补偿 = 旋钮 `acceptEdits|default` + 审批席,或用读工具取内容。
2859
3314
  🔴 **宽于升级前的六类**:根外读探针(`probe`)、MCP / A2A 工具标记、transcript 写、`rule_unreadable`(**规则店读不出时照放** —— 安全轴 fail-open 方向)、
2860
3315
  `artifact_shared_read` —— 升级前这些腿上照问(无人答 ⇒ 拒),缺省旋钮下被释放。**补偿**:`UNATTENDED_PERMISSION_MODE=acceptEdits|default`,或给腿配审批席。
2861
- 想更严设 `acceptEdits` / `default` / `dontAsk`,拼错即拒启。⚰️ **7.109.0 起旋钮退役(设了即拒启),这些腿改按类作答 —— 见 7.109.0 段。** **过渡形**:`UNATTENDED_PERMISSION_MODE` 与写保护派生 deny 行是 7.106.0 过渡形;core 7.37.0 到货后(S-906,`AskRequest.askClass?` / `classes?`)退成 `default` + onAsk 按类作答,并硬删旋钮(拒启点名)—— 已于 7.109.0 兑现。客户端 `bypassPermissions` 不再放掉部署治理层(commandPolicy / 敏感写守卫)的 ask。`config.tool_mount_denied` 的 HTTP 档仍 400。
3316
+ 想更严设 `acceptEdits` / `default` / `dontAsk`,拼错即拒启。⚰️ **7.109.0 起旋钮退役(设了即拒启),这些腿改按类作答 —— 见 7.109.0 段。** **过渡形**:`UNATTENDED_PERMISSION_MODE` 与写保护派生 deny 行是 7.106.0 过渡形;core 7.37.0 到货后(`AskRequest.askClass?` / `classes?`)退成 `default` + onAsk 按类作答,并硬删旋钮(拒启点名)—— 已于 7.109.0 兑现。客户端 `bypassPermissions` 不再放掉部署治理层(commandPolicy / 敏感写守卫)的 ask。`config.tool_mount_denied` 的 HTTP 档仍 400。
2862
3317
  - **会话授权(`remember:"session"` / `allow_session`)对引擎的问也生效**:同会话下一次同工具不再出卡(Write / 非只读 Bash 在 `default` 下同此;
2863
3318
  需要审批席 —— `TOOL_APPROVAL_ENABLED` 开,不要活卡再配 `STREAM_ASK_WINDOW_MS=0`)。`APPROVAL_NEVER_AUTO` / 耐久预算耗尽 / **治理层**
2864
3319
  (`runtime.commandPolicy` 的 ask、`AUTONOMY` 折出的门、敏感写守卫集)的卡改成强制卡(`mandated:true`、`ruleOffersAbsence:"mandated"`,此前 `"shadowed"`),
@@ -2884,67 +3339,67 @@
2884
3339
  引擎按 `default` 跑:这条 worker 每一次写 / 非只读命令再问一次(durable 部署上再 park,fail-closed,无人值守的 worker 卡住等人)。
2885
3340
  没有 leader worker park 的部署零动作;已升级才发现的,逐条答完那些新卡即可(不会放宽)。
2886
3341
 
2887
- ## 7.106.0(车QU,S-795 + S-810)—— 降级壳凭据按 boot 身份取值 · 部分应用的拍也签重启
3342
+ ## 7.106.0(车QU)—— 降级壳凭据按 boot 身份取值 · 部分应用的拍也签重启
2888
3343
 
2889
- - **行为面:反应式降级壳里目标的自有凭据按 boot 那一代的身份取值(S-795)。** 同名 env 变量换值照旧热;降级目标在目录里**换 key 的名字 / 重贴托管密钥**
3344
+ - **行为面:反应式降级壳里目标的自有凭据按 boot 那一代的身份取值。** 同名 env 变量换值照旧热;降级目标在目录里**换 key 的名字 / 重贴托管密钥**
2890
3345
  要重启才进壳 —— `/health.restart.reasons` 会带 `degrade-route` 告诉编排器(托管密钥重贴 7.103.1 起不签,现在签)。候选部分应用(某组被整组拒)的拍现在
2891
- 同样会签(S-810),但审批组 / 模型面组被拒的拍扣下(重启可能起不来),只出 warn `restart_signal_withheld_boot_may_refuse`。**迁移**:无需改配置;按信号
3346
+ 同样会签,但审批组 / 模型面组被拒的拍扣下(重启可能起不来),只出 warn `restart_signal_withheld_boot_may_refuse`。**迁移**:无需改配置;按信号
2892
3347
  重启即可;盯着这条 warn 修被拒的组。
2893
3348
 
2894
- ## 7.106.0(车QR,S-866 云模式波 B)—— 给了 SQL 坐标而没有腿会用它 ⇒ 拒启(点名 `DB_BACKEND` / `SESSION_BACKEND` 出路)· caps 顶层 `sql` 并入 `store.sql` · 目录七行座位与 `center.domainExists` 删除 · 多租租约连接级失败默认 503
3349
+ ## 7.106.0(车QR,云模式波 B)—— 给了 SQL 坐标而没有腿会用它 ⇒ 拒启(点名 `DB_BACKEND` / `SESSION_BACKEND` 出路)· caps 顶层 `sql` 并入 `store.sql` · 目录七行座位与 `center.domainExists` 删除 · 多租租约连接级失败默认 503
2895
3350
 
2896
- - **🔴 行为面:给了 SQL 坐标而没有任何腿会用它 ⇒ 配置期拒启(S-866 ⑤b)。** 命中三形(修前都在**静默跑内存**):只设 `MYSQL_HOST` 而不设
3351
+ - **🔴 行为面:给了 SQL 坐标而没有任何腿会用它 ⇒ 配置期拒启。** 命中三形(修前都在**静默跑内存**):只设 `MYSQL_HOST` 而不设
2897
3352
  `SESSION_BACKEND` / `DB_BACKEND`;只设 `PG_HOST` 而不设 `SESSION_BACKEND` / `DB_BACKEND`;只设 `PG_HOST` + `SESSION_BACKEND=auto`(引擎缺省 mysql,
2898
3353
  PG 坐标没人用)。坐标被用到的形(`SESSION_BACKEND=mysql|auto` + MYSQL 坐标)不受影响。**迁移**:按拒句点名的出路改 —— 要持久 `DB_BACKEND=pg|mysql`;
2899
3354
  要内存 去掉坐标或 `DB_BACKEND=memory`;要尽力而为 `SESSION_BACKEND=auto` 配对的 `DB_BACKEND`。
2900
- - **🔴 wire:`GET /v1/capabilities` 顶层 `sql` 删除,零别名(S-866 ①)。** 对象逐字搬进新键 `store.sql`(`store` = `{declared, backend, durable,
3355
+ - **🔴 wire:`GET /v1/capabilities` 顶层 `sql` 删除,零别名。** 对象逐字搬进新键 `store.sql`(`store` = `{declared, backend, durable,
2901
3356
  degradedReason?, sql?}`,附录 B)。**迁移**:读 `capabilities.sql` 的消费端改读 `capabilities.store?.sql`;`null` 那一义拆成 `store.backend`
2902
3357
  (`memory` / `local` / 降级)与 `store.sql` 缺席。
2903
- - **🔴 wire:`GET /v1/config/catalog` 七行失去中心座位,全部行失去 `center.domainExists`(S-866 ⑤a)。** readFace 四键 / `PERMISSIONS_DISABLE_AUTO_MODE` /
3358
+ - **🔴 wire:`GET /v1/config/catalog` 七行失去中心座位,全部行失去 `center.domainExists`。** readFace 四键 / `PERMISSIONS_DISABLE_AUTO_MODE` /
2904
3359
  `MODEL_DEGRADE_ON` / `MODEL_DEGRADE_REACTIVE` 不再带 `center` / `centerDomain` / `centerPath`,`writeLanes` 恒 `["env"]`;中心在管 models 时
2905
3360
  `summary.centerManaged` −2。**迁移**:删掉读 `center.domainExists` 的分支 —— 有 `center` 块 ⇔ 中心可写。
2906
- - **行为面:多租部署(`REQUIRE_PRINCIPAL=true`)的租约连接级失败默认 503(S-866 ③)。** 新旋钮 `FLEET_LEASE_FAIL_CLOSED` 缺省随姿态派生(多租 true /
3361
+ - **行为面:多租部署(`REQUIRE_PRINCIPAL=true`)的租约连接级失败默认 503。** 新旋钮 `FLEET_LEASE_FAIL_CLOSED` 缺省随姿态派生(多租 true /
2907
3362
  单用户 false):中心拒了本引擎的凭证、凭证文件读不出、中心不可达 / 5xx / 超时 / 坏体(以及中心答 404 / 429 / 3xx 这类 200 / 409 / 4xx 凭证码之外的状态)时,计费入口答 **503 `fleet.lease_unavailable`**(新族
2908
3363
  `fleet.`,`Retry-After` 5,体 `reason`)而不是静默放行。**迁移**:要保留 7.105.0 的放行姿态就显式 `FLEET_LEASE_FAIL_CLOSED=false`;SDK / 壳把
2909
3364
  `fleet.lease_unavailable` 当可重试。
2910
- - **行为面:接了中心而不设 `FLEET_ADVERTISE_ADDRESS` 的引擎开始上报用量(S-866 ④)。** 中心三件齐即每 60s `POST /api/fleet/usage`(不注册、不心跳)。
3365
+ - **行为面:接了中心而不设 `FLEET_ADVERTISE_ADDRESS` 的引擎开始上报用量。** 中心三件齐即每 60s `POST /api/fleet/usage`(不注册、不心跳)。
2911
3366
  不想报就不配中心三件。
2912
3367
 
2913
- ## 7.106.0(车QV,S-891)—— 会话规则 SQL 店:抹除遇计数读不出的行照删,那把键被封、要人恢复
3368
+ ## 7.106.0(车QV)—— 会话规则 SQL 店:抹除遇计数读不出的行照删,那把键被封、要人恢复
2914
3369
 
2915
3370
  - **行为面(只影响库被列外改过的 `DB_BACKEND=mysql|pg` 部署)。** 会话删除 / 2c `overwrite-dst` 抹除到一行计数读不出的 `session_policy`
2916
3371
  行时不再拒 `corrupt`(7.105.0 的半程停),而是照删并**封键**:那把 `(session, principal)` 键之后的读和写都答 500 `corrupt`(与删之前同答;
2917
3372
  这个 principal 在该会话上的新任务拒起,含该会话的 2c 导出),日志一条 `session_policy_erase_sealed_keys` 点名它。**迁移**:按 `USAGE.md` §9.11
2918
3373
  「显式恢复」原地解封那条 `session_policy_rev_mark` 行(`rev` 归 0、`gen` + 1;不要删它);没有坏行的部署零动作。
2919
3374
 
2920
- ## 7.106.0(车RA,S-895 / S-896 / S-897 / S-904 / S-885)—— 模型钥匙缺席不再借网关钥匙 · settings 权限桶超帽 / 坏项响亮拒 · SUP 路由的问带部署出身 · 新请求键 `inheritEnv` · 目录 `retired[]`
3375
+ ## 7.106.0(车RA)—— 模型钥匙缺席不再借网关钥匙 · settings 权限桶超帽 / 坏项响亮拒 · SUP 路由的问带部署出身 · 新请求键 `inheritEnv` · 目录 `retired[]`
2921
3376
 
2922
- - **🔴 行为面:目录条目声明了 `apiKeyEnv` 而进程里没有这个变量 ⇒ 该模型钥匙中毒(S-896)。** 修前静默回落网关钥匙(别家服务的钥匙可能被送到错的端点);修后打这个模型的任务 `failed`、句点名变量名、网关钥匙零字节,`GET /v1/models` 配对标注 `unknown`,起服不受影响。**迁移**:给进程设上那个变量,或从条目删掉 `apiKeyEnv`(走网关钥匙就别声明)。包根类型面 `ModelKeyPoison*` 改名(零别名,tsc 红即通知)。
2923
- - **🔴 行为面:`settings.permissions.allow / deny / ask` 超过 1000 条或含非串 / 空串项 ⇒ 400 `request.field_invalid`(S-904)。** 修前静默截到 1000 条、静默丢坏项(仓库层写上千条规则就能把排在后面的托管 deny 挤出引擎视野);修后 fresh 面 400,体带 `field` / `reason`(`over_cap` | `bad_entry`)/ `count` + `cap` 或 `index`;续跑腿照判 ⇒ 409 `resume_blocked_by_policy` + `blockedBy` + 同组字段。**迁移**:合并规则前按桶去重、控制在 1000 条内;壳按 `errorCode` + `reason` 出句。
2924
- - **行为面:编排路由判到 supervisor 的 shell / 写工具问带 `authoredBy:"deployment"`(S-897;clay 裁定「supervisor 路由的 always 像部署治理钉一样打治理位」)。** 只在 `ROUTER_ENABLED` 开且判到 supervisor 时:这些问变成强制问(卡与 park 行 `mandated:true`),「本会话放行」退不掉、`auto` 下分类器不再替答、`bypassPermissions` 不再放行。**迁移**:无;壳侧 KNOWN-LIMITS 里「SUP 单个强制词被放行」的例外句可删。
2925
- - **additive:请求键 `inheritEnv: "all" | "scrub"`(S-895)** —— host 车道 ∧ 单用户部署(读数 `capabilities.projectContext`)才兑现 `"all"`;托管 × `"all"` ⇒ 422 `request.host_posture_refused`;非 host 车道 × `"all"` / 词表外 ⇒ 400 `request.field_invalid`(`"scrub"` 是缺省,任何车道受理);缺席 = 清洗且清掉该会话上一条声明。7.105.0 及以前发它 ⇒ 400 `request.body_shape`,壳按服务端版本闸发。
2926
- - **additive:`GET /v1/config/catalog` 顶层 `retired[]`(S-885)** —— 恒在场,从 `RETIRED_ENVS` 同一张表派生;包根只读导出 `RETIRED_ENVS`。消费端删手抄退役名单改读它。
3377
+ - **🔴 行为面:目录条目声明了 `apiKeyEnv` 而进程里没有这个变量 ⇒ 该模型钥匙中毒。** 修前静默回落网关钥匙(别家服务的钥匙可能被送到错的端点);修后打这个模型的任务 `failed`、句点名变量名、网关钥匙零字节,`GET /v1/models` 配对标注 `unknown`,起服不受影响。**迁移**:给进程设上那个变量,或从条目删掉 `apiKeyEnv`(走网关钥匙就别声明)。包根类型面 `ModelKeyPoison*` 改名(零别名,tsc 红即通知)。
3378
+ - **🔴 行为面:`settings.permissions.allow / deny / ask` 超过 1000 条或含非串 / 空串项 ⇒ 400 `request.field_invalid`。** 修前静默截到 1000 条、静默丢坏项(仓库层写上千条规则就能把排在后面的托管 deny 挤出引擎视野);修后 fresh 面 400,体带 `field` / `reason`(`over_cap` | `bad_entry`)/ `count` + `cap` 或 `index`;续跑腿照判 ⇒ 409 `resume_blocked_by_policy` + `blockedBy` + 同组字段。**迁移**:合并规则前按桶去重、控制在 1000 条内;壳按 `errorCode` + `reason` 出句。
3379
+ - **行为面:编排路由判到 supervisor 的 shell / 写工具问带 `authoredBy:"deployment"`(clay 裁定「supervisor 路由的 always 像部署治理钉一样打治理位」)。** 只在 `ROUTER_ENABLED` 开且判到 supervisor 时:这些问变成强制问(卡与 park 行 `mandated:true`),「本会话放行」退不掉、`auto` 下分类器不再替答、`bypassPermissions` 不再放行。**迁移**:无;壳侧 KNOWN-LIMITS 里「SUP 单个强制词被放行」的例外句可删。
3380
+ - **additive:请求键 `inheritEnv: "all" | "scrub"`** —— host 车道 ∧ 单用户部署(读数 `capabilities.projectContext`)才兑现 `"all"`;托管 × `"all"` ⇒ 422 `request.host_posture_refused`;非 host 车道 × `"all"` / 词表外 ⇒ 400 `request.field_invalid`(`"scrub"` 是缺省,任何车道受理);缺席 = 清洗且清掉该会话上一条声明。7.105.0 及以前发它 ⇒ 400 `request.body_shape`,壳按服务端版本闸发。
3381
+ - **additive:`GET /v1/config/catalog` 顶层 `retired[]`** —— 恒在场,从 `RETIRED_ENVS` 同一张表派生;包根只读导出 `RETIRED_ENVS`。消费端删手抄退役名单改读它。
2927
3382
 
2928
- ## 7.105.0(车QQ 部分)—— 门前三族只读路要凭据(S-672)· 会话规则写口拒退役 / 无前缀工具名(S-800)· `ServiceDeps.runnerFor` 必填(S-175)
3383
+ ## 7.105.0(车QQ 部分)—— 门前三族只读路要凭据 · 会话规则写口拒退役 / 无前缀工具名 · `ServiceDeps.runnerFor` 必填
2929
3384
 
2930
3385
  ### wire:HTTP / 错误码
2931
3386
 
2932
- - **🔴 行为面:门前三族只读路在配了 service 凭据的部署上要凭据(S-672)。** `GET /v1/tasks`(及 `…/:id/{turns,stream,artifacts,tool-results/:ref}`、
3387
+ - **🔴 行为面:门前三族只读路在配了 service 凭据的部署上要凭据。** `GET /v1/tasks`(及 `…/:id/{turns,stream,artifacts,tool-results/:ref}`、
2933
3388
  `/v1/tasks/source-summary`)、`GET /v1/usage/{summary,series,breakdown}`、`GET /v1/workflows[/:id[/journal|/stream]]`、`GET /v1/fleet/stream`:部署配了
2934
3389
  `SERVICE_AUTH_TOKEN` / `SERVICE_AUTH_TOKENS` 时,请求必须带 service token、只读 `TRACE_TOKEN` 或验过的 principal(registry 登录令牌 / 直连门签名 principal 令牌)
2935
3390
  之一,否则 **401 `auth.unauthorized`**(与全局凭据门同一句)。只带调用方自写的 `x-agent-principal` 头不算。**迁移**:这几条读口带上与提交任务同一把
2936
3391
  service token(或登录令牌);没配 service 凭据的部署不受影响。`/.well-known/agent-card.json` 不变(匿名)。契约 §0.56。
2937
- - **会话规则写口拒「写进去就跑不了」的工具名(S-800)。** `PUT /v1/sessions/:id/policy` 与 `POST /v1/sessions/:id/sync/import` 的 `policy` 面:`toolAllow` /
3392
+ - **会话规则写口拒「写进去就跑不了」的工具名。** `PUT /v1/sessions/:id/policy` 与 `POST /v1/sessions/:id/sync/import` 的 `policy` 面:`toolAllow` /
2938
3393
  `toolDeny` 里有引擎退役名(`Task` / `KillShell` / `MultiEdit` / `bash` / `Recall` …)或含 `__` 却无协议前缀的名字 ⇒ **400 `rules.legacy_tool_name`**
2939
3394
  (新码,体带 `field` / `name`)。7.104.x 及以前照收、之后这个会话每一跑拒启。**迁移**:换成现役名(句子里带指引)/ 给协议工具名加 `mcp__` 等前缀;
2940
3395
  对未知前缀族严格的消费方收下 `rules.` 族(400,改请求再写,原样重试不改判)。部署自己挂了与退役名同名工具的,写口仍拒 —— 走部署级工具策略。
2941
3396
 
2942
3397
  ### 类型面与嵌入方
2943
3398
 
2944
- - **🔴 `ServiceDeps.runnerFor` 必填(S-175)。** 修前可选,缺席时每只任务静默跑在 `deps.runner`(最宽的那只)上;现在缺席 = 编译错,绕过类型的 deps 在
3399
+ - **🔴 `ServiceDeps.runnerFor` 必填。** 修前可选,缺席时每只任务静默跑在 `deps.runner`(最宽的那只)上;现在缺席 = 编译错,绕过类型的 deps 在
2945
3400
  `createHttpServer` 入口抛(报文点名 `runnerFor`)。**迁移**:单 Runner 的嵌入方显式传 `runnerFor: () => runner`(一句表态,不是回落);按场景分有手 / 无手两只 Runner 的嵌入方传自己的选路函数(本仓自己的装配在 `boot/stage-10-http-server.ts`,该工厂不在包根导出面)。
2946
3401
 
2947
- ## 7.105.0(车QP 部分)—— 续读不再答 416 `limit.retention_evicted`(S-211 ①)· `TOOL_RESULT_TTL_SEC ≤ 0` 拒启(S-211 ⑤)· 记号表加索引(S-546 A9)
3402
+ ## 7.105.0(车QP 部分)—— 续读不再答 416 `limit.retention_evicted`· `TOOL_RESULT_TTL_SEC ≤ 0` 拒启· 记号表加索引
2948
3403
 
2949
3404
  - **续读(`Last-Event-ID` / `?from=`)不再答 416 `limit.retention_evicted`**(`GET /v1/runs/:id/events`、`GET /v1/tasks/:id/stream`、
2950
3405
  `GET /v1/images/bakes/:id/events`)。这个码从来判不出一次真淘汰:账本没有局部头部裁剪,唯一的删除是整棵会话树连删 —— run 行
@@ -2963,14 +3418,14 @@
2963
3418
 
2964
3419
  ### wire:HTTP / SSE / 错误码 / 帧
2965
3420
 
2966
- #### 同步提交腿 `POST /v1/tasks` 的拒因分诊(统一规则;S-271 / S-724)
3421
+ #### 同步提交腿 `POST /v1/tasks` 的拒因分诊(统一规则)
2967
3422
 
2968
3423
  - **prepare 期拒只在零工作时答错误体(行为面)**:`corrupt_session`(500)/ `rewind.store_unconfigured`(409)/ `rewind.capture_disabled`(422)/ 名册超界三码(503)与其余 prepare 期拒同一条分诊 —— 零工作(整次提交 turns = 0 ∧ tokens = 0)⇒ 错误体;
2969
3424
  已做过工作的多级 run(`verify` / `cascade`)末级才被拒 ⇒ 200 + failed 体、照常计费与幂等缓存。相对 7.103.2:这几码此前**没有**状态档映射、
2970
3425
  恒 200 + failed 体,所以调用方看到的变化只有「零工作那一形从 200 变成对应 4xx / 5xx」。7.103.2 已有状态档的码在「多级 run 末级才被拒」这一形上的变化
2971
- 见 S-271 一组第二条。
3426
+ 见下面「core 名册超界三码在同步提交腿上改答 503」一节。
2972
3427
 
2973
- #### 会话存档读不出:500 `corrupt_session`;部分记录被跳过:`engine_notice` `session.records_skipped`(S-612)
3428
+ #### 会话存档读不出:500 `corrupt_session`;部分记录被跳过:`engine_notice` `session.records_skipped`
2974
3429
 
2975
3430
  内部构造面一条见「类型面与嵌入方」小节。
2976
3431
 
@@ -2987,9 +3442,9 @@
2987
3442
  - **新 `engine_notice` 码 `session.records_skipped`**(只在文件后端):会话照常唤醒、这一轮照跑,但历史里有 N 条记录读不出被跳过 ⇒ 同一轮里一帧
2988
3443
  `{ dropped, entriesKept, sessionId }`。对未知码严格的消费方要收下这只码(附录 D.3 白名单 26 码);没升级的壳按未知 `engine_notice` 码处置。
2989
3444
  非流式同步口 `POST /v1/tasks` 不收通告帧(所有通告码同一姿态),那一腿上只有运维日志 `session_repo_corrupt_read`。
2990
- - **老壳所见**:没消费 cli L-568 的壳遇到形 A,屏上是 500 的 `error` 原句加错误码。
3445
+ - **老壳所见**:没消费这一形的 cli 壳遇到形 A,屏上是 500 的 `error` 原句加错误码。
2991
3446
 
2992
- #### core 名册超界三码在同步提交腿上改答 503(S-271)
3447
+ #### core 名册超界三码在同步提交腿上改答 503
2993
3448
 
2994
3449
  - **🔴 同步提交腿三码改 503(wire 值形变更)**:`POST /v1/tasks` 上 `config.tool_name_too_long` / `config.tool_contract_too_long` /
2995
3450
  `config.tool_roster_bound`(一只工具的名 / 契约 / `modelGate` 等身份成员超过名册的界,引擎在 prepare 期拒、零计费)由 **200 带 failed 体**
@@ -3004,7 +3459,7 @@
3004
3459
  `rewind.child_scope_unsupported`、`config.memory_capture_unsupported` 等)在这一形上此前答 4xx / 5xx(跳过计费、不进幂等缓存),它们零工作的拒(常态)不变;
3005
3460
  本版新映射的码(`rewind.store_unconfigured` / `rewind.capture_disabled` / 名册超界三码)此前恒 200 + failed 体,见本小节统一规则。**迁移**:多轮提交的客户端对这些码两形都要认(错误体 `errorCode` / 200 体 `terminal.code`)。
3006
3461
 
3007
- #### 请求词 `fileHistory` + `wiring_manifest.fileHistory` + rewind 两码进错误码目录(S-724)
3462
+ #### 请求词 `fileHistory` + `wiring_manifest.fileHistory` + rewind 两码进错误码目录
3008
3463
 
3009
3464
  `FILE_HISTORY_CAPTURE=false` 只关捕获一条见「env 与启动」小节。
3010
3465
 
@@ -3020,7 +3475,7 @@
3020
3475
  operator 同投)多一段 `fileHistory: "on" | "disabled"`(缺席 = 老引擎,不是「在捕获」)。2c sync 面「没有历史店」的 501 句子改为
3021
3476
  `session sync is not available on this deployment: no file-history store is wired, …`(按句子全文匹配的客户端注意)。
3022
3477
 
3023
- #### 同步提交撞 park 的 200 体改为「结果本身 + 回执三键」;park 中的 run 行带 `result`(S-173,additive)
3478
+ #### 同步提交撞 park 的 200 体改为「结果本身 + 回执三键」;park 中的 run 行带 `result`(additive)
3024
3479
 
3025
3480
  持久数据面与混版窗 / 回滚的修复语句见「存储与一次性迁移」小节,内部面见「类型面与嵌入方」小节。
3026
3481
 
@@ -3037,7 +3492,7 @@
3037
3492
  - **同一列的其它读者(行为面,如实)**:会话列表 `lastTaskRunId` 在 park 中在场(此前只在终局在场);`GET /v1/tasks` 列表行的
3038
3493
  `turns` / `tokens` / `costMicroUsd` 在 park 中带停下来那一刻的读数;`/v1/usage/*` 把 park 行按那一刻的读数计入(下界,终局时整块替换)。
3039
3494
 
3040
- #### 删会话后旧的审批卡消失(S-790 / S-506)
3495
+ #### 删会话后旧的审批卡消失
3041
3496
 
3042
3497
  会话化身的新列 + 一次性回填、记忆 opt-out 载体见「存储与一次性迁移」小节,嵌入方读口见「类型面与嵌入方」小节。
3043
3498
 
@@ -3045,26 +3500,26 @@
3045
3500
  消失),本副本上在跑的停掉 —— 做完才删会话记录。**迁移**:依赖「删了会话之后还能对它的旧审批卡做决定」的调用方,那张卡自本版起不在了;
3046
3501
  决定一张 7.104.0 之前删会话留下的旧卡答 `409 decide.not_parked`。有本副本结束不了的子代(在别的副本上:耐久行的写者不是本副本)⇒ 删除开始之前就拒,答 **409
3047
3502
  `conflict.session_children_alive`**(体带 `remaining` = 那些子代的 id 列表,与 `GET /v1/agents/roster` 的 `handle` 同一个串),什么都没动,
3048
- 等它们收尾后重试即可;本副本停得掉却没在时限内停净 ⇒ `500 internal.error`,会话记录保留,重试收敛;有子代的会话删除会慢一些(每轮重新枚举,至多 6 轮)。两处如实登记(修复验证轮 opus 腿,S-886 / S-887):500 之后**立刻**重试,停止仍在落盘的子代会被判成够不着 ⇒ 那一次答 409(句子说「删之前就拒」,但上一次已删了账本;再晚一拍重试即收敛);曾开耐久审批、留下 parked 子代、之后关闭耐久审批(或切到多租户形)的会话,删除会一直 409(本副本没有 checkpoint 店,作废不了那张卡;7.103.2 上这一形答 200)—— 出路候 S-887。
3503
+ 等它们收尾后重试即可;本副本停得掉却没在时限内停净 ⇒ `500 internal.error`,会话记录保留,重试收敛;有子代的会话删除会慢一些(每轮重新枚举,至多 6 轮)。两处如实登记(修复验证轮 opus 腿):500 之后**立刻**重试,停止仍在落盘的子代会被判成够不着 ⇒ 那一次答 409(句子说「删之前就拒」,但上一次已删了账本;再晚一拍重试即收敛);曾开耐久审批、留下 parked 子代、之后关闭耐久审批(或切到多租户形)的会话,删除会一直 409(本副本没有 checkpoint 店,作废不了那张卡;7.103.2 上这一形答 200)—— 出路候后续修复。
3049
3504
  - **parked 决定的复核(行为面)**:决定腿在 claim 之前 / 之后各读一次根会话上是哪一位住客,不在或换了人(包括同一个人删了重建)⇒ 回滚、
3050
3505
  `409 decide.not_parked`;行上没有根会话锚 ⇒ `409 decide.row_unrevivable`。零新码、零新体键。
3051
3506
 
3052
- #### 回决门键闭集的 `unsupported` 桶换成员与文案(S-355)+ 续跑折叠体 `blockedBy` 恒在(S-607)
3507
+ #### 回决门键闭集的 `unsupported` 桶换成员与文案+ 续跑折叠体 `blockedBy` 恒在
3053
3508
 
3054
- - **`/decide` 的 400 `request.body_shape` 换桶(S-355,诊断面)**:`permissionModeAfter`(plan_review 的字段)与 `permissionMode`(提交体的键)由
3509
+ - **`/decide` 的 400 `request.body_shape` 换桶(诊断面)**:`permissionModeAfter`(plan_review 的字段)与 `permissionMode`(提交体的键)由
3055
3510
  `unknownKeys` 移到 `unsupportedKeys`;判决不变(都拒、同码同串)。两道回决门(`/decide`、`plan_review`)的 `unsupported` 文案由一句通用标签改为
3056
3511
  **按去处分句**:`unsupported (a body field of <那条门的路径> — …): k`、`unsupported (a path segment of <带这一段的 URL> — …): k`、
3057
3512
  `unsupported (a submit-body key of POST /v1/tasks — …): k`。键名 `unknownKeys` / `unsupportedKeys`、状态码、`Accepted:` 全表不变。
3058
3513
  **迁移**:按 `unknownKeys` 精确匹配这两个键的调用方 / 测试改读 `unsupportedKeys`;按文案全文匹配的改按两个机读桶判。
3059
3514
  内部面:`decideBodyKeyIssue` / `planReviewBodyKeyIssue` 删,统一为 `decisionBodyKeyIssue(door, body)`(`src/http/routes/approvals-assistant.ts`)。
3060
- - **续跑折叠体 `409 resume_blocked_by_policy` 的 `blockedBy` 恒在(S-607,additive)**:此前只在原拒绝带子码时在场;现在值 = 同一只错误**直接**出去时
3515
+ - **续跑折叠体 `409 resume_blocked_by_policy` 的 `blockedBy` 恒在(additive)**:此前只在原拒绝带子码时在场;现在值 = 同一只错误**直接**出去时
3061
3516
  的 `errorCode`(带码 ⇒ 原码,与此前逐字相同;不带码 ⇒ 按状态的粗码 `request.rejected` / `not_found.resource` / `request.unprocessable` /
3062
3517
  `capability.unavailable` 等)。**迁移**:把「`blockedBy` 缺席」读成「这次拒绝没带子码」的消费方,在本版起的 server 上会读到粗码(判型族按
3063
3518
  `blockedBy ?? errorCode` 取码的,粗码不命中任何专属族,判型不变)。
3064
3519
 
3065
- #### 耐久 ask 回决口收 `settledBy`(S-843)
3520
+ #### 耐久 ask 回决口收 `settledBy`
3066
3521
 
3067
- - **耐久 ask 回决口收 `settledBy`(S-843,additive)**:`POST /v1/tasks/:taskId/asks/:askId/decision` 的体可带 `settledBy`(只配 `decision:"deny"`;
3522
+ - **耐久 ask 回决口收 `settledBy`(additive)**:`POST /v1/tasks/:taskId/asks/:askId/decision` 的体可带 `settledBy`(只配 `decision:"deny"`;
3068
3523
  直连门上 `400 settled_by_not_in_proof`,与 `/decide` 同 —— live `/respond` 口没有这一臂;超过 16 字符 / 空串 ⇒ 400),其余规则与拒句与
3069
3524
  `/decide`、`/respond` 相同。缺席 = 今形。
3070
3525
  `400 request.body_shape` 的拒因句末尾多了 `/ settledBy`(按句子全文匹配的客户端注意)。
@@ -3073,7 +3528,7 @@
3073
3528
  现在裁决之前 400(码 = 这条口体拒的一贯码 `request.body_shape`),卡还在。`/decide` 上此前走到引擎、由引擎按词表拒;现在 400
3074
3529
  `request.field_invalid`。引擎的三个词(`human` / `timeout` / `policy`)都在 16 字符以内,合法请求不受影响。
3075
3530
 
3076
- #### `401 auth.unauthorized` 的 message 换成出路句(S-850)
3531
+ #### `401 auth.unauthorized` 的 message 换成出路句
3077
3532
 
3078
3533
  - **`401 auth.unauthorized` 的 `error` 换句(wire 文案,码不变)**:此前恒为 `unauthorized` 一个词,现在按这道门收什么给三句出路句之一(凭据门 /
3079
3534
  运维口 / 要调用方身份,逐字见 `docs/ASSISTANT-WIRE-CONTRACT.md` 附录 A.1)。按 `error == "unauthorized"` 字面判的调用方改按 `errorCode`
@@ -3092,7 +3547,7 @@
3092
3547
 
3093
3548
  ### env 与启动
3094
3549
 
3095
- #### 多租户姿态 ∧ 不分租户的执行车道拒启 + 执行车道合成步(S-775)
3550
+ #### 多租户姿态 ∧ 不分租户的执行车道拒启 + 执行车道合成步
3096
3551
 
3097
3552
  - **🔴 `REQUIRE_PRINCIPAL=true` ∧ 最终生效的执行车道不分租户 ⇒ 拒启**(新交叉不变量 `multi-tenant-shared-lane`)。**按能力表不按词**:判据读
3098
3553
  执行车道能力表的「分不分租户」一位,**今天覆盖 host / ssh / adb**(worker 宿主 / 一台 SSH 对端 / 一台 ADB 设备,所有任务共享同一个目标);
@@ -3107,17 +3562,17 @@
3107
3562
  `loadConfig()` 拒的形,本版起 `loadConfig()` 照返回 —— 判据在合成步里。包根新导出 `composeExecutionLane(config, ctx)` 与它的同步判据半场
3108
3563
  `assertExecutionLaneInvariants(config)`(同一只,本仓两个入口调的就是它):在 `loadConfig()` 之后调(车QK F4)。
3109
3564
 
3110
- #### `CONFIG_PROVIDER` 闭集拒启(S-841)
3565
+ #### `CONFIG_PROVIDER` 闭集拒启
3111
3566
 
3112
3567
  类型面一条见「类型面与嵌入方」小节。
3113
3568
 
3114
- - **🔴 认不出的 `CONFIG_PROVIDER` ⇒ 拒启(S-841,行为面)**:合法值只有 `local` / `remote` / 不设(空串 = 不设);**逐字比较**,大小写与首尾空白都不宽容。
3569
+ - **🔴 认不出的 `CONFIG_PROVIDER` ⇒ 拒启(行为面)**:合法值只有 `local` / `remote` / 不设(空串 = 不设);**逐字比较**,大小写与首尾空白都不宽容。
3115
3570
  此前认不出的词照起,而且一个进程里三处读法不一:配置源当它是 `local`(配了中心也一样)、隐式 host 执行车道与起服落点披露当它「不是 local」、
3116
3571
  local 配置源的根落回进程 cwd 而车道文件覆写读本地根。拒因句即通知(点名旋钮、列合法词)。**迁移**:改成 `local` / `remote` 之一或删掉。
3117
3572
 
3118
- #### 旧负名与正名同设 ⇒ 拒启(墓碑一张表)(S-588)
3573
+ #### 旧负名与正名同设 ⇒ 拒启(墓碑一张表)
3119
3574
 
3120
- - **🔴 D 族旧负名在场即拒启,不论正名在不在(S-588,行为面)**:下面四个旧名自 server 3.0.0 起就是墓碑,但此前只在**正名没设**时才拒;
3575
+ - **🔴 D 族旧负名在场即拒启,不论正名在不在(行为面)**:下面四个旧名自 server 3.0.0 起就是墓碑,但此前只在**正名没设**时才拒;
3121
3576
  正名设了而旧名还留着,旧名被静默忽略、照常起服。本版起两名同设同样拒启,拒句与其余退役名同一句、同一个码 `[config.env_key_retired]`。
3122
3577
  **迁移**:删掉旧名;若只设了旧名,按下表换成正名(极性相反,别把旧值照抄过去):
3123
3578
 
@@ -3153,9 +3608,9 @@
3153
3608
  `MODEL_CHEAP_*` 给同一只模型造第二种形的部署。**迁移**:在 `config.d/models.json` 写两条不同名的条目(同一个上游 id,各自的形),把 roles
3154
3609
  指过去;不需要第二种形就去掉 `MODEL_CHEAP_ID`。
3155
3610
 
3156
- #### scratchpad 宣告不归 `SANDBOX_ENV_FACTS` 管(S-842)
3611
+ #### scratchpad 宣告不归 `SANDBOX_ENV_FACTS` 管
3157
3612
 
3158
- - **`SANDBOX_ENV_FACTS=false` 不再关会话 scratchpad(S-842,行为面)**:本键此后只管沙箱事实(profile / capabilities / pkgSource / egress / resume)。
3613
+ - **`SANDBOX_ENV_FACTS=false` 不再关会话 scratchpad(行为面)**:本键此后只管沙箱事实(profile / capabilities / pkgSource / egress / resume)。
3159
3614
  会话 scratchpad 的宣告是写面的宣告(core 据它开根围栏的洞,并用同一次裁决决定提示词教不教),与本键无关 ⇒ 这类部署的提示词**开始**出现
3160
3615
  `# Scratchpad Directory` 一节;远程车道(e2b / k8s / local-docker / ssh)的 `/tmp/scratchpad/<sid>` 此后在本键关着时也可 Write(与本键开着同形)。
3161
3616
  缺省部署:提示词重新出现这一节(此前被 core 跳过),每轮那一句 `scratchpad advertised writable directory skipped` 消失。**迁移**:无动作;
@@ -3163,7 +3618,7 @@
3163
3618
  ⚠️ 数据根很深(`<LOCAL_DATA_ROOT>/scratchpad/<段>` 超过 160 字符,根约 107 字符以上)的部署:会话 scratchpad **不再铸出**(不建、不豁免、不宣告),
3164
3619
  每个任务一行 warn `scratchpad_not_minted`。此前它照建、照豁免,提示词里只有一条被截断的假路径。**迁移**:缩短 `LOCAL_DATA_ROOT`。
3165
3620
 
3166
- #### `FILE_HISTORY_CAPTURE=false` 只关捕获(S-724)
3621
+ #### `FILE_HISTORY_CAPTURE=false` 只关捕获
3167
3622
 
3168
3623
  请求词 `fileHistory`、能力词 `fileHistoryCapture`、rewind 两码见「wire」小节。
3169
3624
 
@@ -3177,21 +3632,21 @@
3177
3632
 
3178
3633
  ### 存储与一次性迁移
3179
3634
 
3180
- #### 一次性迁移的窗登记表(S-590)
3635
+ #### 一次性迁移的窗登记表
3181
3636
 
3182
- - **一次性迁移的窗(S-590)**:`src/plugins/one-time-migrations.ts` 的每条迁移在「引入它的版本发布日 + 30 天」之后的第一个 minor 删码,逐条日期只在该文件的
3637
+ - **一次性迁移的窗**:`src/plugins/one-time-migrations.ts` 的每条迁移在「引入它的版本发布日 + 30 天」之后的第一个 minor 删码,逐条日期只在该文件的
3183
3638
  `ONE_TIME_MIGRATIONS` 登记表(随包在 `dist/plugins/one-time-migrations.d.ts`;起动日志行 `one_time_migrations_applied` 新增的 `removableAfter` 读数同源)。
3184
3639
  **跨版跳升**(从 7.73.x 及更早,或从 7.93.4 及更早)要经过一只还带着对应迁移的版本起一次。自建 `StoreBackend` 的嵌入方:`runOneTimeMigrations()`
3185
3640
  在**最后一条**删码时从接口上删(tsc 红即通知)。
3186
3641
 
3187
- #### 会话化身:`session_meta.incarnation` 新列 + 一次性回填(S-790 / S-506)
3642
+ #### 会话化身:`session_meta.incarnation` 新列 + 一次性回填
3188
3643
 
3189
3644
  删会话带走子代、parked 决定的复核见「wire」小节。
3190
3645
 
3191
3646
  - **新列(持久数据面)**:`session_meta.incarnation`(MySQL 协议 `VARCHAR(64) NOT NULL DEFAULT ''`;PG 同名同宽 `COLLATE "C"`)—— 同一个会话 id 上
3192
3647
  **这一位住客**的不透明令牌。新库由中央 DDL 建;存量库由起服的一次性迁移 **M5** 加列并给每一行铸一只互不相同的令牌(窗与删法见
3193
3648
  `src/plugins/one-time-migrations.ts` 的 `ONE_TIME_MIGRATIONS` 登记表;起动日志行 `one_time_migrations_applied` 多两键
3194
- `sessionIncarnationColumn` / `sessionIncarnationsBackfilled`)。**先升库再升副本**这条既有顺序不变:旧副本连上已加列的库会被 S-547 列册探针
3649
+ `sessionIncarnationColumn` / `sessionIncarnationsBackfilled`)。**先升库再升副本**这条既有顺序不变:旧副本连上已加列的库会被列册探针
3195
3650
  判「库比代码新」拒启。回填之后读到空令牌的行 ⇒ 读口响亮拒(`session.incarnation_missing`,parked 决定因此拒、记忆座退回按 id 绑定并 warn),
3196
3651
  **不**当作通配 —— 手工改库的运维给那一行填一只随机令牌即可(`session.incarnation_missing` 是内部错误码,日志可见;wire 上是通用 500,不是新码)。local 文件车道:令牌落在数据根的 `session-incarnations.json`(与
3197
3652
  `session-titles.json` 同一族边档),存量会话第一次被读时补铸并落盘,不在起动期扫。**该文件读不出**(坏 JSON / 形不对 / 权限;缺文件不算,那是「还没有」)⇒ 严格拒:
@@ -3199,7 +3654,7 @@
3199
3654
  拒因不带原文;这一拒记在进程里,修完要重启才重读。**出路** = 修好该文件,或把它移开,然后重启。**移开的代价**:所有旧会话的化身在下一次被读时
3200
3655
  重铸 —— 每只旧会话都成了一位新住客,上一位住客声明的记忆采集 opt-out 从此不再绑它们(按部署缺省采集);要保住 opt-out 就修文件,别移开。
3201
3656
  令牌不上 wire、不进模型上下文,日志只打前 8 位。
3202
- - **滚动升级窗(SQL 两车道)**:第一台 7.104.0 副本起动跑完 M5 之后,**此前已经在跑**的 ≤ 7.103.x 旧副本不会重新对账列集(S-547 探针只在起动期跑),
3657
+ - **滚动升级窗(SQL 两车道)**:第一台 7.104.0 副本起动跑完 M5 之后,**此前已经在跑**的 ≤ 7.103.x 旧副本不会重新对账列集(列册探针只在起动期跑),
3203
3658
  它们新建的会话行落列缺省 `incarnation = ''`。窗内现象:这些会话上的 parked 决定答 `500 internal.error`(读口响亮拒 `session.incarnation_missing`,
3204
3659
  claim 之前就拒,什么都不动);7.104.0 副本对每只这样的会话打一行 `session_incarnation_unavailable reason=session.incarnation_missing`(按会话去重);
3205
3660
  记忆座对它们退回按 id 绑定并 warn `memory_session_incarnation_unknown`。**出路**:全部副本升到 7.104.0(旧副本全部退出)之后,重启其中任意一台 ——
@@ -3207,7 +3662,7 @@
3207
3662
  - **记忆 opt-out 不再跨住客继承(local 文件载体)**:会话声明过记忆采集 opt-out、被删、同一个 id 重建之后,新住客按部署缺省采集。
3208
3663
  ⚠️ SQL 部署的 opt-out 载体(`session_capture_optout`)今天不存令牌 ⇒ 那一形的记录仍按 id 绑(新住客仍被扣 opt-out,保守方向),另车处理。
3209
3664
 
3210
- #### park 中的 run 行带 `result`:持久数据面与混版窗 / 回滚(S-173)
3665
+ #### park 中的 run 行带 `result`:持久数据面与混版窗 / 回滚
3211
3666
 
3212
3667
  wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一列的其它读者)见「wire」小节。
3213
3668
 
@@ -3223,7 +3678,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3223
3678
  PostgreSQL:`UPDATE task_run SET result = NULL WHERE status NOT IN ('suspended','needs_review') AND result -> 'terminal' ->> 'kind' = 'paused';`
3224
3679
  回滚到 7.103.x 前若想连 park 行的结果一起撤(旧版读面不会用到它),再加 `UPDATE task_run SET result = NULL WHERE status IN ('suspended','needs_review');`。
3225
3680
 
3226
- #### local 车道 JSONL 店的坏记录:安全轴三店拒用、其余跳过留痕(S-582)
3681
+ #### local 车道 JSONL 店的坏记录:安全轴三店拒用、其余跳过留痕
3227
3682
 
3228
3683
  内部构造面见「类型面与嵌入方」小节。
3229
3684
 
@@ -3243,7 +3698,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3243
3698
 
3244
3699
  ### 部署:sema-up
3245
3700
 
3246
- #### sema-up 数据根按项目分、一条根只归一个项目(S-851)
3701
+ #### sema-up 数据根按项目分、一条根只归一个项目
3247
3702
 
3248
3703
  - **sema-up 自动数据根按项目分 + 项目标记(部署面)**:多盘机不给 `--data-root` 时,新装项目的数据根是 `<大盘>/sema-data/<project>`(此前是
3249
3704
  `<大盘>/sema-data`,同机第二个项目会自动落进同一份目录);任何来源的数据根首次使用时落一只 `.sema-up-project` 标记,之后装 / 重跑(含
@@ -3280,28 +3735,28 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3280
3735
  = 本进程阀门的生效判决,只喂配置目录该行的 `effectiveValue`。自建 `ServiceDeps` 的嵌入方填自己进程的真实判决;没有接记忆整理的填
3281
3736
  `{ enabled: false, source: "explicit" }`。(记忆整理阀门;正文见「env 与启动」小节)
3282
3737
  - **类型面(硬 breaking,tsc 红即通知)**:`ServiceConfig.configProvider` `string` → `"local" | "remote"`;`createConfigProvider` 的入参
3283
- `provider` 同收、`localDir` **必填**(不再回落 `process.cwd()` —— 传你的本地配置根;只造中心源的调用方随便传一个,它不被读)。(S-841;正文见「env 与启动」小节)
3738
+ `provider` 同收、`localDir` **必填**(不再回落 `process.cwd()` —— 传你的本地配置根;只造中心源的调用方随便传一个,它不被读)。(正文见「env 与启动」小节)
3284
3739
 
3285
3740
  #### 包导出面:自建会话店 / 自建后端 / 自建 `ServiceDeps`
3286
3741
 
3287
3742
  - **嵌入方**:公共导出的 `OwnerAwareSessionStore` 多一只可选读口 `sessionFaceOf`(属主 + 化身一次读)—— 自建会话店要让 parked 决定可用必须实现它
3288
3743
  (缺席的部署决定整条 500,不静默跳过复核);`StoreBackend.runOneTimeMigrations()` 的报告型多两键(`sessionIncarnationColumn` /
3289
- `sessionIncarnationsBackfilled`,自建后端 tsc 即通知)。其余改名(`ParkedDecideDeps.sessionOwnerOf` → `sessionFaceOf` 等)都在内部装配面,不在包导出面。(S-790 / S-506;正文见「wire」小节与「存储与一次性迁移」小节)
3744
+ `sessionIncarnationsBackfilled`,自建后端 tsc 即通知)。其余改名(`ParkedDecideDeps.sessionOwnerOf` → `sessionFaceOf` 等)都在内部装配面,不在包导出面。(正文见「wire」小节与「存储与一次性迁移」小节)
3290
3745
  - **自建 `ServiceDeps` 的嵌入方**:新增可选位 `sealedKeyPublic`(只含 `latest` 的公钥面);不传 ⇒ 你的 caps 体里没有这一段,其余不变。(`sealedKey`;正文见「wire」小节)
3291
3746
 
3292
3747
  #### 内部构造面(对包消费方零影响)
3293
3748
 
3294
3749
  - 内部面(非公开导出):三家 run 店的 `setSuspended` / `setNeedsReview` 收第二个必填参数 `result`(结果或 `null`),`result` 列经同一只入口
3295
- `sealRunRowResult`(封口 + 脱敏)落列。契约全文见 `docs/ASSISTANT-WIRE-CONTRACT.md` §5.0c。(S-173;正文见「wire」小节与「存储与一次性迁移」小节)
3750
+ `sealRunRowResult`(封口 + 脱敏)落列。契约全文见 `docs/ASSISTANT-WIRE-CONTRACT.md` §5.0c。(正文见「wire」小节与「存储与一次性迁移」小节)
3296
3751
  - **内部构造面(对包消费方零影响)**:`observability/corrupt-read-seat.ts` 的 `createCorruptReadSeat` 多一个可选第 4 位 `leg`;`plugins/session-event-payload.ts`
3297
- 的 `decodeSessionEventPayload` 对坏体抛 `SessionError("corrupt_session")`(此前是 `StoreCorruptError`)。都不在包的导出面上。(S-612;正文见「wire」小节)
3752
+ 的 `decodeSessionEventPayload` 对坏体抛 `SessionError("corrupt_session")`(此前是 `StoreCorruptError`)。都不在包的导出面上。(正文见「wire」小节)
3298
3753
  - **内部构造面(对包消费方零影响)**:`createFilePermissionRuleStores` 的 opts 多一个 `warn`(两份日志的腐读座;`onError` 只接 core 规则文件);
3299
3754
  `FileRuleApprovalRecordStore` / `FileRuleImportTicketStore` 构造参数里原 `onError` 位改为 `warn: Logger["warn"]`;`FileApprovalNonceStore` /
3300
3755
  `FileApprovalExemptionStore` / `FileApprovalAskStore` / `FileResumeAnchorStore` / `FileSendFileLedger` 多一个可选 `{ warn }`、`FileRunStore` 的 opts 多
3301
3756
  `warn`(均可缺席,缺席 ⇒ `console.warn`)。`observability/corrupt-read-seat.ts` 的 `createSkippedRecordSink` 删除(分级收进重放属主)。这些构造器都不在
3302
- 包的导出面上(`package.json` `exports` 只开 `.` / `./main` / `./device-protocol`),`StoreBackend` 交出的实例型不变 —— 列在这里给仓内 fork 与自建装配口。(S-582;正文见「存储与一次性迁移」小节)
3757
+ 包的导出面上(`package.json` `exports` 只开 `.` / `./main` / `./device-protocol`),`StoreBackend` 交出的实例型不变 —— 列在这里给仓内 fork 与自建装配口。(正文见「存储与一次性迁移」小节)
3303
3758
 
3304
- ## 7.103.2 —— core 7.33.8 提货:`GIT_CONFIG_PARAMETERS` 里的嵌套命令凭据助手不论第几条都整只扣;OTLP 头变量一族不进宿主子进程(S-845)
3759
+ ## 7.103.2 —— core 7.33.8 提货:`GIT_CONFIG_PARAMETERS` 里的嵌套命令凭据助手不论第几条都整只扣;OTLP 头变量一族不进宿主子进程
3305
3760
 
3306
3761
  - 宿主子进程(host shell / 三条 git 腿 / 语言服务器 / bake-runner)自本版起:`GIT_CONFIG_PARAMETERS` 里要往里读一层命令的内联凭据助手(`!sh -c '…口令…'`)不论第几条
3307
3762
  ⇒ 整只不交(7.103.1 上第 4 条起放行;鉴权头 / URL userinfo / 口令旗等其它凭据形任何位置早就整只扣),同一只里无害的 `-c` 一起没了。
@@ -3337,7 +3792,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3337
3792
  · **不在本条范围**:`local-docker` 与 `e2b` 两条车道不经这一组装,它们的死工作目录报法本节未核。
3338
3793
  · 零 wire 键、零 DDL、零新旋钮。
3339
3794
 
3340
- ## 7.103.0(车OY 部分)—— server 进程出网认 `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`(S-776)
3795
+ ## 7.103.0(车OY 部分)—— server 进程出网认 `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`
3341
3796
 
3342
3797
  - **出网跟着代理变量走**:server 进程(HTTP 服务与 `run-local`)的出网 —— 引擎 → 网关、中心拉取 / 公告 / 凭证续签、WebSearch、对象存储、OTLP … ——
3343
3798
  自本版起在 **Node 运行时**按 `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`(小写同认且优先)走;回环目标恒直连。`NO_PROXY` 不支持 CIDR。**谁受伤**:env 里因别的原因带着 `HTTP(S)_PROXY`、此前
@@ -3350,7 +3805,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3350
3805
 
3351
3806
  ## 7.103.0(车OR 部分)—— core 7.33.1 提货:模型调用超时按段重排(`MODEL_CONNECT_TIMEOUT_MS` 退役 / `MODEL_FIRST_BYTE_TIMEOUT_MS` / failover 拓扑首字节 lane / 看门狗 `0` 义 / `wiring_manifest.hands`)
3352
3807
 
3353
- - **`MODEL_CONNECT_TIMEOUT_MS` 删除,设了即拒启**(S-753;任何值,含 `0`;空串 = 未设):拒句带码 `[config.env_key_retired]`,点名替代键。
3808
+ - **`MODEL_CONNECT_TIMEOUT_MS` 删除,设了即拒启**(任何值,含 `0`;空串 = 未设):拒句带码 `[config.env_key_retired]`,点名替代键。
3354
3809
  它名义「建连」、实际计到**响应头**:本仓自带的 30 000 缺省把自托管网关的 prefill(发生在响应头之前)在 30 s 处掐断、同 body 重发、
3355
3810
  报「connection lost」。core 7.33.0 起建连(TCP + TLS)是传输层自己的钟,不再有旋钮。**迁移**:删掉这个键;要给响应头等待设上限,
3356
3811
  改设下一条的新键(值语义变了,别照抄旧值)。
@@ -3359,7 +3814,7 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3359
3814
  `GATEWAY_MAX_RETRIES`),期间流上一帧 `status {phase:"reconnecting", errClass:"stall"}`,终局句点名 `firstByteTimeoutMs`。合法域
3360
3815
  `[0, 2147483647]` 整数,其余拒启。
3361
3816
  - **failover 拓扑(`MODEL_GATEWAY_FALLBACK_URLS`)的首字节 lane = core 缺省**:每条网关路由首窗到点后都有 core 缺省的一次加宽重试,之后才
3362
- 交给 failover。server **不铸** core 7.33.1 #1128 的 `firstByteRetries` 座(任何拓扑;S-753 车PA):它只在构造期,而调用方可按请求写
3817
+ 交给 failover。server **不铸** core 7.33.1 的 `firstByteRetries` 座(任何拓扑;车PA):它只在构造期,而调用方可按请求写
3363
3818
  `resilience.allowFailover: false` 关掉 failover(那一次只用主网关、身后没有备)—— 按拓扑铸 0 会让那一次少一次加宽重试。**谁受伤**:主网关接了
3364
3819
  TCP 却不回响应头时,缺省下要等完 core 的首字节 lane(缺省首窗 + 一次加宽重试;以 core 7.33.x 缺省计约 15 分钟;core 改缺省即变)才切备,
3365
3820
  **时间预算短于那一段的调用切不到备**(code-review council 每个镜头 180 s 与 team discuss 600 s:lane 没走完就被取消,备网关一次都没被尝试 ——
@@ -3371,11 +3826,11 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3371
3826
  failover 拓扑上首字节段设 `0` ⇒ 挂住的主网关**永不**被首字节 lane 切走(只剩 run 级时限收尾)。依赖「设 0 也还有 300 s 兜底」的部署改设
3372
3827
  一个大数。启动日志 `listening` 行 `brain` 段:`connectTimeoutMs` 键删、`firstByteTimeoutMs` 键加(`null` = core 缺省),三只看门狗键设 `0` 时
3373
3828
  显示 `0`(此前显示 `null`)。
3374
- - **`wiring_manifest` 帧多一段 `hands: { mounted, reason? }`**(core 7.33.1 #1039,租户可见,与 `lsp` 同形):`mounted: false` +
3829
+ - **`wiring_manifest` 帧多一段 `hands: { mounted, reason? }`**(core 7.33.1,租户可见,与 `lsp` 同形):`mounted: false` +
3375
3830
  `reason: "no_execution_env"` = **这条腿**没有手(按腿的正面陈述 —— 同一台部署上 scan / council / discuss 这类无手车道也读 false);
3376
3831
  `mounted: true` ≠ shell 可达。operator 面的 `configFingerprint` **一次性变值**
3377
3832
  (同装配各腿仍相等)—— 持久化 / 钉了指纹的读者会见一次跳变。
3378
- - **`GIT_CONFIG_KEY_<i>` 不再被剥**(core 7.33.1 #1129):宿主子进程(host shell / git 腿 / 语言服务器 / bake-runner)里,普通的 git env
3833
+ - **`GIT_CONFIG_KEY_<i>` 不再被剥**(core 7.33.1):宿主子进程(host shell / git 腿 / 语言服务器 / bake-runner)里,普通的 git env
3379
3834
  配置组原样到达;只有某个 KEY 的值带 `<scheme>://<userinfo>@`(令牌 insteadOf)时这一条扣下(7.103.0 是本仓整组扣;7.103.1 起判定全在 core 7.33.6,见本段末条)。🔴 **安全轴披露(core
3380
3835
  KL-1129a)**:`GIT_CONFIG_VALUE_<i>` **不在** core 的凭据形状判据里 —— 组里 KEY 是 `http.extraHeader`、VALUE 是 `Authorization: Bearer …`
3381
3836
  这一形会**原样**进宿主子进程(含模型能驱动的 host shell),并在 `isolateConfig` 的 git 腿上作为命令级配置**生效**(`GIT_CONFIG_GLOBAL /
@@ -3416,23 +3871,23 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3416
3871
  glob `?`;`safe.directory` 写进宿主自有的全局配置文件(`GIT_CONFIG_GLOBAL`;仓库级配置对它无效);`@scope` 包 URL 写进仓库级配置。(把 `@` 写成 `%40`
3417
3872
  同样触发判据 —— 不可用。)**已知边界**(core 7.33.6):① 子进程看得见占位行 `sema.withheld=`(见上);② 运行时才拼出来的口令(`$(…)` / `$VAR` / `read` 取值、
3418
3873
  由展开给出的程序名)core 读不到、照原样交出;③ `http.extraHeader` 下的**非凭据**头(trace / 路由头)照样按键扣,要它到达写进 git 配置文件。
3419
- **带口令的代理(core 7.33.5 #1150 / 7.33.6 #1165)**:`http_proxy` / `https_proxy` / `all_proxy` 与 `npm_config_https_proxy` / `npm_config_proxy` /
3874
+ **带口令的代理(core 7.33.5 / 7.33.6)**:`http_proxy` / `https_proxy` / `all_proxy` 与 `npm_config_https_proxy` / `npm_config_proxy` /
3420
3875
  `ftp_proxy`(大小写两形)值里带 userinfo / `%40` ⇒ 宿主子进程拿不到它(`family-rule`);只有地址的代理与 `NO_PROXY` 照到;写死口令的 `GIT_SSH_COMMAND` /
3421
3876
  `GIT_PROXY_COMMAND`(`sshpass -p <口令>` …)同样不到。出路见 `docs/DEPLOY-PREREQS.md`(服务进程自己的出网不受影响)。
3422
- ⤷ **`GIT_CONFIG_PARAMETERS`(S-783)随 core 7.33.5 #1141 收口**:git 的命令级配置 env(`git -c` 传给子进程的那一份)按 git 自己的引号语法读,
3877
+ ⤷ **`GIT_CONFIG_PARAMETERS`随 core 7.33.5 收口**:git 的命令级配置 env(`git -c` 传给子进程的那一份)按 git 自己的引号语法读,
3423
3878
  任一条带凭据(或 git 会拒的写法)⇒ 整只不到宿主子进程;干净的列表逐字节原样。7.103.0 此处「不在剥密族表里」的披露降级为「core 扣它」。
3424
- ⤷ 7.103.2(core 7.33.8 #1183)起按判、不论第几条(7.103.1 / core 7.33.6 上第 4 条起的嵌套命令凭据助手 `!sh -c '…'` 读不到、整只原样到 —— S-845;其它凭据形任何位置
3879
+ ⤷ 7.103.2(core 7.33.8)起按判、不论第几条(7.103.1 / core 7.33.6 上第 4 条起的嵌套命令凭据助手 `!sh -c '…'` 读不到、整只原样到;其它凭据形任何位置
3425
3880
  都整只扣);任一条带凭据 ⇒ 整只变量不交,同一只里无害的 `-c` 一起没了。凭据别写进它;无害设置按腿分(隔离配置的 project-memory / center-plugins 两腿只能留在 env:
3426
3881
  删掉凭据条目或改用 `GIT_CONFIG_COUNT` 组;其余四腿另可写进宿主 git 配置文件)—— 出路见 `docs/DEPLOY-PREREQS.md` 同段。
3427
3882
 
3428
- ## 7.103.0(车OW 部分)—— `/health.modelRefusals` 是**免鉴权面**上的新键(S-768;7.103.0 验收 G2 格补披露)
3883
+ ## 7.103.0(车OW 部分)—— `/health.modelRefusals` 是**免鉴权面**上的新键(7.103.0 验收 G2 格补披露)
3429
3884
 
3430
3885
  - **披露**:`GET /health` 不鉴权(既有),7.103.0 起它多带 `modelRefusals`(与 fleet 心跳同一对象):条目名与拒因码经 settings-schema 的 `isReportableRefusalName` 出口筛过(7.103.1 换钉 6.3.0 后 = 白名单闭形 ∧ 无密钥形 ∧ 无 URL userinfo),但**合规的条目名本身会出现在免鉴权面上**。不想让匿名读到目录条目名的部署:把 `/health` 放在反代 / 网关的鉴权后面,或按 USAGE「健康面」节改用带鉴权的 `/v1/capabilities` 读同一对象。
3431
3886
  - 无操作项;零 wire 键增删之外的变化。
3432
3887
 
3433
3888
  ## 7.102.0(车OI 部分)—— core 7.32.0 提货带来的四条(后台 shell 退出硬收 / Esc 不收后台 / 读根授权与 artifact store / parked 继承工具新失败形)
3434
3889
 
3435
- - **后台 shell 在进程退出与会话删除时被硬收(core #1107,行为面)**:
3890
+ - **后台 shell 在进程退出与会话删除时被硬收(core 侧变更,行为面)**:
3436
3891
  - **进程退出**:屏蔽 SIGTERM 的后台循环、崩溃出口上宽限跑不完的后台进程,升级后在退出边界被组 SIGKILL 收掉(改前活过引擎,成孤儿)。
3437
3892
  - **`DELETE /v1/sessions/:id`**:7.101.1 只走软梯子(SIGTERM → `HOST_BG_KILL_GRACE_MS` → 组 SIGKILL —— 屏蔽 SIGTERM 的 shell 在宽限后同样死);
3438
3893
  7.102.0 起是「软 → 等一次宽限 → 硬」:SIGTERM 处理器照样有一次宽限跑完,宽限之后再补硬面一枪组 SIGKILL 并出受据。有后台行的会话,
@@ -3442,33 +3897,33 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3442
3897
  - **谁受伤**:① 依赖「引擎挂了后台进程还在跑」而又没有声明保留的部署 —— 迁移:给那条任务写 `retainBackgroundProcesses: true`(或用 env
3443
3898
  级保留),或者干脆把服务交给进程管理器;② **受控退(SIGTERM 排空)时没有开着的连接** —— 退出很快落到退出边界,硬面的组 SIGKILL 紧跟
3444
3899
  早收割的 SIGTERM,后台进程的**优雅退出可能被截断**(7.101.1 在这里只发 SIGTERM,进程作为孤儿把处理器跑完)。这是 core 7.32 契约
3445
- 「每个退出终点软后硬」带来的;缓解(受控退在早收割 + 一次宽限之后再退出)候 S-758,本版不做。要保住优雅退出的长活服务,声明保留。
3446
- - **声明读根落在本地 artifact store 里 ⇒ Artifact 挂载拒(core #1093,部署面 NARROWING,本服务今天零影响)**:core 7.32.0 起
3900
+ 「每个退出终点软后硬」带来的;缓解(受控退在早收割 + 一次宽限之后再退出)候后续,本版不做。要保住优雅退出的长活服务,声明保留。
3901
+ - **声明读根落在本地 artifact store 里 ⇒ Artifact 挂载拒(core 侧变更,部署面 NARROWING,本服务今天零影响)**:core 7.32.0 起
3447
3902
  `additionalReadDirectories` / `additionalDirectories` 里**任何一条**在 artifact store 之内(或就是它、或包含它),挂载期
3448
3903
  `config.artifact_host_invalid`(改前只拒「store 在根内」一个方向)。本服务今天**没有** artifact host,这条到达不了;将来接 host 时,别把
3449
3904
  读根声明到 store 目录里。同批:读根按身份判 —— 声明的根在 run 首次 shell 判定前被换成软链,不再为链的目标作保。
3450
- - **parked 子代停在「继承工具」上的 `/decide` allow ⇒ 422 `parked_resume.startup_failed`(core #1110,新失败形,非回归)**:core 7.32.0 起
3905
+ - **parked 子代停在「继承工具」上的 `/decide` allow ⇒ 422 `parked_resume.startup_failed`(core 侧变更,新失败形,非回归)**:core 7.32.0 起
3451
3906
  子代继承场景层工具,停在这类工具上的审批在赎回交不出继承座时被拒(审批留 pending,`deny` 可结)。本版对一层行交座(不再落这一形;前提是行的根会话现在仍属于这张卡的租户),孙代行 / 根会话已删或易主的行仍落
3452
- (core #1112 候)。7.31.x 的子代根本没有这些工具,所以这不是旧卡的回归。
3907
+ (候 core 侧后续)。7.31.x 的子代根本没有这些工具,所以这不是旧卡的回归。
3453
3908
  - **类型面(本仓内部 API,三句)**:删 `ServiceDeps.parkedReviveTool` / `ParkedDecideDeps.reviveTool`,改 `parkedReviveSurface` /
3454
3909
  `reviveSurface`(按行解析赎回面的工厂,零别名);受害 = 手铸这两个 deps 的嵌入方,tsc 红即通告;补偿 = 固定工具形 `() => ({ reviveTool })`。
3455
3910
 
3456
- ## 7.101.0 —— 十四条(`run-local` 执法三张审批名单 / 人停下的 run 退 1 / 模型目录 fail-closed 三条 + 类型面 `ServiceConfig.modelRefusals` · `ServiceConfig.lspEnvAllow` / 记忆抹除面 409 撤 + 存量只读位一次性 `chmod`(滚动窗内会被旧副本再锁,起服 warn 点名)/ settings 层 `crossSessionInbound: accept` 改答 hold / 子进程剥名收窄 / SQL `session_meta` 新列 / 沙箱名单形错拒启 + 空串值照注入 / `WEB_SEARCH_ENDPOINT` 带 userinfo 拒启 / 配置目录两行 `csv` → `secret` / 被拒名撞档位别名 ⇒ 模型面组拒;S-690 / S-694 / S-699 / S-704 / S-705 / S-712 / S-713 / S-716 / S-723)
3911
+ ## 7.101.0 —— 十四条(`run-local` 执法三张审批名单 / 人停下的 run 退 1 / 模型目录 fail-closed 三条 + 类型面 `ServiceConfig.modelRefusals` · `ServiceConfig.lspEnvAllow` / 记忆抹除面 409 撤 + 存量只读位一次性 `chmod`(滚动窗内会被旧副本再锁,起服 warn 点名)/ settings 层 `crossSessionInbound: accept` 改答 hold / 子进程剥名收窄 / SQL `session_meta` 新列 / 沙箱名单形错拒启 + 空串值照注入 / `WEB_SEARCH_ENDPOINT` 带 userinfo 拒启 / 配置目录两行 `csv` → `secret` / 被拒名撞档位别名 ⇒ 模型面组拒)
3457
3912
 
3458
3913
  - **`run-local` 上 `APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO` 生效**(改前:这条一次性 CLI 腿不读三张名单,名单工具照跑,只有启动日志一条 `tool_policy_only_sensitive_baseline` warn)。改后与 HTTP 腿同一只策略:`APPROVAL_DENY` 命中 ⇒ 当场拒;`APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` 命中 ⇒ stdin 是 TTY 就 `y/N` 问人(问句多一行这次调用的参数),否则当场拒并在 stderr 点名三张名单键(`APPROVAL_NEVER_AUTO` 不吃 `APPROVAL_AUTO_BUDGET` 预算)。**谁受伤**:无 TTY(CI)跑 `run-local`、而 `.env` 与服务共用并带着名单的脚本 —— 名单工具从「照跑」变「当场拒」。**迁移**:给 CLI 环境单独一份 `.env`(不带名单),或设 `APPROVAL_AUTO_BUDGET=<N>` 让 require 名单前 N 次自动批,或在终端里跑(TTY 问人)。`tool_policy_only_sensitive_baseline` 在 `run-local` 上不再出现(名单已执法)。
3459
3914
  - **`run-local`:人拒掉一次工具调用而停下的 run 退 1**(改前退 0)。这类 run 的终局是 completed + `haltedOnUserRejection`(无 TTY 当场拒、TTY 答 N 都是这一形),意思是「停在等人指示」而不是「干完了活」;改后退 1(`--json` 形同样退 1),stdout 仍是模型停下前产出的文字(常为空);非 `--json` 形 stderr 多一行 `task stopped (haltedOnUserRejection): … continue it with --session <id>`。**谁受伤**:靠「`AUTONOMY=ask` / 名单被拒后仍退 0」继续往下跑的脚本。**迁移**:要把「被拒」当成功的脚本改看 stderr 停因行或 `--json` 输出的 `haltedOnUserRejection`。
3460
- - **本部署服务不了的目录条目不可用(S-704 ①,行为面)**:`provider:"anthropic"` 的目录条目在没配 `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 的部署上不进可选目录(`GET /v1/models` 不列、不当缺省),显式选中 ⇒ 400 `request.model_unavailable`(拒因码 `config.model_no_brain`);此前它落网关 brain、带着条目自己的钥匙。不合 settings-schema `ModelEntry` 形的条目同律(`config.model_entry_invalid`;坏 `baseUrl` 此前被退回部署网关)。目录里每条都不可用 ⇒ 那一代模型面整拒(上一代继续服务)。**迁移**:配 anthropic 凭据,或把条目改成 `gateway` / `vllm` 并给它自己的 `baseUrl`;按 `sema_registry_model_no_brain` / `sema_registry_model_entry_invalid` 日志修条目。
3461
- - **一条坏条目只丢它自己(S-704 ②,行为面,所有目录型域)**:schema 逐条丢掉的条目不再让 refresh / 迟到 boot 整拒候选;其余条目照用,坏条目每条一行 `config_entry_dropped`(坐标 + 字段诊断)。**谁受伤**:依赖「一条坏条目冻结整份候选、上一代继续服务」的部署 —— 现在新一代(少那一条)生效。**迁移**:按日志坐标修那一条。
3462
- - **被拒条目的名字撞档位词 / CC 别名 ⇒ 这份候选的模型面整组被拒(S-712,行为面)**:目录里一条不可用(本机无 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` 让它们起得来(DEBTS S-749)。没有字符串名的被丢行不触发本条(没有可保留的名字,与停用同处置)。同批:模型面三条不变量(缺省模型 / 路由端点 / 本条)不成立时只拒**模型面这一组**(目录,以及带模型引用、随它同代的 collab 模板 —— boot 按组回落盘上 LKG 时同样整组取 LKG 那一代),同候选的审批名单 / 限额照落(此前整份候选不落,boot 腿日志还写成 `config_source_unreachable_using_env`;拉取成功而应用失败现在是 `config_apply_refused`)。
3463
- - **`MODEL_ID` 不再是 loadConfig 期的硬要求(S-705)**:目录有可用条目即可省;目录应用之后仍没有缺省模型 ⇒ 拒启(`config.default_model_missing`,句首保留 `MODEL_ID is required`)。中心超出 `CONFIG_BOOT_FETCH_BUDGET_MS` 且无 LKG 时 boot 那一刻没有目录:没写 `MODEL_ID` 就拒启 —— 写一个 `MODEL_ID` 兜底或调大预算。
3464
- - **类型面**:`ServiceConfig.modelRefusals`(新必填席;手铸 `ServiceConfig` 的消费方 tsc 即红 —— env 形写 `{}`)与 `ServiceConfig.lspEnvAllow`(S-699 新必填席 `readonly string[]`,同样 tsc 即红 —— 缺省形写 `[]`);`SealedKeyPoisonReason` 删 `unsupported_alg`(形错的 sealed 密文现在让整条不可用,到不了毒丸臂);`FoldedReadWarning` 带 `scope` 判别位、`FetchEffectiveResult` 新键 `droppedEntries`。
3465
- - **记忆抹除面的 409 `memory.layer_unwritable` 撤销(S-697,随 core 7.31.0 #1076 提货;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 错误码目录)删掉那一臂。
3466
- - **settings 层里残留的 `crossSessionInbound: "accept"` ⇒ 跨会话消息 hold(core 7.31.0 #1078,行为面)—— 本服务不受影响(只 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`。
3467
- - **子进程剥名收窄(core 7.31.0 #1081,运行面;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]` 是嵌入方构造执行环境时的选项,不是部署级放回旋钮(S-852,7.104.0 起文档写明)。
3468
- - **SQL 后端:`session_meta` 新列 `instruction_source`(S-690,存储面)**:存量 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」表。
3469
- - **沙箱名单形错拒启 + 空串值照注入(S-713,行为面)**:`E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` 写了空段、尾逗号(`A,`)、带 `-` / `.` 的键名(`MY-TOKEN`)或点名名单型旋钮(自己 / 另一只沙箱名单 / `LSP_ENV_ALLOW`)⇒ **拒启**(拒句点名键与第几段,不回显原值;修前静默吞或照转发)。点到的键值为空串(compose `X=${X:-}` 在宿主没设时的常态)⇒ **照注入空串**(修前不注入):local-docker 上 `-e X=` 盖掉镜像里的同名缺省值,e2b 上盖掉 `SANDBOX_PKG_SOURCE` 推导出的同名包源变量。**迁移**:按拒句修名单;不想盖缺省值就把那个名从名单里删掉。
3470
- - **`WEB_SEARCH_ENDPOINT` 带 userinfo ⇒ 拒启(S-716,行为面)**:`WEB_SEARCH_PROVIDER` 点名了后端、`WEB_SEARCH_ENDPOINT` 形如 `https://user:pw@host/…`(或只带 `user@`)的部署升级后拒启(`config.web_search_invalid`);每请求 `settings.webSearch.endpoint` 带这一形从 202 变 `400 request.field_invalid`(修前这一形本来就用不了:fetch 每次都抛,错误文本还带出口令)。**迁移**:brave / tavily 的凭据走 `WEB_SEARCH_API_KEY`(或 `settings.webSearch.apiKey`);带 basic-auth 的 SearXNG 在前面放一层注入鉴权的反代。
3471
- - **配置目录两行 `csv` → `secret`(S-713,wire 形变)**:`GET /v1/config/catalog` 的 `E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` 两行 `type` `csv` → `secret`、`valueClass` `plain` → `secret`、`effectiveValue` 从名字数组变 `{ present }`,`summary.secret` 计数 +2。读这两行名单内容的消费方改读起服行 `remote_exec_enabled.sandboxEnvKeys`(只键名);这两只旋钮的原文从此也不进 host shell / git 子进程 / 语言服务器(在这些子进程里读它们的脚本收不到了)。
3915
+ - **本部署服务不了的目录条目不可用(行为面)**:`provider:"anthropic"` 的目录条目在没配 `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 的部署上不进可选目录(`GET /v1/models` 不列、不当缺省),显式选中 ⇒ 400 `request.model_unavailable`(拒因码 `config.model_no_brain`);此前它落网关 brain、带着条目自己的钥匙。不合 settings-schema `ModelEntry` 形的条目同律(`config.model_entry_invalid`;坏 `baseUrl` 此前被退回部署网关)。目录里每条都不可用 ⇒ 那一代模型面整拒(上一代继续服务)。**迁移**:配 anthropic 凭据,或把条目改成 `gateway` / `vllm` 并给它自己的 `baseUrl`;按 `sema_registry_model_no_brain` / `sema_registry_model_entry_invalid` 日志修条目。
3916
+ - **一条坏条目只丢它自己(行为面,所有目录型域)**:schema 逐条丢掉的条目不再让 refresh / 迟到 boot 整拒候选;其余条目照用,坏条目每条一行 `config_entry_dropped`(坐标 + 字段诊断)。**谁受伤**:依赖「一条坏条目冻结整份候选、上一代继续服务」的部署 —— 现在新一代(少那一条)生效。**迁移**:按日志坐标修那一条。
3917
+ - **被拒条目的名字撞档位词 / 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`)。
3918
+ - **`MODEL_ID` 不再是 loadConfig 期的硬要求**:目录有可用条目即可省;目录应用之后仍没有缺省模型 ⇒ 拒启(`config.default_model_missing`,句首保留 `MODEL_ID is required`)。中心超出 `CONFIG_BOOT_FETCH_BUDGET_MS` 且无 LKG 时 boot 那一刻没有目录:没写 `MODEL_ID` 就拒启 —— 写一个 `MODEL_ID` 兜底或调大预算。
3919
+ - **类型面**:`ServiceConfig.modelRefusals`(新必填席;手铸 `ServiceConfig` 的消费方 tsc 即红 —— env 形写 `{}`)与 `ServiceConfig.lspEnvAllow`(新必填席 `readonly string[]`,同样 tsc 即红 —— 缺省形写 `[]`);`SealedKeyPoisonReason` 删 `unsupported_alg`(形错的 sealed 密文现在让整条不可用,到不了毒丸臂);`FoldedReadWarning` 带 `scope` 判别位、`FetchEffectiveResult` 新键 `droppedEntries`。
3920
+ - **记忆抹除面的 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 错误码目录)删掉那一臂。
3921
+ - **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`。
3922
+ - **子进程剥名收窄(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 起文档写明)。
3923
+ - **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」表。
3924
+ - **沙箱名单形错拒启 + 空串值照注入(行为面)**:`E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` 写了空段、尾逗号(`A,`)、带 `-` / `.` 的键名(`MY-TOKEN`)或点名名单型旋钮(自己 / 另一只沙箱名单 / `LSP_ENV_ALLOW`)⇒ **拒启**(拒句点名键与第几段,不回显原值;修前静默吞或照转发)。点到的键值为空串(compose `X=${X:-}` 在宿主没设时的常态)⇒ **照注入空串**(修前不注入):local-docker 上 `-e X=` 盖掉镜像里的同名缺省值,e2b 上盖掉 `SANDBOX_PKG_SOURCE` 推导出的同名包源变量。**迁移**:按拒句修名单;不想盖缺省值就把那个名从名单里删掉。
3925
+ - **`WEB_SEARCH_ENDPOINT` 带 userinfo ⇒ 拒启(行为面)**:`WEB_SEARCH_PROVIDER` 点名了后端、`WEB_SEARCH_ENDPOINT` 形如 `https://user:pw@host/…`(或只带 `user@`)的部署升级后拒启(`config.web_search_invalid`);每请求 `settings.webSearch.endpoint` 带这一形从 202 变 `400 request.field_invalid`(修前这一形本来就用不了:fetch 每次都抛,错误文本还带出口令)。**迁移**:brave / tavily 的凭据走 `WEB_SEARCH_API_KEY`(或 `settings.webSearch.apiKey`);带 basic-auth 的 SearXNG 在前面放一层注入鉴权的反代。
3926
+ - **配置目录两行 `csv` → `secret`(wire 形变)**:`GET /v1/config/catalog` 的 `E2B_SANDBOX_ENV` / `DOCKER_SANDBOX_ENV` 两行 `type` `csv` → `secret`、`valueClass` `plain` → `secret`、`effectiveValue` 从名字数组变 `{ present }`,`summary.secret` 计数 +2。读这两行名单内容的消费方改读起服行 `remote_exec_enabled.sandboxEnvKeys`(只键名);这两只旋钮的原文从此也不进 host shell / git 子进程 / 语言服务器(在这些子进程里读它们的脚本收不到了)。
3472
3927
 
3473
3928
  ## 7.100.0 —— 十条 BREAKING(部署面 `CROSS_SESSION_INBOUND=accept` 拒启 / 类型面 `MailboxStore.ack` / WebSearch 配置形错响亮 / 请求面 `settings.webSearch` / WebSearch 报错句换形 / deny 部署的「无人可答」记部署政策 / 记忆抹除面新 409 / 审批名单热应用 / 子进程剥名 / local 车道回滚前收敛 ask 账本)
3474
3929
 
@@ -3477,30 +3932,33 @@ wire 面(同步提交撞 park 的 200 体、`GET /v1/runs/:id` 行形、同一
3477
3932
  - **部署 env:WebSearch 旋钮形错 ⇒ 拒启**。`WEB_SEARCH_PROVIDER` 点名了后端时,`WEB_SEARCH_ENDPOINT`(不是 `scheme://host[:port][/path]` 形的绝对 URL)、`WEB_SEARCH_SEARXNG_PARAMS`(任一段不是 `name=value`、名不是参数名、同名两次、把数组 / 对象的 JSON 文本填进来)、`WEB_SEARCH_MAX_RESULTS` / `WEB_SEARCH_TIMEOUT_MS`(非数或 < 1,含 `30s` 这类带单位的)任一形错,进程起不来,stderr 首屏带键名与机读码 `config.web_search_invalid`。改前这些被静默吸收或落默认。**空串 / 未设不受影响;没配 `WEB_SEARCH_PROVIDER` 的部署不读这四键。** **迁移**:按拒启句把那一键改对或删掉。
3478
3933
  - **每请求 `settings.webSearch` 形错 ⇒ `400 request.field_invalid`**(不分车道,请求面 BREAKING),错误句点名字段。**`provider` 缺席或不在词表里同样 400**(改前:整段丢弃、静默改用部署后端)—— 从 `settings.json` 带着拼错 provider(或只写了 `apiKey` / `endpoint`、没写 provider,或一个空的 `webSearch: {}`)的壳,修后提交即 400。**迁移**:按错误句改请求体(`provider` 写 `brave` / `tavily` / `searxng` 之一,不需要 per-request 搜索就整段删掉);`searxngParams` 用对象 `{ name: value }` 或串 `name=value;name=value`。
3479
3934
  - **brave / tavily 非 2xx 报错句换形**:`<provider> search failed: HTTP <status> — <响应体摘录>`(改前 `<provider> search failed (<status>): …`)。按旧句形匹配的消费方要改。
3480
- - **`UNATTENDED_APPROVAL_POLICY=deny` 下「无人可答」记在部署政策名下(S-689,行为面;点名 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` / 墙钟兜顶。
3481
- - **记忆抹除面:三个既有端点新答 409 `memory.layer_unwritable`(S-693,行为面)**:`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(#1076)提货版撤销本预检与这个码。
3482
- - **审批名单热应用(S-668 波 2,行为面)**:`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」的部署核对名单。
3935
+ - **`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` / 墙钟兜顶。
3936
+ - **记忆抹除面:三个既有端点新答 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提货版撤销本预检与这个码。
3937
+ - **审批名单热应用(行为面)**:`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」的部署核对名单。
3483
3938
  - **回滚到 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 原样读得动。
3484
- - **子进程按名剥凭据形变量(core 7.30.1 #1072,运行面)**:工具子 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`。
3939
+ - **子进程按名剥凭据形变量(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`。
3485
3940
 
3486
3941
  ## 7.99.0 —— 三条 BREAKING(行为面 / 类型面 / 运行时下限)
3487
3942
 
3488
- - **显式签发方不再算托管证据(7.99.0,S-671 / B-10;按 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` 托管形前置。
3489
- - **`ServiceConfig.configCenter.token` 删除,换成 `credential`(7.99.0,S-651 波 A-1,类型面)**:凭证改为一只每次请求取值的活对象;新旋钮 `SEMA_REGISTRY_TOKEN_FILE`(与 `SEMA_REGISTRY_TOKEN` 二选一,都设 ⇒ 拒启)。手铸 `ServiceConfig` 的消费方 tsc 即红。**盘上数据**:旧 LKG 文件(`config-lkg-<worker>.json`,formatVersion 1)按凭证身份分箱后一次性迁移 —— 此刻凭证是该 worker 的拉取令牌且新箱无文件 ⇒ 迁进新箱、旧文件改名 `.migrated-v1`;其它形响亮拒一行(点名旧路径与出路);迁移代码到期删除(S-683,10-31)。旧 prompt 活动状态目录暂不迁移(S-685)。
3490
- - **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,S-682);开了 engine-strict 的安装在范围外会失败。**迁移**:Node 升到 20.19+ 或 22.12+。
3943
+ - **显式签发方不再算托管证据(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` 托管形前置。
3944
+ - **`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 活动状态目录暂不迁移。
3945
+ - **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+。
3491
3946
 
3492
3947
  ## SQL 存储面 BREAKING(3.0.0 之后;列增批自 7.101.0 起入表)
3493
3948
 
3494
- **常设口径**:本仓**不出 `ALTER TABLE` 增量迁移**(成文裁定:预生产期零存量用户窗口,schema 变更
3495
- 一律删表/删库重建);boot 对旧形 schema **拒启并带恢复动作文案**,不会静默跑在错形表上。只用
3496
- file/local 存储形(未配 SQL 后端)的部署不受本节任何条目影响。
3949
+ **常设口径**:代码是 schema 的唯一真源,启动 DDL 里没有 `ALTER TABLE` 增量 seam;列集对账与拒启句永不改库 —— boot 对旧形
3950
+ schema **拒启并打印要执行的 `ALTER TABLE … ADD COLUMN …`**,不会静默跑在错形表上。进程自己对已存在的表发的 DDL 只有两种:幂等加索引(只动索引、不碰列)与
3951
+ 登记在册的一次性迁移(每条有窗、有登记行);加列 / 改列 / 改名 / 删表只有一次性迁移做。出路是闭集三条,没有销毁性的一条:
3952
+ 部署与这个库匹配的构建;库比构建旧(缺列)⇒ 部署者自己执行拒启句打印的 `ALTER`;库比构建新(多列)⇒ 部署持有那些列的构建(先升库、再升副本)。
3953
+ 下表前三行是预生产期(零存量用户窗口)各版当年的升级动作,保留作历史;今天的升级动作以拒启句为准。
3954
+ 只用 file/local 存储形(未配 SQL 后端)的部署不受本节任何条目影响。
3497
3955
 
3498
3956
  | 窗 | 变更 | 升级动作 |
3499
3957
  |---|---|---|
3500
3958
  | **7.6.0**(2026-08-08) | SQL 双端归一化第一刀:隔离键排序规则钉死(MySQL 腿表级 `COLLATE utf8mb4_bin`/PG 腿逐列 `COLLATE "C"`)+索引名 36 条+列名/宽度收窄 | **删库重建**(两方言) |
3501
3959
  | **7.8.0**(2026-08-09) | SQL 命名三轴归一化第二刀:9 张表名单数化、epoch 毫秒列补 `_ms` 后缀 5 列、approval 两表 `version→rev`;wire 面零变化 | **删库重建**(两方言) |
3502
3960
  | **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 产物是可恢复窗缓存,转录内联预览不受影响) |
3503
- | **7.101.0** | `session_meta` 新列 `instruction_source VARCHAR(64) NULL`(PG `COLLATE "C"`;S-690 项目指令换源通告的基线) | 两方言按拒启句里给出的 `ALTER TABLE session_meta ADD COLUMN …` 加列,或删库重建;**先升库、再升副本**(加列后旧副本重启见幽灵列拒启) |
3961
+ | **7.101.0** | `session_meta` 新列 `instruction_source VARCHAR(64) NULL`(PG `COLLATE "C"`;项目指令换源通告的基线) | 两方言按拒启句里给出的 `ALTER TABLE session_meta ADD COLUMN …` 由部署者自己加列;**先升库、再升副本**(加列后旧副本重启见幽灵列拒启) |
3504
3962
 
3505
3963
  > 列增批此前只记在 CHANGELOG / `docs/DEPLOY-PREREQS.md`(7.92.0 `session_policy`、7.93.4 `approval_ask.settled_by` 各加过一列),自 7.101.0 起同样入本表。7.101.0 这一列的拒启句自带可粘贴的 `ALTER`,本仓仍不替你执行。
3506
3964
 
@@ -3580,7 +4038,7 @@ file/local 存储形(未配 SQL 后端)的部署不受本节任何条目影响
3580
4038
  - **内网坐标默认值清理(1.180.0,npm 包卫生)**:`MODEL_GATEWAY_BASEURL` 缺省从内部网关 IP 改为
3581
4039
  `http://127.0.0.1:8000/v1` 占位——**依赖旧缺省的部署必须显式配置**;配了 `OA_ISSUE_TOKEN` 的部署
3582
4040
  现在必须同时给 `OA_ISSUE_BASEURL` 或 `GIT_API_BASEURL`(不再有烤死的内网主机兜底,缺失=启动即错)。
3583
- - **模型网关端点去出厂缺省(7.98.0,S-623;上一条那个占位本身也删了)**:`MODEL_GATEWAY_BASEURL` **没有出厂缺省**。配置能派发到的
4041
+ - **模型网关端点去出厂缺省(7.98.0;上一条那个占位本身也删了)**:`MODEL_GATEWAY_BASEURL` **没有出厂缺省**。配置能派发到的
3584
4042
  每一条 openai 兼容路由都必须解析到显式端点(目录条目自己的 `baseUrl`,或本键),否则拒启(码
3585
4043
  `config.model_route_endpoint_missing`,拒因点名模型并给出本机写法 `MODEL_GATEWAY_BASEURL=http://127.0.0.1:8000/v1`);
3586
4044
  只设 `MODEL_GATEWAY_FALLBACK_URLS` 不设本键同拒。**你要做什么**:凡隐式依赖本机 8000 网关的部署,显式写上那一行;