@sema-agent/settings-schema 1.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 (56) hide show
  1. package/CHANGELOG.md +728 -0
  2. package/LICENSE +103 -0
  3. package/README.md +129 -0
  4. package/dist/api/auth-bridge.d.ts +331 -0
  5. package/dist/api/auth-bridge.js +210 -0
  6. package/dist/api/auth.d.ts +216 -0
  7. package/dist/api/auth.js +138 -0
  8. package/dist/api/scopes.d.ts +344 -0
  9. package/dist/api/scopes.js +222 -0
  10. package/dist/api/wire.d.ts +60 -0
  11. package/dist/api/wire.js +89 -0
  12. package/dist/bundle.d.ts +13 -0
  13. package/dist/bundle.js +67 -0
  14. package/dist/config-fns.d.ts +318 -0
  15. package/dist/config-fns.js +472 -0
  16. package/dist/cross-domain.d.ts +34 -0
  17. package/dist/cross-domain.js +118 -0
  18. package/dist/file-edit.d.ts +36 -0
  19. package/dist/file-edit.js +125 -0
  20. package/dist/file-store.d.ts +89 -0
  21. package/dist/file-store.js +238 -0
  22. package/dist/fleet.d.ts +498 -0
  23. package/dist/fleet.js +317 -0
  24. package/dist/hash.d.ts +32 -0
  25. package/dist/hash.js +59 -0
  26. package/dist/hooks.d.ts +5477 -0
  27. package/dist/hooks.js +627 -0
  28. package/dist/index.d.ts +22 -0
  29. package/dist/index.js +26 -0
  30. package/dist/local-load.d.ts +42 -0
  31. package/dist/local-load.js +172 -0
  32. package/dist/migrate.d.ts +255 -0
  33. package/dist/migrate.js +542 -0
  34. package/dist/node.d.ts +11 -0
  35. package/dist/node.js +11 -0
  36. package/dist/reader.d.ts +18 -0
  37. package/dist/reader.js +1 -0
  38. package/dist/remote-exec.d.ts +274 -0
  39. package/dist/remote-exec.js +182 -0
  40. package/dist/resolve-roster.d.ts +28 -0
  41. package/dist/resolve-roster.js +108 -0
  42. package/dist/safety-merge-spec.d.ts +327 -0
  43. package/dist/safety-merge-spec.js +70 -0
  44. package/dist/scheduler-store-node.d.ts +72 -0
  45. package/dist/scheduler-store-node.js +119 -0
  46. package/dist/scheduler-store.d.ts +67 -0
  47. package/dist/scheduler-store.js +89 -0
  48. package/dist/secret-refs.d.ts +33 -0
  49. package/dist/secret-refs.js +48 -0
  50. package/dist/sha256.d.ts +16 -0
  51. package/dist/sha256.js +114 -0
  52. package/dist/skills-manifest.d.ts +12 -0
  53. package/dist/skills-manifest.js +54 -0
  54. package/dist/types.d.ts +13560 -0
  55. package/dist/types.js +2118 -0
  56. package/package.json +138 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,728 @@
1
+ # Changelog
2
+
3
+ (始于 0.8.1;更早版本的变更记录散在 commit message 与 README「发版纪律」注记。)
4
+
5
+ > ⚠️ **包名分水岭**:`1.0.0` 起包名 = `@sema-agent/settings-schema`;`0.19.0` 及更早 =
6
+ > `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
7
+ > 包名是**历史记录**,如实保留不追改。
8
+
9
+ ## 1.0.0 — 改名(#361 步①;clay 裁 [5156],开工帖 [5295])
10
+
11
+ **`@sema-agent/registry-core` → `@sema-agent/settings-schema`。纯改名件。**
12
+
13
+ ### 零语义变更(这是本版唯一要记住的一句)
14
+
15
+ `0.19.0` → `1.0.0` 之间**没有任何行为差异**:零字段增删、零默认值改动、零校验收紧(**没有任何
16
+ `.strict()` 化**)、零导出增删、零依赖变动(runtime deps 仍只有 `zod ^3.24.0`,peer 同段)。
17
+ diff 面只有**名字与文档**。
18
+
19
+ ### 消费方迁移(两步 —— **版号段也要动**)
20
+
21
+ 1. `package.json` 依赖:`"@sema-agent/registry-core": "^0.19.0"` → `"@sema-agent/settings-schema": "^1.0.0"`,
22
+ 然后重生成 lockfile(`npm install` / `npm i --package-lock-only`)。
23
+ ⚠️ **只换名不换版号段会直接装不上**:新名的最低版本就是 `1.0.0`,`^0.19.0` 在新名下没有任何匹配
24
+ 版本,`npm install` 报 `No matching version found`。(codex 复审 R2-F1 逮到的真坑 —— 原文把迁移
25
+ 写成「前缀整体替换即可」,对 import 说明符成立,对**依赖 range** 不成立。)
26
+ 2. 代码 import 说明符:`@sema-agent/registry-core…` → `@sema-agent/settings-schema…`,**纯前缀替换**,
27
+ 21 个 subpath 的后缀一个不动。
28
+
29
+ 这两步之外什么都不用改:无 API 改名、无类型改形、无行为差异。
30
+
31
+ ### 零语义变更的**发布物实证**(不是自证)
32
+
33
+ 把 npm 上**真实已发布的** `@sema-agent/registry-core@0.19.0` tarball(shasum `310c716b…`,发布于
34
+ 2026-08-20T15:57Z,旧名 `latest`)拆开,与本版 `npm pack` 出的 `@sema-agent/settings-schema@1.0.0`
35
+ 逐文件比对:
36
+
37
+ - `dist/` 文件清单**完全相同**:两边各 **52** 个文件,零增零删(整包 56 个 = 52 dist + `package.json`
38
+ + `README.md` + `CHANGELOG.md` + `LICENSE`);
39
+ - 原样比对有差异的是 **12 个文件**(8 个 `.js` + 4 个 `.d.ts`)、**16 个被替换的行位**,内容**全部是
40
+ 注释**(文件头 JSDoc 里的 subpath 自述);
41
+ - **把注释剥掉再比,差异文件数 = 0** —— 即**可执行码与类型声明签名逐字未变**。
42
+
43
+ ⚠️ 措辞如实:`.d.ts` **文件字节确实变了**(4 个文件的头部注释),变的只是注释,**不是**「.d.ts 一个
44
+ 字节没动」——R2-F2 纠的就是初稿这处夸大(初稿还把 56 当成 dist 文件数、把 32 个 ± 行当成 28 行)。
45
+
46
+ **剥注释用的是 TypeScript 自带 scanner,不是 esbuild**(codex R3-F1 逮到的**测量伪影**,值得记一笔):
47
+ 初稿用 `esbuild.transformSync(src, {loader:"ts"})` 剥 `.d.ts` 的注释——但 ts loader 会把**纯类型声明
48
+ 整份擦掉**,`dist/fleet.d.ts`(23,619 字节)和 `dist/scheduler-store.d.ts`(3,674 字节)在它手里都变成
49
+ **0 字节输出**。空 == 空,那两个文件的「相等」是**空对空的假绿**:真出现破坏性类型改动也照样报 0 差异。
50
+ 换成 `ts.createScanner(..., /*skipTrivia*/ true, ...)` 逐 token 比对——它只跳注释与空白,**声明一个不删**
51
+ ——并加一道**自证门**:任何文件的 token 流若为空就判该次比较无效并报红。实测 52 个文件零空流,12 个
52
+ 有原样差异的文件 token 流全等。
53
+
54
+ 复现(`OLD`/`NEW` = 两边 `npm pack` + `tar xzf` 后的 `package/dist`;`REPO` = 本仓,用它解析 typescript):
55
+
56
+ ```bash
57
+ npm pack @sema-agent/registry-core@0.19.0 # 旧名最后一版真品
58
+ npm pack # 本仓当前版
59
+ ```
60
+
61
+ ```js
62
+ // node token-diff.mjs <OLD_dist> <NEW_dist> <REPO>
63
+ import fs from "node:fs"; import path from "node:path"; import { createRequire } from "node:module";
64
+ const [OLD, NEW, REPO] = process.argv.slice(2);
65
+ const ts = createRequire(path.join(REPO, "package.json"))("typescript");
66
+ const walk = (r, rel = "") => fs.readdirSync(path.join(r, rel), { withFileTypes: true })
67
+ .flatMap((e) => (e.isDirectory() ? walk(r, path.join(rel, e.name)) : [path.join(rel, e.name)]));
68
+ const tokens = (text) => { // skipTrivia=true → 只跳注释/空白,声明全留
69
+ const s = ts.createScanner(ts.ScriptTarget.Latest, true, ts.LanguageVariant.Standard, text);
70
+ const out = []; for (let k = s.scan(); k !== ts.SyntaxKind.EndOfFileToken; k = s.scan()) out.push(k + ":" + s.getTokenText());
71
+ return out.join(" ");
72
+ };
73
+ const raw = [], tok = [], erased = [];
74
+ for (const f of walk(OLD).sort()) {
75
+ const a = fs.readFileSync(path.join(OLD, f), "utf8"), b = fs.readFileSync(path.join(NEW, f), "utf8");
76
+ if (a === b) continue;
77
+ raw.push(f); const ta = tokens(a);
78
+ if (ta.length === 0) erased.push(f); // 自证门:空 token 流 = 这次比较无效
79
+ if (ta !== tokens(b)) tok.push(f);
80
+ }
81
+ console.log({ raw: raw.length, tokenDiff: tok.length, vacuous: erased.length });
82
+ process.exit(tok.length === 0 && erased.length === 0 ? 0 : 1);
83
+ ```
84
+
85
+ 实测输出:`{ raw: 12, tokenDiff: 0, vacuous: 0 }`。
86
+
87
+ ### 版号为什么跳 1.0.0
88
+
89
+ **不是**「契约进入稳定期 / API 冻结」的语义信号。旧名的 `0.x` 段已走到 `0.19.0`,新名需要一个不与
90
+ 旧段混淆、也不会被 `^0.x` 脱字号规则(0.x 下不跨 minor)拖累的新起点,故直接从 `1.0.0` 开。
91
+ ⚠️ README「发版纪律(semver)」一节写的是 `0.x` 破坏性必 bump minor 的旧规矩;`1.x` 段的对应
92
+ 规矩(破坏性必 bump major)尚未成文,待后续批补。
93
+
94
+ ### 21 个 subpath 1:1 平移(一个不动)
95
+
96
+ `exports` 表整表逐条只换包名前缀,路径、`types`/`default` 落点、模块名全部不变:
97
+
98
+ | # | 旧 | 新 |
99
+ |---|---|---|
100
+ | 1 | `@sema-agent/registry-core` | `@sema-agent/settings-schema` |
101
+ | 2 | `…/types` | `…/types` |
102
+ | 3 | `…/hash` | `…/hash` |
103
+ | 4 | `…/sha256` | `…/sha256` |
104
+ | 5 | `…/skills-manifest` | `…/skills-manifest` |
105
+ | 6 | `…/secret-refs` | `…/secret-refs` |
106
+ | 7 | `…/resolve-roster` | `…/resolve-roster` |
107
+ | 8 | `…/config-fns` | `…/config-fns` |
108
+ | 9 | `…/reader` | `…/reader` |
109
+ | 10 | `…/cross-domain` | `…/cross-domain` |
110
+ | 11 | `…/remote-exec` | `…/remote-exec` |
111
+ | 12 | `…/safety-merge-spec` | `…/safety-merge-spec` |
112
+ | 13 | `…/node` | `…/node` |
113
+ | 14 | `…/scheduler-store` | `…/scheduler-store` |
114
+ | 15 | `…/hooks` | `…/hooks` |
115
+ | 16 | `…/fleet` | `…/fleet` |
116
+ | 17 | `…/migrate` | `…/migrate` |
117
+ | 18 | `…/api/auth` | `…/api/auth` |
118
+ | 19 | `…/api/auth-bridge` | `…/api/auth-bridge` |
119
+ | 20 | `…/api/scopes` | `…/api/scopes` |
120
+ | 21 | `…/api/wire` | `…/api/wire` |
121
+
122
+ (权威平移表见开工帖 [5295];`test/package-surface.test.ts` 的整表门照旧看着这 21 条 ↔ `src/*.ts` 对齐。)
123
+
124
+ ### 旧名的去向
125
+
126
+ `@sema-agent/registry-core` ≤ `0.19.0` **保持已发布状态**(不 unpublish),**冻结**——不再出新版。
127
+ 后续批打 npm `deprecate` 标指向新名。跨仓消费方的切换归 #361 后续步次,本步只动本仓。
128
+
129
+ ### 仓名不动
130
+
131
+ 本步只改**包名**。仓名 `sema-registry-core` / `github.com/sema-agent/sema-registry-core` 以及
132
+ `package.json` 的 `repository.url` **原样保留**;src 注释里指代本仓/本项目的裸词 `registry-core`
133
+ 同样保留(它们不是包名)。
134
+
135
+ ## 0.19.0 (2026-08-20) —— 旧名 `@sema-agent/registry-core` 的**最后一版**(#282 P1 + #322 limits 域,设计见 DESIGN-282 §2/§4)
136
+
137
+ > 📌 **标题订正(随 1.0.0 批,codex 复审 R1 文档半场)**:本节标题此前一直写着「Unreleased(树上版号
138
+ > 已预挂 0.19.0;最终版号仍由发车批定)」——但 0.19.0 **确已发车**:tag `v0.19.0` 打在提交 `0095e71`,
139
+ > npm 发布时间 2026-08-20T15:57Z,是旧名的 `latest`。当时发车批漏改标题,连 shipped tarball 里的
140
+ > CHANGELOG 都还是「Unreleased」。1.0.0 的改名声明要拿 0.19.0 当「旧名最后一版」的基线,标题不订正
141
+ > 就与之自相矛盾,故在此如实改正;**本节正文一字未动**(内容记录本身是对的)。
142
+
143
+ ### 第 17 域 `limits`(sema-server #322 批1 —— 本地腿闭集缺口的**源头修复**)
144
+
145
+ **病(消费方亲验实录,不是推测)**:server 把 cost/限流族 14 键发成**新顶层域 `limits`**(往 `runtime`
146
+ 里加键会被 zod `"strip"` 静默剥掉,两条腿都是)。远端腿靠 `readEffectiveWire` 的未知顶层键 verbatim 透传
147
+ 即刻可用;**本地腿读不到** —— `FileConfigStore` 的域表(`PORTABLE_DOMAINS`)是闭集,`config.d/limits.json`
148
+ 根本不进 effective,且**零告警**(下游看到的「域缺席」与「文件不存在」逐字同形)。CLI/桌面单机形正是热更新
149
+ 战役的主诉求形,故缺口在本包修,不在下游自建第二条读盘腿。
150
+
151
+ - **新域 `limits`(additive)**:14 键全 `.optional()` 无默认(ABSENT = center 不管这一键 ⇒ 消费方回自己的
152
+ env 底)。键集 = `rateLimitPerMin` / `maxPrincipalCostUsd` / `costQuotaWindowSec` / `maxTaskCostUsd` /
153
+ `maxTaskTokens` / `infraCostRates{toolCall,sandboxSec,egressGb}MicroUsd` / `attachmentOrphanGraceMs` /
154
+ `workspaceFileMaxBytes` / `attachmentMaxBytes` / `attachmentMimeAllowlist` / `attachmentUnboundTtlMs` /
155
+ `drainGraceMs` / `runStaleSec` / `toolResultTtlSec`。进 `PORTABLE_DOMAINS`(本地腿真读),
156
+ `DOMAIN_READ_FALLBACK.limits = "throw"`(与 runtime 同判据:坏形静默降级 = 中央成本天花板蒸发 = 预算轴放权)。
157
+ - **判据分工(宽进严出)**:本包只判**结构**(类型 / 有限数 / 数组元素类型);业务域值(下限、`0` 关断哨兵、
158
+ 跨键不变量)属主唯一 = 消费方(server `stage-limits`:坏值 ⇒ 整批响亮拒 + 旧值继续服务)。本包收窄阈值 =
159
+ 双属主漂移,且处置更糟(契约层拒 = 整份 local effective 抛,全域连坐)。
160
+ - **本域 open-world(`.passthrough()`,与 `PrincipalCapsWire.runtimeCaps/budget` 同判据)**:限额面按消费方
161
+ 的发布节奏**分批加键**,而消费方的依赖是 `^0.x` 段(0.x 脱字号不跨 minor)。默认 strip 会让「消费方新增
162
+ 了一个限额键、契约层版号还没跟上」= 键被静默剥掉 = 那条天花板悄悄回落 env 底 —— 本域要根治的病换个位置
163
+ 复发。已知键照旧严判结构;未知键原样承运,认不认归消费方。附带:老 TOC 编辑新 center 的 limits 文档不会
164
+ 把不认识的键写没(strip 语义下 `writeDomainFile` 会真的丢键)。
165
+ - **与 `runtime` 五键重叠位**:两位都如实解析,**优先级归消费方**(server 已成文:新位赢)。本包不在契约层
166
+ 替消费方折叠。
167
+ - ⚠️ **远端腿的行为变化(如实披露)**:`limits` 此前是 `readEffectiveWire` 眼里的**未知顶层键**(verbatim
168
+ 透传,不校验);收编成域之后它按域解析 —— 未知键仍 verbatim(open-world,见上),但**已知键的类型错**
169
+ (如 `rateLimitPerMin: "7"`)现在会让整份 wire 载荷抛(gate 域纪律,与 runtime 同),消费方走整包
170
+ catch / fail-static,而不是像此前那样落到消费方的「整批拒 + 点名」。这是 gate 域的既定处置,不是新政策,
171
+ 但对已在发这个域的消费方是一次可观察的变化。
172
+ - **消费方接线提示(缺一件就仍然到不了终点)**:
173
+ 1. `EffectiveConfig` 的**闭集投影**下游(如 server `mapToServiceEffective`)必须显式透传 `limits` ——
174
+ 域收编与投影透传是两件事,少这一行本地腿照样在最后一米丢域;
175
+ 2. 三个新 warning kind(`unknown-keys-dropped` / `unknown-keys-carried` / `unread-config-file`)要接进
176
+ 消费方的结构化日志/诊断面,否则本包点了名而部署里仍然听不见(现状:server 的本地/远端两个 provider
177
+ 都只保留 `domain-defaulted`);
178
+ 3. `limits` 的**未知键**(含 `infraCostRates` 的未知费率名)现在原样送到消费方并被本包点名:键表在
179
+ 消费方手里,认或拒由它定,本包不再无声抹掉。
180
+
181
+ ### 静默剥键/静默不读的**防复发门**(fail-loud,行为不变)
182
+
183
+ 同族两病,同一后果:配置写了、进程跑着、值没到,而没有任何一个字说出来。方向是**响亮**不是收紧(收紧成
184
+ `.strict()` / throw 会打死「新 center → 老消费方」的前向兼容,那是另一种事故)。`EffectiveReadWarning` 加
185
+ 两个 kind(additive union member —— 用 `switch` 穷举该类型的消费方需补臂):
186
+
187
+ - `"unknown-keys-dropped"`(`buildEffective`,新导出 `droppedKeys`):域文档里被 schema 丢掉的键逐个点名,
188
+ **含嵌套**(点号路径,如 `infraCostRates.toolCalMicroUsd` / `commandPolicy.0.typo` —— codex 复审 F2:
189
+ 只看顶层等于对「拼错的嵌套键」完全失明,顶层那个父键还在)。`runtime` 的治理三件除外(有成文抬升路径)。
190
+ 剥除行为本身不变。边界如实登记:深度/键数有上限、数组长度不同即跳过(元素级裁剪由各自 clamp 告警)、
191
+ 只比对纯 JSON 对象、整段包 try/catch 且不回显其错误(与 `parseDomain` 的 R13 同纪律)。
192
+ - `"unknown-keys-carried"`(open-world 域,codex 复审 R2-F2):`.passthrough()` 解决了「值到不了」,但没
193
+ 解决「键名拼错了没人说」——`toolResultsTtlSec`(多一个 s)会完好穿过本包,而消费方只遍历自己的键表,
194
+ 那条天花板就悄悄没生效。**承运 + 点名两件一起做**:值照送(消费方有权认新键),名照报。已知键表由
195
+ schema 的 `shape` 单源派生;新开 open-world 域必须登记(有机器门:任何 `passthrough` 域缺登记即红)。
196
+ - 两条 parse 告警的判据**单点**(`parseDomainLoud`),`buildEffective` 与 `FileConfigStore.getDomain` 共用
197
+ (codex 复审 R2-F3:`getDomain` 是 `exportBundle` 的读法 —— 此前它直接 `parseDomain`,于是导出会把携带
198
+ 未知键的域静默剥成一份"干净"的 bundle,再导入 = 持久的配置丢失,全程零告警)。
199
+ - `"unread-config-file"`(`FileConfigStore.getEffective`,strict + tolerant 两腿):`config.d/` 里存在但
200
+ 本地读取集永远不会读的 `*.json` 点名,并区分 `not-a-domain`(名字不是域 —— #322 当年的形)与
201
+ `non-portable-domain`(域认识但单机刻意不读)。只在挂了 `onWarning` 时才 readdir(诚实登记:本门的
202
+ 响亮程度取决于消费方接不接这个座)。忽略隐藏/临时文件、非 `.json`、`remote-exec.json`。
203
+ - `loadLocalConfig(root, opts?)`:additive —— 返回值新增 `warnings: EffectiveReadWarning[]`,可选
204
+ `opts.onWarning` 实时转发。此前单机 lane **从不**挂告警座,默认形就是「没有通道 = 没有声音」。
205
+ - `PORTABLE_DOMAINS` 旁立注释门:开新顶层域必须同步登记本表(漏登记 = 消费端静默缺配置),并写明
206
+ `unread-config-file` 只是兜底、登记仍是第一现场义务。
207
+
208
+ ### #282 registry-core 现代化 P1(先落的半批)
209
+
210
+ ⚠️ **发车批注意**:DESIGN-282 §4 把 P1 记作「additive+门」,但本批实际含**一处类型面 BREAKING**(下条)。
211
+ 版号选择请据此定(§2 倾向 1.0.0 承载 BREAKING 面),发布帖需点名该删除;走 0.19.0 也要在帖里显式列出。
212
+
213
+ **BREAKING(类型面):删 `RuntimeWire` 别名。** 0.7.1 双写撤销后它已只是 `RuntimeConfig` 的别名,保留
214
+ 理由写的是「防下游 type import 断编译」——本批逐仓实证不成立:sema-server / sema-web / sema-cli 三个真
215
+ 消费仓 `grep -w RuntimeWire` **零命中**(仅本包内部 `EffectiveConfig.runtime` 用着)。`EffectiveConfig
216
+ .runtime` 现直接标注 `RuntimeConfig`;两处提及该别名的 stale JSDoc(types.ts 的「WIRE TRANSITION 双写
217
+ pending service 确认」段、resolve-roster.ts 的「limit residue + governance mirror」句)按 0.7.1 真状态
218
+ 改写。消费方**零动作**(该别名与 `RuntimeConfig` 类型逐字相同,且无人 import)。
219
+
220
+ **新导出:`NON_PORTABLE_DOMAIN_REASONS`**(`file-store.ts`)—— 非便携域的排除理由表,
221
+ `satisfies Record<Exclude<DomainName, PortableDomain>, string>` 在编译期把键集与 `PORTABLE_DOMAINS`
222
+ 双向咬死(新域静默排除 = 编译错)。`entitlement` 的排除理由随之补齐(此前是唯一裸排除项)。
223
+ 同时把 `PORTABLE_DOMAINS` 的口径写诚实:它是**本地读取集 + bundle 默认集,不是 API 级硬边界**
224
+ (`exportBundle`/`readBundle` 的 `domains` 参数仍可显式传任意域)。
225
+
226
+ **门(新增,非运行时):**
227
+ - 域四件同在门(`test/domain-completeness.test.ts`):每域断言 `DOMAIN_SCHEMAS` 条目 ∧ `EffectiveConfig`
228
+ 字段 ∧ `buildEffective` 解析行(行为探针)∧ `DOMAIN_READ_FALLBACK` 档位 —— 开域漏第 3 步从此测试红。
229
+ 同文件另钉非便携理由表的双向键集与理由实质性。
230
+ - 弃用双标门(`test/deprecation-hygiene.test.ts`):导出条目沾弃用类措辞(头注 / **声明体内的成员注释** /
231
+ 标识符名)—— 必须带标准 `@deprecated <理由>` 标签,或进豁免表(带理由 **+ 逐条钉住被豁免的措辞原文**)。
232
+ 裸散文弃用、裸标签、陈旧豁免行、被豁免导出体内新增的弃用散文,四种都红。解析走 TypeScript AST。
233
+
234
+ ## 0.18.0 (2026-08-13)
235
+
236
+ **[3759] `SAFETY_MERGE_SPEC.permissionMode.tighten.order` 补全壳可寻址模式词表(补 `auto`/`dontAsk`)。**
237
+
238
+ - 新序(LOOSEST→STRICTEST):`bypassPermissions < auto < acceptEdits < default < dontAsk < plan`。
239
+ - 病:序外词让两层 settings 同设 `permissions.defaultMode` 时 tighten 折叠只剩 throw 一条路——修前
240
+ 整份 settings 静默丢(壳侧已改按单元拒,本件是语义源头修)。
241
+ - 序位锚定(server task-settings.ts 真翻译,非猜):bypass ⇒ shellGate off(无门);auto ⇒ classify
242
+ 且分类器可自动放行任何良性 ask(⊇ acceptEdits 的仅编辑自批);dontAsk=ask 全翻 deny(allow 规则
243
+ 仍过)严于 default 松于 plan(handsReadOnly,连 allow 写也拒)。
244
+ - 纯 additive(既有四词相对序不变);消费方对序值零硬编码,spec 即生效。conformance 测试补六词全序钉。
245
+
246
+ ## 0.17.1 (2026-08-06)
247
+
248
+ **0.17.0 stale-dist 重发**:npm 上的 0.17.0 tarball **不含** `ActorAssertionWire`(发布窗口内工作树
249
+ 被本机并行进程回滚了 `src/types.ts` 的该块,dist 打包时已缺;SDK 预制车拆包发现)。0.17.1 = 同一
250
+ 内容的正确出厂,发布流程补「拆包验字节」终检。消费方请跳过 0.17.0 直用 0.17.1。
251
+
252
+ ## 0.17.0 (2026-08-06)
253
+
254
+ **design/171 §5.1 `ActorAssertionWire`(新导出)——决策者身份断言的跨仓同源锚(server 铸、cli/web/SDK 呈)。**
255
+
256
+ - 形=`{ id, label?, verified?, via? }` strict;规范条款入 doc 注:actor 永不参与权限判定,id/verified
257
+ 恒 server 铸(wire 请求方只可提交 label);`via: "owner"|"operator"`=受理路径审计维(server 扩,
258
+ additive)。首个消费点=sema-server design/172 车4 回决端点(#151)。
259
+ - 纯 additive。
260
+
261
+ ## 0.16.0 (2026-08-05)
262
+
263
+ **caps wire 整体读边界 schema(clay 令 2026-08-05:网络边界读入必 schema,禁裸 as-cast+逐键 unknown)。**
264
+
265
+ - `PrincipalCapsWire`(新导出)——`?principal=` caps 响应体的 center 铸/server 读同源锚。逐面容错
266
+ 极性照在档裁定编码(schema doc 注逐面点名):治理面 runtimeCaps/budget=严格已知键+passthrough
267
+ 未知键(新 cap 透传,值漂移整体拒=fail-closed);能力面 scenario/allowlist/execution=宽读
268
+ ([565]/[580] fail-open 裁定,归一与 drift 诊断在消费端);orgMemory=宽读(C3 失败域隔离,仅由
269
+ PrincipalOrgMemoryWire 在目录腿校验);principal=严格 string(C8 回声核);顶层 passthrough 开放世界。
270
+ - 纯 additive。
271
+
272
+ ## 0.15.0 (2026-08-05)
273
+
274
+ **design/170 件A(org 记忆准入)additive 半场(board [2687] clay 三裁开工;[2681]/[2684] center 提货单的 schema 承载件)。**
275
+
276
+ - `EntitlementTier.orgMemory?: Record<org-scope, { write?: boolean }>`——org 记忆授权束,bundle 级
277
+ 与 visibleSkills 同轴:tier ⊕ roles 跨束**并集**(write:true 在并集中胜出,「展开」轴)。刻意
278
+ **不挂 defaults**(全员默认 org 授权恰是准入面要防的形;要全员授,建显式 tier)。键形状门=
279
+ `org:` 前缀正则(严校验单一真源在 core 的 v2 scope 契约;此处只拦挂错轴的类别错误)。
280
+ - `PrincipalOrgMemoryWire`(新导出)——`?principal=` caps wire 上的解析段 `{ gen, scopes }`,center
281
+ 铸、server 消费的同源锚。**段级三值语义**:键整体缺席=center 不支持(能力握手,消费方按瞬时
282
+ 处理);`scopes: {}` 空表=取数成功的负结果(终局);有表=逐条目。`gen`=单调世代号(publish
283
+ 模式=globalRevision / live 模式=store version),消费方拒退挂此(进程生命周期内防 LB 陈旧副本)。
284
+ - 纯 additive:未配置实例零行为变化;旧消费端对新键零感知(zod strip 语义不变)。
285
+
286
+ ## 0.14.0 (2026-08-03)
287
+
288
+ **cron durable 键分叉的迁移半场(board [2439]/[2440]/[2444];server 裁 (a) 一次性迁移,拒读侧双键容忍窗)。**
289
+
290
+ - 病灶:旧铸键链 `sessionId ?? principal ?? taskId ?? "default"` 让 **durable** 行的隔离键随会话走——
291
+ 新会话新 sessionId ⇒ 旧 durable job 对 CronList/CronDelete 永远 not_found(test 红榜
292
+ `cron-durable-session-scope-orphan` 角度 2 根因,core 半场已在 5.5.0 分叉铸键)。
293
+ - 修:`parseSchedulerStore` 增**纯层归一臂** `normalizeDurableScope`——durable 行(`lifetime`
294
+ 缺席或非 `"session"`,窄读 forward-compat 字段)且 `scope !== (principal ?? "default")` ⇒ 重铸
295
+ scope。幂等;session-scoped 行零触碰;未知字段保留不破 forward-compat。
296
+ - 为什么放 parse 不放 loader:`loadSchedulerStore` 与 `mutateSchedulerStore` 都各自经 parse——
297
+ 单点归一,两读者(server 写侧 backend / shell daemon 读侧)同愈,无第二机制;盘面在下一次
298
+ save 收敛(不做读时写放大)。
299
+ - round-trip 身份不变量自此对**归一形**成立(fixture 取归一不动点);旧键形的重铸行为有专钉
300
+ (三形:sessionId 键+lifetime durable / lifetime 缺席 / 无 principal ⇒ "default")。
301
+ - 消费端提醒:装上本版起,读到的 durable 行 scope 恒等于 `principal ?? "default"`——按旧
302
+ sessionId 键查询 durable 行的调用方(若有)会 not_found;这正是迁移的语义,非回归。
303
+
304
+ ## 0.13.0 (2026-08-02)
305
+
306
+ **#100 根修:`readEffectiveWire` 对 `prompts` 键改 wire 分歧域处理(verbatim 透传+缺席保缺席)。**
307
+
308
+ - 病灶:wire 上的 `prompts` 被按 center **存储域** schema(PromptsConfig,bindings 形)parse——center
309
+ worker-lane 组装下发的**解析终形**被零告警吞成 `{bindings:[]}`,且键缺席也被物化 ⇒ 消费端(server)
310
+ promptsGate 恒败,boot LKG 种子门/refresh 候选门/deferred-boot 门自 server 3.24.0 全部误拒
311
+ (remote 热配置面冻结,server [2327] 公开更正)。
312
+ - 修:prompts=第二个 wire 分歧域(同 skills 先例)——不进 buildEffective 域 parse,按 wire 在场性
313
+ verbatim 挂回;消费端校验属主不变(server validatePromptsDomain,[1057]⑤ lane 纪律)。
314
+ - `EffectiveWire` 类型如实改形:`prompts?: unknown`(可选;存储形永不该在此出现)——导出类型形变
315
+ ⇒ 定 minor。`EffectiveConfig`/`PromptsConfig`/`emptyEffective`(center 存储面)零变更。
316
+ - 红先:解析终形 verbatim 出/缺席进缺席出 两钉先红后绿;既有未知域 verbatim 钉与 skills 钉零回归。
317
+
318
+ ## 0.12.1 (2026-08-02)
319
+
320
+ **doc-only:`UsageEntry.inputTokens` 语义澄清(engine 3.0 计量统一后的两面同名不同义)。**
321
+
322
+ - 类型头注的「mirrors modelUsageTracker」说法失真修正:worker per-task 面存未命中分量,本面
323
+ `inputTokens`=**归一化总输入(含 cache)**;字段级 JSDoc 同批补。零 schema/行为变更。
324
+
325
+ ## 0.12.0 (2026-08-02)
326
+
327
+ **`readEffectiveWire`([2281] 裁B):GET /effective wire 载荷在消费端边界的容错读。**
328
+
329
+ - **新导出 `readEffectiveWire(raw, onWarning?)`**(config-fns):远程消费方(server)把 res.json() 交给它
330
+ 而不是裸 `as` 断言——「两个契约共用一个拼写不是一个被检查的契约」。已知域**委托** `buildEffective`
331
+ 原判据(同 `parseDomain` + `DOMAIN_READ_FALLBACK`:catalog 坏形→default+warning,gate 坏形→throw,
332
+ 含 governance legacy-lift 与 hosts read-grandfather);`skills` 是唯一 wire 分歧位,按 **manifest 形**
333
+ 单独判(全量域 schema 会拒合法 manifest / 对重名形发假 warning——redirect 判别钉在测试);未知顶层键
334
+ **open-world verbatim 透传**(新 center 新域到老 server 不丢不校不炸;legacy `teams` 键继续流)。
335
+ 垃圾载荷(非对象 / version 非有限数)THROW——那不是坏域,是根本不是 effective config。
336
+ - **新导出 `SkillsManifestSchema`**(types):`SkillsManifest` 的 zod 运行时孪生,从 `SkillSpec` 派生
337
+ (omit content / require contentHash),schema/entry 型/interface 三者零漂移;contentHash 只 `min(1)`
338
+ (hash 格式是 center 写侧关切,读侧再钉会让老 reader 拒新 center 的合法 hash 方案)。
339
+
340
+ ## 0.11.0 (2026-07-30)
341
+
342
+ **RB-368 生态半场(大黑板 [2099] 挂账的诚实缺口):fleet 批报 lane 可表达「cost 未知」。**
343
+
344
+ - **`UsageEntry.costMicroUsd` required → optional**:unpriced 部署(模型无价目)对 cost 只有「未知」
345
+ 这个业务态,required 逼 worker 编 0 = center 账面一个精确的谎(且无任何信号标明是编的)。缺席=未知;
346
+ 写了键 = producer 声称自己知道(0 就是真 0)。旧 producer 全带键 ⇒ 零破坏。
347
+ - **`AggregatedPrincipalUsage` 补 `costUnknown: boolean`**(principal 级 + byModel 级):窗口内掺
348
+ ≥1 条缺席 entry ⇒ true,已知部分照加 ⇒ `costMicroUsd` 语义在 costUnknown=true 时为**下界**。
349
+ 不传染抹账(一个 unpriced worker 不抹整 principal 已知成本史)、不破老读端(仍是 number);读端应渲
350
+ 「≥ X(部分未知)」。与 server 单 run 内「传染性未知」不同层:单 run 是一个 producer 的一笔账,
351
+ 窗口聚合是跨 worker 审计总账,下界+标记比整体未知信息量大。
352
+ - 红先(schema Required 拒收 + 聚合无标记两红→绿);全量 462 绿,tsc 0。
353
+ - **消费端注意**(minor bump 的理由):构造 `AggregatedPrincipalUsage` 的代码需补 `costUnknown` 字段
354
+ (tsc 会红);读 `aggregateUsage` 输出的面建议接 costUnknown 渲染。
355
+
356
+ ## 0.10.24 (2026-07-29)
357
+
358
+ **全面扫查批(五类门矩阵 [2021] 复核本包)——契约语义零改动,加门 + 发布物形态修:**
359
+
360
+ - **F1 `RESERVED_WORKER_ENV` 契约表活测试**(`test/reserved-worker-env.test.ts`,6 用例):39 保留键
361
+ env/secretEnv 双面逐键拒 + 拒绝消息指名具体归属字段(归属映射是 `Record<string,string>`,tsc 不强制
362
+ 全覆盖,只有这条断言看着它)+ 三 DB 族齐全 + 密钥族指路 secretRefs + 反向门钉「执行基座键刻意不保留」
363
+ (0.1.30 撤销 R22 那一刀,防无意加回拒掉线上 worker 部署)。
364
+ - **F2 exports 表(21 subpath)活测试**(`test/package-surface.test.ts`):逐 subpath src 源在场/命名约定/
365
+ 双入口一致/整表真加载求值/files 白名单/prepublishOnly 双门。判据全部构建无关,无条件降级臂。
366
+ - **F3 `api/wire` 已发布 wire 常量冻结**(折入 `test/api-auth.test.ts`):OAUTH_ERROR_CODES/
367
+ DEVICE_AUTH_STATUSES/端点路径/scope claim/协议时长逐字钉死 + slow_down 增量语义。
368
+ - **F4 roster 角色族划分冻结**(折入 `test/resolve-roster.test.ts`):主/cheap 两族逐字钉(跨仓契约,
369
+ server config.ts 直接 import 当唯一语义源)+ 反向门钉 `verifier` 刻意不入族(未设走 default 兜底链)。
370
+ - **F5 README 域数量纠腐**:15 → 16(0.10.18 加 `prompts` 未回填),并留同源门防复发(今日真红首例)。
371
+ - **F6 doc rot**:README 4 处产品旧名 `sema-registry` 中性化为「config-center 产品(现 sema-web)」+
372
+ 新增命名说明段(包名与产品名解耦,不随产品改名变动)。
373
+ - **F7 `esbuild` 显式入 devDependencies**(wire-purity 门直调它却靠 vitest 传递带入;离线 CI 免炸)。
374
+ - **D2 发布物形态修**:`removeComments` 关(dist d.ts 的 JSDoc 从 **0 → 553 条**回到包里——契约包的
375
+ 注释就是契约文档,server 1.323.0 同病先例);sourcemap/declarationMap 关 + 构建前清 dist(此前包里
376
+ 每个 `.map` 都指向不存在的 `../src/*.ts`,`types.js.map` 一个 61.9 kB);两道门常驻钉(先红后绿)。
377
+ - **core devDep `^1.279.0` → `^2.1.0`**(词表锁步锚此前永远解析不到 2.x——对端一致性锚在旧词表上;
378
+ core 覆盖评分轮自领项)。
379
+
380
+ 461 测试全绿(+24);tsc 0;变异红证:删 MYSQL_PASSWORD/verifier 入 cheap 族/改 subpath 名 → 各自门红。
381
+
382
+ ## 0.10.23 (2026-07-28)
383
+
384
+ **`PLUGIN_ORIGIN` 收紧到 https-only(契约冻结 board [1362] 收紧①/[1366]① 的 API 层单真源修)**。
385
+ 此前 https-only 只落在 web UI 层(表单/JSON/import 三面 superRefine),schema 层对 `^https?://` 之外
386
+ 一律放行("Deliberately permissive on FORM")⇒ `ssh:`/scp 形/`git:`/`file:`/裸 `http:`/`owner/repo`
387
+ shorthand 全部可经 API 直写入库——同一条规则两处真源,API 这处敞了 8 天([1366]③ 上报的缺口,
388
+ 维护权移交后归本仓)。现收紧到 schema 单真源:非 `https://` 一律拒(报错点名契约与镜像走法:国内
389
+ 镜像走 `PLUGINS_ALLOW_HOSTS` 加 https 镜像域,不开 http 口;shorthand 展开域消费端无法判定,写全)。
390
+ secrets 纪律不变严(no inline token/userinfo/secret query·fragment/NUL)。**对存量的影响**:库里若已有
391
+ 非 https 形声明,重解析将失败——这是收紧的本意(fail-loud 优于静默物化一个 worker 会拒 clone 的形)。
392
+ 红先行:`test/plugins.test.ts` 新钉七形反例(含 marketplace.url 同规则)+ 翻转两处旧断言
393
+ (scp 形此前被断言为合法)。437 测试全绿。
394
+
395
+ ## 0.10.22 (2026-07-27)
396
+
397
+ **server AI 接手维护**(clay 令:本仓此前无持有方;server 已是本契约两侧的消费者——auth-bridge
398
+ 验证方实现 + `@sema-agent/sdk/registry` 客户端引擎)。接手首车三件:
399
+
400
+ - **修欠账:typecheck gate 归零**——12 个 tsc 红(0.6 域重构后测试引用已删键 autonomy/approvalRequire、
401
+ ModelEntry.cost 收紧后测试字面量缺 cacheRead/cacheWrite、SAFETY_MERGE_SPEC 联合窄化、SchedulerRecord
402
+ 索引签名)全部按现契约真形修正,运行时语义零变化(434 测试前后同绿)。此前 vitest 绿掩盖 tsc 红
403
+ =无人守门的实证。
404
+ - **新 `api/wire` subpath:零依赖 wire 子集**——auth/scopes 的端点路径、协议常量、纯函数
405
+ (normalizeUserCode/nextPollInterval)移入 `src/api/wire.ts`(零 import),`api/auth`/`api/scopes`
406
+ re-export ⇒ 既有导入面字节兼容。零运行时依赖的客户端(`@sema-agent/sdk/registry`)可运行时直取,
407
+ 值拷贝+同源锚可退位。纯度=esbuild 真打包门(test/wire-purity:bundle 零 import、零 zod)。
408
+ - ROADMAP「在飞」核账:scheduler 生命周期契约的 store 原语半场 0.10.13/14 已 SHIPPED,条目移入版本锚;
409
+ daemon 侧语义(reap/once 即删/标记)属消费方实现面,不在本仓。
410
+
411
+ ## 0.10.21 (2026-07-19)
412
+
413
+ - **prompts 入 `PORTABLE_DOMAINS`**(server codex-8 实锚):local FileConfigStore 此前不枚举 prompts——
414
+ `config.d/prompts.json` 永远读不到、不进 version hash(catalog 编辑不触发 refresh)。端到端钉随车
415
+ (文件→getEffective→effective.prompts + version 变动)。
416
+
417
+ ## 0.10.20 (2026-07-19)
418
+
419
+ - **prompts 域 catalog 轴**(board [985]a/[1242]/[1248] 过轮定稿;core design/148 S1 seam 同形):
420
+ `PublishedPromptArtifactEnvelope`/`PromptEpochArtifactPayload`/`PromptCatalogSnapshot`/
421
+ `PromptArtifactSection` zod(传输门;语义权威=core `verifyPromptArtifact`);`PROMPT_ARTIFACT_LIMITS`
422
+ 镜像常量(逐键 === core `ARTIFACT_LIMITS`,对表钉在 server 仓 CI);`EffectivePromptsWire` 双轴下发形
423
+ (declarations|catalog 至少一轴,过渡窗可并存);`PromptsConfig.catalog` 存储位(local
424
+ config.d/prompts.json 同形直携,两 lane 同形)。纯 additive,存量零迁移。
425
+
426
+ ## 0.10.18 (2026-07-18)
427
+
428
+ - **prompts 域正式注册**([1064]② 补位):`DOMAIN_SCHEMAS.prompts=PromptsConfig`+
429
+ `DOMAIN_READ_FALLBACK.prompts="default"`(内容域,坏形→空默认=「无 prompts 管理」语义;
430
+ fail-closed 由 PUBLISH_MODE 发布闸承担)+`EffectiveConfig.prompts`+buildEffective 组装
431
+ (parseOr 车道)——center 域写门/store 携带/effective 携带全链解锁,第 16 域。
432
+ 域数钉测试(15→16)四处随迁。
433
+
434
+ ## 0.10.17 (2026-07-18)
435
+
436
+ - `PromptTextDeclaration.contentHash?`(additive,[1062]③ core 1.315 补位):逐 section 对账锚
437
+ 形校验(`sha256:<64hex>`),契约层显式声明消灭非 strict parse strip 断锚;EffectivePrompts.sections
438
+ 同型自动带。node 绑定:`sectionContentHash(text)`(core 校验同刻度=sha256(text))+
439
+ `promptsContentDigest` 顺带返回 `sectionHashes[]`(center 物化免二次铸)。契约测试 +3。
440
+
441
+ ## 0.10.16 (2026-07-18)
442
+
443
+ - **prompts 域 schema v1**(center prompts 战役;board [1050] 五定夺/[1051] clay 产品终稿/
444
+ [1057] M2 下发形):`PromptTextDeclaration`(core 形逐字,slot 闭集 identity/scenario/behavior)
445
+ /`PromptBinding`(三维 global/worker/scenario,selector superRefine,covering=层间整 slot 替换+
446
+ 层内保序语义成文)/`PromptsConfig`(v1=bindings;overlays/profiles/modelPolicies 留位 additive)
447
+ /`EffectivePrompts`(下发形 [1057] 逐字:packId 内容寻址+contentDigest+基线 sections+
448
+ scenarioOverrides 整包替换)。node 绑定新增 `promptsContentDigest`(canonical sha256 非盐化,
449
+ packId=`center:`+前 12)。契约测试 12 题。@server 消费投影/@web M2 存储解析即可开。
450
+
451
+ ## 0.10.15 (2026-07-17)
452
+
453
+ - **BREAKING(现网无用户,clay 亲裁直删,board [1051]③a)**:`ScenarioEntry.prompt` 字段废弃移除
454
+ ——配置域 prompt 单入口收敛为 center prompts binding(scenario 维度);引擎 API 层
455
+ `TaskSpec.systemPrompt` 保留(另一层)。存量数据带 prompt = parse 时 strip,不炸。
456
+ - 立案:scenarios 等域的**域级 publish 强制闸**([1050]④,fail-closed 兜底先行姿势)——设计与
457
+ 实现随 center prompts 战役 schema 班车,见 ROADMAP。
458
+
459
+ ## 0.10.14 (2026-07-17)
460
+
461
+ - `mutateSchedulerStore(path, fn, {retries})`(node 绑定,additive):共享 scheduler store 的
462
+ **唯一跨进程变更原语**——optimistic base 见证(raw 文本)+有界重放(默认 5)+原子提交;
463
+ 裸 load→save 的 lost-update 竞态从此有正位(server L1-2 与壳侧 codex F1 双向合流,
464
+ 黑板 [1001]①/[1003]②)。诚实边界成文:见证→rename 微窗仍在(非锁协议),fn 必须纯可重放。
465
+ `load/save` 裸 API 保留(只读/初始化用途);写路径消费方(server backend/壳 daemon/reap)
466
+ 随各自班车迁移。契约测试 6 题(round-trip/缺失文件/abort 零写/并发重放不丢他方更新/
467
+ 有界耗尽诚实失败/retries:0)。
468
+
469
+ ## 0.10.13 (2026-07-17)
470
+
471
+ - `ModelEntry.promptGuidance?: string[]`(additive):per-model prompt-guidance 句(装配 behavior 槽
472
+ per-model 缓解句),形对齐 core 消费面 `model.promptGuidance`。契约层显式声明防 FileConfigStore
473
+ lane parse 期 strip(0.10.10 autoCompactTokens 同族病);ABSENT = 零迁移。契约测试 4 题。
474
+
475
+ ## 0.10.12 (2026-07-16)
476
+
477
+ **新增(additive patch):`FileConfigStore.getEffective({tolerant:true})` —— 单域坏形文件不再连坐全域
478
+ (server 侧点名接单的 seam)。病灶=strict `getEffective` 对任何一个坏形 domain 文件 throw,消费者
479
+ (server 单点 catch)只能整包回落 env——一个坏 models.json 把 skills/mcp/scenarios 全域连坐。**
480
+
481
+ - **形状**:`getEffective({tolerant:true})` → `{ effective, domainErrors: [{domain, error}] }`。
482
+ - **处置表 = parse 层既有 `DOMAIN_READ_FALLBACK` 同一张表**:catalog 域(models/skills/mcp/plugins/
483
+ scenarios/collab/hosts…)坏文件 → 该域 schema default + `domainErrors` 单列(fail-closed);
484
+ **gate 域(governance/rosters/entitlement/execution/runtime/workers)tolerant 也照旧 throw**
485
+ ——READ 容错不放宽 gate fail-loud,defaulting=放权不许,消费方对 gate 域继续 fail-static on last-good。
486
+ - **version 哨兵**:坏文件以其文本 hash 参与 content-hash——坏≠absent、坏A≠坏B、坏→修好均 bump
487
+ (lock-step 纪律,version-gated poller 不漏拍)。
488
+ - **零行为变化**:strict `getEffective` / `getVersion` 逐字节不变;全健康时 tolerant 与 strict
489
+ 逐字节一致(含 version)。
490
+ - 钉测 +5(test/file-store-tolerant.test.ts);全量 401 绿;build 绿。
491
+
492
+ ## 0.10.11 (2026-07-15)
493
+
494
+ **新增(additive patch):models 池结构级 `default?` 键 —— 显式默认模型(server 1.200
495
+ resolveDefaultModelName 已落地消费,优先级第一级 = 本键)。病灶=registry-core 的 ModelsConfig 是
496
+ strip 语义的 z.object,未声明的 `default` 在 parse 期即丢;加键后 server 零改动即生效。**
497
+
498
+ - **形状**:`models.default?: string`(min 1,optional 无 default)—— 取值 = catalog 模型 `name`
499
+ (目录键)。与 `roles.default`(角色词)是两回事:这是结构级键,消费方优先于 roles/档位绑定。
500
+ ABSENT = 沿既有 roles/档位 fallback 链,存量 doc 零迁移。
501
+ - **ref 完整性**:悬空(不在 models 内)写入时 fail-loud(照 roles/allowlist/activeTierGroup 的
502
+ superRefine 同款先例);未经 schema 的本地/存量 lane 由消费方 warn 降级——「写面 fail-loud +
503
+ 读面 graceful」双层姿势与 activeTierGroup 一致。
504
+ - **per-worker 视图**:resolveEffectiveForWorker 直通 + 集外悬空-drop(照 roles 的 dangling-{model}
505
+ drop 先例)——roster 收窄后 default 指到 worker 模型集之外 ⇒ 剔除,消费方 fallback 链接手。
506
+ (不加此腿则该函数显式重建 models 对象会把键静默丢掉,roster'd worker 面失效。)
507
+ - 钉测 +6(在场保留/缺席零迁移/空串拒/悬空拒/buildEffective roundtrip/per-worker 三腿);全量 396 绿
508
+ (390+6);build 绿。
509
+
510
+ ## 0.10.10 (2026-07-14)
511
+
512
+ **新增(additive patch):`ModelEntry.autoCompactTokens?` / `charsPerToken?`(server
513
+ 点名)。病灶=ModelEntry 是 strip 语义的 z.object,center 显式下发的这两个字段在本地 FileConfigStore
514
+ lane parse 期即丢。**
515
+
516
+ - **形状**:`autoCompactTokens?: number`(正整数,auto-compaction 触发阈值/tokens);
517
+ `charsPerToken?: number`(有限正数,允许小数如 3.5,本地 token 估算用)。两者 optional 无
518
+ default——ABSENT = 消费方自身默认,存量条目零迁移、不凭空长键。
519
+ - **语义**:契约层只保真下发值,不定义压缩行为本身(消费方=壳/引擎 compaction 配置,
520
+ safety-merge autoCompaction seam)。
521
+ - 钉测 +4(整域 round-trip 保真 + 双字段正数校验 + ABSENT 零迁移);全量 390 绿(386+4);build 绿。
522
+
523
+ ## 0.10.9 (2026-07-14)
524
+
525
+ **新增(additive patch):`ExecutionPublicKey.workerId?` — 执行域公钥↔worker 绑定(service
526
+ 接单合意)。**
527
+
528
+ - **形状**:`execution.publicKeys[].workerId?: string`(min 1 / max 128,optional 无 default —
529
+ 存量登记条目零迁移)。取值 = 上报方 worker 的 `SEMA_REGISTRY_WORKER` env(service 上报载荷带
530
+ `workerId`;该 env 未配 = 单 worker 部署,上报省略)。
531
+ - **语义**:多 worker 部署下 seal 侧(web 贴 key 面)凭它按**目标 worker** 过滤选钥——A worker 的
532
+ 密文只有 A 的私钥能解,选错钥 = 执行侧解密失败(晚且难查);ABSENT = 未绑定,seal 侧 fallback
533
+ newest(仅适合单 worker 部署)。
534
+ - 钉测 +3(带/不带 workerId 双腿 round-trip + 底线形状);全量 386 绿(383+3);build/e2e 绿。
535
+ - 另捎带:0.10.8 后已合入的 `peerDependencies: { zod: ^3.24.0 }` 声明(cbca45f,宿主同段强
536
+ dedup 单实例;deps 保留保独立可装)随本班车首发。
537
+
538
+ ## 0.10.8 (2026-07-13)
539
+
540
+ Scope migration — no contract changes.
541
+
542
+ - **Package renamed**: `@sema-ai/registry-core` → `@sema-agent/registry-core` (ecosystem-wide npm scope
543
+ unification under the sema-agent org). Old @sema-ai/registry-core versions remain published and will be
544
+ deprecated pointing here.
545
+ - **Build hygiene**: `removeComments` enabled for the dist build; source-comment wording pass (no code
546
+ changes — emitted .js byte-identical to 0.10.7 modulo the rebuild).
547
+
548
+ ## 0.10.7 (2026-07-13)
549
+
550
+ Housekeeping release — no contract changes (dist identical to 0.10.6 modulo rebuild).
551
+
552
+ - **npm hygiene** (ecosystem order): strip intranet coordinates from README and
553
+ `repository` (now github.com/clayboby/sema-registry-core); drop `publishConfig`
554
+ (leg-1 registry now comes from the project `.npmrc` scope mapping, so the tarball
555
+ carries no internal URLs).
556
+ - **License**: MIT → BUSL-1.1 (ecosystem ruling; prior MIT copies remain MIT).
557
+ - **Publish legs**: the legacy internal release leg retired; `publish:dual` = internal source-of-truth
558
+ registry + npmjs (public), npmjs leg with explicit scope override.
559
+
560
+ ## 0.10.6 — 2026-07-13
561
+
562
+ **新增(additive patch):`SealedApiKey.setAt?`(ISO,center 写面 server 端盖章)。** write-only 的
563
+ masked GET 面靠它+publicKeyId 展示「已于 X 设置」——密文本体永不回读;optional(执行侧解密不依赖,
564
+ 本地手写配置零迁移)。钉测 +1,全量 383 绿。
565
+
566
+ ## 0.10.5 — 2026-07-13
567
+
568
+ **新增(additive patch):sealed-box 密钥托管契约 — 产品拍板铁律修订:「不存 secret 值」精化为「不存
569
+ 可解明文」(center 可存不可解密的密文)。痛点=接入模型只能填 env-NAME,用户不知道密钥本体去哪配。**
570
+
571
+ - **`ModelEntry.sealedApiKey?`**(默认模式「直接贴 key」的存储形态):`{ ciphertext(base64),
572
+ publicKeyId, alg: "libsodium-sealedbox-x25519" }`。浏览器端用执行域公钥 crypto_box_seal 加密,
573
+ 明文不出浏览器;center 无私钥永远解不开;caps/config 原样下发,执行侧私钥解密注入 env。
574
+ **形状 only 校验**(base64 底线 + max 8192 防 blob;内容对 center 永远不透明)。
575
+ - **互斥语义 = 优先级裁决**:与 `apiKeyEnv`(专家模式 env-NAME 引用)双设合法,执行侧注入时
576
+ **sealed 优先**压过 env 引用;刻意不 schema 层拒双设(切模式免清旧字段)。JSDoc 双向互注。
577
+ - **`execution.publicKeys?`**(执行域公钥登记,收编 execution 域循 sessionMirror 先例零新域):
578
+ `{ publicKeyId, publicKey(base64 恒 44 字符=32 字节 X25519 regex 钉死), createdAt, notes? }[]`。
579
+ center **只登记公钥**,私钥执行侧生成持有永不上行;publicKeyId 表内唯一(密文 ref 目标);
580
+ 多把并存合法(轮换窗口)。optional 无 default = 存量文档字节稳定零迁移。
581
+ - **write-only 纪律(消费方约定,JSDoc 钉死)**:center GET 面永不回 ciphertext 本体(只回
582
+ publicKeyId+设置时间);密文字段绝不进任何日志。schema 不执法读面,这是 API 层契约义务。
583
+ - 钉测 +11(test/sealed-key-0.10.5.test.ts:密文 round-trip / 形状 only 不验内容 / alg literal /
584
+ 双设合法+ABSENT 零迁移 / X25519 长度钉死 / id 唯一+轮换并存 / 存量 execution 文档字节稳定);
585
+ 全量 382 绿(371+11);build 绿。
586
+
587
+ ## 0.10.4 — 2026-07-12
588
+
589
+ **新增(additive patch):`runtimeCaps.autoMode` — auto-mode 分类器 arm 线收编(core 批2a seam `RuntimeCaps.autoMode`,`=== true` 显式 opt-in 默认 OFF,allowObservers 同极性)。**
590
+
591
+ - **形状**:`EntitlementRuntimeCaps.autoMode?: boolean`(optional,零迁移——存量文档不含此键=ABSENT
592
+ 语义,字节不变)。
593
+ - **三态语义(ABSENT ≠ false,照 allowObservers 纪律)**:ABSENT = center 没说话 → wire 上**不下发键**
594
+ (core 是唯一默认源,缺席绝不补成显式 false);`true` = 显式为该 principal arm 分类器(部署无 classify
595
+ 腿时 core 侧 no-op——能力门在 core);`false` = 显式 org deny。compose 合成 `RUNTIME_CAP_STRICT.autoMode
596
+ = false`(deny 胜),与 core 的 `=== true` opt-in 检查正交。
597
+ - **与既有 `allowAutoMode` 的分工(勘察结论,两键并存语义清晰)**:`allowAutoMode` = 用户侧 auto 权限模式
598
+ 的按人**准入闸**(may-I ceiling,壳/settings 面,tighten-only;当前全生态零 wire 消费者=壳侧预留位);
599
+ `autoMode` = center 对**服务端分类器腿本身**的部署 arm 决定(core RuntimeCaps 直连)。JSDoc 双向互注。
600
+ - 钉测 +5(照 allowObservers 五测形状:true/false round-trip / ABSENT 不注默认 / 非 boolean 拒 /
601
+ STRICT 表极性 / tier 挂载端到端含双键并存);全量 371 绿(366+5);build 绿。
602
+
603
+ ## 0.10.3 — 2026-07-12
604
+
605
+ **新增(additive patch,发版纪律「patch 只装 additive 字段」):`runtimeCaps.allowObservers` — observer
606
+ agents 开闸线收编(service 1.175.0 宽读透传 wire 已钉,core 1.270.0/1.273.0
607
+ `=== true` 显式 opt-in)。**
608
+
609
+ - **形状**:`EntitlementRuntimeCaps.allowObservers?: boolean`(optional,零迁移——存量文档不含此键
610
+ =ABSENT 语义,字节不变)。
611
+ - **三态语义(ABSENT ≠ false)**:ABSENT = center 没说话 → wire 上**不下发键**(core 是唯一默认源;
612
+ service toCoreRuntimeCaps 缺键不补 false 的纪律与此对钉——补 false 会伪造「center 说过话」的显式
613
+ 判决,污染 env-baseline 合成序);`true` = 显式开 observer agents;`false` = 显式 org 关,**压过
614
+ 节点级 env 基线 `EXPERIMENTAL_OBSERVER_AGENTS`**(center 带键必赢)。
615
+ - **⚠️ core 消费极性与其余 allow* 相反**:引擎侧 `=== true` 显式 opt-in(默认 OFF,undefined ships
616
+ dark)——本键是 ENABLE 线不只是 ceiling;但 compose 合成极性不变:`RUNTIME_CAP_STRICT.allowObservers
617
+ = false`(deny 胜,与 core 的 opt-in 检查正交)。
618
+ - 钉测 +5(true/false round-trip / ABSENT 不注默认 / 非 boolean 拒[service fail-closed THROW 依赖
619
+ schema 真值] / STRICT 表极性 / tier 挂载端到端);全量 366 绿(361+5);build 绿。
620
+
621
+ ## 0.10.2 — 2026-07-12
622
+
623
+ **修复 + 文案勘误(附B 三单合评审 M-1 / MAJOR-1;PM 拍向=保 C 行为、改 A/B 文案)。**
624
+
625
+ - **M-1 根治:`SESSION_MIRROR_ENGINE_URL` trim 前置**(`z.string().trim().pipe(NON_SECRET_URL)…`,
626
+ trim 在 url/refine 之前)。合评审实证:`" https://…"` 带前导空白时写侧收(new URL 容忍前导空白)
627
+ 而壳读侧逐字符比对拒 = 全员镜像**静默 degraded**。0.10.2 起前导/尾随空白在 schema 层归一后再验,
628
+ **存储值即 trim 后值**(所见即所存);trim 只归一空白不放水(trim 后仍非法照拒)。钉测 +2
629
+ (前导空白/尾随空白→归一通过且存储值已 trim;纯空白/trim 后非 loopback http 仍拒)。
630
+ - **MAJOR-1 文案勘误(TSDoc,行为不变=保 C)**:`SessionMirrorPolicy` 对 required:true 治理态的表述
631
+ 由「本地 --target 只能改目标不能关镜像」勘正为「**本地覆盖不生效:既不能改目标也不能关闭
632
+ (org 压一切)**」——0.10.1 CHANGELOG/commit 中旧措辞以本条为准(WEB-SETUP-RECON 附B r1 勘误)。
633
+ - 全量 361 绿(359+2);additive patch,零形状变更、零迁移。
634
+
635
+ ## 0.10.1 — 2026-07-12
636
+
637
+ **新增(additive patch,发版纪律「patch 只装 additive 字段」):`execution.sessionMirror` — org 默认
638
+ 会话镜像目标(WEB-SETUP-RECON 附B,产品拍板两层;附B 单A/单B/单C 并行切分的先行腿)。**
639
+
640
+ - **形状**:`sessionMirror?: { engineUrl: string, required: boolean=false }`,挂在 execution 域。
641
+ 整个对象 optional,**缺省 INERT**(无下发=老 center/老壳/0.8–0.10 存量 execution 文档零行为差、
642
+ 零迁移——存量文档本就不可能含此键)。
643
+ - **域归属=收编 execution,零新域**(design/142 S3 草案同款尺量,详见 commit message 与 SessionMirrorPolicy
644
+ JSDoc):同一治理轴(required 与 ExecutionPolicy.required 完全同构=壳锁定/managed-settings 心智)
645
+ +无独立读损语义(损坏退默认=required:true 审计强制静默蒸发=放权,与 execution throw 理由逐字同款
646
+ ——tierGroups 收编 models 的同款判据)+无独立写面(纯声明字段,无动作端点,RBAC 同 editor 档)。
647
+ #74 双表态/缺域 fixture/PORTABLE 全部零新增(execution 既有表态罩住)。
648
+ - **engineUrl 写侧传输闸**(`SESSION_MIRROR_ENGINE_URL`):**https 或 loopback http**(127.0.0.1/
649
+ localhost/::1/[::1],与壳 isLoopbackEngineUrl 逐字同表)——非 loopback 明文 http 在 **schema 层就拒**
650
+ (镜像上行带会话内容+Bearer 凭证;写侧 fail-loud 早于读侧 evaluateEngineRouting 执法)。基线复用
651
+ NON_SECRET_URL(禁 userinfo 凭证/禁 query/fragment 夹带 secret-shaped 值)。
652
+ - **两层语义**:required:false(默认)=便利默认值(壳解析序第三腿:本地显式 --target > 本值 >
653
+ connect 回落;开关仍用户 sync on,隐私 opt-in 先例不破);required:true=org 治理强制(镜像默认开
654
+ 且不可关,--target 只能改目标——CC managed-settings 锁定语义,S3 沙箱锁同构)。ENFORCEMENT HONESTY
655
+ 同域头注:今天 CLIENT-SIDE 执法。
656
+ - **开放演化**:对象不 .strict()(zod 默认 strip 未知键)——v2 加 audit 字段类(保留窗/脱敏面等)
657
+ 恒 additive,v2 文档被 v1 消费者读到=未知键剥除,forward-compatible。
658
+ - EffectiveConfig 投影直通(execution 既有腿);钉测 10(零新域/INERT 存量字节稳定/两层 round-trip/
659
+ 传输闸四通三拒/NON_SECRET 基线/malformed/投影/corrupt=throw 不降级/v2 strip);全量 359 绿。
660
+
661
+ ## 0.10.0 — 2026-07-12
662
+
663
+ **新增(additive,兼容):第 15 域 `projects`(142-S3 项目身份登记簿+无仓 projectId 铸造权威)。**
664
+ 草案=design/142 S3 projects 域草案;口径=铸造离线自由/使用注册执法(core 六答,已收账)。
665
+
666
+ - **形状**:`ProjectsConfig = { projects: Record<projectId, ProjectRegistration> }`;
667
+ `ProjectRegistration = { displayName, gitRemotes[], defaultScopes[], registeredBy, registeredAt, notes? }`。
668
+ 复合键 `(tenant, projectId)` 的 tenant 半边走 center **scope 轴**(每 scope 一份域文档),不进文档
669
+ ——fork 后同一 projectId 可合法存在于两个 scope,互不相见。
670
+ - **宽读严写**:新导出 `PROJECT_ID_REGEX` = generic lowercase 规范 UUID(读面收 v4——
671
+ 外部/历史铸造也是合法身份);铸造侧(core marker / center mint 端点)恒产 **uuidv7**。自持镜像
672
+ +dev-only conformance 纪律(core 公开导出后切单源,TODO 在 JSDoc)。
673
+ - **gitRemotes 底线校验**:归一化 `host/path` 形态——非空/无空白/不含 `://`(出现即未归一化,
674
+ fail-loud);`.max(16)`;空数组=无仓合法。**superRefine:租户内一条 remote 只属一个 project**
675
+ (找回阶梯/防重铸要求映射确定;撞了写入即拒)。
676
+ - **defaultScopes 开放值域**(开放值域纪律):z.string() 不 enum;方向=v2 scope 键串
677
+ (`proj`/`userproj` JSDoc-only,S4 细化),本域只登记不解释。
678
+ - **#74 立规过门**:`DOMAIN_READ_FALLBACK.projects = "throw"`(退默认=身份簿蒸发+claim 读改写面
679
+ clobber 存量登记=数据丢失,比放权更狠);**PORTABLE_DOMAINS 不进**(租户身份数据不可搬——bundle
680
+ 导入=凭空复制身份注册,design/142 §1.4 威胁①);缺省 INERT(`{projects:{}}`,老快照/0.9 存量
681
+ 读面零变化)。写权限=editor 档(登记簿非注入面,DOMAIN_WRITE_ROLE 注释落裁定)。
682
+ - 钉测 11(注册域/INERT/round-trip/宽读 v4/坏键拒/REGEX 镜像/remote 底线/remote 撞项目/开放值域/
683
+ corrupt=throw 不降级/0.9 字节稳定);全量 349 绿。
684
+
685
+ ## 0.8.1 — 2026-07-11
686
+
687
+ **修复(S3 评审 M-1:收紧毁存量,E2 血训模式)。** 0.8.0 给 hosts 域加了 `.max` 收紧
688
+ (`HostEntry.name`/`HostStatus.host` → 63、`hosts` 数组 → 1024),但 store 持久化的是 RAW JSON、
689
+ 每次读都经 `parseDomain` 重校验——0.7 时代**合法**的超限存量(64 字符机器名 / 2000 条数组)在 0.8 下
690
+ 读取即 THROW,并炸掉整个 scope 的 `getEffective`(连带 /effective、caps、publish 全线)。两层修复:
691
+
692
+ 1. **hosts 精确 grandfather(读路径)** — `grandfatherHostsRead`(config-fns):`buildEffective` 解析
693
+ hosts 前对**且仅对** 0.8.0 新增的两条界做 clamp:
694
+ - name 超 63 → **整条跳过**(不截断——截断会伪造一个与任何 ORCH_HOST_ID 都不匹配的新身份,还可能
695
+ 撞进重名 refine);
696
+ - 数组超 1024 → `slice(0, 1024)`(先跳过后截断,给合法条目腾位);
697
+ - 每次 clamp 经 `onWarning` 回调发 `hosts-grandfathered` 审计告警;
698
+ - **良构数据恒等返回原引用 → 字节不变**。
699
+ regex/类型/重名等非本次收紧项**不**放行,仍交 zod(这是定向 grandfather,不是宽松解析器)。
700
+
701
+ 2. **buildEffective 逐域降级护栏(通用,防未来一切收紧)** — 坏域退 schema 默认 + `domain-defaulted`
702
+ 告警,不炸全 scope;但「退默认」逐域判安全性(`DOMAIN_READ_FALLBACK`,`satisfies Record<DomainName,…>`
703
+ 强制未来新域显式表态):
704
+
705
+ | 域 | 策略 | 理由 |
706
+ |---|---|---|
707
+ | models / skills / mcp / plugins / scenarios / systems / collab | 退默认 | 加法能力目录,退空=能力消失,fail-closed |
708
+ | hosts | 退默认 | 空注册表=只失自动排布(可用性面);自注册回登为 approved:false=待批,fail-closed;且精确 grandfather 先行 |
709
+ | rosters | **fail-loud** | 丢 roster → resolveEffectiveForWorker 落 global fallback=**全目录**,静默放宽受限 worker 的模型面(放权) |
710
+ | workers | **fail-loud** | 退空 fleet spec → reconciler 会**拆光**全部在管 worker(毁灭性 apply,比读故障更糟) |
711
+ | runtime | **fail-loud** | 丢中心下发的限速/成本天花板=预算面 fail-open |
712
+ | governance | **fail-loud** | 丢 autonomy/commandPolicy/approvalRequire 三闸=放权 |
713
+ | entitlement | **fail-loud** | 丢 org kill-switch/预算天花板/tier 限制=放权 |
714
+ | execution | **fail-loud** | required:true(沙箱强制)翻回 false=放权 |
715
+
716
+ fail-loud 域坏档时消费者按既有姿势 fail-static(守住 last-good),比端出去掉闸的 effective 安全。
717
+
718
+ **API(additive,兼容)**:`buildEffective` 第 4 参可选 `onWarning?: (w: EffectiveReadWarning) => void`;
719
+ `FileConfigStore` 构造第 2 参可选 `{ onWarning }`;新导出 `grandfatherHostsRead` /
720
+ `GrandfatherHostsReadResult` / `EffectiveReadWarning` / `DOMAIN_READ_FALLBACK` /
721
+ `HOST_NAME_MAX` / `HOSTS_ARRAY_MAX`(types)。
722
+
723
+ **写路径不动**:`parseDomain` 保持严格——超限**新写入**在 save 时照旧 fail-loud 拒绝
724
+ (0.8.0「poisoned publish」意图不变);center 各 store 的 setDomain/PUT 走的就是它。
725
+
726
+ **订正(S3 批报告失实处)**:「center 本就兜底 probes」不成立——center hosts/status PUT 并无独立
727
+ probe 上限,schema 即闸;probes 上报属 WRITE 路径,其 fail-loud **保持**(有意设计),本修复只涉
728
+ config-hosts 读路径。