@sema-agent/settings-schema 10.1.1 → 11.0.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 (235) hide show
  1. package/CHANGELOG.md +414 -0
  2. package/README.md +141 -65
  3. package/bin/settings-schema.mjs +13 -6
  4. package/conformance/VERSION +1 -1
  5. package/conformance/baseline.json +3 -1
  6. package/conformance/cases/c01-entry-salvage-then-typo/expected.json +3 -1
  7. package/conformance/cases/c02-hosts-clamp-stacked/expected.json +12 -5
  8. package/conformance/cases/c02-hosts-clamp-stacked/meta.json +1 -1
  9. package/conformance/cases/c03-literal-dotted-top-key/expected.json +22 -2
  10. package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +3 -1
  11. package/conformance/cases/c06-legacy-governance-lift/expected.json +11 -101
  12. package/conformance/cases/c06-legacy-governance-lift/meta.json +1 -1
  13. package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +3 -1
  14. package/conformance/cases/c08-limits-unknown-carried-64/expected.json +203 -2
  15. package/conformance/cases/c09-limits-unknown-carried-65/expected.json +204 -2
  16. package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +3 -1
  17. package/conformance/cases/c11-unicode-unknown-keys/expected.json +20 -2
  18. package/conformance/cases/c12-prototype-name-top-keys/expected.json +3 -1
  19. package/conformance/cases/c13-models-field-null/expected.json +3 -1
  20. package/conformance/cases/c14-models-field-empty-array/expected.json +6 -1
  21. package/conformance/cases/c15-models-field-number/expected.json +3 -1
  22. package/conformance/cases/c16-deep-nesting-205/expected.json +14 -2
  23. package/conformance/cases/c17-empty-domain-file/expected.json +3 -1
  24. package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +3 -1
  25. package/conformance/cases/c19-wire-envelope-no-version/expected.json +3 -1
  26. package/conformance/cases/c20-governance-absent-lifts/expected.json +11 -86
  27. package/conformance/cases/c20-governance-absent-lifts/meta.json +1 -1
  28. package/conformance/cases/c21-governance-empty-object-wins/expected.json +6 -5
  29. package/conformance/cases/c21-governance-empty-object-wins/input.json +1 -4
  30. package/conformance/cases/c21-governance-empty-object-wins/meta.json +1 -1
  31. package/conformance/cases/c23-mixed-validity-models/expected.json +3 -1
  32. package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +22 -2
  33. package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +6 -1
  34. package/conformance/cases/c26-hosts-array-1024/expected.json +3 -1
  35. package/conformance/cases/c27-hosts-array-1025/expected.json +6 -7175
  36. package/conformance/cases/c27-hosts-array-1025/meta.json +1 -1
  37. package/conformance/cases/c28-large-document-over-1mb/expected.json +14 -2
  38. package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +3 -1
  39. package/conformance/cases/c30-version-triple-a-first/expected.json +6 -1
  40. package/conformance/cases/c31-version-triple-b-changed/expected.json +6 -1
  41. package/conformance/cases/c32-version-triple-a-restored/expected.json +6 -1
  42. package/conformance/cases/c33-limits-nested-carried-key/expected.json +18 -2
  43. package/conformance/cases/c34-skills-content-vs-manifest/expected.json +19 -3
  44. package/conformance/cases/c35-portable-domain-file-is-null/expected.json +3 -1
  45. package/conformance/cases/c36-skills-entry-without-content/expected.json +6 -2
  46. package/conformance/cases/c37-skills-field-null/expected.json +6 -2
  47. package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +3 -1
  48. package/conformance/cases/c39-hidden-file-in-config-d/expected.json +3 -1
  49. package/conformance/cases/c40-s712-identity-only-what-reads-out/expected.json +11 -4
  50. package/conformance/cases/c41-s792-encoded-pem-identity/expected.json +9 -3
  51. package/conformance/cases/c42-s792-unknown-key-secret-redacted/expected.json +39 -2
  52. package/conformance/cases/c43-s792-form-and-deep-encoded-pem/expected.json +4 -1
  53. package/conformance/cases/c44-s792-utf8-escape-glued-token/expected.json +3 -1
  54. package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/expected.json +19 -10
  55. package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/meta.json +1 -1
  56. package/conformance/cases/{c46-s811-host-name-url-userinfo-characterization → c46-s811-host-name-url-userinfo-withheld}/expected.json +12 -5
  57. package/conformance/cases/c46-s811-host-name-url-userinfo-withheld/meta.json +9 -0
  58. package/conformance/cases/{c47-s811-roles-key-url-userinfo-characterization → c47-s811-roles-key-url-userinfo-withheld}/expected.json +23 -3
  59. package/conformance/cases/{c47-s811-roles-key-url-userinfo-characterization → c47-s811-roles-key-url-userinfo-withheld}/input.json +6 -0
  60. package/conformance/cases/c47-s811-roles-key-url-userinfo-withheld/meta.json +10 -0
  61. package/conformance/cases/c48-s935-model-headers-transported/expected.json +6 -1
  62. package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +3 -1
  63. package/conformance/cases/c50-s784-lane-host-legal/expected.json +3 -1
  64. package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +3 -1
  65. package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +3 -1
  66. package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +3 -1
  67. package/conformance/cases/c54-s784-lane-adb-legal/expected.json +3 -1
  68. package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +3 -1
  69. package/conformance/cases/c56-s784-lane-device-legal/expected.json +3 -1
  70. package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +3 -1
  71. package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +3 -1
  72. package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +3 -1
  73. package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +3 -1
  74. package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +3 -1
  75. package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +3 -1
  76. package/conformance/cases/c63-s784-host-two-replicas/expected.json +3 -1
  77. package/conformance/cases/c64-s784-multitenant-local-store/expected.json +3 -1
  78. package/conformance/cases/c65-s784-pg-without-db/expected.json +3 -1
  79. package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +3 -1
  80. package/conformance/cases/c67-s784-retired-field-loud/expected.json +3 -1
  81. package/conformance/cases/c67-s784-retired-field-loud/meta.json +1 -1
  82. package/conformance/cases/c68-s784-device-local-store/expected.json +3 -1
  83. package/conformance/cases/c69-deep-encoded-token-past-every-reading/expected.json +3 -1
  84. package/conformance/cases/c70-rewritten-token-in-front-of-encoded-pem-header/expected.json +3 -1
  85. package/conformance/cases/c71-one-scanner-write-reads-display-forms/expected.json +119 -0
  86. package/conformance/cases/c71-one-scanner-write-reads-display-forms/input.json +24 -0
  87. package/conformance/cases/c71-one-scanner-write-reads-display-forms/meta.json +10 -0
  88. package/conformance/cases/c72-dangling-reference-write-seat-refuses/expected.json +111 -0
  89. package/conformance/cases/c72-dangling-reference-write-seat-refuses/input.json +26 -0
  90. package/conformance/cases/c72-dangling-reference-write-seat-refuses/meta.json +6 -0
  91. package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +3 -1
  92. package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +3 -1
  93. package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +6 -1
  94. package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +11 -1
  95. package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +11 -1
  96. package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +16 -2
  97. package/conformance/cases/cli04-env-value-with-newline/expected.json +3 -1
  98. package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +6 -1
  99. package/conformance/cases/t01-absent-domain-key-not-null/expected.json +3 -1
  100. package/conformance/cases/t03-prototype-name-key-not-swallowed/expected.json +29 -2
  101. package/conformance/cases/t04-secret-literal-never-in-warning-value/expected.json +3 -1
  102. package/conformance/cases/z01-every-domain-empty-object/expected.json +8 -4
  103. package/conformance/cases/z01-every-domain-empty-object/input.json +0 -1
  104. package/conformance/cases/z01-every-domain-empty-object/meta.json +1 -1
  105. package/conformance/cases/z02-every-domain-unknown-key/expected.json +163 -23
  106. package/conformance/cases/z02-every-domain-unknown-key/input.json +0 -3
  107. package/conformance/cases/z02-every-domain-unknown-key/meta.json +1 -1
  108. package/dist/api/auth-bridge.d.ts +51 -181
  109. package/dist/api/auth-bridge.js +58 -33
  110. package/dist/api/auth.d.ts +37 -146
  111. package/dist/api/auth.js +16 -26
  112. package/dist/api/feedback.d.ts +87 -0
  113. package/dist/api/feedback.js +66 -0
  114. package/dist/api/pull-token.d.ts +32 -0
  115. package/dist/api/pull-token.js +88 -0
  116. package/dist/api/scopes.d.ts +82 -174
  117. package/dist/api/scopes.js +23 -18
  118. package/dist/bundle.d.ts +15 -7
  119. package/dist/bundle.js +28 -27
  120. package/dist/cli.d.ts +3 -1
  121. package/dist/cli.js +132 -81
  122. package/dist/config-d-file.d.ts +14 -0
  123. package/dist/config-d-file.js +67 -0
  124. package/dist/config-fns.d.ts +87 -186
  125. package/dist/config-fns.js +207 -262
  126. package/dist/conformance/contract-adapter.d.ts +9 -2
  127. package/dist/conformance/contract-adapter.js +15 -7
  128. package/dist/conformance/corpus.d.ts +3 -0
  129. package/dist/conformance/corpus.js +5 -0
  130. package/dist/conformance/derive.d.ts +3 -0
  131. package/dist/conformance/index.d.ts +2 -2
  132. package/dist/conformance/index.js +2 -2
  133. package/dist/conformance/run.js +67 -22
  134. package/dist/conformance/types.d.ts +31 -15
  135. package/dist/conformance/types.js +5 -0
  136. package/dist/conformance/warnings.d.ts +1 -1
  137. package/dist/conformance/warnings.js +1 -4
  138. package/dist/cross-domain.d.ts +66 -22
  139. package/dist/cross-domain.js +164 -93
  140. package/dist/cross-session.d.ts +29 -11
  141. package/dist/default-model.d.ts +43 -0
  142. package/dist/default-model.js +34 -0
  143. package/dist/execution-lane-index.d.ts +4 -8
  144. package/dist/execution-lane-index.js +4 -8
  145. package/dist/execution-lanes.d.ts +31 -8
  146. package/dist/execution-lanes.js +23 -5
  147. package/dist/file-edit.js +5 -2
  148. package/dist/file-store.d.ts +7 -6
  149. package/dist/file-store.js +37 -50
  150. package/dist/fleet.d.ts +364 -762
  151. package/dist/fleet.js +277 -224
  152. package/dist/hooks.d.ts +1151 -4737
  153. package/dist/hooks.js +59 -15
  154. package/dist/index.d.ts +10 -4
  155. package/dist/index.js +13 -7
  156. package/dist/integer.d.ts +11 -0
  157. package/dist/integer.js +11 -0
  158. package/dist/issue-path.d.ts +10 -0
  159. package/dist/issue-path.js +10 -0
  160. package/dist/loopback.d.ts +26 -0
  161. package/dist/loopback.js +54 -0
  162. package/dist/migration-receipt.d.ts +42 -0
  163. package/dist/migration-receipt.js +12 -0
  164. package/dist/one-time-migrations.d.ts +56 -0
  165. package/dist/one-time-migrations.js +819 -0
  166. package/dist/prompts-digest.d.ts +1 -1
  167. package/dist/prompts-digest.js +3 -2
  168. package/dist/reader.d.ts +2 -2
  169. package/dist/remote-exec.d.ts +45 -187
  170. package/dist/remote-exec.js +13 -7
  171. package/dist/resolve-roster.d.ts +18 -3
  172. package/dist/resolve-roster.js +28 -25
  173. package/dist/retired-envs.d.ts +24 -0
  174. package/dist/retired-envs.js +114 -0
  175. package/dist/retired-form.d.ts +31 -0
  176. package/dist/retired-form.js +28 -0
  177. package/dist/safety-merge-spec.d.ts +131 -191
  178. package/dist/safety-merge-spec.js +18 -14
  179. package/dist/scheduler-lifetime.d.ts +5 -0
  180. package/dist/scheduler-lifetime.js +7 -0
  181. package/dist/scheduler-store-migration.d.ts +14 -0
  182. package/dist/scheduler-store-migration.js +14 -0
  183. package/dist/scheduler-store-node.d.ts +24 -9
  184. package/dist/scheduler-store-node.js +25 -15
  185. package/dist/scheduler-store.d.ts +47 -14
  186. package/dist/scheduler-store.js +32 -61
  187. package/dist/secret-refs.d.ts +3 -3
  188. package/dist/secret-refs.js +1 -1
  189. package/dist/secret-scan.d.ts +14 -24
  190. package/dist/secret-scan.js +45 -23
  191. package/dist/sha256-core.d.ts +16 -0
  192. package/dist/sha256-core.js +138 -0
  193. package/dist/sha256.d.ts +6 -1
  194. package/dist/sha256.js +8 -98
  195. package/dist/skills-manifest.js +1 -1
  196. package/dist/types.d.ts +1501 -13536
  197. package/dist/types.js +494 -438
  198. package/dist/url-shape.d.ts +34 -0
  199. package/dist/url-shape.js +61 -0
  200. package/dist/web-admin-credential.d.ts +96 -0
  201. package/dist/{center-credential.js → web-admin-credential.js} +46 -43
  202. package/dist/web-admin-env.d.ts +33 -0
  203. package/dist/web-admin-env.js +33 -0
  204. package/dist/worker-row-verdict.d.ts +16 -0
  205. package/dist/worker-row-verdict.js +31 -0
  206. package/dist/workers-rows.d.ts +34 -0
  207. package/dist/workers-rows.js +42 -0
  208. package/dist/zod-unwrap.d.ts +11 -0
  209. package/dist/zod-unwrap.js +25 -0
  210. package/package.json +17 -9
  211. package/conformance/cases/c46-s811-host-name-url-userinfo-characterization/meta.json +0 -6
  212. package/conformance/cases/c47-s811-roles-key-url-userinfo-characterization/meta.json +0 -6
  213. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/expected.json +0 -49
  214. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/input.json +0 -26
  215. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/meta.json +0 -4
  216. package/conformance/migrate-workers/m02-g5-idempotent/expected.json +0 -38
  217. package/conformance/migrate-workers/m02-g5-idempotent/input.json +0 -33
  218. package/conformance/migrate-workers/m02-g5-idempotent/meta.json +0 -5
  219. package/conformance/migrate-workers/m03-g5-refused-no-lane/expected.json +0 -71
  220. package/conformance/migrate-workers/m03-g5-refused-no-lane/input.json +0 -42
  221. package/conformance/migrate-workers/m03-g5-refused-no-lane/meta.json +0 -4
  222. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/expected.json +0 -52
  223. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/input.json +0 -30
  224. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/meta.json +0 -4
  225. package/conformance/migrate-workers/m05-row-verdict-reserved-env/expected.json +0 -82
  226. package/conformance/migrate-workers/m05-row-verdict-reserved-env/input.json +0 -68
  227. package/conformance/migrate-workers/m05-row-verdict-reserved-env/meta.json +0 -4
  228. package/dist/center-credential.d.ts +0 -116
  229. package/dist/issue-text.d.ts +0 -10
  230. package/dist/issue-text.js +0 -8
  231. package/dist/migrate-workers.d.ts +0 -71
  232. package/dist/migrate-workers.js +0 -351
  233. package/dist/migrate.d.ts +0 -255
  234. package/dist/migrate.js +0 -542
  235. /package/conformance/cases/{c46-s811-host-name-url-userinfo-characterization → c46-s811-host-name-url-userinfo-withheld}/input.json +0 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * 退役 env 名的**墓碑表** —— 一张表,本包是它的唯一属主:引擎(server)起服时按它拒启、目录 wire 的 `retired[]` 由它投影,
3
+ * 壳在起本机引擎之前、web-admin 在给 worker 渲染 env 之前读同一张(谁都不再手抄、不再从别人的构建产物里正则抽)。
4
+ *
5
+ * **进表的判据(一条):没有任何受支持的引擎还读这个名。** 一个名字还被在跑的引擎当活旋钮读时就进表,等于让照旧配置的部署拒启 ——
6
+ * 改名的那一版只登记现名,旧名等引擎换读现名之后的那一版再进表。
7
+ *
8
+ * 🪦 **墓碑是永久的响亮拒,不设到期**。一行墓碑就是那句拒启句本身,成本一行;删掉它 = 旧名重新被悄悄忽略。
9
+ * ⇒ 本表只增不减,**唯一的删除条件是这个名字要被赋予新含义**:那一次提交同时删掉这一行,并在发布说明里写明旧名改作何用。
10
+ * (与一次性迁移不是一回事:迁移碰真数据,所以有窗、窗关即删码;墓碑不碰数据,只拒启。)
11
+ *
12
+ * **旧名在场即拒,替代名在不在都一样**:判据只问旧名在不在场,不看替代键设没设、设成什么 ——「新旧两个名字都留着」正是
13
+ * 迁移到一半的部署最常见的形,旧名在那一形里若被静默忽略,运维会以为它还在生效。空串 = 未设(compose `${X:-}` 透传的空值
14
+ * 不是一次表态),不拒。
15
+ *
16
+ * **链只有一跳**:一行的去向永远是现名,不是另一个也已退役的名字(否则照拒句改完仍被拒)。一个名字第二次改名时,指向它的
17
+ * 旧行同拍改指新名。
18
+ *
19
+ * 墓碑分三族,族是**闭集**,每族各说各的尾句(渲染是穷举映射,加一族不写尾句 = 编译红):
20
+ * · `renamed` = 同一能力换了个键名,值语义逐字不变 ⇒「照新名改写即可」;
21
+ * · `replaced` = 有替代键,但**值语义变了**(缺省 / `0` 义 / 计量段 / 极性不同)⇒ 点名新键 + 说清变了什么,**不许**说「语义不变」
22
+ * —— 照抄旧值过去就是另一个意思;
23
+ * · `removed` = 能力本身没了,`why` 是「为什么没了」,**没有可 rename 的目标**。
24
+ * 拒句带码 {@link RETIRED_ENV_REFUSAL_CODE}(拒启码,出现在拒句方括号里)。
25
+ *
26
+ * 行形 = 字面元组(第三元是族词),一行一个旧名。纯数据 + 纯函数,零 IO,browser-safe。
27
+ */
28
+ import { WEB_ADMIN_ENV } from "./web-admin-env.js";
29
+ /** 墓碑拒启码(机读;拒句方括号里)。 */
30
+ export const RETIRED_ENV_REFUSAL_CODE = "config.env_key_retired";
31
+ const OA_REMOVED = "the OA scenario was removed in 5.0.0";
32
+ const negativeAliasWhy = (old, positive) => `negative-name alias retired in server 3.0.0 — unset it; the polarity is inverted: ${old}=true is ${positive}=false (the positive name defaults on)`;
33
+ export const RETIRED_ENVS = [
34
+ ["TIDB_HOST", "MYSQL_HOST", "renamed"],
35
+ ["TIDB_PORT", "MYSQL_PORT", "renamed"],
36
+ ["TIDB_USER", "MYSQL_USER", "renamed"],
37
+ ["TIDB_PASSWORD", "MYSQL_PASSWORD", "renamed"],
38
+ ["TIDB_DATABASE", "MYSQL_DATABASE", "renamed"],
39
+ ["TIDB_POOL_SIZE", "MYSQL_POOL_SIZE", "renamed"],
40
+ ["ANTHROPIC_BASEURL", "ANTHROPIC_BASE_URL", "renamed"],
41
+ // web-admin 连接名两代前的 `CONFIG_CENTER_*` / `REGISTRY_ADMIN_TOKEN`,直指现名(一跳)。
42
+ ["CONFIG_CENTER_URL", WEB_ADMIN_ENV.url, "renamed"],
43
+ ["CONFIG_CENTER_TOKEN", WEB_ADMIN_ENV.token, "renamed"],
44
+ ["CONFIG_CENTER_DRY_RUN", WEB_ADMIN_ENV.dryRun, "renamed"],
45
+ ["CONFIG_CENTER_WORKER", WEB_ADMIN_ENV.worker, "renamed"],
46
+ ["REGISTRY_ADMIN_TOKEN", WEB_ADMIN_ENV.adminToken, "renamed"],
47
+ // OA 场景整体退役:配置本身作废,无替代名。
48
+ ["OA_API_BASEURL", OA_REMOVED, "removed"],
49
+ ["OA_SERVICE_TOKEN", OA_REMOVED, "removed"],
50
+ ["OA_ISSUE_TOKEN", OA_REMOVED, "removed"],
51
+ ["OA_ISSUE_BASEURL", OA_REMOVED, "removed"],
52
+ ["OA_ISSUE_OWNER", OA_REMOVED, "removed"],
53
+ ["OA_ISSUE_REPO", OA_REMOVED, "removed"],
54
+ ["OA_ISSUE_LABELS", OA_REMOVED, "removed"],
55
+ ["APPROVAL_POLL_MS", "the OA poll-approval lane was removed in 5.0.0; the durable checkpoint lane is the only gate", "removed"],
56
+ // 合不上 = 交给用户:冲突解决模型整条通道删除,本键没有替代名。
57
+ ["LEADER_CONFLICT_ROUNDS", "the bounded merge-conflict-resolution agent was deleted in 7.83.0; an unmergeable result goes back to the user: leader returns result.conflict (branch + conflicting files) and the run status is needs_human", "removed"],
58
+ // 名义「建连」、实际计到响应头的旋钮。替代键计的是同一段,但缺省、`0` 义与重试形都变了。
59
+ ["MODEL_CONNECT_TIMEOUT_MS", "MODEL_FIRST_BYTE_TIMEOUT_MS", "replaced", "since core 7.33.0 the TCP + TLS connect clock is the transport's own; the wait from sending the request to its response headers — what this key really bounded — is MODEL_FIRST_BYTE_TIMEOUT_MS (unset = core's own default, plus an upload allowance and one widened retry; 0 = no engine clock on that segment and the transport's header / body clocks off too — the TCP + TLS connect keeps the transport's own clock)"],
60
+ // 旧负名:替代键在、但极性相反(照抄旧值过去恰好是反义)。
61
+ ["PROJECT_MEMORY_DISABLED", "PROJECT_MEMORY_ENABLED", "replaced", negativeAliasWhy("PROJECT_MEMORY_DISABLED", "PROJECT_MEMORY_ENABLED")],
62
+ ["CONFIG_LKG_DISABLED", "CONFIG_LKG_ENABLED", "replaced", negativeAliasWhy("CONFIG_LKG_DISABLED", "CONFIG_LKG_ENABLED")],
63
+ ["HOST_BG_DISABLED", "HOST_BG_ENABLED", "replaced", negativeAliasWhy("HOST_BG_DISABLED", "HOST_BG_ENABLED")],
64
+ ["HOST_EXEC_SPOOL_DISABLED", "HOST_EXEC_SPOOL_ENABLED", "replaced", negativeAliasWhy("HOST_EXEC_SPOOL_DISABLED", "HOST_EXEC_SPOOL_ENABLED")],
65
+ // 无人值守腿的模式旋钮退役:这些腿的答集是常量,不是旋钮。
66
+ ["UNATTENDED_PERMISSION_MODE", "since server 7.109.0 the unattended legs (leader workers and their repair legs, run-local, and their durable resumes) always run permissionMode \"default\" with an approver that answers by ask class: a machine answers only \"ordinary\" asks, and every other class goes to the leg's approver seat (run-local's terminal prompt) or parks / is refused — there is no mode to choose", "removed"],
67
+ ];
68
+ // 冻结:拿到导出的人改不了拒启判据(读拒句的与投影 wire 的是同一个数组对象)。
69
+ for (const row of RETIRED_ENVS)
70
+ Object.freeze(row);
71
+ Object.freeze(RETIRED_ENVS);
72
+ /** 墓碑表 → wire 投影(纯数据)。**同一张表、同序**;族是闭集,穷举 switch(加一族不写这里 ⇒ 编译红)。 */
73
+ export function buildRetiredEnvWire() {
74
+ return RETIRED_ENVS.map((row) => {
75
+ switch (row[2]) {
76
+ case "renamed":
77
+ return { name: row[0], kind: row[2], replacement: row[1] };
78
+ case "replaced":
79
+ return { name: row[0], kind: row[2], replacement: row[1], reason: row[3] };
80
+ case "removed":
81
+ return { name: row[0], kind: row[2], reason: row[1] };
82
+ default: {
83
+ const unhandled = row;
84
+ throw new Error(`unhandled retired-env kind: ${String(unhandled[2])}`);
85
+ }
86
+ }
87
+ });
88
+ }
89
+ /** 每族的拒句片段 —— 穷举映射型:加一族不补这里即编译红;句子的**次序**也只读这张表(声明序),不另列一份。 */
90
+ const RETIRED_ENV_SENTENCE = {
91
+ renamed: (hits) => `${hits.map(([old, to]) => `${old} → use ${to}`).join("; ")} — rename the env key(s); the value semantics are unchanged`,
92
+ replaced: (hits) => `${hits.map(([old, to, , why]) => `${old} → ${to} (${why})`).join("; ")} — set the replacement deliberately: ` +
93
+ `its value semantics differ from the retired key's, so do not copy the old value across unread`,
94
+ removed: (hits) => `${hits.map(([old, why]) => `${old} (${why})`).join("; ")} — remove the env key(s): the capability itself was retired, ` +
95
+ `there is no replacement name and no rename that restores it`,
96
+ };
97
+ function retiredEnvSentence(kind, hit) {
98
+ const ofKind = hit.filter((h) => h[2] === kind);
99
+ return ofKind.length > 0 ? [RETIRED_ENV_SENTENCE[kind](ofKind)] : [];
100
+ }
101
+ /**
102
+ * 读给它的 env 记录,判有没有退役名在场 —— 拒启句的**唯一铸点**:有 ⇒ 整句(带 {@link RETIRED_ENV_REFUSAL_CODE};族序 renamed →
103
+ * replaced → removed,族内按表序;只点名键、从不回显值);没有 ⇒ `undefined`。空串 = 未设。
104
+ *
105
+ * 纯函数:不读 `process.env`(读方传自己要判的那份 env —— 引擎起服传进程 env,壳传它要交给子进程的那份,web-admin 传它要渲染的
106
+ * worker env);拒不拒(抛 / 退出码 / 400)是读方的事。
107
+ */
108
+ export function retiredEnvRefusal(env) {
109
+ const hit = RETIRED_ENVS.filter(([old]) => env[old] !== undefined && env[old] !== "");
110
+ if (hit.length === 0)
111
+ return undefined;
112
+ const parts = Object.keys(RETIRED_ENV_SENTENCE).flatMap((kind) => retiredEnvSentence(kind, hit));
113
+ return `retired env name(s) set [${RETIRED_ENV_REFUSAL_CODE}] — refused while present, whether or not the replacement is also set: ${parts.join(" | ")}.`;
114
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * retired 形的**拒句**与**墓碑**(11.0.0)—— 包内私有(不进主桶)。
3
+ *
4
+ * 一条律:**旧形只有一种去处 —— 登记过窗的一次性迁移改写它(`./one-time-migrations`);读写两面遇旧形都响亮拒,拒句点名迁移 id。**
5
+ * 拒句只在这里拼(一个模板),三处用它:retired 域(`RETIRED_DOMAINS`,读者 throw `RetiredDomainError`)、retired 键(域 schema 里的
6
+ * {@link retiredKey} 墓碑字段,zod issue)、保留名闸里「迁移搬得走」的 env 键({@link migrationSignpost})。
7
+ *
8
+ * 墓碑是**拒**,不是第二种读法:它不把旧形读成任何值,只说「这里有一份没迁的旧形」以及去哪儿迁。迁移族按登记表的窗整族删,
9
+ * 墓碑留下 —— 到那时拒句里的迁移 id 由删码那一车改写(登记表那一行的 `removal` 点名了这件事)。
10
+ */
11
+ import { z } from "zod";
12
+ /** 迁移命令行的唯一拼写:`npx` 全名形 —— 没装本包的运维粘贴即可跑(裸 bin 名在没装本包的机器上是 `command not found`)。参数是一个 `config.d` 目录。 */
13
+ export declare const MIGRATE_COMMAND: "npx @sema-agent/settings-schema migrate";
14
+ /** 拒句尾的迁移指路:存量由哪一条一次性迁移改写、两种跑法(子路径的函数 / 目录命令)。`before` = 旧形不再合法的那一版。
15
+ * 刻意短:它挂在 zod issue 句尾,读侧逐条容错时每一条被丢的条目都要过一遍出门脱敏。 */
16
+ export declare function migrationSignpost(migration: string, before: string): string;
17
+ /** 一个retired 形的整句:`<form> was retired in <版本> — now <今天住哪>; <指路>`。 */
18
+ export interface RetiredForm {
19
+ /** retired的版本。 */
20
+ readonly retiredIn: string;
21
+ /** 事实今天住哪(一句,点名新位)。 */
22
+ readonly now: string;
23
+ /** 改写存量的一次性迁移 id(`./one-time-migrations` 的闭集;到期门核它在登记表里)。 */
24
+ readonly migration: string;
25
+ }
26
+ export declare function retiredFormSentence(form: string, t: RetiredForm): string;
27
+ /**
28
+ * retired**键**的墓碑字段:放在该键原来所在的对象形里,键缺席 = 合法,键在场(任何值)= 一条 issue(路径就是那个键、句子点名迁移)。
29
+ * 输出形里它恒缺席(型上是 `?: undefined`),JSON Schema 上是 `not: {}`(「不许出现」)—— 墓碑写在旧键原来的位置上,schema 自己说明它retired了。
30
+ */
31
+ export declare function retiredKey(key: string, t: RetiredForm): z.ZodOptional<z.ZodNever>;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * retired 形的**拒句**与**墓碑**(11.0.0)—— 包内私有(不进主桶)。
3
+ *
4
+ * 一条律:**旧形只有一种去处 —— 登记过窗的一次性迁移改写它(`./one-time-migrations`);读写两面遇旧形都响亮拒,拒句点名迁移 id。**
5
+ * 拒句只在这里拼(一个模板),三处用它:retired 域(`RETIRED_DOMAINS`,读者 throw `RetiredDomainError`)、retired 键(域 schema 里的
6
+ * {@link retiredKey} 墓碑字段,zod issue)、保留名闸里「迁移搬得走」的 env 键({@link migrationSignpost})。
7
+ *
8
+ * 墓碑是**拒**,不是第二种读法:它不把旧形读成任何值,只说「这里有一份没迁的旧形」以及去哪儿迁。迁移族按登记表的窗整族删,
9
+ * 墓碑留下 —— 到那时拒句里的迁移 id 由删码那一车改写(登记表那一行的 `removal` 点名了这件事)。
10
+ */
11
+ import { z } from "zod";
12
+ /** 迁移命令行的唯一拼写:`npx` 全名形 —— 没装本包的运维粘贴即可跑(裸 bin 名在没装本包的机器上是 `command not found`)。参数是一个 `config.d` 目录。 */
13
+ export const MIGRATE_COMMAND = "npx @sema-agent/settings-schema migrate";
14
+ /** 拒句尾的迁移指路:存量由哪一条一次性迁移改写、两种跑法(子路径的函数 / 目录命令)。`before` = 旧形不再合法的那一版。
15
+ * 刻意短:它挂在 zod issue 句尾,读侧逐条容错时每一条被丢的条目都要过一遍出门脱敏。 */
16
+ export function migrationSignpost(migration, before) {
17
+ return `data stored before ${before}: run the one-time migration ${migration} (@sema-agent/settings-schema/one-time-migrations, or ${MIGRATE_COMMAND} <dir>)`;
18
+ }
19
+ export function retiredFormSentence(form, t) {
20
+ return `${form} was retired in ${t.retiredIn} — now ${t.now}; ${migrationSignpost(t.migration, t.retiredIn)}`;
21
+ }
22
+ /**
23
+ * retired**键**的墓碑字段:放在该键原来所在的对象形里,键缺席 = 合法,键在场(任何值)= 一条 issue(路径就是那个键、句子点名迁移)。
24
+ * 输出形里它恒缺席(型上是 `?: undefined`),JSON Schema 上是 `not: {}`(「不许出现」)—— 墓碑写在旧键原来的位置上,schema 自己说明它retired了。
25
+ */
26
+ export function retiredKey(key, t) {
27
+ return z.never({ error: retiredFormSentence(key, t) }).optional();
28
+ }
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * #14 SAFETY MERGE-SPEC — the ONE machine-readable per-category merge/enforcement table that every settings
3
- * resolver (TOC shell-adapter + TOB center/service) reads, so they never re-implement (and drift on) the merge
3
+ * resolver (TOC shell-adapter + TOB web-admin/service) reads, so they never re-implement (and drift on) the merge
4
4
  * law. This formalizes settings-core's v2-design §3 merge-spec into a published-data contract; the SEMANTIC
5
- * author is settings-core, center maintains the formalized artifact here (registry-core), the axis VALUE domains
5
+ * author is settings-core, web-admin maintains the formalized artifact here (this package), the axis VALUE domains
6
6
  * are core's (@sema-agent/core SAFETY_AXIS_VOCABULARY — validated by a dev-only conformance test, never a runtime
7
- * import). Each consumer keeps its OWN key→category map (client's SemaSettings KEY_CONTRACTS, center's
7
+ * import). Each consumer keeps its OWN key→category map (client's SemaSettings KEY_CONTRACTS, web-admin's
8
8
  * config-field→category map); THIS file is only the shared category spec they all cite — no third copy of the law.
9
9
  *
10
10
  * Per-category behavior is fully determined by `mergeShape` + `minTrust` + `tighten` + `enforcement` + `fail` — and,
@@ -52,7 +52,13 @@
52
52
  */
53
53
  import { z } from "zod";
54
54
  /** How values from different layers/principals combine for a category. */
55
- export declare const MergeShape: z.ZodEnum<["denyFirst", "replace", "runAll", "overrideByName", "concat"]>;
55
+ export declare const MergeShape: z.ZodEnum<{
56
+ concat: "concat";
57
+ replace: "replace";
58
+ denyFirst: "denyFirst";
59
+ runAll: "runAll";
60
+ overrideByName: "overrideByName";
61
+ }>;
56
62
  export type MergeShape = z.infer<typeof MergeShape>;
57
63
  /** The trust-tier VOCABULARY a category — or, since 1.1.0, one of its members — names as its admission floor
58
64
  * (the MINIMUM trust a layer/principal must have to set it). The RANK is v2-design §1:29,
@@ -60,7 +66,14 @@ export type MergeShape = z.infer<typeof MergeShape>;
60
66
  * {@link isAtLeast}. `task` (1.2.0) is the runtime task overlay — the lowest trust, the loosest floor.
61
67
  * ⚠️ This enum's DECLARATION ORDER is NOT the rank (it is the 1.1.0 order with `task` appended — kept byte-stable
62
68
  * because reordering is breaking); never index it as a ladder — use {@link trustRank}. */
63
- export declare const MinTrust: z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>;
69
+ export declare const MinTrust: z.ZodEnum<{
70
+ local: "local";
71
+ session: "session";
72
+ global: "global";
73
+ project: "project";
74
+ managed: "managed";
75
+ task: "task";
76
+ }>;
64
77
  export type MinTrust = z.infer<typeof MinTrust>;
65
78
  /** The trust RANK of a floor / layer word — v2-design §1:29 verbatim (`MANAGED 6 > GLOBAL 5 > PROJECT 4 > LOCAL 3 >
66
79
  * SESSION 2 > TASK 1`), the ONE published ladder every resolver compares against (1.2.0). Higher = more trusted.
@@ -80,7 +93,10 @@ export declare function isAtLeast(layer: MinTrust, minTrust: MinTrust): boolean;
80
93
  * suggestion (consent flow) rather than drop it silently. This package returns that metadata only — it performs
81
94
  * no admission and no degradation; whether a given consumer version implements the outlet is that consumer's
82
95
  * contract. */
83
- export declare const MemberDirection: z.ZodEnum<["loosen", "tighten"]>;
96
+ export declare const MemberDirection: z.ZodEnum<{
97
+ loosen: "loosen";
98
+ tighten: "tighten";
99
+ }>;
84
100
  export type MemberDirection = z.infer<typeof MemberDirection>;
85
101
  /** One member's admission row. `minTrust` ABSENT ⇒ the category's `minTrust` applies: a row can refine the floor
86
102
  * only by SAYING so; omission never lowers it (fail-closed by construction).
@@ -95,33 +111,30 @@ export type MemberDirection = z.infer<typeof MemberDirection>;
95
111
  * fail-closed (it loses only the convenience of low-trust tightening, it can never admit a loosening write).
96
112
  * Resolution is value-aware: pass the candidate value to {@link memberAdmission} / {@link memberMinTrust}. */
97
113
  export declare const MemberAdmission: z.ZodObject<{
98
- direction: z.ZodEnum<["loosen", "tighten"]>;
99
- minTrust: z.ZodOptional<z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>>;
114
+ direction: z.ZodEnum<{
115
+ loosen: "loosen";
116
+ tighten: "tighten";
117
+ }>;
118
+ minTrust: z.ZodOptional<z.ZodEnum<{
119
+ local: "local";
120
+ session: "session";
121
+ global: "global";
122
+ project: "project";
123
+ managed: "managed";
124
+ task: "task";
125
+ }>>;
100
126
  boolPole: z.ZodOptional<z.ZodObject<{
101
127
  strict: z.ZodBoolean;
102
- minTrust: z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>;
103
- }, "strip", z.ZodTypeAny, {
104
- strict: boolean;
105
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
106
- }, {
107
- strict: boolean;
108
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
109
- }>>;
110
- }, "strip", z.ZodTypeAny, {
111
- direction: "loosen" | "tighten";
112
- minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
113
- boolPole?: {
114
- strict: boolean;
115
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
116
- } | undefined;
117
- }, {
118
- direction: "loosen" | "tighten";
119
- minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
120
- boolPole?: {
121
- strict: boolean;
122
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
123
- } | undefined;
124
- }>;
128
+ minTrust: z.ZodEnum<{
129
+ local: "local";
130
+ session: "session";
131
+ global: "global";
132
+ project: "project";
133
+ managed: "managed";
134
+ task: "task";
135
+ }>;
136
+ }, z.core.$strip>>;
137
+ }, z.core.$strip>;
125
138
  export type MemberAdmission = z.infer<typeof MemberAdmission>;
126
139
  /** The RESOLVED admission a consumer branches on — the category fallback already applied, so `minTrust` is never
127
140
  * absent here. Produced by {@link resolveMemberAdmission} / {@link memberAdmission}. */
@@ -137,187 +150,114 @@ export interface ResolvedMemberAdmission {
137
150
  }
138
151
  /** WHERE the category is enforced (STRENGTH) — MUST stay in lockstep with `EffectiveKey.enforcement` (types.ts).
139
152
  * gate=data-plane engine, server=control-plane/TOB boundary, resolver=merger correctness, client=UI only. */
140
- export declare const SpecEnforcement: z.ZodEnum<["gate", "server", "resolver", "client"]>;
153
+ export declare const SpecEnforcement: z.ZodEnum<{
154
+ gate: "gate";
155
+ server: "server";
156
+ resolver: "resolver";
157
+ client: "client";
158
+ }>;
141
159
  export type SpecEnforcement = z.infer<typeof SpecEnforcement>;
142
160
  /** Fail direction when enforcement can't be evaluated. fail-OPEN is allowed for `client` OR `resolver`
143
161
  * enforcement on NON-secret keys (additive merges like mcpServers/rules/env); `gate`/`server`/secret → CLOSED. */
144
- export declare const FailMode: z.ZodEnum<["closed", "open"]>;
162
+ export declare const FailMode: z.ZodEnum<{
163
+ closed: "closed";
164
+ open: "open";
165
+ }>;
145
166
  export type FailMode = z.infer<typeof FailMode>;
146
167
  /** The monotone tighten-only direction for a category (which way is "stricter"). `enumRank.order` lists values
147
- * from LOOSEST→STRICTEST; `boolStricter.strict` is the bool value that is the tighter one; `setNarrower` = a
148
- * subset is tighter; `policyDenyWins` = deny beats allow; `none` = not rank-tightenable (replace / conflict-reject). */
149
- export declare const TightenRule: z.ZodDiscriminatedUnion<"rule", [z.ZodObject<{
168
+ * from LOOSEST→STRICTEST — the category's whole vocabulary: a word outside it is refused, and a ONE-word order (11.0.0:
169
+ * `shellGate`, whose engine vocabulary is the single floor word) is the degenerate rank where the only merge is identity;
170
+ * `boolStricter.strict` is the bool value that is the tighter one; `setNarrower` = a subset is tighter; `policyDenyWins` =
171
+ * deny beats allow; `none` = not rank-tightenable (replace / conflict-reject). */
172
+ export declare const TightenRule: z.ZodDiscriminatedUnion<[z.ZodObject<{
150
173
  rule: z.ZodLiteral<"none">;
151
- }, "strip", z.ZodTypeAny, {
152
- rule: "none";
153
- }, {
154
- rule: "none";
155
- }>, z.ZodObject<{
174
+ }, z.core.$strip>, z.ZodObject<{
156
175
  rule: z.ZodLiteral<"policyDenyWins">;
157
- }, "strip", z.ZodTypeAny, {
158
- rule: "policyDenyWins";
159
- }, {
160
- rule: "policyDenyWins";
161
- }>, z.ZodObject<{
176
+ }, z.core.$strip>, z.ZodObject<{
162
177
  rule: z.ZodLiteral<"setNarrower">;
163
- }, "strip", z.ZodTypeAny, {
164
- rule: "setNarrower";
165
- }, {
166
- rule: "setNarrower";
167
- }>, z.ZodObject<{
178
+ }, z.core.$strip>, z.ZodObject<{
168
179
  rule: z.ZodLiteral<"boolStricter">;
169
180
  strict: z.ZodBoolean;
170
- }, "strip", z.ZodTypeAny, {
171
- strict: boolean;
172
- rule: "boolStricter";
173
- }, {
174
- strict: boolean;
175
- rule: "boolStricter";
176
- }>, z.ZodObject<{
181
+ }, z.core.$strip>, z.ZodObject<{
177
182
  rule: z.ZodLiteral<"enumRank">;
178
- order: z.ZodArray<z.ZodString, "many">;
179
- }, "strip", z.ZodTypeAny, {
180
- rule: "enumRank";
181
- order: string[];
182
- }, {
183
- rule: "enumRank";
184
- order: string[];
185
- }>]>;
183
+ order: z.ZodArray<z.ZodString>;
184
+ }, z.core.$strip>], "rule">;
186
185
  export type TightenRule = z.infer<typeof TightenRule>;
187
186
  export declare const MergeCategorySpec: z.ZodObject<{
188
- mergeShape: z.ZodEnum<["denyFirst", "replace", "runAll", "overrideByName", "concat"]>;
189
- minTrust: z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>;
190
- tighten: z.ZodDiscriminatedUnion<"rule", [z.ZodObject<{
187
+ mergeShape: z.ZodEnum<{
188
+ concat: "concat";
189
+ replace: "replace";
190
+ denyFirst: "denyFirst";
191
+ runAll: "runAll";
192
+ overrideByName: "overrideByName";
193
+ }>;
194
+ minTrust: z.ZodEnum<{
195
+ local: "local";
196
+ session: "session";
197
+ global: "global";
198
+ project: "project";
199
+ managed: "managed";
200
+ task: "task";
201
+ }>;
202
+ tighten: z.ZodDiscriminatedUnion<[z.ZodObject<{
191
203
  rule: z.ZodLiteral<"none">;
192
- }, "strip", z.ZodTypeAny, {
193
- rule: "none";
194
- }, {
195
- rule: "none";
196
- }>, z.ZodObject<{
204
+ }, z.core.$strip>, z.ZodObject<{
197
205
  rule: z.ZodLiteral<"policyDenyWins">;
198
- }, "strip", z.ZodTypeAny, {
199
- rule: "policyDenyWins";
200
- }, {
201
- rule: "policyDenyWins";
202
- }>, z.ZodObject<{
206
+ }, z.core.$strip>, z.ZodObject<{
203
207
  rule: z.ZodLiteral<"setNarrower">;
204
- }, "strip", z.ZodTypeAny, {
205
- rule: "setNarrower";
206
- }, {
207
- rule: "setNarrower";
208
- }>, z.ZodObject<{
208
+ }, z.core.$strip>, z.ZodObject<{
209
209
  rule: z.ZodLiteral<"boolStricter">;
210
210
  strict: z.ZodBoolean;
211
- }, "strip", z.ZodTypeAny, {
212
- strict: boolean;
213
- rule: "boolStricter";
214
- }, {
215
- strict: boolean;
216
- rule: "boolStricter";
217
- }>, z.ZodObject<{
211
+ }, z.core.$strip>, z.ZodObject<{
218
212
  rule: z.ZodLiteral<"enumRank">;
219
- order: z.ZodArray<z.ZodString, "many">;
220
- }, "strip", z.ZodTypeAny, {
221
- rule: "enumRank";
222
- order: string[];
223
- }, {
224
- rule: "enumRank";
225
- order: string[];
226
- }>]>;
227
- enforcement: z.ZodEnum<["gate", "server", "resolver", "client"]>;
228
- fail: z.ZodEnum<["closed", "open"]>;
229
- /** The compile target / seam this category lands on (free text, for traceability). */
213
+ order: z.ZodArray<z.ZodString>;
214
+ }, z.core.$strip>], "rule">;
215
+ enforcement: z.ZodEnum<{
216
+ gate: "gate";
217
+ server: "server";
218
+ resolver: "resolver";
219
+ client: "client";
220
+ }>;
221
+ fail: z.ZodEnum<{
222
+ closed: "closed";
223
+ open: "open";
224
+ }>;
230
225
  seam: z.ZodString;
231
- /** When the category's VALUE domain is core's, the cited `SAFETY_AXIS_VOCABULARY` dimension (conformance-checked). */
232
- coreAxis: z.ZodOptional<z.ZodEnum<["toolEffect", "egress", "irreversibility", "safetyAxis", "severity", "shellGate", "permissionDecision"]>>;
233
- /** 1.1.0 — member-level admission (see the file header). ABSENT ⇒ the category is a whole key: its `minTrust`
234
- * admits or rejects the whole value. PRESENT ⇒ each named member is admitted on its own row (fallback to the
235
- * category `minTrust` when the row omits one); the member set is closed — {@link membersOf} enumerates it. */
226
+ coreAxis: z.ZodOptional<z.ZodEnum<{
227
+ permissionDecision: "permissionDecision";
228
+ toolEffect: "toolEffect";
229
+ egress: "egress";
230
+ irreversibility: "irreversibility";
231
+ safetyAxis: "safetyAxis";
232
+ severity: "severity";
233
+ shellGate: "shellGate";
234
+ }>>;
236
235
  members: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
237
- direction: z.ZodEnum<["loosen", "tighten"]>;
238
- minTrust: z.ZodOptional<z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>>;
236
+ direction: z.ZodEnum<{
237
+ loosen: "loosen";
238
+ tighten: "tighten";
239
+ }>;
240
+ minTrust: z.ZodOptional<z.ZodEnum<{
241
+ local: "local";
242
+ session: "session";
243
+ global: "global";
244
+ project: "project";
245
+ managed: "managed";
246
+ task: "task";
247
+ }>>;
239
248
  boolPole: z.ZodOptional<z.ZodObject<{
240
249
  strict: z.ZodBoolean;
241
- minTrust: z.ZodEnum<["local", "session", "project", "global", "managed", "task"]>;
242
- }, "strip", z.ZodTypeAny, {
243
- strict: boolean;
244
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
245
- }, {
246
- strict: boolean;
247
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
248
- }>>;
249
- }, "strip", z.ZodTypeAny, {
250
- direction: "loosen" | "tighten";
251
- minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
252
- boolPole?: {
253
- strict: boolean;
254
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
255
- } | undefined;
256
- }, {
257
- direction: "loosen" | "tighten";
258
- minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
259
- boolPole?: {
260
- strict: boolean;
261
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
262
- } | undefined;
263
- }>>>;
264
- }, "strip", z.ZodTypeAny, {
265
- enforcement: "gate" | "server" | "resolver" | "client";
266
- tighten: {
267
- rule: "none";
268
- } | {
269
- rule: "policyDenyWins";
270
- } | {
271
- rule: "setNarrower";
272
- } | {
273
- strict: boolean;
274
- rule: "boolStricter";
275
- } | {
276
- rule: "enumRank";
277
- order: string[];
278
- };
279
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
280
- mergeShape: "concat" | "replace" | "denyFirst" | "runAll" | "overrideByName";
281
- fail: "closed" | "open";
282
- seam: string;
283
- members?: Record<string, {
284
- direction: "loosen" | "tighten";
285
- minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
286
- boolPole?: {
287
- strict: boolean;
288
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
289
- } | undefined;
290
- }> | undefined;
291
- coreAxis?: "permissionDecision" | "toolEffect" | "egress" | "irreversibility" | "safetyAxis" | "severity" | "shellGate" | undefined;
292
- }, {
293
- enforcement: "gate" | "server" | "resolver" | "client";
294
- tighten: {
295
- rule: "none";
296
- } | {
297
- rule: "policyDenyWins";
298
- } | {
299
- rule: "setNarrower";
300
- } | {
301
- strict: boolean;
302
- rule: "boolStricter";
303
- } | {
304
- rule: "enumRank";
305
- order: string[];
306
- };
307
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
308
- mergeShape: "concat" | "replace" | "denyFirst" | "runAll" | "overrideByName";
309
- fail: "closed" | "open";
310
- seam: string;
311
- members?: Record<string, {
312
- direction: "loosen" | "tighten";
313
- minTrust?: "local" | "session" | "global" | "project" | "managed" | "task" | undefined;
314
- boolPole?: {
315
- strict: boolean;
316
- minTrust: "local" | "session" | "global" | "project" | "managed" | "task";
317
- } | undefined;
318
- }> | undefined;
319
- coreAxis?: "permissionDecision" | "toolEffect" | "egress" | "irreversibility" | "safetyAxis" | "severity" | "shellGate" | undefined;
320
- }>;
250
+ minTrust: z.ZodEnum<{
251
+ local: "local";
252
+ session: "session";
253
+ global: "global";
254
+ project: "project";
255
+ managed: "managed";
256
+ task: "task";
257
+ }>;
258
+ }, z.core.$strip>>;
259
+ }, z.core.$strip>>>;
260
+ }, z.core.$strip>;
321
261
  export type MergeCategorySpec = z.infer<typeof MergeCategorySpec>;
322
262
  /** The category spec. Keys = the unified settings categories both seats map their concrete keys/fields into.
323
263
  * Faithful to settings-core v2-design §3 (the semantic source of record). */
@@ -374,7 +314,7 @@ export declare const SAFETY_MERGE_SPEC: {
374
314
  readonly minTrust: "global";
375
315
  readonly tighten: {
376
316
  readonly rule: "enumRank";
377
- readonly order: ["off", "classify", "always"];
317
+ readonly order: ["always"];
378
318
  };
379
319
  readonly enforcement: "gate";
380
320
  readonly fail: "closed";
@@ -582,7 +522,7 @@ export declare const SAFETY_MERGE_SPEC: {
582
522
  };
583
523
  readonly enforcement: "server";
584
524
  readonly fail: "closed";
585
- readonly seam: "config-center → governanceBaseline (SSO/SCIM/audit/budget, TOB-only)";
525
+ readonly seam: "web-admin → governanceBaseline (SSO/SCIM/audit/budget, TOB-only)";
586
526
  };
587
527
  };
588
528
  export type SafetyMergeCategory = keyof typeof SAFETY_MERGE_SPEC;