@sema-agent/server 7.122.0 → 7.124.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 (256) hide show
  1. package/MIGRATION.md +209 -0
  2. package/README.md +7 -2
  3. package/README.zh-CN.md +5 -2
  4. package/USAGE.md +76 -56
  5. package/dist/approval-ask-audit-store.d.ts +27 -32
  6. package/dist/approval-ask-audit-store.js +10 -9
  7. package/dist/approval-crash-convergence.d.ts +2 -2
  8. package/dist/approval-crash-convergence.js +5 -5
  9. package/dist/approval-deny-reasons.d.ts +163 -51
  10. package/dist/approval-deny-reasons.js +79 -8
  11. package/dist/approval-policy-settlement.d.ts +4 -1
  12. package/dist/approval-policy-settlement.js +3 -2
  13. package/dist/approval-reconciler.d.ts +3 -3
  14. package/dist/approval-reconciler.js +10 -10
  15. package/dist/approval.d.ts +1 -1
  16. package/dist/approval.js +1 -1
  17. package/dist/audit.d.ts +1 -1
  18. package/dist/audit.js +53 -23
  19. package/dist/auth-bridge.d.ts +8 -8
  20. package/dist/auth-bridge.js +6 -6
  21. package/dist/auth-keys.d.ts +2 -2
  22. package/dist/auto-mode-face.d.ts +13 -9
  23. package/dist/auto-mode-face.js +8 -7
  24. package/dist/boot/budget-tracing.js +1 -1
  25. package/dist/boot/execution-env.js +1 -0
  26. package/dist/boot/leader.d.ts +1 -1
  27. package/dist/boot/memory-consolidation.d.ts +4 -4
  28. package/dist/boot/org-memory.d.ts +3 -3
  29. package/dist/boot/org-memory.js +5 -5
  30. package/dist/boot/resolve-spec.js +7 -7
  31. package/dist/boot/runner-deps.d.ts +1 -1
  32. package/dist/boot/runtime-caps.d.ts +1 -1
  33. package/dist/boot/runtime-caps.js +10 -10
  34. package/dist/boot/shutdown.d.ts +2 -2
  35. package/dist/boot/shutdown.js +2 -2
  36. package/dist/boot/side-query-lane.d.ts +3 -3
  37. package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
  38. package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
  39. package/dist/boot/stage-03-store-backend.d.ts +2 -2
  40. package/dist/boot/stage-04-stores.d.ts +1 -1
  41. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  42. package/dist/boot/stage-06-runners.d.ts +2 -2
  43. package/dist/boot/stage-06-runners.js +6 -6
  44. package/dist/boot/stage-07-capability-layer.d.ts +2 -2
  45. package/dist/boot/stage-07-capability-layer.js +6 -5
  46. package/dist/boot/stage-08-reapers.d.ts +3 -3
  47. package/dist/boot/stage-08-reapers.js +3 -3
  48. package/dist/boot/stage-09-leader.d.ts +3 -3
  49. package/dist/boot/stage-09-leader.js +7 -7
  50. package/dist/boot/stage-10-http-server.d.ts +3 -3
  51. package/dist/boot/stage-10-http-server.js +19 -19
  52. package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
  53. package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
  54. package/dist/boot/{config-center.js → web-admin.js} +39 -20
  55. package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
  56. package/dist/brain.d.ts +1 -1
  57. package/dist/brain.js +1 -1
  58. package/dist/budget.d.ts +3 -3
  59. package/dist/canonical-json.d.ts +2 -2
  60. package/dist/capabilities/center-plugins.d.ts +1 -1
  61. package/dist/capabilities/center-wiring.d.ts +12 -5
  62. package/dist/capabilities/center-wiring.js +11 -2
  63. package/dist/capabilities/composite-members.d.ts +1 -1
  64. package/dist/capabilities/composite-members.js +1 -1
  65. package/dist/capabilities/scenarios.js +2 -2
  66. package/dist/capabilities/team.d.ts +1 -1
  67. package/dist/capabilities/tool-defer.d.ts +1 -1
  68. package/dist/center-credential-renewer.d.ts +1 -1
  69. package/dist/center-credential-renewer.js +7 -7
  70. package/dist/center-credential.d.ts +9 -9
  71. package/dist/center-credential.js +6 -6
  72. package/dist/config-catalog.d.ts +7 -10
  73. package/dist/config-catalog.js +16 -16
  74. package/dist/config-d-migration.d.ts +32 -0
  75. package/dist/config-d-migration.js +59 -0
  76. package/dist/config-invariants.d.ts +14 -4
  77. package/dist/config-invariants.js +31 -2
  78. package/dist/config-lkg.d.ts +34 -11
  79. package/dist/config-lkg.js +76 -48
  80. package/dist/config-provider.d.ts +26 -21
  81. package/dist/config-provider.js +25 -27
  82. package/dist/config-types.d.ts +59 -50
  83. package/dist/config.d.ts +17 -54
  84. package/dist/config.js +99 -181
  85. package/dist/execution-lane-caps.d.ts +1 -1
  86. package/dist/fleet/drain-entry.d.ts +1 -1
  87. package/dist/fleet/engine-signal.d.ts +61 -30
  88. package/dist/fleet/engine-signal.js +29 -5
  89. package/dist/fleet/fleet-bus.d.ts +12 -3
  90. package/dist/fleet/fleet-bus.js +13 -9
  91. package/dist/fleet/serving-lease.d.ts +3 -3
  92. package/dist/fleet/serving-lease.js +1 -1
  93. package/dist/fleet-client.d.ts +15 -13
  94. package/dist/fleet-client.js +9 -7
  95. package/dist/fleet-lease.d.ts +3 -3
  96. package/dist/fleet-lease.js +2 -2
  97. package/dist/host-lsp-manager.d.ts +1 -1
  98. package/dist/hosted-posture.d.ts +4 -4
  99. package/dist/http/admission.js +4 -4
  100. package/dist/http/checkpoint-ctx.d.ts +20 -3
  101. package/dist/http/checkpoint-ctx.js +13 -5
  102. package/dist/http/dispatch.js +7 -16
  103. package/dist/http/durable-run-leg.js +2 -1
  104. package/dist/http/health-self-report.d.ts +7 -4
  105. package/dist/http/health-self-report.js +3 -3
  106. package/dist/http/idempotency.d.ts +1 -1
  107. package/dist/http/resume-legs.d.ts +4 -3
  108. package/dist/http/resume-legs.js +31 -18
  109. package/dist/http/route-ctx.d.ts +8 -0
  110. package/dist/http/routes/admin-config-refresh.d.ts +1 -1
  111. package/dist/http/routes/admin-config-refresh.js +1 -1
  112. package/dist/http/routes/admin-drain.d.ts +1 -1
  113. package/dist/http/routes/admin-drain.js +5 -4
  114. package/dist/http/routes/approvals-assistant.js +4 -4
  115. package/dist/http/routes/capabilities.js +6 -5
  116. package/dist/http/routes/config-catalog.js +2 -3
  117. package/dist/http/routes/diagnostics.js +1 -1
  118. package/dist/http/routes/runs.js +8 -4
  119. package/dist/http/routes/sessions-list.js +2 -1
  120. package/dist/http/routes/sessions.js +2 -5
  121. package/dist/http/routes/side-query.js +3 -3
  122. package/dist/http/routes/tasks.js +3 -2
  123. package/dist/http/run-meta.d.ts +1 -1
  124. package/dist/http/run-meta.js +2 -2
  125. package/dist/http/server.d.ts +7 -7
  126. package/dist/http/server.js +1 -1
  127. package/dist/http/stored-body-replay.d.ts +4 -3
  128. package/dist/http/stored-body-replay.js +5 -5
  129. package/dist/index.d.ts +2 -1
  130. package/dist/index.js +1 -1
  131. package/dist/key-resolver.d.ts +1 -1
  132. package/dist/leader/leader.d.ts +7 -6
  133. package/dist/leader/leader.js +3 -1
  134. package/dist/leader/run-entry.d.ts +2 -2
  135. package/dist/leader/run-entry.js +3 -3
  136. package/dist/leader/wire.d.ts +4 -4
  137. package/dist/leader/wire.js +2 -1
  138. package/dist/main.js +1 -1
  139. package/dist/mcp-tool-faces.d.ts +2 -2
  140. package/dist/model-entry-refusal.d.ts +20 -11
  141. package/dist/model-entry-refusal.js +22 -17
  142. package/dist/model-provider.d.ts +2 -2
  143. package/dist/model-route-endpoint.d.ts +22 -2
  144. package/dist/model-route-endpoint.js +9 -3
  145. package/dist/model-route-gap.d.ts +103 -0
  146. package/dist/model-route-gap.js +80 -0
  147. package/dist/model-route-url.d.ts +1 -1
  148. package/dist/model-route-url.js +2 -1
  149. package/dist/model-select.d.ts +24 -21
  150. package/dist/model-select.js +22 -17
  151. package/dist/namespaced-rule-name.d.ts +16 -30
  152. package/dist/namespaced-rule-name.js +2 -20
  153. package/dist/observability/fail-open.d.ts +0 -4
  154. package/dist/observability/fail-open.js +0 -4
  155. package/dist/observability/metrics.d.ts +1 -1
  156. package/dist/org-memory-admission.d.ts +1 -1
  157. package/dist/plugins/approval-ask-store-file.d.ts +4 -2
  158. package/dist/plugins/approval-ask-store-file.js +3 -3
  159. package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
  160. package/dist/plugins/approval-ask-store-memory.js +10 -4
  161. package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
  162. package/dist/plugins/approval-ask-store-sql.js +20 -13
  163. package/dist/plugins/caching-session-store.d.ts +0 -10
  164. package/dist/plugins/caching-session-store.js +0 -3
  165. package/dist/plugins/file-run-store.js +9 -3
  166. package/dist/plugins/leader-run-store-sql.d.ts +3 -2
  167. package/dist/plugins/leader-run-store-sql.js +3 -2
  168. package/dist/plugins/local-session-store.d.ts +20 -27
  169. package/dist/plugins/local-session-store.js +19 -17
  170. package/dist/plugins/memory-run-store.js +9 -3
  171. package/dist/plugins/one-time-migrations.js +51 -0
  172. package/dist/plugins/scheduler-support.d.ts +26 -7
  173. package/dist/plugins/scheduler-support.js +96 -53
  174. package/dist/plugins/session-policy-store-sql.js +1 -2
  175. package/dist/plugins/store-backend.js +1 -1
  176. package/dist/plugins/store-contracts.d.ts +20 -4
  177. package/dist/plugins/web-search.d.ts +1 -1
  178. package/dist/plugins/web-search.js +2 -1
  179. package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
  180. package/dist/posture-source.d.ts +1 -1
  181. package/dist/read-face-posture.d.ts +3 -3
  182. package/dist/read-face-posture.js +1 -1
  183. package/dist/rule-entry-list.d.ts +3 -13
  184. package/dist/rule-entry-list.js +1 -12
  185. package/dist/run-local.js +10 -7
  186. package/dist/runtime-caps-resolver.d.ts +4 -4
  187. package/dist/runtime-caps-resolver.js +2 -2
  188. package/dist/runtime-governance.d.ts +36 -13
  189. package/dist/runtime-governance.js +7 -2
  190. package/dist/sealed-key.d.ts +4 -4
  191. package/dist/sealed-key.js +3 -2
  192. package/dist/security.d.ts +3 -3
  193. package/dist/service-version.d.ts +1 -1
  194. package/dist/service-version.js +5 -0
  195. package/dist/session-policy-wire.d.ts +47 -49
  196. package/dist/session-policy-wire.js +41 -36
  197. package/dist/session-sync.d.ts +5 -1
  198. package/dist/session-sync.js +2 -1
  199. package/dist/session-titler.d.ts +0 -11
  200. package/dist/session-titler.js +3 -5
  201. package/dist/shared-memory-scope-authorizer.d.ts +4 -4
  202. package/dist/spec-fields.d.ts +4 -4
  203. package/dist/spec-fields.js +1 -4
  204. package/dist/task-a2a.d.ts +1 -1
  205. package/dist/task-settings.d.ts +4 -5
  206. package/dist/task-settings.js +5 -8
  207. package/dist/tool-approval.d.ts +43 -4
  208. package/dist/tool-approval.js +147 -98
  209. package/dist/trace/core-keyset-guard.d.ts +1 -1
  210. package/dist/trace/project.d.ts +3 -3
  211. package/dist/trace/redact.d.ts +2 -23
  212. package/dist/trace/redact.js +1 -6
  213. package/dist/trace/self-minted-wire.d.ts +147 -3
  214. package/dist/trace/self-minted-wire.js +50 -9
  215. package/dist/unattended-permission-mode.d.ts +3 -3
  216. package/dist/unattended-permission-mode.js +2 -2
  217. package/dist/url-refusal.d.ts +35 -0
  218. package/dist/url-refusal.js +15 -0
  219. package/dist/user-authored-text.d.ts +31 -0
  220. package/dist/user-authored-text.js +18 -0
  221. package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
  222. package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
  223. package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
  224. package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
  225. package/dist/{config-center → web-admin-client}/center-request.js +5 -4
  226. package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
  227. package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
  228. package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
  229. package/dist/{config-center → web-admin-client}/facade.js +2 -2
  230. package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
  231. package/dist/{config-center → web-admin-client}/http-client.js +15 -15
  232. package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
  233. package/dist/{config-center → web-admin-client}/read-face.js +4 -4
  234. package/dist/web-admin-client/read-warnings.d.ts +137 -0
  235. package/dist/web-admin-client/read-warnings.js +168 -0
  236. package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
  237. package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
  238. package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
  239. package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
  240. package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
  241. package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
  242. package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
  243. package/package.json +3 -3
  244. package/skills/find-skills.md +2 -2
  245. package/dist/config-center/read-warnings.d.ts +0 -109
  246. package/dist/config-center/read-warnings.js +0 -110
  247. package/dist/url-shape.d.ts +0 -31
  248. package/dist/url-shape.js +0 -41
  249. /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
  250. /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
  251. /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
  252. /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
  253. /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
  254. /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
  255. /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
  256. /package/dist/{config-center → web-admin-client}/types.js +0 -0
package/USAGE.md CHANGED
@@ -110,13 +110,13 @@ ANTHROPIC_API_KEY=sk-ant-… # 可选:ANTHROPIC_BASE_URL / ANTHROPIC_VERSION /
110
110
  中心 / config.d 下发的候选目录里有解析不到的条目 ⇒ 候选的模型面这一组被拒、上一代模型面继续服务(同候选其余组照落)。
111
111
  - 🔴 **目录里的 anthropic 条目要本机真有 anthropic 路由**(S-704,7.101.0 起):`provider:"anthropic"` 的目录条目只在本服务配了
112
112
  `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` 时可用;没配 ⇒ 该条目**不进可选目录**(`GET /v1/models` 不列、不当缺省,缺省顺延到下一条
113
- 可用条目),启动 / 刷新日志一行 `sema_registry_model_no_brain`(带码 `config.model_no_brain` 与出路),显式点它(`body.model` /
113
+ 可用条目),启动 / 刷新日志一行 `web_admin_model_no_brain`(带码 `config.model_no_brain` 与出路),显式点它(`body.model` /
114
114
  `@名` / `settings.model` / `compactionModel` / side-query)⇒ 400 `request.model_unavailable`。**7.100.0 及以前**这种条目会落到网关
115
115
  brain、带着**它自己的** `apiKeyEnv` 钥匙打到网关。不合 settings-schema 形的条目同律(码 `config.model_entry_invalid`,如非 http(s)
116
116
  的 `baseUrl` —— 此前被「退回部署网关」;读腿逐条丢掉的条目同样留名字,点它照样 400);目录里**每条**都不可用 ⇒ 那一代模型面这一组被拒。
117
- 🔴 **日志与拒因句里的条目名先过名筛**(7.115.0 起):被拒条目的名字写进启动 / 刷新日志(`sema_registry_model_no_brain` / `_entry_invalid` 的 `model`、`sema_registry_models` 行的 `unavailable`、缺省 / 档位 / 角色绑定三条 warn 里指向被拒条目的名字)与「缺省模型缺席」「被拒名被增广铸出」两句拒因之前,先问 settings-schema 的 `isReportableRefusalName`(`[A-Za-z0-9._:/@+-]` 闭形、无密钥形、无带 userinfo 的 URL 形)。**不可披露的名只写码**:warn 不带 `model`、改带 `modelNameWithheld: true`(`unavailable` 只列可披露的名并带 `unavailableNamesWithheld` 个数);拒因句里该位写 `(name withheld)`。引擎自己的判决不受影响(显式点它照样拿拒因码);**要在日志里认出是哪一条**,把目录条目名改成名筛的闭形字符集(或按 `code` / `provider` / `fields` 在目录里找)。显式选中不可用条目的 400 回显不在此列(它回显的是调用方自己点的那个名)。
117
+ 🔴 **日志与拒因句里的条目名先过名筛**(7.115.0 起):被拒条目的名字写进启动 / 刷新日志(`web_admin_model_no_brain` / `_entry_invalid` 的 `model`、`web_admin_models` 行的 `unavailable`、缺省 / 档位 / 角色绑定三条 warn 里指向被拒条目的名字)与「缺省模型缺席」「被拒名被增广铸出」两句拒因之前,先问 settings-schema 的 `isReportableRefusalName`(`[A-Za-z0-9._:/@+-]` 闭形、无密钥形、无带 userinfo 的 URL 形)。**不可披露的名只写码**:warn 不带 `model`、改带 `modelNameWithheld: true`(`unavailable` 只列可披露的名并带 `unavailableNamesWithheld` 个数);拒因句里该位写 `(name withheld)`。引擎自己的判决不受影响(显式点它照样拿拒因码);**要在日志里认出是哪一条**,把目录条目名改成名筛的闭形字符集(或按 `code` / `provider` / `fields` 在目录里找)。显式选中不可用条目的 400 回显不在此列(它回显的是调用方自己点的那个名)。
118
118
  🔴 **被拒条目的名字不许被档位 / 别名铸到别的条目上**(S-712):不可用条目恰好叫 `sonnet` / `opus` / `pro` / `best` 这类档位词或 CC 别名、
119
- 而档位表会铸出这个词时,这份候选的模型面整组被拒(码 `config.model_refused_name_minted`,warn `sema_registry_model_plane_refused` 点名
119
+ 而档位表会铸出这个词时,这份候选的模型面整组被拒(码 `config.model_refused_name_minted`,warn `web_admin_model_plane_refused` 点名
120
120
  「被拒名 → 目标条目」)—— 否则显式点它、或绑它的角色,会静默跑在另一条条目的端点与账号上;出路:改名 / 修好条目,或改绑那条档位绑定。
121
121
  - **failover ≠ Anthropic↔vLLM**:failover 给所有 brain 发**同一个 model**(同协议同 id 的冗余);云↔本地是**按 `model.provider` 路由**的选择,不是故障转移(两者 model id/参数不同,不能透明互切)。设 `MODEL_PROVIDER=anthropic` + `MODEL_ID=claude-…` 让整个服务走 Anthropic。
122
122
  - **缺省推断**:`MODEL_PROVIDER` **未设**、但显式配了 Anthropic 协议 base URL(`ANTHROPIC_BASE_URL`)**和**对应凭证(`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`)时,缺省自动判 `anthropic` 并打一行启动 warn(`model_provider_inferred`)——纯净机直连 Anthropic 兼容上游不再需要显式第七个键。显式 `MODEL_PROVIDER` 恒赢;只给 base URL 或只给凭证不推断;两者皆无 = `gateway`,与以前逐字节一致。
@@ -336,7 +336,7 @@ MODEL_EXTRA_BODY='{"top_k":40}' # JSON 逃生口(top_k / logit_bias 等;penalt
336
336
 
337
337
  **可选 — 目录条目的供应商附加请求头(`headers`,S-931,7.108.0;两条读腿打通 = S-935,7.109.0)**
338
338
  ```jsonc
339
- // config.d/models.json(或配置中心 models 域)的一条条目:
339
+ // config.d/models.json(或 web-admin models 域)的一条条目:
340
340
  { "name": "claude-1m", "id": "<上游模型 id>", "provider": "anthropic", "api": "anthropic-messages",
341
341
  "headers": { "anthropic-beta": "context-1m-2025-08-07" } }
342
342
  ```
@@ -344,14 +344,14 @@ MODEL_EXTRA_BODY='{"top_k":40}' # JSON 逃生口(top_k / logit_bias 等;penalt
344
344
  谁受伤 = 无(缺席 ⇒ 请求逐字节同 7.107.0);补偿 = n/a(按请求变化 ⇒ 目录写两条不同名的条目,走既有的模型选择)。
345
345
  - **白名单是闭集**,每个名字带「读它的线路」:今天只有 `anthropic-beta`(只在 `api: "anthropic-messages"` 的条目上)。表外的名字(含
346
346
  `authorization` / `x-api-key` —— 凭据只走 `sealedApiKey` / `apiKeyEnv`)、大小写变体(只认小写规范拼写)、写在不读它的线路上、值不是
347
- 可见 ASCII(或含换行)⇒ **这条条目不可用**:不进可选目录,warn `sema_registry_model_entry_invalid` 点名条目与 `headers.<名>`(不回显值),
347
+ 可见 ASCII(或含换行)⇒ **这条条目不可用**:不进可选目录,warn `web_admin_model_entry_invalid` 点名条目与 `headers.<名>`(不回显值),
348
348
  显式选中它 ⇒ 400 `request.model_unavailable` `[config.model_entry_invalid]`;其余条目照常服务。
349
349
  - **per-model**:头铸进这一只模型(core `Model.headers`),同一条 anthropic 路由上别的条目不受影响;值逐字 —— core 会把它自己要开的 beta
350
350
  并进同一个 `anthropic-beta` 头(core anthropic 腿的 beta 头合并律),不会互相覆盖。模型面热应用:改了下一次请求即生效(降级壳焊住的目标除外,那一只按
351
351
  `degrade-route` 重启片走)。
352
352
  - **请求面没有 `betas`**:头是部署 ↔ 供应商的契约(计费 / 配额 / 兼容性由运维承担),不是租户可表态的位 —— `POST /v1/tasks` 带 `betas` ⇒
353
353
  400 `request.body_shape`(键闭集)。
354
- - **读腿**(7.109.0 起,S-935):`config.d/models.json` 与配置中心两条读腿逐字交出 `headers`。`@sema-agent/settings-schema` 6.4.0 的 `ModelEntry.headers`
354
+ - **读腿**(7.109.0 起,S-935):`config.d/models.json` 与 web-admin 两条读腿逐字交出 `headers`。`@sema-agent/settings-schema` 6.4.0 的 `ModelEntry.headers`
355
355
  是解析透明键 —— **契约包只做自由文本安全判**(与 `compat` / `extraBody` 同一只闸:**秘密形的值**(形似令牌 / 密钥)在那一步就让条目不可用,拒因字段是
356
356
  整键 `headers`、不回显值),**形(头名白名单 × 线路 × 值形)由本服务判**(`src/model-entry-headers.ts`,上面那几条)。
357
357
 
@@ -369,7 +369,7 @@ OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer xxx # 逗号分隔的 k=v
369
369
  MODEL_ID=<your-model-name> MODEL_CHEAP_ID=<your-cheap-model-name>
370
370
  ```
371
371
  - 调用方可在 `objective` 里 `@<模型名>` 选模型,**只认已配置的名单**(`MODEL_ID` / `MODEL_CHEAP_ID`,或目录条目)——注入不了 `baseUrl`/`apiKey`;无 `@` → 默认模型;`@` 点中一条已发布但本部署不可用的目录条目 ⇒ 400 `request.model_unavailable`(S-704)。
372
- - **`GET /v1/models`**(带 Bearer)→ `{models:[{name,id,provider,reasoning,vision}],default}`,只含名字/能力、**不含密钥** —— 消费方(如 OA)拿它做 `@` 自动补全下拉的数据源。
372
+ - **`GET /v1/models`**(带 Bearer)→ `{models:[{name,id,provider,reasoning,vision,…}],default,defaultModel,droppedEntries}`,只含名字/能力、**不含密钥** —— 消费方(如 OA)拿它做 `@` 自动补全下拉的数据源;`droppedEntries`(7.123.0 起恒在场,零条 = `[]`)是本代目录里被读腿逐条丢掉的条目(下标 + 闭集原因词 + 可披露身份),契约 §A.1d。
373
373
  - 不设 `MODEL_CHEAP_ID` → 所有角色 = 主模型(行为不变)。
374
374
  - `MODEL_CHEAP_ID` 写成与 `MODEL_ID` **同一个 id**(7.104.0 起)→ 那就是主模型本身:不铸 cheap 槽,所有角色 = 主模型,起服一行
375
375
  `config_env_entry_cheap_same_as_main`(同时设的其余 `MODEL_CHEAP_*` 键一并不生效)。要给同一只上游 id 第二种形(另一个价 / 思考 /
@@ -419,7 +419,7 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
419
419
  (env `MEMORY_SCOPE` 的 org 形 + **单用户部署**的 `projects[].defaultScopes` org 键)直通;**多租户**
420
420
  部署里由调用方 `projectId` 选中的登记簿 org 键算 **request 来源**,必须拿到授权目录的逐 principal
421
421
  授予才准入,拿不到一律 fail-closed 拒(纯读外泄面:projectId 只过形状门不过授权)。目录源**三态单选,
422
- 授权面不双源合并**:config-center 远程腿(per-principal `orgMemory` 段)> `MEMORY_ORG_DIRECTORY_JSON`
422
+ 授权面不双源合并**:web-admin 远程腿(per-principal `orgMemory` 段)> `MEMORY_ORG_DIRECTORY_JSON`
423
423
  静态表 > 缺席(request 来源的 org scope 恒拒)。同一个目录也是 `GET /v1/memory/export` /
424
424
  `POST /v1/memory/sync/:scope` 的 `org:` 属主门真源(写面另需条目 `write:true`);拒绝形 = 终局
425
425
  `memory.admission_denied`(403)/ 瞬时 `memory.admission_required`(503,带 `retryAfterSec`)。
@@ -427,16 +427,16 @@ MODEL_CODE_ROLES=default,subagent # 不设=全中立;仅这些角色在「
427
427
  | env | 缺省 | 说明 |
428
428
  |---|---|---|
429
429
  | `MEMORY_ORG_ADMISSION_MODE` | `enforce` | `enforce`=判决即结果;`audit`=**运维诊断位**——准入面判决照算、拒绝降为日志+metric,零行为变化(不整拒、不窄化写面);`/v1/memory/export`、`/v1/memory/sync/:scope` 的 `org:` 属主门在 audit 下**逐字保持收编前的 operator-only**(未验证的目录不得开数据面)。两模式都要求目录 client 在场 |
430
- | `MEMORY_ORG_DIRECTORY_JSON` | 缺省 | 单机形静态授权表 `{"<principal>":{"org:acme":{"write":true}}}`。**启动期整表校验,坏表拒启动**。有 config-center 时被忽略(center 胜 + warn) |
430
+ | `MEMORY_ORG_DIRECTORY_JSON` | 缺省 | 单机形静态授权表 `{"<principal>":{"org:acme":{"write":true}}}`。**启动期整表校验,坏表拒启动**。有 web-admin 时被忽略(center 胜 + warn) |
431
431
  | `MEMORY_ORG_GRANT_TTL_MS` | `60000`(`[1000, 3600000]`) | 授予/负结果的缓存 TTL = 「有界 LKG」:**新任务/新 resume 腿**的准入判决滞后 ≤ 此值;**在跑任务不受吊销影响**(判决点在 prepare 期) |
432
432
  | `MEMORY_ORG_UNAVAILABLE_BACKOFF_MS` | `10000`(`[500, 600000]`) | 目录取不到之后的退避窗(只用于取数失败臂,不用于负结果) |
433
433
  | `MEMORY_DELEGATION_EVIDENCE` | 缺省(=引擎自缺省 `static-face`) | **委派臂的证据标准**(core 5.45.0 起)。`static-face`=今日行为:委派的 attestation 缺失/未知**且**静态工具面够得着外部内容 ⇒ 标记本会话记忆为已污染(可能性即暴露)。`attested-only`=**只**豁免那一条静态面标记,且**真的豁免了一次**才响亮通告(`engine_notice` 的 `memory.delegation_static_mark_waived`,每个 prepared leg **至多**一次);送达 `external` attestation 照标、非委派的污染类工具照标、委派工具自身被分类为污染的照标。⚠️ 通告**不是 leg 计数器**:不含委派的 leg、污染面没挂载的 leg、送达了 attestation 的委派都不发 —— 看不到通告的常态含义是「没有可豁免的事」,不是「配置坏了」。坏值**启动期拒**。**部署席 only**(TaskSpec 无同名键,任务/受治脚本无法据此放松部署)。⚠️ **已接受的代价**:`attested-only` 下**后台**子代的真实外部接触不标记本会话(其内容经 TaskOutput / 任务通知注入 / AgentTranscript 摘要回流,三条都不带 attestation);异常收尾的前台子代同理。已标记的会话永不回滚清洗。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.delegationEvidence`(`null`=本部署未设,引擎自缺省) |
434
434
  | `MEMORY_PROVENANCE` | 缺省(=引擎自缺省 `carry`) | **记忆 provenance 总开关**(core 5.46.0 起)。一个会话被判为**已暴露**之后,它的记忆写怎么处置。`carry`=引擎缺省:**普通**记忆写照常提交,但带上引擎铸的 `origin` 标记(随条目走后端/同步/导出包);指令形文件(feedback / pinned / triggers / applies-when)仍被扣下隔离;派生索引的会话散文照回滚;内容扫描门原样跑(**标记不是豁免**)。`off`=此前的行为:不铸 origin 标记,已暴露会话的 harvest **一条都不收**(整体隔离候人审)。⚠️ 已提交的标记在编辑时照样带下去 —— `off` 停的是**铸**,从不抹掉已记的事实。与 `MEMORY_DELEGATION_EVIDENCE` **正交**(四种组合全合法):那一键决定**什么时候**判会话为已暴露,本键决定判了之后**对写做什么**。坏值**启动期拒**(`OFF`/`false`/`none` 这类「看起来像关掉」的写法一律不折成缺省 —— 静默回默认 = 一台自认为「暴露会话零收录」的部署其实在照常收录)。**部署席 only**(TaskSpec 无同名键,任务/受治脚本无法据此改姿态);**不冻进 checkpoint**(resume 腿跟当前部署配置走)。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.provenance`(`null`=本部署未设,引擎自缺省) |
435
- | `MEMORY_CAPTURE_POLICY` | 缺省(=引擎自缺省 `open`) | **记忆采集 opt-out 的部署姿态**(core 7.0.0 起)。任务可带 `memory.capture:"off"` 声明「本会话不进长期记忆」(一次性,resume 恒不采集,无反向拼写),本键决定怎么裁那条声明:`open`=按面值生效,**只有**该 principal 的显式 `false` verdict 拒(403 `memory.capture_optout_denied`),resolver 故障**放行**+披露(隐私轴 fail-safe:错拒=记了用户明说不要记的会话,不可逆);`governed`=verdict **必答**(混合车队:部分用户强制留存),故障/缺席**拒跑**(fail-closed);`capture-required`=全体声明拒(一行配置)。verdict 源**两条**(析取):①SQL 店后端上的授权表 `memory_optout_grant`(三层折叠:per-principal 行 → 部署缺省行 → 代码缺省 allow;管理面 `GET|PUT /v1/admin/memory-optout`(PUT=部署缺省行)· `PUT|DELETE …/:principal`,operator-only,能力位 `memoryOptOutGrant`,零缓存写后即生效);②非 dry-run 的 config center 在该 principal 的 entitlement caps 里发 `allowMemoryOptOut`。🔴 **`governed` 而两源皆无 ⇒ 启动期拒启**(无源 = 每个声明都被拒且没人知道为什么;接 `DB_BACKEND=mysql|pg`、接非 dry-run center,或改姿态)。⚠️ **center-only 源的语义**(只配了 center、没有 SQL 授权表):`allowMemoryOptOut` 在 entitlement schema 里是**可选键** —— center 不发它 = 该 principal 的 verdict **缺席** = `governed` 下每次 opt-out 恒拒(403 `memory.capture_optout_denied`),而 worker **照常起动**;这一形部署级证不死(per-principal 授权只有运行期才知道),所以 server 两处响亮:启动期一行 `memory_capture_governed_center_only_source`、运行期首次真缺席一行 `memory_capture_governed_verdict_absent`(每进程一次,纯披露不改判)。要确定性 verdict 就接 SQL 授权表(它三层折叠后恒答显式 boolean)。坏值**启动期拒**(`Governed`/`required`/`off` 一律不折成缺省:两种姿态的故障极性**相反**)。**部署席 only**;**不冻进 checkpoint**。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.capturePolicy`(`null`=本部署未设)。记录载体(core 7.0.2 起):SQL 后端(`DB_BACKEND=mysql\|pg`)上记录落 `session_capture_optout` 表(跨副本存活,随中央 schema 自建零旋钮)——**远端车道(e2b/k8s)的 `capture:"off"` 声明自此真持久**;`DB_BACKEND=local` 自 7.71.0 起在记忆引擎接线时供 core 的控制面文件三腿(钉在本部署记忆引擎那只控制面目录上,按记忆平面取用)⇒ 单机默认部署(`CONFIG_PROVIDER=local`、`REMOTE_EXEC` 未设)上声明与中途翻转 verb 从 409 转为真受理(此前该 409 在这一形上是结构性的:core 判「远端」看的是执行环境的接口形,host 车道同被判 remote);记忆面暗的部署本席位缺席而 core 也不走采集腿。今天仍答 409 `config.memory_capture_unsupported` 的只剩把记忆引擎接了却没给任何店的自建装配形。用户面四口:提交键 `memoryCapture:"off"`(声明形)· `POST /v1/runs/:id/memory/capture-optout`(live 中途翻转,owner 门)· `POST /v1/sessions/:id/memory/erase`(所有者自助抹除,select 硬限本会话)· `GET /v1/sessions/:id/memory-status`(状态读面,owner 门,五可选键诚实缺席)。契约全文 `docs/ASSISTANT-WIRE-CONTRACT.md` §12 |
435
+ | `MEMORY_CAPTURE_POLICY` | 缺省(=引擎自缺省 `open`) | **记忆采集 opt-out 的部署姿态**(core 7.0.0 起)。任务可带 `memory.capture:"off"` 声明「本会话不进长期记忆」(一次性,resume 恒不采集,无反向拼写),本键决定怎么裁那条声明:`open`=按面值生效,**只有**该 principal 的显式 `false` verdict 拒(403 `memory.capture_optout_denied`),resolver 故障**放行**+披露(隐私轴 fail-safe:错拒=记了用户明说不要记的会话,不可逆);`governed`=verdict **必答**(混合车队:部分用户强制留存),故障/缺席**拒跑**(fail-closed);`capture-required`=全体声明拒(一行配置)。verdict 源**两条**(析取):①SQL 店后端上的授权表 `memory_optout_grant`(三层折叠:per-principal 行 → 部署缺省行 → 代码缺省 allow;管理面 `GET|PUT /v1/admin/memory-optout`(PUT=部署缺省行)· `PUT|DELETE …/:principal`,operator-only,能力位 `memoryOptOutGrant`,零缓存写后即生效);②非 dry-run 的 web-admin 在该 principal 的 entitlement caps 里发 `allowMemoryOptOut`。🔴 **`governed` 而两源皆无 ⇒ 启动期拒启**(无源 = 每个声明都被拒且没人知道为什么;接 `DB_BACKEND=mysql|pg`、接非 dry-run center,或改姿态)。⚠️ **center-only 源的语义**(只配了 center、没有 SQL 授权表):`allowMemoryOptOut` 在 entitlement schema 里是**可选键** —— center 不发它 = 该 principal 的 verdict **缺席** = `governed` 下每次 opt-out 恒拒(403 `memory.capture_optout_denied`),而 worker **照常起动**;这一形部署级证不死(per-principal 授权只有运行期才知道),所以 server 两处响亮:启动期一行 `memory_capture_governed_center_only_source`、运行期首次真缺席一行 `memory_capture_governed_verdict_absent`(每进程一次,纯披露不改判)。要确定性 verdict 就接 SQL 授权表(它三层折叠后恒答显式 boolean)。坏值**启动期拒**(`Governed`/`required`/`off` 一律不折成缺省:两种姿态的故障极性**相反**)。**部署席 only**;**不冻进 checkpoint**。运维读面 = `GET /v1/diagnostics/wiring` 的 `memoryPosture.capturePolicy`(`null`=本部署未设)。记录载体(core 7.0.2 起):SQL 后端(`DB_BACKEND=mysql\|pg`)上记录落 `session_capture_optout` 表(跨副本存活,随中央 schema 自建零旋钮)——**远端车道(e2b/k8s)的 `capture:"off"` 声明自此真持久**;`DB_BACKEND=local` 自 7.71.0 起在记忆引擎接线时供 core 的控制面文件三腿(钉在本部署记忆引擎那只控制面目录上,按记忆平面取用)⇒ 单机默认部署(`CONFIG_PROVIDER=local`、`REMOTE_EXEC` 未设)上声明与中途翻转 verb 从 409 转为真受理(此前该 409 在这一形上是结构性的:core 判「远端」看的是执行环境的接口形,host 车道同被判 remote);记忆面暗的部署本席位缺席而 core 也不走采集腿。今天仍答 409 `config.memory_capture_unsupported` 的只剩把记忆引擎接了却没给任何店的自建装配形。用户面四口:提交键 `memoryCapture:"off"`(声明形)· `POST /v1/runs/:id/memory/capture-optout`(live 中途翻转,owner 门)· `POST /v1/sessions/:id/memory/erase`(所有者自助抹除,select 硬限本会话)· `GET /v1/sessions/:id/memory-status`(状态读面,owner 门,五可选键诚实缺席)。契约全文 `docs/ASSISTANT-WIRE-CONTRACT.md` §12 |
436
436
 
437
437
  ⚠️ **拒启动**:多租户 + 记忆面点亮 + `projects[].defaultScopes` 里有 org 键 + 目录源缺席 ⇒ 启动报错
438
438
  并点名 projectId(该部署的每个此类请求都会在 prepare 期整拒,响亮拒启动比静默全拒服务诚实)。
439
- ⚠️ **回滚脚枪**:回滚到「无 config-center」模板前先清掉残留的 `MEMORY_ORG_DIRECTORY_JSON` —— 否则
439
+ ⚠️ **回滚脚枪**:回滚到「无 web-admin」模板前先清掉残留的 `MEMORY_ORG_DIRECTORY_JSON` —— 否则
440
440
  它作为 operator 自证通道**复活旧授权**(详见 `docs/DEPLOY-PREREQS.md`)。
441
441
 
442
442
  **可选 — 模型级联 cascade(core 1.45,opt-in)**
@@ -488,6 +488,13 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
488
488
  **7.106.0+**(S-810):候选**部分应用**(某组被整组拒、其余组已提交)的拍也照同一律算这一信号 —— 修前那一拍不签;被拒的是审批组 / 模型面组时
489
489
  (新进程 boot 重判可能拒启)信号扣下、只出 warn `restart_signal_withheld_boot_may_refuse`(点名组与差异)。
490
490
  钉:`test/health-readyz.test.ts` / `test/health-readiness-single-source.test.ts`。
491
+ - **引擎信号 `engineSignal`(7.123.0+,`/health` 与 fleet 心跳都带,恒在场)**:引擎态整只,型 = settings-schema `EngineSignal`
492
+ (`@sema-agent/settings-schema/fleet`;字段以契约包为准)。不带 `instanceId`(身份只在体顶层)。与扁平键**同一次读数**:
493
+ `engineSignal.draining`(排空事实 `{actionId, since, deadlineAt}`)在场 ⇔ 扁平 `draining: true`,`drainingSince` = `engineSignal.draining.since`;
494
+ `ready` / `restart` / 成员三键 / `/health` 世代账两版本与嵌套里的同名键同值。缺席 = 更早的引擎。⚠️ `/health` 无鉴权而排空中
495
+ `engineSignal.draining.actionId` 是本次排空的动作号:引擎自起的排空是引擎的闭集词,经 `POST /v1/admin/drain` 进的是调用方自取的幂等键原样
496
+ —— 用不透明 id(推荐 `manual:<uuid>`),别放秘密或人名。扁平布尔对 `draining` / `drainingSince`
497
+ 在 settings-schema 12.0.0 删、本引擎 7.124.0+ 删发 —— 读它们的编排脚本 / 壳改读 `engineSignal.draining`。
491
498
  - **配置接力位 `configHandoff`(7.121.0+,只在 `/health`,不上心跳)**:`{ state: "missing", version, since }`,**在场 ⇔ 部署声明了耐久接力(`CONFIG_LKG_DURABLE=true`
492
499
  ∧ LKG 启用)∧ 应用着的那一代没在下一次起服将用的凭证身份的 LKG 桶里确认耐久落盘** —— 中心断着时重启按**此刻的凭证身份**选 LKG 桶,那只桶里没有这一代就回到
493
500
  别的配置。三种形:LKG 发布失败(保留候选、启动期技能债)、部分应用(某组被整拒、其余组已热应用,LKG 停在上一个完整世代)、凭据换了人(凭证文件换成别的身份,
@@ -498,7 +505,7 @@ MODEL_CASCADE_LADDER=deepseek-flash,deepseek-pro # 目录里的模型名,cheap
498
505
  `SERVICE_AUTH_TOKEN(S)`),`kinds` ⊆ `service_token` / `sso`(装了鉴权桥:登记中心的登录令牌)/ `direct_door_jwt`(直连门),
499
506
  `identityAttach` = `available`(kinds 里有 `sso` 或 `direct_door_jwt`)/ `unavailable`;`operator` = `present`(`OPERATOR_PRINCIPALS`
500
507
  非空)/ `absent`;`center = { issuer?, webBaseUrl?, sessionsVisible }` —— `issuer` = 鉴权桥的 issuer(`AUTH_BRIDGE_ISSUER`,缺席回退
501
- `SEMA_REGISTRY_URL`;没有桥 ⇒ 缺席),`webBaseUrl` = `SEMA_REGISTRY_WEB_URL` 原样(缺席即缺席),`sessionsVisible` = `true` /
508
+ `SEMA_WEB_ADMIN_URL`;没有桥 ⇒ 缺席),`webBaseUrl` = `SEMA_WEB_ADMIN_WEB_URL` 原样(缺席即缺席),`sessionsVisible` = `true` /
502
509
  `false` / `"unknown"`:中心车道配齐 ∧ `FLEET_ADVERTISE_ADDRESS` 在 ∧ 鉴权桥在 ∧ 会话枚举面在,缺一 ⇒ `false`;齐了而多租户 ⇒ `true`,
503
510
  单用户 ⇒ `"unknown"`(一条会话归谁看提交它的请求带没带身份)。两只 URL 过展示面的同一条脱敏律(凭据 / query 值不上,尾斜杠折掉)。
504
511
  ⚠️ 无鉴权面:令牌、运维名单、worker 名、中心凭证都**不上**。钉:`test/health-self-report.test.ts`。
@@ -647,18 +654,18 @@ SEND_USER_FILE_SANDBOX_PUT_ENDPOINT=… # 可选:沙箱直传 PUT 的端
647
654
 
648
655
  **可选 — 接配置控制面(中心化模型/角色/团队配置)**
649
656
  ```bash
650
- # 新名(orchestrator 现注入);旧名 CONFIG_CENTER_* 在场即 boot 拒启,只认 SEMA_REGISTRY_*
651
- # 凭证两键名 SEMA_REGISTRY_TOKEN / SEMA_REGISTRY_TOKEN_FILE 与「二选一」判官的属主 = @sema-agent/settings-schema
652
- # `CENTER_CREDENTIAL_ENV` / `judgeCenterCredentialDeclaration`(6.1.0 起;管理面 / 壳 / 本服务 import 同一处)
653
- SEMA_REGISTRY_URL=http://<config-center-host>:3100 # 启动拉 GET /api/config/effective(Bearer+ETag),覆盖 env 兜底
654
- SEMA_REGISTRY_TOKEN=<SERVICE_PULL_TOKEN 的值> # 取自配置控制面主机 .env;只读拉取令牌
655
- # SEMA_REGISTRY_TOKEN_FILE=/path/to/token # 或:凭证文件(与上一行二选一,都设=拒启)。每条中心请求都重读 ⇒ 轮换 / 换账号改写文件即可,
657
+ # 名字只有一张表(settings-schema WEB_ADMIN_ENV);旧名(SEMA_REGISTRY_* 八只、更早的 CONFIG_CENTER_* / REGISTRY_ADMIN_TOKEN)在场即 boot 拒启,只认 SEMA_WEB_ADMIN_*
658
+ # 凭证两键名 SEMA_WEB_ADMIN_TOKEN / SEMA_WEB_ADMIN_TOKEN_FILE 与「二选一」判官的属主 = @sema-agent/settings-schema
659
+ # `WEB_ADMIN_ENV` / `judgeWebAdminCredentialDeclaration`(6.1.0 起;管理面 / 壳 / 本服务 import 同一处)
660
+ SEMA_WEB_ADMIN_URL=http://<web-admin-host>:3100 # 启动拉 GET /api/config/effective(Bearer+ETag),覆盖 env 兜底
661
+ SEMA_WEB_ADMIN_TOKEN=<SERVICE_PULL_TOKEN 的值> # 取自配置控制面主机 .env;只读拉取令牌
662
+ # SEMA_WEB_ADMIN_TOKEN_FILE=/path/to/token # 或:凭证文件(与上一行二选一,都设=拒启)。每条中心请求都重读 ⇒ 轮换 / 换账号改写文件即可,
656
663
  # 中心请求面不重启;文件不可读 / 为空 = error 级 center_credential_unreadable,不当作无凭证。
657
- # 内容两种类(S-698,7.102.0;判别 = settings-schema parseCenterCredentialFile):
664
+ # 内容两种类(S-698,7.102.0;判别 = settings-schema parseWebAdminCredentialFile):
658
665
  # · 裸行 = 静态 bearer(worker 拉取令牌 / 用户 JWT),不续签,行为同 7.101.0;
659
666
  # · JSON 信封 {"kind":"user-session",accessToken,refreshToken,expiresAt,issuer}(壳登录写)
660
667
  # = 人的会话:引擎在到期前 CENTER_CREDENTIAL_RENEW_LEAD_MS 内自己续签并原子改写同一文件
661
- # (续签只向与 SEMA_REGISTRY_URL 同源的 issuer 发;400 先重读文件再判,壳与引擎两写者不打架)。
668
+ # (续签只向与 SEMA_WEB_ADMIN_URL 同源的 issuer 发;400 先重读文件再判,壳与引擎两写者不打架)。
662
669
  # 🔴 拒启两形:内容读不成([config.center_credential_malformed]:`{` 开头坏 JSON / 信封多键缺键 /
663
670
  # issuer 非 http(s) / 裸行不是令牌)、多租户(REQUIRE_PRINCIPAL=true)读到信封
664
671
  # ([config.center_credential_user_session_multi_tenant])。运行期同形 = 该次取值 fail-closed + 一次 warn。
@@ -670,23 +677,25 @@ SEMA_REGISTRY_TOKEN=<SERVICE_PULL_TOKEN 的值> # 取自配置控制面主机
670
677
  # 身份的,直到重启(`/health` 报 restartRequired,reasons 含 skills);热面(models / roles /
671
678
  # limits / 审批名单 …)在新身份第一份候选到达那一拍换代。「换账号即降档 + 当场拉取」候 S-667(不在 7.100.0)。
672
679
  # 用户 JWT 形(CLI 登录)⇒ skill 正文 / prompt 产物走 /api/v1/me/…;盘上 LKG 与 prompt 状态按「worker + 凭证身份」分箱。
673
- SEMA_REGISTRY_DRY_RUN=true # 安全灰度:只 LOG 中心配置 vs env 推导的差异,不 apply
674
- # SEMA_REGISTRY_LIVE_URL=http://<中心活性入口>:3100 # 7.121.0:fleet **活性组**(心跳 / 注销、服务租约 —— settings-schema FLEET_LIVE_PATHS)打的中心基址。
680
+ SEMA_WEB_ADMIN_DRY_RUN=true # 安全灰度:只 LOG 中心配置 vs env 推导的差异,不 apply
681
+ # SEMA_WEB_ADMIN_LIVE_URL=http://<中心活性入口>:3100 # 7.121.0:fleet **活性组**(心跳 / 注销、服务租约 —— settings-schema FLEET_LIVE_PATHS)打的中心基址。
675
682
  # 给「管理面在就绪门后、活性面另走一条不看就绪的入口」的部署(k8s:第二只 Service 带
676
- # publishNotReadyAddresses,Ingress 的活性规则指它)。缺席 = SEMA_REGISTRY_URL。用量、配额租约、
677
- # 拉配置始终打 SEMA_REGISTRY_URL。中心基址三席(SEMA_REGISTRY_URL / _LIVE_URL / _WEB_URL)同一条判据:
683
+ # publishNotReadyAddresses,Ingress 的活性规则指它)。缺席 = SEMA_WEB_ADMIN_URL。用量、配额租约、
684
+ # 拉配置始终打 SEMA_WEB_ADMIN_URL。中心基址三席(SEMA_WEB_ADMIN_URL / _LIVE_URL / _WEB_URL)同一条判据:
678
685
  # 可解析的 http(s) URL,不带凭据 / query / fragment(基址后面要拼路径),坏形拒启(没接中心也拒)。
679
686
  # 拒句只点名规则,不回显 scheme:不是合格 http(s) 形的值(`host:8080`、`<令牌>:<口令>@host`、`ftp://…`)
680
687
  # 整只成 `«redacted:url»`;合格 http(s) 形只到 `scheme://host[:port]`,后面的凭据 / 路径 / query / fragment 一律 `/…`。
681
- # SEMA_REGISTRY_WEB_URL=https://<中心 web 面> # 7.121.0:这个中心 **web 面**的固定基址,引擎原样转述到 `/health` 的 `center.webBaseUrl`
688
+ # SEMA_WEB_ADMIN_WEB_URL=https://<中心 web 面> # 7.121.0:这个中心 **web 面**的固定基址,引擎原样转述到 `/health` 的 `center.webBaseUrl`
682
689
  # (壳按它拼会话深链,路径怎么拼归壳)。缺席即缺席,引擎不拼不猜。形判同上(三席一条判据);
683
- # 只在接了中心(SEMA_REGISTRY_URL)时挂。
684
- SEMA_REGISTRY_WORKER=<worker名> # 可选:拉取 /effective?worker=<名> 取该 worker 的 roster(reconciler 按 worker 注);不设=全局 roster(向后兼容)
690
+ # 只在接了中心(SEMA_WEB_ADMIN_URL)时挂。7.124.0 起与中心身份起服互证:必须与 AUTH_BRIDGE_ISSUER
691
+ # (缺席 = SEMA_WEB_ADMIN_URL)同主机同端口(http ↔ https 同族,路径不比),否则拒启 —— 壳按 issuer 认中心、
692
+ # 按它拼深链,两者必须是同一台 web-admin。基址 / 活性基址是传输地址,不参与(可以是集群内地址)。
693
+ SEMA_WEB_ADMIN_WORKER=<worker名> # 可选:拉取 /effective?worker=<名> 取该 worker 的 roster(reconciler 按 worker 注);不设=全局 roster(向后兼容)
685
694
  FLEET_ADVERTISE_ADDRESS=http://<本机可达IP>:8090 # 可选:设了才启公告环(announce/heartbeat/注销:在中心注册成可路由实例)。
686
695
  # 必须是可解析的 http(s) base URL、不带 userinfo / query / fragment(与中心基址三席同一条判据)——
687
696
  # host:port 等坏形 boot 响亮拒(拒启码 config.fleet_advertise_address_invalid;
688
697
  # 7.121.0 起无条件解析,没接中心也拒;空串 = 未设)。公告环、成员围栏判官、/health.center 都读这一份。
689
- # 🔴 7.106.0 起(S-866 ④)用量批报**不再**看本键:中心三件(URL + 凭证 + SEMA_REGISTRY_WORKER)
698
+ # 🔴 7.106.0 起(S-866 ④)用量批报**不再**看本键:中心三件(URL + 凭证 + SEMA_WEB_ADMIN_WORKER)
690
699
  # 配齐即每 60s 向中心 POST /api/fleet/usage(不公告的引擎也报用量;中心据此对租约单调对账)。
691
700
  # 不想报就不配中心三件。caps `centerWiring.usageReport` 可读。
692
701
  # FLEET_LEASE_FAIL_CLOSED=true # S-866 ③(7.106.0):租约**连接级**失败(中心拒了本引擎的凭证 / 凭证文件读不出;中心
@@ -701,9 +710,9 @@ FLEET_ADVERTISE_ADDRESS=http://<本机可达IP>:8090 # 可选:设了才启公
701
710
  # generation(连同 leaseState / leaseUntil);排空口按它比 expectedGeneration。
702
711
  # 服务租约只在中心于心跳答复里宣告 capabilities.servingLease 之后生效;没宣告 ⇒ leaseState none,
703
712
  # 零续租零 503;位撤掉再宣告不重置 T_max 的钟(最后一次授予的到期 / 本进程第一次见到位的时刻照算)。
704
- # 🔴 设了它就必须配齐中心三件(URL + 凭证 + SEMA_REGISTRY_WORKER)与 FLEET_ADVERTISE_ADDRESS
713
+ # 🔴 设了它就必须配齐中心三件(URL + 凭证 + SEMA_WEB_ADMIN_WORKER)与 FLEET_ADVERTISE_ADDRESS
705
714
  # (不公告就听不到能力位),缺一 ⇒ 起服拒启 config.fleet_member_unfenced —— 成员不许悄悄脱离围栏。
706
- # 续租打 POST /api/fleet/live/serving-lease(契约 FLEET_PATHS.servingLease;活性基址见 SEMA_REGISTRY_LIVE_URL)。
715
+ # 续租打 POST /api/fleet/live/serving-lease(契约 FLEET_PATHS.servingLease;活性基址见 SEMA_WEB_ADMIN_LIVE_URL)。
707
716
  # 心跳答复体读不出 / 不是 JSON 对象 = 没有能力读数(位与租约钟原样,warn fleet_announce_reply_unreadable)。
708
717
  # FLEET_SCOPE=acme # 7.121.0:本引擎所在的**租户 scope**(配置渲染器为多租引擎写 = 它的 per-worker 令牌绑的 scope)。缺席 =
709
718
  # 缺省 scope global;在场必须是 scope id 形(小写字母 / 数字 / 内部连字符,1–64;空串拒启
@@ -723,14 +732,14 @@ FLEET_ADVERTISE_ADDRESS=http://<本机可达IP>:8090 # 可选:设了才启公
723
732
  ```
724
733
  - 中心**空/未发布** → `applyEffective` 回落 env + 内建 teams 并 warn `config_center_unpublished`,**不影响在跑的服务**(接了也安全)。
725
734
  - **逐条容错**(S-704 ②,7.101.0 起):目录里一条条目不合形(如 `contextWindow:"abc"`)⇒ **只丢那一条**(warn `config_entry_dropped`,
726
- 点名坐标 `models.<下标>` 与字段诊断),其余条目照用;refresh 拍 / 迟到的 boot 拉取**不再因此整拒候选**(此前一条坏条目让整份目录停在
735
+ 点名坐标 `models.<下标>`、闭集原因词 `reasonCode` 与字段诊断;7.123.0 起同一条也在 `GET /v1/models` 的 `droppedEntries` 里自报),其余条目照用;refresh 拍 / 迟到的 boot 拉取**不再因此整拒候选**(此前一条坏条目让整份目录停在
727
736
  上一代 —— 上一代若还是 env,env 模型就一直服务)。颗粒更粗的失效(整个域读不懂、拼错键、坏文件)仍整拒候选、保 LKG。
728
737
  - **没有 `MODEL_ID` 也能起**(S-705,7.101.0 起):目录(`config.d/models.json` 或中心)有可用条目时 env 可以不写 `MODEL_ID` —— 缺省模型取
729
738
  目录缺省。判据在目录应用**之后**:env `MODEL_ID` 或目录缺省任一在场即过;两者皆无 ⇒ 拒启(码 `config.default_model_missing`,指路二选一)。
730
739
  中心拉取超出 `CONFIG_BOOT_FETCH_BUDGET_MS` 又没有 LKG 时,boot 那一刻没有目录 ⇒ 没有 `MODEL_ID` 兜底就拒启(调大预算让 boot 等目录,
731
740
  或写一个 `MODEL_ID` 兜底)。
732
- - **灰度姿势**(配置控制面 AI 建议):先 `SEMA_REGISTRY_DRY_RUN=true` 起一轮,看日志 `sema_registry_dry_run`(中心给的 models/roles/teams + 会否覆盖 default、per-model apiKeyEnv)对得上 env 再去掉该 flag 真正 apply。
733
- - 拉取**只读、只取逻辑配置**(模型名册/角色/团队);密钥/网关仍在本服务 env(中心只发 env-**名** 引用,不发密钥值)。回滚=去掉 `SEMA_REGISTRY_URL` 即纯 env。
741
+ - **灰度姿势**(配置控制面 AI 建议):先 `SEMA_WEB_ADMIN_DRY_RUN=true` 起一轮,看日志 `web_admin_dry_run`(中心给的 models/roles/teams + 会否覆盖 default、per-model apiKeyEnv)对得上 env 再去掉该 flag 真正 apply。
742
+ - 拉取**只读、只取逻辑配置**(模型名册/角色/团队);密钥/网关仍在本服务 env(中心只发 env-**名** 引用,不发密钥值)。回滚=去掉 `SEMA_WEB_ADMIN_URL` 即纯 env。
734
743
  - **配置热更新真表(7.38+ 现行)**——refresh 拍(60s 轮询,或 `POST /v1/admin/config/refresh` 手动触发,见 API 表)对各域的生效方式:
735
744
 
736
745
  | 域 | 生效 | 说明 |
@@ -740,7 +749,7 @@ FLEET_ADVERTISE_ADDRESS=http://<本机可达IP>:8090 # 可选:设了才启公
740
749
  | tier 变更(档位组 / 档位绑定) | **热**(下一 refresh 拍) | 与 models 同一条换代腿:tier 表随模型面在 commit 前原子换进全部 boot Runner,下一任务按新档位路由,`/health` 不报 `restartRequired`(7.100.0 起 `models-tiers` 重启理由退役——它在生产上从未发出过) |
741
750
  | plugins(插件引用) | 重启生效 | 插件只在启动期物化;改了之后 `/health` 报 `restartRequired`,`restart.reasons` 含 `skills`(7.100.0 前这一改动**不报**,要等一次无关的重启) |
742
751
  | skills / mcp / a2a / scenarios(技能 / MCP / A2A / 场景) | 重启生效 | 只在启动期物化;中心改了 ⇒ `/health` 报 `restartRequired`,`restart.reasons` 各含其名。**换账号**(凭证身份变化)同理:这些面仍是上一身份的直到重启(候 S-667) |
743
- | 审批名单(`governance.approvalRequire`) | **热**(下一 refresh 拍) | 7.100.0 起:下一个任务调名单里的工具即停车等审批;撤键回 env 底(`APPROVAL_REQUIRE`)。**没有 checkpoint 店**的部署(`DURABLE_APPROVAL` 关 / 后端无 checkpoint 面)发非空名单 ⇒ 审批组**整组拒**(旧名单继续服务、`configAppliedVersion` 停旧代、拒因见日志 `sema_registry_approval_require_invalid` 与诊断端点 `configApply.groups.approvalGate`)—— 与启动期「名单已配却无 durable 门 ⇒ 拒启」同一条判据。此前 `/health` 报 `restartRequired`(`runtime-gates`,该理由退役) |
752
+ | 审批名单(`governance.approvalRequire`) | **热**(下一 refresh 拍) | 7.100.0 起:下一个任务调名单里的工具即停车等审批;撤键回 env 底(`APPROVAL_REQUIRE`)。**没有 checkpoint 店**的部署(`DURABLE_APPROVAL` 关 / 后端无 checkpoint 面)发非空名单 ⇒ 审批组**整组拒**(旧名单继续服务、`configAppliedVersion` 停旧代、拒因见日志 `web_admin_approval_require_invalid` 与诊断端点 `configApply.groups.approvalGate`)—— 与启动期「名单已配却无 durable 门 ⇒ 拒启」同一条判据。此前 `/health` 报 `restartRequired`(`runtime-gates`,该理由退役) |
744
753
  | 记忆整理阀门判决 + 驱动席(`MEMORY_CONSOLIDATION_DRIVER=on`,或未设而出厂缺省按目录派生 —— 7.104.0 起) | 重启生效 | 阀门开关与整理跑用的模型都在启动期定一次;中心改了 roles / 档位 / 目录条目后,**判决会翻**(派生开 ↔ 关,含只把主模型挪到整理座那一条上)或开着而座漂了 ⇒ `/health` 报 `restartRequired`,`restart.reasons` 含 `memory-consolidation`(7.100.0 新理由;7.104.0 起派生关的那台同样报) |
745
754
 
746
755
  生效与否的观测口=`/health` 世代账键(`configTargetVersion`/`configAppliedVersion`+两 ordinal+`configApplyStaleMs`,见 API 表 `/health` 行)——target≠applied 持续=「改了没生效」的机读信号。
@@ -953,7 +962,7 @@ APPROVAL_GRANT='mcp__figma__*,a2a__planner__*,Bash(git:*)' # 逗号分隔的 a
953
962
  `Read(//<dir>/**)` 读目录。`auto` 模式下交出任意代码的条目(整只 shell、解释器 / 启动器前缀)交分类器判(引擎的剔除表)。
954
963
  命令规则 `Bash(<命令>)` 按命令判每一只跑 shell 命令的工具(`Bash` 与 `Monitor`;7.122.0 起);`Monitor(<命令>)` 不是规则拼法(引擎读成空 ⇒ 启动拒,见下)。
955
964
  坏值 ⇒ **启动拒**(句子点名那一条、引擎给的原因词、怎么写):引擎读成空的条目(`*`、`mcp__*`、写路径形 `Edit(src/**)`、域名形、带空白的名字;
956
- 7.118.0 起条目名也过引擎的判官 —— 退役名 / 无前缀短名 / 协议名服务器段铸不出读成 `tool_name`,句子带现名)、工具段为空的协议名(`mcp__srv__`)。
965
+ 7.118.0 起条目名也过引擎的判官 —— 退役名 / 无前缀短名 / 协议名服务器段铸不出、工具段为空(`mcp__srv__`,7.123.0 起由引擎判;此前本服务另判)读成 `tool_name`,句子带现名或改法)。
957
966
  内容形里带逗号的规则写不进(这张表的分隔符就是逗号)。
958
967
  - **永远清不掉的**:任何一层的 deny(`APPROVAL_DENY`、请求 / 会话规则的 deny、命令策略拒档、敏感写路径)、ask 规则(`APPROVAL_REQUIRE`、请求的 ask)、
959
968
  `APPROVAL_NEVER_AUTO`、`MANUAL_MODE_SHELL_GATE=always`、写保护路径、治理、PreToolUse hook 的问、plan 模式。命中而清不掉时卡上带
@@ -961,11 +970,11 @@ APPROVAL_GRANT='mcp__figma__*,a2a__planner__*,Bash(git:*)' # 逗号分隔的 a
961
970
  - **不是白名单**:它只放,不收窄任何东西(「只许这些工具」是会话规则 `PUT /v1/sessions/:id/policy` 的 `toolAllow`)。
962
971
  - **射程如实**:规则对**每一个租户、每一条腿**生效;`mcp__<server>__*` 也覆盖那台服务器将来新增的工具。按需写窄;要收回某一只,写
963
972
  `APPROVAL_DENY` / `APPROVAL_REQUIRE`(压过本键),或删掉规则重启。
964
- - **A2A 如实**:运维声明的对端(配置中心 / `config.d`,刻意不收 `toolAxes`)上,每次技能调用都是引擎自己的外发标记问(`tool_marks_a2a`),allow 层清不掉它;
973
+ - **A2A 如实**:运维声明的对端(web-admin / `config.d`,刻意不收 `toolAxes`)上,每次技能调用都是引擎自己的外发标记问(`tool_marks_a2a`),allow 层清不掉它;
965
974
  只有请求体自带的对端(单用户闸)能在 `toolAxes` 里把某个技能的 `egress` 降为 `false`,那之后才是普通问,本键才清得掉。
966
975
  - **看得见**:起服日志一行 `approval_grant_in_force`(条数 + 规则 + 一句当前效果:清什么、清不掉什么);`GET /v1/diagnostics/wiring`(运维面)`serverGates.approvalGrant`
967
976
  = 规则原样(空表 = 未设);`GET /v1/config/catalog` 一行。客户端能力面(`/v1/capabilities`)不报它。
968
- - v1 只有 env 一个写入通道(配置中心与 settings 契约没有这个键)。
977
+ - v1 只有 env 一个写入通道(web-admin 与 settings 契约没有这个键)。
969
978
 
970
979
  **可选 — 写保护名表(S-138;缺席=引擎缺省表在岗)**
971
980
 
@@ -992,6 +1001,11 @@ WRITE_PROTECTED_TABLE_REPLACE='[{"name":".envrc","kind":"basename"}]' # 整表
992
1001
  - 租户面 `GET /v1/capabilities` → `writeProtection: {armed, rows, replaced}`(只给计数,不给行名);
993
1002
  - operator 面 `GET /v1/diagnostics/wiring` → `writeProtection: {rows[], source, droppedDefaultRows?}`
994
1003
  (`source`:`default` / `extra` / `replace` / `off`;逐行内容只在这一面)。
1004
+ - **配置根(`SEMA_CONFIG_DIR`)之内的整棵树都在这张表的射程里**(引擎 7.46.0 起):缺省表里的 `.sema` 行不只守家目录下的 `~/.sema`,也被放在你声明的配置根下 ——
1005
+ 根之内**任何**路径(不止配置文件)的写(`Write` / `Edit` / `NotebookEdit`)都要过 `write_protection` 一问。所以**配置根不要设成工作目录本身或它的祖先**
1006
+ (容器里 `SEMA_CONFIG_DIR=/workspace` 而项目在 `/workspace/proj`、或直接设成 `HOME`):项目里的每一次写都出一张卡,allow 规则清不掉它,`acceptEdits` 不放,
1007
+ `dontAsk` 拒,无人值守腿(leader、无终端的 `run-local`)拒(leader 配了耐久审批时停驻等人答),只有 `bypassPermissions` 放行。**起服不报、首条任务也不报** —— 第一次知道是第一次写。出路:把配置根指到项目之外的专用目录
1008
+ (不设即缺省 `~/.sema`);确实要保留祖先形配置根的,`WRITE_PROTECTED_TABLE_REPLACE` 给一张不含 `.sema` 行的表可去掉这一问,代价是 `~/.sema` 下的这一问一并没了。
995
1009
  - **与 `SENSITIVE_WRITE_PATTERNS` 并列、不合流**:那一根是**模式**(正则/glob)型 DENY 集,这一根是
996
1010
  字面名表的 `allow → ask` 降级。两套互不覆盖,读面也分开报 —— 一条路径被哪一套拦住,是两个不同的问题
997
1011
  (解法一个是改模式、一个是改名表)。
@@ -1050,12 +1064,12 @@ READ_DENY_PATTERNS='[{"pattern":"**/secrets/**"},{"pattern":".ssh","caseSensitiv
1050
1064
  deny 追加对 leader worker **静默不生效**(core 内建 deny 表仍在)。扩面(7.56 起)再补三席:计费/遥测
1051
1065
  `tracer`(连同后台腿的 principal 归因)、治理窗 `USAGE_WINDOWS` 两键(连同 `POST /v1/leader` 的准入门)、
1052
1066
  center 发布的提示词目录 —— 治理窗那一席的细节见 §9.2。
1053
- - **组织下发腿(config-center,7.29 起)**:四键(`READ_FACE` / `READ_DENY_PATTERNS` /
1054
- `READ_DENY_BUILTIN_TIERS` / `READ_DENY_BUILTIN_EXCLUDE`)也可由 config-center 的 `readFace` 域下发
1067
+ - **组织下发腿(web-admin,7.29 起)**:四键(`READ_FACE` / `READ_DENY_PATTERNS` /
1068
+ `READ_DENY_BUILTIN_TIERS` / `READ_DENY_BUILTIN_EXCLUDE`)也可由 web-admin 的 `readFace` 域下发
1055
1069
  (`{face?, denyPatterns?, denyBuiltinTiers?, denyBuiltinExclude?}`)。三条规则:
1056
1070
  ① **本机 env 显式恒赢**(逐键判)——env 是这台机器的部署主权,下发值不会静默盖掉它,被忽略的键留一条
1057
- `sema_registry_read_face_env_wins` warn;② **坏值整域拒**——任何一个成员过不了引擎自己的校验器就整域不落、
1058
- 保留 env 前值 + `sema_registry_read_face_invalid` warn(半应用一份 READ 姿态比不应用更危险);
1071
+ `web_admin_read_face_env_wins` warn;② **坏值整域拒**——任何一个成员过不了引擎自己的校验器就整域不落、
1072
+ 保留 env 前值 + `web_admin_read_face_invalid` warn(半应用一份 READ 姿态比不应用更危险);
1059
1073
  ③ **一席热、三席重启**(server 7.69.0 起,引擎侧交付了 read-face 的活体座席):`face` 是**热换席** ——
1060
1074
  下发或撤回一个档位,下一拍 refresh(≤60s,或手动 `POST /v1/admin/config/refresh`)当场换进全部 Runner,
1061
1075
  **不重启、也不再签 `read-face` 重启理由**(已在飞的任务保留它准备时的档位,新任务读新档);三个 deny 键
@@ -1101,7 +1115,7 @@ TASK_WRITE_FACE_ESCALATION=allow # 词表 allow|refuse;坏词启动期响亮
1101
1115
  **托管 ⇔ `REQUIRE_PRINCIPAL=true`**,只认运维自己的声明,零推断。
1102
1116
  🔴 **签发方配置不算证据**:`PRINCIPAL_JWT_PUBKEYS` / `_ISS` / `_AUD` 与 `AUTH_BRIDGE_ISSUER` 在不在场都不改变判定
1103
1117
  (7.95.0–7.98.x 曾把它们当证据,并对「配了签发方却没设 `REQUIRE_PRINCIPAL`」的机器拒启;那条拒启随之删除)。
1104
- auth-bridge 那条 `?? configCenter.baseUrl` 回退、`SEMA_REGISTRY_*`(含 worker 名)同样不读。
1118
+ auth-bridge 那条 `?? webAdmin.baseUrl` 回退、`SEMA_WEB_ADMIN_*`(含 worker 名)同样不读。
1105
1119
  ⚠️ 反面是**全量召回缺口**:忘设 `REQUIRE_PRINCIPAL` 的团队机器按单用户运行、本门放行 —— 多租机器必须自己设它,
1106
1120
  后果与被排除的候选(`OPERATOR_PRINCIPALS`、`SERVICE_AUTH_TOKENS` 条目数、`DB_BACKEND`、`BIND_HOST`)逐条写在
1107
1121
  `docs/DEPLOY-PREREQS.md`。
@@ -1587,7 +1601,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
1587
1601
  | `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役 |
1588
1602
  | `GET /v1/agents/roster` | 后台 agent **名册**(7.29 起,需 durable background-agent store,否则 501 `capability.background_agent_store_required`):调用方自己 scope 的 `a…` 行,新→旧。行只带 `handle`/`name`/`agentType`/`status`/`spawnedAt`/`updatedAt`/`settledAt`(content-free;子代产物正文走 `GET /v1/runs/<id>/subagents/<handle>/output`)。查询:`?limit=`(1..100,默认 20)、`?before=`(上一页的 `nextBefore` 游标)、`?status=`(running\|parked\|completed\|failed\|killed)、`?session=`(按会话树窄化)、`?scope=`(**仅** service-token/单用户形;带 principal 的调用方锁定自己)。回体 `{agents,total,nextBefore?,truncated?}`;`truncated:true` = 租户行数超过名册窗(500),`total` 此时是窗内数。非属主的行**不出现也不计数**(无存在性 oracle) |
1589
1603
  | `GET /v1/capabilities/scenarios/<name>` | 单个场景的只读详情:工具面、提示词概览、**本部署现在跑不跑得动**(见下) |
1590
- | `POST /v1/admin/drain` `{"actionId":"…","worker":"…","deadlineAt":…}` | **排空口**(7.121.0 起体 = settings-schema `DrainRequest`;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,空名单 ⇒ 501)。体 `{ actionId, worker, deadlineAt, scope?, expectedGeneration?, instanceId?, term? }`:`actionId` 幂等键(人手形自取,如 `manual:<uuid>`)、`worker` 本引擎的 worker 名(`SEMA_REGISTRY_WORKER`)、`deadlineAt` 到期自停的 epoch ms、`scope` 本引擎的租户 scope(`FLEET_SCOPE`;不带 = 缺省 scope `global`,与没设 `FLEET_SCOPE` 的引擎相符 —— 多租引擎要带它自己的)、`expectedGeneration` fleet 成员的代际(`FLEET_GENERATION`;非成员不带)、`instanceId` 本进程身份(`GET /health` 读;不带则不比)。身份逐字段比(`worker` / `expectedGeneration` 缺席对缺席),不符 ⇒ `409 conflict.fleet_identity`(什么都不变);首次 ⇒ `200 {actionId, since, deadlineAt, state:"draining"}` 并**进入排空**(拒新提交、本副本可抢占的在飞腿当拍让出、活的审批卡改路耐久停驻、在飞归零或到期限即停);再来 ⇒ `200 … state:"already_draining"` 回显第一次的 `since` / `deadlineAt`,不重置。体坏 ⇒ `400 request.field_invalid`;`deadlineAt` 离本引擎此刻超过 `FLEET_LEASE_OUTAGE_MAX_MS`(缺省 24 h,一台实例活着而不服务的最长时长;7.122.0 起)⇒ 同码 400(什么都不变;拒句点名字段与上界的值;只在这一发会进入排空时判 —— 已在排空或硬停已在进行时任何重发都回 `already_draining`),已过的期限照收(进入即到期);嵌入宿主(无收尾链)⇒ `501 capability.drain_state_required`。没有 worker 身份的引擎(没配 `SEMA_REGISTRY_WORKER`)恒 409 —— 用 SIGTERM。经本口进的排空之后,平台随后发的第一发 SIGTERM 被吸收、不缩短期限(第二发判据见「排空期的第二发信号」)。7.120.x 的 `{"reason":"…"}` 声明形与 `/health.drainReason` 已退役。 |
1604
+ | `POST /v1/admin/drain` `{"actionId":"…","worker":"…","deadlineAt":…}` | **排空口**(7.121.0 起体 = settings-schema `DrainRequest`;operator-only —— principal 须在 `OPERATOR_PRINCIPALS` 内,空名单 ⇒ 501)。体 `{ actionId, worker, deadlineAt, scope?, expectedGeneration?, instanceId?, term? }`:`actionId` 幂等键(人手形自取,如 `manual:<uuid>`)、`worker` 本引擎的 worker 名(`SEMA_WEB_ADMIN_WORKER`)、`deadlineAt` 到期自停的 epoch ms、`scope` 本引擎的租户 scope(`FLEET_SCOPE`;不带 = 缺省 scope `global`,与没设 `FLEET_SCOPE` 的引擎相符 —— 多租引擎要带它自己的)、`expectedGeneration` fleet 成员的代际(`FLEET_GENERATION`;非成员不带)、`instanceId` 本进程身份(`GET /health` 读;不带则不比)。身份逐字段比(`worker` / `expectedGeneration` 缺席对缺席),不符 ⇒ `409 conflict.fleet_identity`(什么都不变);首次 ⇒ `200 {actionId, since, deadlineAt, state:"draining"}` 并**进入排空**(拒新提交、本副本可抢占的在飞腿当拍让出、活的审批卡改路耐久停驻、在飞归零或到期限即停);再来 ⇒ `200 … state:"already_draining"` 回显第一次的 `since` / `deadlineAt`,不重置。体坏 ⇒ `400 request.field_invalid`;`deadlineAt` 离本引擎此刻超过 `FLEET_LEASE_OUTAGE_MAX_MS`(缺省 24 h,一台实例活着而不服务的最长时长;7.122.0 起)⇒ 同码 400(什么都不变;拒句点名字段与上界的值;只在这一发会进入排空时判 —— 已在排空或硬停已在进行时任何重发都回 `already_draining`),已过的期限照收(进入即到期);嵌入宿主(无收尾链)⇒ `501 capability.drain_state_required`。没有 worker 身份的引擎(没配 `SEMA_WEB_ADMIN_WORKER`)恒 409 —— 用 SIGTERM。经本口进的排空之后,平台随后发的第一发 SIGTERM 被吸收、不缩短期限(第二发判据见「排空期的第二发信号」)。7.120.x 的 `{"reason":"…"}` 声明形与 `/health.drainReason` 已退役。 |
1591
1605
  | `GET /v1/config/catalog` | **配置目录自描述**(operator-only —— `explicitOperatorOk`,空名单=谁都不是)。逐 env 键一行:`{name, domain, type, semantics, writeLanes, effectiveLane, envHeld, envTiming, staticDefault?/derivedDefaultNote?, effectiveValue, valueClass, danger, center?{domain,path,precedence,timing,restartSlice?,managedNow,effectiveNow}}`(🔴 7.106.0 起 `center.domainExists` 删除:座位在加载期对契约 `DOMAIN_SCHEMAS` 核过域 + 路径,核不过即拒启 ⇒ 有 `center` 块 ⇔ 中心可写;readFace 四键 / `PERMISSIONS_DISABLE_AUTO_MODE` / `MODEL_DEGRADE_ON` / `_REACTIVE` 七行的座位随之删除,S-866 ⑤a);顶层带 `restartSlices`(重启片闭集)与 `centerDomains`(settings-schema 现行域表)。**两轴不混**:`writeLanes`=谁能写,`effectiveLane`=现在谁在生效(env-wins 族 env 占位 ⇒ center 腿 `effectiveNow:false`)。secret 类值**永不回传**(只回在场位;opaque 回在场位+长度;URL 剥 userinfo)。完备性由仓内 AST 双向对账门执法(分母=全 `src/` 生产 env 读取点)。旋钮 `CONFIG_CATALOG_ENABLED=false`(合规部署)⇒ 路径 404 + 能力位 `configCatalog:false`。响应 `Cache-Control: no-store`。**7.57.0 起**:`enum` 行的 `effectiveValue` **恒落在该行自己的 `enumValues` 闭集内**(仓内机器门执法)——此前 `SESSION_BACKEND` 回的是**内部标签** `tidb`(自 5.0.0 起是**退役公名**,写回去 boot 拒),现归一成公名 `mysql`;`MODEL_DEFAULT_THINKING` 补上一直被解析器接受、却漏在目录闭集外的 `xhigh`,并改为回**实算值**(`off`/未设 ⇒ `null`)而不是 env 原文。 |
1592
1606
  | `POST /v1/admin/config/refresh` | **配置手动刷新**(operator-only,与上一行同门:空 `OPERATOR_PRINCIPALS` ⇒ 恒 403)。改完中心配置 / `config.d` 之后不想等 60s 轮询就调它:触发**一次既有**的 refresh 拍(在飞则汇入那一拍,绝不并发双拍),返回时该拍已落地。200 体 `{triggered:true,targetVersion,appliedVersion}` —— 两个世代号与 `/health` 的 `configTargetVersion`/`configAppliedVersion` 同源。本部署没有配置管道(纯 env worker:既没配 `CONFIG_CENTER`、也不是 `CONFIG_PROVIDER=local`)⇒ 409 `config.refresh_unavailable` 指路,不会回一个「触发了但什么都没发生」的 200。 |
1593
1607
  | `GET /health` | 健康(无需鉴权)。**7.67.0+** 恒带 `startedAt`(引擎进程起点 epoch ms,一次铸;与 `pid` 并列的换代锚——值变了就是换了一条命)。7.37.0+ 配置管道在场时带世代账键:`configTargetVersion`(本副本**最后见到**的配置版本,身份标)、`configAppliedVersion`(最后一次真落地的版本)、`configTargetOrdinal`/`configAppliedOrdinal`(7.38.0-rc.2 起,**收货序数**——`CONFIG_PROVIDER=local` 下 version 是内容哈希不承诺序,「改了没生效」看序数对不对齐)、`configApplyStaleMs`(target≠applied **持续**时长;收敛时键缺席)—— 编排器据此摘掉「配置持续落后」的副本 |
@@ -1654,7 +1668,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
1654
1668
  > **折叠(consolidation)阀门**。一个从未折叠过的记忆库只涨不折,检索质量随库龄衰减;开着 ⇒ worker 装上两个
1655
1669
  > operator 口(人在自己选的节奏上跑折叠),引擎面整理两席接上(下一根旋钮的前置)。
1656
1670
  > 🔴 **出厂缺省 = 开,但只在整理座不落主模型时生效**:
1657
- > - **未设 + 便宜模型在场**(`MODEL_CHEAP_ID` 设了,或目录 `config.d/models.json` / 配置中心给 `roles.consolidate` /
1671
+ > - **未设 + 便宜模型在场**(`MODEL_CHEAP_ID` 设了,或目录 `config.d/models.json` / web-admin 给 `roles.consolidate` /
1658
1672
  > `roles.summarize` / `flash` 档位绑了主模型之外的条目)⇒ **开**。判据按**装配后**的整理座(引擎自己的解析器:
1659
1673
  > consolidate → summarize,含 flash 档位缺省)解到的**目录条目**是不是主模型那一条(按条目身份,同 id 异网关的两条算两只;
1660
1674
  > `MODEL_CHEAP_ID` 与 `MODEL_ID` 写成同一个 id 则不铸 cheap 槽 —— 那就是主模型,算「没有便宜模型」),不按 env 拼写。
@@ -1665,7 +1679,7 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
1665
1679
  > ⇒ **恒关、零提示**(配不配便宜模型它都开不了;缺省不造新拒启)。
1666
1680
  > - **显式 `on` / `off` 恒赢**。显式 `on` 而座落主模型 ⇒ 照开,起服一行 warn `memory_consolidation_on_main_model`
1667
1681
  > 说清按主模型计费(部署方显式承担)。
1668
- > - 起服**判一次**:之后配置中心热改 roles / 档位(或 boot 拉取超窗、目录迟到),阀门不跟着翻,但翻的需要由
1682
+ > - 起服**判一次**:之后 web-admin 热改 roles / 档位(或 boot 拉取超窗、目录迟到),阀门不跟着翻,但翻的需要由
1669
1683
  > `restart.reasons ∋ "memory-consolidation"` 报出来 —— 判决会翻(派生开 ↔ 关,含只把主模型挪到整理座那一条上)或开着而座漂了 ⇒ 报;
1670
1684
  > 判决不翻的目录变化不报。
1671
1685
  > 启动日志 `memory_consolidation_driver_armed` 带一位 `valve`(`explicit` / `derived`)与模型 id。配置目录这一行
@@ -2026,7 +2040,7 @@ k8s 沙箱(pod `activeDeadlineSeconds` 真硬死线)向引擎声明 `lifetimeMs`
2026
2040
 
2027
2041
  ### 9.4 auto 模式(`permissionMode:"auto"`):武装三态、本地 org deny、自查(与 core 的意图武装式合修)
2028
2042
 
2029
- **背景**:此前引擎只在「组织授予」(config-center 解出的 per-principal `runtimeCaps.autoMode === true`)时武装
2043
+ **背景**:此前引擎只在「组织授予」(web-admin 解出的 per-principal `runtimeCaps.autoMode === true`)时武装
2030
2044
  auto 分类器,而无 center 的本地/自托管部署没有任何授予路径 ⇒ 壳选了 auto,引擎跑的仍是 default + 静态只读
2031
2045
  白名单(真实用户诊断属实)。core 的新武装式对齐 CC 的「用户开 + 组织拒」极性:
2032
2046
 
@@ -2053,11 +2067,15 @@ GET /v1/capabilities?permissionMode=auto
2053
2067
  → permissionModeAuto: { accepted:true, classifierSeat:true, entitlementSource:false, armed:true, model:"default" }
2054
2068
  GET /v1/capabilities?permissionMode=default
2055
2069
  → permissionModeAuto: { …, armed:false, reason:"mode_not_auto" }
2070
+ GET /v1/capabilities?permissionMode=auto (AUTONOMY=plan 的部署)
2071
+ → permissionModeAuto: { …, armed:false, reason:"operator_floor" }
2056
2072
  ```
2057
2073
 
2058
2074
  - `armed`:按上式此刻会不会武装(`?permissionMode=` 折进本次意图;查询串缺席 = 按 auto 意图答「若请求会不会武装」;
2059
2075
  core 闭集之外 400 `request.field_invalid`)。
2060
- - `reason`(未武装时,闭集**六词**,判序即武装式合取序):`mode_not_auto`(意图不是 auto)/ `deployment_incapable`
2076
+ - `reason`(未武装时,闭集**七词**,判序即武装式合取序):`mode_not_auto`(意图不是 auto,且原样到得了引擎 —— 改请求)/ `operator_floor`
2077
+ (7.123.0 起:本部署 `AUTONOMY=plan` 的入口地板把意图改成了别的词、不是 auto —— 意图缺席、`auto`、任何比 `plan` 松的词都是这一词;
2078
+ 出路是运维换档,改请求的词到不了 auto;7.122.0 在这里答 `mode_not_auto`)/ `deployment_incapable`
2061
2079
  (装配面没挂分类器席位——生产装配恒挂,桩与一次性 CLI 不挂)/ `org_denied`(`caps.autoMode === false`:center 显式 deny、
2062
2080
  center 硬失败 fail-closed 拒项)/ `local_denied`(本地旋钮 `PERMISSIONS_DISABLE_AUTO_MODE=true`,改本机 env)/ `settings_denied`
2063
2081
  (settings 层 `permissions.disableAutoMode:"disable"`——本面不产,归 run 级面)/ `resolver_fault`(per-principal resolver 抛错,
@@ -2082,7 +2100,9 @@ GET /v1/capabilities?permissionMode=default
2082
2100
  `permissionMode`;写它的只有提交入口与下面的 `plan_review` 写回。运维 `AUTONOMY=plan` 是**提交入口的模式词地板**:受理时盖进提交体
2083
2101
  (请求不带模式词 ⇒ `plan`;带任何词 ⇒ 钳成 `plan`;bundle 的 `defaultMode` 不动,顶层赢),之后不再按段续跑重钳;热改 `AUTONOMY` 只影响之后提交的任务,
2084
2102
  在飞的 run 保持它的入口词。工具表与 `default` 同面(写手、委派工具 `Agent` 都在),
2085
- 写与非只读调用在**调用时**由引擎的 plan 门问(有人可答)/ 拒(无人可答);委派的子代以 plan 为天花板继承同一道门。所以请求体带
2103
+ 写与非只读调用在**调用时**由引擎的 plan 门问(有人可答)/ 拒(无人可答)—— 问是一张审批卡,人批了就写,
2104
+ **射程是写面根围栏之内**(任务 `cwd`、引擎宣告的可写目录〔记忆目录、会话 scratchpad〕、请求的 `additionalDirectories`):批准只清模式门,引擎文件工具自己的根围栏不受批准影响,
2105
+ 围栏外的路径批了也不写(`tool_end.errorCode` = `path_not_in_root`,拒句点名 roots;写面声明为 open 的任务除外);委派的子代以 plan 为天花板继承同一道门。所以请求体带
2086
2106
  `agents`(自定义子代定义)的任务进 plan 照常起跑。此前本服务把用户选的 plan 另翻成「只读手 + 剥委派工具」,带 `agents` 的任务因此整轮被引擎拒
2087
2107
  (`config.agents.no_delegation_tool`);只读手现在只是 `AUTONOMY=read-only` 一个词的事(子代同受只读,委派照挂)。
2088
2108
 
@@ -2181,7 +2201,7 @@ WebSearch 工具的 `tool_result` 错误文本,回到模型的对话里,**不是
2181
2201
  **读面 / 展示面**(账本 / SSE / turns / 审批预览 / `GET /v1/sessions/:id`);**不碰**引擎会话存档(审计真源:store 里怎么写就怎么回、HTTP 读面才脱敏,之后每一次续轮按原文回送模型路由)与 session-sync 七口 `/v1/sessions/:id/sync/*`(逐字 durable log 出入)——这两面是**原形**——**工具结果发往「该 run 实际选中的模型路由」的请求体是原文**。⚠️ 「实际选中的路由」
2182
2202
  不等于 `MODEL_GATEWAY_BASEURL` 一根:本部署的模型出口至少四条——默认网关(`MODEL_GATEWAY_BASEURL`)、
2183
2203
  备用网关(`MODEL_GATEWAY_FALLBACK_URLS`,failover 拓扑参与)、`provider:"anthropic"` 模型的**独立直连
2184
- 路由**(缺省根 `https://api.anthropic.com`,除非显式配 `ANTHROPIC_BASEURL`)、以及配置中心可对**单个
2204
+ 路由**(缺省根 `https://api.anthropic.com`,除非显式配 `ANTHROPIC_BASEURL`)、以及 web-admin 可对**单个
2185
2205
  目录模型**下发的 per-model `baseUrl` 覆盖(见 `docs/ARCHITECTURE.md` §10「Trace/redaction」)。要让内容
2186
2206
  不出机器,靠**读侧敏感路径门**(`READ_DENY_PATTERNS` 等,见 §「执行 lane 与租户门」附近)并核对**上述
2187
2207
  四条路由每一条**都指向自己控制的基础设施——只把 `MODEL_GATEWAY_BASEURL` 指到私有网关、放着
@@ -2242,7 +2262,7 @@ docker 推送的鉴权走构建宿主上的 docker 凭据存储(`docker login`),
2242
2262
  ### 9.8 出网代理:`HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`(7.103.0 起)
2243
2263
 
2244
2264
  server 进程(HTTP 服务与 `run-local`)**所有走 undici 的出网跳**都认这三只平台标准变量:引擎 → 模型网关(http 网关发**绝对 URL 形请求**、https 网关经 `CONNECT` 隧道)、
2245
- 配置中心拉取 / fleet 公告 / 凭证续签、WebSearch、对象存储、OTLP、hook 模型调用、core 的 MCP streamable-http / A2A / WebFetch 工具 …
2265
+ web-admin 拉取 / fleet 公告 / 凭证续签、WebSearch、对象存储、OTLP、hook 模型调用、core 的 MCP streamable-http / A2A / WebFetch 工具 …
2246
2266
  实现是**一只**进程级 dispatcher,在启动时装一次;没有另外的开关 —— 这三只变量本身就是配置通道。
2247
2267
 
2248
2268
  - **读法**(与 undici 读 env 逐字同序):小写 `http_proxy` / `https_proxy` / `no_proxy` 同认**且优先**;https 目标在 `HTTPS_PROXY` 缺席 / 空时
@@ -2472,7 +2492,7 @@ server 进程(HTTP 服务与 `run-local`)**所有走 undici 的出网跳**都认
2472
2492
  ### 9.10 模型钥匙的 sealed 形(本地车道)(7.104.0 起)
2473
2493
 
2474
2494
  把模型 key 以**密文**写进 `config.d/models.json`:文件里只有密文,明文只在引擎进程的内存里出现。本节写本地车道(`CONFIG_PROVIDER=local`
2475
- 的 HTTP 服务进程);接配置中心的部署走中心形(web 面贴 key、中心存密文),开箱是同一条路径。⚠️ `run-local` 一次性 CLI **不开保管店**:
2495
+ 的 HTTP 服务进程);接 web-admin 的部署走中心形(web 面贴 key、中心存密文),开箱是同一条路径。⚠️ `run-local` 一次性 CLI **不开保管店**:
2476
2496
  同一份 `config.d` 里的 sealed 条目在 `run-local` 下是 `no_key_store`(见下表),响亮失败,不会退回别的 key。
2477
2497
 
2478
2498
  **① 取公钥。** `GET /v1/capabilities`(与其它能力位同门,在服务凭据门之后)多一段 `sealedKey`,三键:
@@ -2511,15 +2531,15 @@ const ciphertext = Buffer.from(sodium.crypto_box_seal(sodium.from_string(apiKey)
2511
2531
  这只模型的每一次模型调用都失败(用它的任务响亮失败),**不退回 `apiKeyEnv`,也不退回网关 `MODEL_API_KEY`**。🔴 **7.106.0 起(S-896)两种写法
2512
2532
  「坏了之后」方向相同**:只写 `apiKeyEnv` 而本服务进程里那个 env 变量没设(或是空串)⇒ 这只模型的钥匙同样中毒 —— 起服照常,每一次模型调用都失败、
2513
2533
  拒句点名那个变量(理由 `env_missing`),**不退回网关 `MODEL_API_KEY`**(7.105.0 及以前在这里静默退回网关 key)。配置应用时仍有一行 warn
2514
- `sema_registry_model_key_env_missing`(hint 说中毒与出路)。出路:在跑本服务的进程环境里设上那个变量并重启;真想让这只模型用网关 key,就从条目上删掉 `apiKeyEnv`。
2534
+ `web_admin_model_key_env_missing`(hint 说中毒与出路)。出路:在跑本服务的进程环境里设上那个变量并重启;真想让这只模型用网关 key,就从条目上删掉 `apiKeyEnv`。
2515
2535
 
2516
2536
  **⑤ 三种失败词**(配置应用那一拍每只模型一行 warn;用这只模型的任务在模型调用处失败,错误句里带失败词与 `publicKeyId`):
2517
2537
 
2518
2538
  | 失败词 | 什么时候出 | 怎么修 |
2519
2539
  |---|---|---|
2520
- | `sealed_decrypt_failed` | 本进程**持有**这个 `publicKeyId` 的私钥,但开不开:密文不是对着这把公钥封的、被截断或改坏(短于 48 字节)、缺了应有的 `=` 补齐。warn `sema_registry_model_sealed_key_open_failed` | 对着 caps 当前给的公钥重封,写回条目 |
2521
- | `stale_ciphertext` | 本进程**没有**这个 `publicKeyId` 的私钥:密文是对着别的进程 / 别的宿主 / 别的副本的公钥封的,或那把钥匙的私钥文件被删、读不了。warn `sema_registry_model_sealed_key_no_private_key`(带本机持有的 id) | 对着**这个进程** caps 给的公钥重封;或把那个 id 的私钥文件放回保管目录后重启 |
2522
- | `no_key_store` | 本进程没有保管店:起服时保管目录建不了、改不了权限(只读挂载 / 权限不够 / 数据根不是目录),caps 没有 `sealedKey` 段。warn `sema_registry_model_sealed_key_no_store` | 修好保管目录(进程要能建它、每次起服把它设成 `0700`)后重启 |
2540
+ | `sealed_decrypt_failed` | 本进程**持有**这个 `publicKeyId` 的私钥,但开不开:密文不是对着这把公钥封的、被截断或改坏(短于 48 字节)、缺了应有的 `=` 补齐。warn `web_admin_model_sealed_key_open_failed` | 对着 caps 当前给的公钥重封,写回条目 |
2541
+ | `stale_ciphertext` | 本进程**没有**这个 `publicKeyId` 的私钥:密文是对着别的进程 / 别的宿主 / 别的副本的公钥封的,或那把钥匙的私钥文件被删、读不了。warn `web_admin_model_sealed_key_no_private_key`(带本机持有的 id) | 对着**这个进程** caps 给的公钥重封;或把那个 id 的私钥文件放回保管目录后重启 |
2542
+ | `no_key_store` | 本进程没有保管店:起服时保管目录建不了、改不了权限(只读挂载 / 权限不够 / 数据根不是目录),caps 没有 `sealedKey` 段。warn `web_admin_model_sealed_key_no_store` | 修好保管目录(进程要能建它、每次起服把它设成 `0700`)后重启 |
2523
2543
 
2524
2544
  **⑥ 保管目录与轮换。** 保管目录 = `<数据根>/sealed-key/`(数据根 = `LOCAL_DATA_ROOT` → `CONFIG_LOCAL_DIR` → `AGENT_DATA_DIR` → `~/.ai-agent`),
2525
2545
  每把钥匙一个文件 `<publicKeyId>.json`(文件 `0600`,目录 `0700`)。**私钥只在这里**:丢了,对着它封的密文全部变成 `stale_ciphertext`,
@@ -2539,7 +2559,7 @@ const ciphertext = Buffer.from(sodium.crypto_box_seal(sodium.from_string(apiKey)
2539
2559
  或放好钥匙文件)再起其余副本 —— 空目录上并发首启会各自生成一把,各副本只持有自己那一把,直到下次重启。目录要对每个副本**可写**(每次起服
2540
2560
  会把它设成 `0700`;只读挂载 ⇒ 建店失败 ⇒ `no_key_store`)。⚠️ 只共享 `sealed-key/` 这一个子目录:`DB_BACKEND=local` 的整个数据根禁止跨容器 /
2541
2561
  跨主机共享(`docs/DEPLOY-PREREQS.md`)。
2542
- - **走中心形**:接配置中心,执行侧公钥登记在中心(起服时带管理令牌自动上报,否则把公钥打印出来供手工登记),web 面对着登记的公钥封、中心存密文。
2562
+ - **走中心形**:接 web-admin,执行侧公钥登记在中心(起服时带管理令牌自动上报,否则把公钥打印出来供手工登记),web 面对着登记的公钥封、中心存密文。
2543
2563
  调用方不必逐台去问 caps;但同一个 worker 的多个副本各有各的保管店这件事中心形不改变 —— 要它们都开得了同一份密文,仍要共享保管目录。
2544
2564
 
2545
2565
  ### 9.11 会话规则店:抹除封键与显式恢复(7.106.0 起)
@@ -35,10 +35,12 @@
35
35
  * `ask` 铸造点(呈卡帧 register 后、emit 前):wire approvalId / 出处 taskId / owner /
36
36
  * toolName / `legTracked`(出处腿是否在协调器 `runWithContext` 视野里 —— decided
37
37
  * 臂的收敛前提,见下)/ 窗死线 / 铸造时刻。
38
- * `settle` 决议点(`settle()` 公共咽喉,五臂全过):outcome(allowed/denied/expired)+
38
+ * `settle` 决议点(`settle()` 公共咽喉,五臂全过):outcome({@link SETTLE_OUTCOME} 三词)+
39
39
  * `parkRouted`(窗到期/断连等 park 路由臂如实标注 —— 该行的续命在 durable park 面,
40
- * 收敛器**不**把它当孤儿)+ 宿主自报(在场才带)+ `cause:"shutdown_before_park"`(S-929:这次等待是被**有序关停**
41
- * 结束的 —— `drainForShutdown` 按断连同路收场的活卡;park 路由的那几行**等观察到 core 已处置这次调用才落**(F1:停车行提交 / 承载它的腿退场,后者恒在 `leg_closed` 之前),两者皆无就退出 ⇒ 无此行;闭集 {@link AuditShutdownCause},词表外 ⇒ 计坏行、结清照认)。
40
+ * 收敛器**不**把它当孤儿)+ 宿主自报(在场才带)+ **`cause`(成因闭集 {@link SettleCause},`approval-deny-reasons.ts`)**:
41
+ * `outcome:"expired"`(非人结局)恒带、人答(`allowed` / `denied`)恒缺席 —— 写口的联合型逼每个非人调用点点名一个;
42
+ * 词表外 ⇒ 计坏行、结清照认;本版之前落盘的 `expired` 行没有 `cause`(存量审计行不回填,读面缺席即缺席)。
43
+ * `cause:"shutdown_before_park"`(S-929)= 这次等待是被**有序关停**结束的 —— `drainForShutdown` 按断连同路收场的活卡;park 路由的那几行**等观察到 core 已处置这次调用才落**(F1:停车行提交 / 承载它的腿退场,后者恒在 `leg_closed` 之前),两者皆无就退出 ⇒ 无此行。
42
44
  * `leg_closed` 腿闭点(`runWithContext` finally;只为铸过审计行的 taskId 落,防账本膨胀):
43
45
  * 「决议之后腿有没有闭」是 decided 臂唯一的机械证据面 —— 没有它,「批完跑完」与
44
46
  * 「批了、执行窗内崩」在账本字节上同形,收敛器只能二选一地撒谎。
@@ -169,7 +171,7 @@
169
171
  */
170
172
  import type { HostDecision } from "./host-decision.js";
171
173
  import { AppendLog } from "@sema-agent/core";
172
- import type { HolderGoneReason, VOID_REASONS } from "./approval-deny-reasons.js";
174
+ import { SETTLE_OUTCOME, type HolderGoneCause, type SettleCause } from "./approval-deny-reasons.js";
173
175
  /** 数据子目录名(挂在 local 数据根下,与 `workflow-notify/` 同层同形)。 */
174
176
  export declare const APPROVAL_ASK_AUDIT_DIR = "approval-ask-audit";
175
177
  /** 账本文件名(目录内唯一一只;启动收敛据它判「盘上有没有前世审计证据」,见 `approval-crash-convergence.ts` 的 `openAuditEvidenceForConvergence`)。 */
@@ -194,38 +196,30 @@ export interface AuditAskInput {
194
196
  expiresAtMs: number;
195
197
  mintedAtMs: number;
196
198
  }
197
- /**
198
- * S-929:审计账本上「这件事因**有序关停**而结束」的成因词(闭集,今天一个词)。settle 行的 `cause` 与收敛行的 `cause`
199
- * 共用这一个词。读盘词表 = {@link AUDIT_SHUTDOWN_CAUSE_WORDS}(编译期穷举)。词表外的值(新版本写的、本二进制不认识的成因 / 手改)⇒
200
- * **计坏行**(`corruptLines`,坏值响亮律 —— 不静默读成「没写成因」),但**不丢该 settle 行的结清**(F4:outcome / parkRouted 照认 ——
201
- * 因为一个成因词把整条结清行丢掉,会把一张已结清的卡收成 pending 孤儿,方向比「少认一个成因」更坏)。
202
- */
203
- export type AuditShutdownCause = typeof VOID_REASONS.HOLDER_SHUTDOWN;
204
- /**
205
- * 成因词的读盘词表(F4:`satisfies Record<AuditShutdownCause, true>` ⇒ 闭集加一个词而本表没跟 = **编译红**;判定走 `Object.hasOwn`,
206
- * 原型链上的名字不算词 —— CLAUDE.md 词表律)。唯一读者 = {@link readShutdownCause}。
207
- */
208
- export declare const AUDIT_SHUTDOWN_CAUSE_WORDS: {
209
- readonly shutdown_before_park: true;
210
- };
211
- /** 收敛行 `cause` 的闭集(`GET /v1/approvals` `crashConverged[].cause`):崩溃孤儿 / 有序关停截断的腿(S-929 +1;与 `crashed_before_park` 同形)。
212
- * 🔴 **词表属主 = `approval-deny-reasons.ts` 的 `VOID_REASONS`**(`HOLDER_CRASHED` / `HOLDER_SHUTDOWN`):启动收敛把同一问的问账行收成 VOID 时
213
- * `deniedReason` 写的就是这两个词 —— 同一问在 `crashConverged` 与决断口 410 体上只有一个成因词(本型不再自带一份字面量)。
214
- * wire 值闭集登记在 `trace/self-minted-wire.ts` 的 `crashConvergedCause`(`satisfies Record<CrashConvergedCause, …>` 双向绑定 ⇒ 加词不登记 = tsc 红,
215
- * wire 变更清单从那张表 diff —— F3)。 */
216
- export type CrashConvergedCause = HolderGoneReason;
217
- /** 决议点入参(`settle()` 公共咽喉挂线;五臂全过,不漏窗到期/断连/取消)。 */
218
- export interface AuditSettleInput {
199
+ /** 决议点入参共有的位(联合型的两臂都带)。 */
200
+ interface AuditSettleBase {
219
201
  approvalId: string;
220
- outcome: "allowed" | "denied" | "expired";
221
202
  /** 走了 park 路由(windowRouteUnavailable)—— 该行的续命在 durable park 面,收敛器不当孤儿。 */
222
203
  parkRouted?: boolean;
223
- /** S-929:这次等待是被有序关停结束的(`ToolApprovalCoordinator.drainForShutdown`);缺席 = 别的臂。 */
224
- cause?: AuditShutdownCause;
225
204
  /** 宿主自报来源(HostSettledBy;在场才带)。收敛器不消费,纯审计。 */
226
205
  settledBy?: string;
227
206
  settledAtMs: number;
228
207
  }
208
+ /**
209
+ * 决议点入参(`settle()` 公共咽喉挂线;五臂全过,不漏窗到期/断连/取消)。**判别联合**:`cause` 在场 ⇔ 非人结局(`outcome:"expired"`)——
210
+ * 人答(`allowed` / `denied`)不带 `cause`,非人结局不点名成因就**编译不过**(类型面上没有「`expired` 而无成因」这个值)。
211
+ */
212
+ export type AuditSettleInput = (AuditSettleBase & {
213
+ outcome: typeof SETTLE_OUTCOME.ALLOWED | typeof SETTLE_OUTCOME.DENIED;
214
+ cause?: undefined;
215
+ }) | (AuditSettleBase & {
216
+ outcome: typeof SETTLE_OUTCOME.EXPIRED;
217
+ cause: SettleCause;
218
+ });
219
+ /** 收敛行 `cause` 的闭集(`GET /v1/approvals` `crashConverged[].cause`):崩溃孤儿 / 有序关停截断的腿(S-929 +1;与 `crashed_before_park` 同形)。
220
+ * 🔴 **词表属主 = `approval-deny-reasons.ts` 的 {@link HolderGoneCause}**(本表两词的子集):启动收敛把同一问的问账行收成 VOID 时 `denied_reason` 写的就是这两个词 ——
221
+ * 同一问在 `crashConverged` 与决断口 410 体上只有一个成因词。wire 值闭集登记在 `trace/self-minted-wire.ts` 的 `crashConvergedCause`
222
+ * (`satisfies Record<HolderGoneCause, …>` 双向绑定 ⇒ 加词不登记 = tsc 红,wire 变更清单从那张表 diff —— F3)。 */
229
223
  /**
230
224
  * [ref] **迟到人工结算点**入参:调用方(两条 HTTP decide 腿)只交 **checkpoint 锚 + 这次结算的事实**,
231
225
  * `approvalId` 的反查与「算不算迟到」的判据**属主在店内**(一处成文,见 {@link FileApprovalAskAuditStore.recordLateSettle})
@@ -302,9 +296,9 @@ export interface CrashConvergedRow {
302
296
  * 不是语义(改这个值会让把它当闭集判别式读的消费端整行丢弃,须与消费端同窗改)。
303
297
  */
304
298
  decision: "denied";
305
- /** 成因注(闭集 {@link CrashConvergedCause}):`crashed_before_park` = 进程崩了;`shutdown_before_park`(S-929)= 腿被**有序关停**截断
299
+ /** 成因注(闭集 {@link HolderGoneCause}):`crashed_before_park` = 进程崩了;`shutdown_before_park`(S-929)= 腿被**有序关停**截断
306
300
  * (判据见头注「收敛行的 `cause`」)。两者的 `orphanState` / `resumeSafe` 判据相同。 */
307
- cause: CrashConvergedCause;
301
+ cause: HolderGoneCause;
308
302
  orphanState: CrashOrphanState;
309
303
  /** decided 臂:人当时批的是 approve(这句话不许被终态同码吞掉)。 */
310
304
  originalDecision?: "approve";
@@ -447,7 +441,7 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
447
441
  * {@link causeOf})。前世账本里没有这只 `approvalId` 的铸造行(崩在 ask 账落行之后、本店铸造行之前,或本店那时不在)⇒ `crashed_before_park`:
448
442
  * 没有有序关停的证据,就不说它是有序关停。判据读的是构造时冻结的前世账本 ⇒ 同一份账本跨几次启动恒得同一个词。
449
443
  */
450
- causeFor(approvalId: string): CrashConvergedCause;
444
+ causeFor(approvalId: string): HolderGoneCause;
451
445
  /** S-929 收敛行的成因注(判据见头注「收敛行的 `cause`」):组的最后一个事件行之后、收敛行(若已收敛)之前,有本 taskId 的
452
446
  * 有序关停记号 ⇒ `shutdown_before_park`;否则 `crashed_before_park`。 */
453
447
  private causeOf;
@@ -466,4 +460,5 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
466
460
  /** 收追加口(优雅关闭腿;SIGKILL 下不跑也不丢 —— 每行已 fsync)。core `AppendLog.close()` 自己吞 `closeSync` 的错、不抛(全函数),本店不再包 catch。 */
467
461
  close(): void;
468
462
  }
463
+ export {};
469
464
  //# sourceMappingURL=approval-ask-audit-store.d.ts.map