@sema-agent/settings-schema 2.1.0 → 3.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.
- package/CHANGELOG.md +229 -0
- package/README.md +35 -4
- package/conformance/VERSION +1 -0
- package/conformance/baseline.json +55 -0
- package/conformance/cases/c01-entry-salvage-then-typo/expected.json +105 -0
- package/conformance/cases/c01-entry-salvage-then-typo/input.json +22 -0
- package/conformance/cases/c01-entry-salvage-then-typo/meta.json +10 -0
- package/conformance/cases/c02-hosts-clamp-stacked/expected.json +96 -0
- package/conformance/cases/c02-hosts-clamp-stacked/input.json +21 -0
- package/conformance/cases/c02-hosts-clamp-stacked/meta.json +10 -0
- package/conformance/cases/c03-literal-dotted-top-key/expected.json +112 -0
- package/conformance/cases/c03-literal-dotted-top-key/input.json +26 -0
- package/conformance/cases/c03-literal-dotted-top-key/meta.json +5 -0
- package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +77 -0
- package/conformance/cases/c04-all-bad-collection-not-salvaged/input.json +18 -0
- package/conformance/cases/c04-all-bad-collection-not-salvaged/meta.json +5 -0
- package/conformance/cases/c05-gate-domain-bad-entry-throws/expected.json +16 -0
- package/conformance/cases/c05-gate-domain-bad-entry-throws/input.json +18 -0
- package/conformance/cases/c05-gate-domain-bad-entry-throws/meta.json +5 -0
- package/conformance/cases/c06-legacy-governance-lift/expected.json +99 -0
- package/conformance/cases/c06-legacy-governance-lift/input.json +20 -0
- package/conformance/cases/c06-legacy-governance-lift/meta.json +9 -0
- package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +72 -0
- package/conformance/cases/c07-hooks-is-not-a-config-domain/input.json +43 -0
- package/conformance/cases/c07-hooks-is-not-a-config-domain/meta.json +6 -0
- package/conformance/cases/c08-limits-unknown-carried-64/expected.json +336 -0
- package/conformance/cases/c08-limits-unknown-carried-64/input.json +74 -0
- package/conformance/cases/c08-limits-unknown-carried-64/meta.json +5 -0
- package/conformance/cases/c09-limits-unknown-carried-65/expected.json +338 -0
- package/conformance/cases/c09-limits-unknown-carried-65/input.json +75 -0
- package/conformance/cases/c09-limits-unknown-carried-65/meta.json +7 -0
- package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +106 -0
- package/conformance/cases/c10-record-key-secret-redacted-twice/input.json +29 -0
- package/conformance/cases/c10-record-key-secret-redacted-twice/meta.json +13 -0
- package/conformance/cases/c11-unicode-unknown-keys/expected.json +88 -0
- package/conformance/cases/c11-unicode-unknown-keys/input.json +13 -0
- package/conformance/cases/c11-unicode-unknown-keys/meta.json +5 -0
- package/conformance/cases/c12-prototype-name-top-keys/expected.json +72 -0
- package/conformance/cases/c12-prototype-name-top-keys/input.json +20 -0
- package/conformance/cases/c12-prototype-name-top-keys/meta.json +11 -0
- package/conformance/cases/c13-models-field-null/expected.json +77 -0
- package/conformance/cases/c13-models-field-null/input.json +11 -0
- package/conformance/cases/c13-models-field-null/meta.json +5 -0
- package/conformance/cases/c14-models-field-empty-array/expected.json +72 -0
- package/conformance/cases/c14-models-field-empty-array/input.json +11 -0
- package/conformance/cases/c14-models-field-empty-array/meta.json +5 -0
- package/conformance/cases/c15-models-field-number/expected.json +77 -0
- package/conformance/cases/c15-models-field-number/input.json +11 -0
- package/conformance/cases/c15-models-field-number/meta.json +5 -0
- package/conformance/cases/c16-deep-nesting-205/expected.json +83 -0
- package/conformance/cases/c16-deep-nesting-205/input.json +421 -0
- package/conformance/cases/c16-deep-nesting-205/meta.json +5 -0
- package/conformance/cases/c17-empty-domain-file/expected.json +73 -0
- package/conformance/cases/c17-empty-domain-file/input.json +10 -0
- package/conformance/cases/c17-empty-domain-file/meta.json +5 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +74 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/input.json +8 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/meta.json +5 -0
- package/conformance/cases/c19-wire-envelope-no-version/expected.json +74 -0
- package/conformance/cases/c19-wire-envelope-no-version/input.json +13 -0
- package/conformance/cases/c19-wire-envelope-no-version/meta.json +5 -0
- package/conformance/cases/c20-governance-absent-lifts/expected.json +84 -0
- package/conformance/cases/c20-governance-absent-lifts/input.json +11 -0
- package/conformance/cases/c20-governance-absent-lifts/meta.json +9 -0
- package/conformance/cases/c21-governance-empty-object-wins/expected.json +72 -0
- package/conformance/cases/c21-governance-empty-object-wins/input.json +12 -0
- package/conformance/cases/c21-governance-empty-object-wins/meta.json +5 -0
- package/conformance/cases/c22-governance-null-throws/expected.json +16 -0
- package/conformance/cases/c22-governance-null-throws/input.json +9 -0
- package/conformance/cases/c22-governance-null-throws/meta.json +5 -0
- package/conformance/cases/c23-mixed-validity-models/expected.json +106 -0
- package/conformance/cases/c23-mixed-validity-models/input.json +27 -0
- package/conformance/cases/c23-mixed-validity-models/meta.json +9 -0
- package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +100 -0
- package/conformance/cases/c24-valid-entries-with-unknown-keys/input.json +25 -0
- package/conformance/cases/c24-valid-entries-with-unknown-keys/meta.json +5 -0
- package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +89 -0
- package/conformance/cases/c25-published-roundtrip-zero-warnings/input.json +24 -0
- package/conformance/cases/c25-published-roundtrip-zero-warnings/meta.json +5 -0
- package/conformance/cases/c26-hosts-array-1024/expected.json +7241 -0
- package/conformance/cases/c26-hosts-array-1024/input.json +3084 -0
- package/conformance/cases/c26-hosts-array-1024/meta.json +5 -0
- package/conformance/cases/c27-hosts-array-1025/expected.json +7248 -0
- package/conformance/cases/c27-hosts-array-1025/input.json +3087 -0
- package/conformance/cases/c27-hosts-array-1025/meta.json +5 -0
- package/conformance/cases/c28-large-document-over-1mb/expected.json +82 -0
- package/conformance/cases/c28-large-document-over-1mb/input.json +11 -0
- package/conformance/cases/c28-large-document-over-1mb/meta.json +5 -0
- package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +77 -0
- package/conformance/cases/c29-salvage-then-domain-refine-fails/input.json +27 -0
- package/conformance/cases/c29-salvage-then-domain-refine-fails/meta.json +5 -0
- package/conformance/cases/c30-version-triple-a-first/expected.json +85 -0
- package/conformance/cases/c30-version-triple-a-first/input.json +18 -0
- package/conformance/cases/c30-version-triple-a-first/meta.json +5 -0
- package/conformance/cases/c31-version-triple-b-changed/expected.json +85 -0
- package/conformance/cases/c31-version-triple-b-changed/input.json +18 -0
- package/conformance/cases/c31-version-triple-b-changed/meta.json +5 -0
- package/conformance/cases/c32-version-triple-a-restored/expected.json +85 -0
- package/conformance/cases/c32-version-triple-a-restored/input.json +18 -0
- package/conformance/cases/c32-version-triple-a-restored/meta.json +5 -0
- package/conformance/cases/c33-limits-nested-carried-key/expected.json +91 -0
- package/conformance/cases/c33-limits-nested-carried-key/input.json +14 -0
- package/conformance/cases/c33-limits-nested-carried-key/meta.json +5 -0
- package/conformance/cases/c34-skills-content-vs-manifest/expected.json +160 -0
- package/conformance/cases/c34-skills-content-vs-manifest/input.json +18 -0
- package/conformance/cases/c34-skills-content-vs-manifest/meta.json +5 -0
- package/conformance/cases/c35-portable-domain-file-is-null/expected.json +76 -0
- package/conformance/cases/c35-portable-domain-file-is-null/input.json +9 -0
- package/conformance/cases/c35-portable-domain-file-is-null/meta.json +5 -0
- package/conformance/cases/c36-skills-entry-without-content/expected.json +144 -0
- package/conformance/cases/c36-skills-entry-without-content/input.json +16 -0
- package/conformance/cases/c36-skills-entry-without-content/meta.json +5 -0
- package/conformance/cases/c37-skills-field-null/expected.json +134 -0
- package/conformance/cases/c37-skills-field-null/input.json +9 -0
- package/conformance/cases/c37-skills-field-null/meta.json +5 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +72 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/input.json +11 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/meta.json +5 -0
- package/conformance/cases/c39-hidden-file-in-config-d/expected.json +72 -0
- package/conformance/cases/c39-hidden-file-in-config-d/input.json +11 -0
- package/conformance/cases/c39-hidden-file-in-config-d/meta.json +5 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +112 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/input.json +39 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/meta.json +8 -0
- package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +85 -0
- package/conformance/cases/cc02-mcp-source-key-is-transported/input.json +20 -0
- package/conformance/cases/cc02-mcp-source-key-is-transported/meta.json +8 -0
- package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +89 -0
- package/conformance/cases/cc03-model-compat-unknown-subkey/input.json +22 -0
- package/conformance/cases/cc03-model-compat-unknown-subkey/meta.json +8 -0
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +102 -0
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/input.json +30 -0
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/meta.json +9 -0
- package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +115 -0
- package/conformance/cases/cli02-control-and-zero-width-chars/input.json +42 -0
- package/conformance/cases/cli02-control-and-zero-width-chars/meta.json +9 -0
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +92 -0
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/input.json +16 -0
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/meta.json +9 -0
- package/conformance/cases/cli04-env-value-with-newline/expected.json +93 -0
- package/conformance/cases/cli04-env-value-with-newline/input.json +23 -0
- package/conformance/cases/cli04-env-value-with-newline/meta.json +5 -0
- package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +109 -0
- package/conformance/cases/cli05-long-and-prefix-colliding-names/input.json +30 -0
- package/conformance/cases/cli05-long-and-prefix-colliding-names/meta.json +5 -0
- package/conformance/cases/z01-every-domain-empty-object/expected.json +72 -0
- package/conformance/cases/z01-every-domain-empty-object/input.json +25 -0
- package/conformance/cases/z01-every-domain-empty-object/meta.json +5 -0
- package/conformance/cases/z02-every-domain-unknown-key/expected.json +228 -0
- package/conformance/cases/z02-every-domain-unknown-key/input.json +59 -0
- package/conformance/cases/z02-every-domain-unknown-key/meta.json +5 -0
- package/conformance/historical/settings-schema@1.0.0.json +999 -0
- package/conformance/historical/settings-schema@1.10.0.json +999 -0
- package/conformance/historical/settings-schema@1.5.0.json +999 -0
- package/conformance/historical/settings-schema@2.0.0.json +999 -0
- package/conformance/historical/settings-schema@2.1.0.json +999 -0
- package/dist/api/auth.d.ts +42 -1
- package/dist/api/auth.js +71 -4
- package/dist/api/scopes.d.ts +9 -1
- package/dist/api/scopes.js +8 -2
- package/dist/config-fns.d.ts +56 -24
- package/dist/config-fns.js +89 -72
- package/dist/conformance/canonical.d.ts +36 -0
- package/dist/conformance/canonical.js +114 -0
- package/dist/conformance/contract-adapter.d.ts +20 -0
- package/dist/conformance/contract-adapter.js +74 -0
- package/dist/conformance/corpus.d.ts +73 -0
- package/dist/conformance/corpus.js +99 -0
- package/dist/conformance/derive.d.ts +48 -0
- package/dist/conformance/derive.js +136 -0
- package/dist/conformance/index.d.ts +22 -0
- package/dist/conformance/index.js +22 -0
- package/dist/conformance/run.d.ts +27 -0
- package/dist/conformance/run.js +424 -0
- package/dist/conformance/types.d.ts +288 -0
- package/dist/conformance/types.js +4 -0
- package/dist/conformance/warnings.d.ts +88 -0
- package/dist/conformance/warnings.js +144 -0
- package/dist/file-store.d.ts +7 -0
- package/dist/file-store.js +6 -2
- package/package.json +7 -5
- package/dist/api/wire.d.ts +0 -60
- package/dist/api/wire.js +0 -89
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,235 @@
|
|
|
6
6
|
> `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
|
|
7
7
|
> 包名是**历史记录**,如实保留不追改。
|
|
8
8
|
|
|
9
|
+
## 3.0.0 — 2026-09-16 — 告警坐标改铸**结构化段** `ConfigPath`(BREAKING)+ 删死出口 `./api/wire`(BREAKING)+ wire 透传判据修原型链漏洞 + 跨仓一致性门 kit(新 subpath `./conformance`)
|
|
10
|
+
|
|
11
|
+
> **版号裁定(发布方)**:本批三件里有两件是**纯 API 面**的破坏性改动 —— ①`EffectiveReadWarning` 的
|
|
12
|
+
> `keys`/`path` 与 `DroppedEntry.path` 从 `string` 改 `ConfigPath`、`isReservedExtensionKey` 第二参改形、
|
|
13
|
+
> `droppedKeys`/`carriedUnknownKeys` 返回值改形;②删已发布的 subpath `./api/wire`。照本档下方「发版纪律」
|
|
14
|
+
> 的「**改形(retype)/ 删除 = major**」判 **3.0.0**。**零别名、零双读、零过渡方法**:消费方的 tsc 红
|
|
15
|
+
> (或 `ERR_MODULE_NOT_FOUND`)就是通知。第三件(S-332)是行为面 bug 修复,随车发。
|
|
16
|
+
> 持久数据面**零影响**:本批不碰任何存储形,`config.d/*.json` 与 `/effective` 载荷一字未变。
|
|
17
|
+
|
|
18
|
+
**三问**:
|
|
19
|
+
- **谁需要** = ① 跨仓一致性门(conformance kit)要**比对**告警坐标,而比对一个有损编码 = 比对器自身二义;
|
|
20
|
+
② 照告警去改配置的运维(`models.1."a.b"` 与 `models.1.a.b` 今天分得清);③ 日后做「点一条告警跳到那一行」
|
|
21
|
+
的写侧,要的是段不是串。
|
|
22
|
+
- **谁受伤** = 读告警坐标的两个消费方各两行 tsc 红(见下方迁移句),以及从 `./api/wire` 直取常量的客户端
|
|
23
|
+
—— 四个消费仓对**现包名** `@sema-agent/settings-schema` 亲核**零 import**;唯一一处 `./api/wire` 取值在
|
|
24
|
+
sdk 的同源锚测试(`sema-sdk/packages/sdk/test/registry-auth.test.ts:28`),它走的是**退役包名**
|
|
25
|
+
`@sema-agent/registry-core`(devDep `^0.17.1`)的已发布冻结版 —— 旧包不可变,本版删出口**打不红它**。
|
|
26
|
+
所以 3.0.0 的实际受伤面是零,但 sdk 那行在它迁到现包名那一拍要一并改 `./api/auth`(名与值不变)。
|
|
27
|
+
- **什么补偿** = `formatConfigPath` 单铸出门形,消费方零复述;`./api/wire` 的每一个名字都在 `./api/auth` /
|
|
28
|
+
`./api/scopes` / 根 barrel 原名原值可取,迁移 = 改一行 import 路径。
|
|
29
|
+
|
|
30
|
+
### ① S-323c 坐标改铸结构化段(BREAKING)
|
|
31
|
+
|
|
32
|
+
**病(2.1.0 头注如实登记的残余)**:点号串是**有损编码**。键名本来就允许含 `.`(见
|
|
33
|
+
`isReservedExtensionKey` 的分段匹配注),于是 `models.1.k` 既编码 `models[1].k`,也编码一个**字面叫
|
|
34
|
+
`models.1.k` 的顶层键**。2.1.0 用两支文法(`PathGrammar`)的段数门挡住了裸 `field.N` 那一半,≥ 三段
|
|
35
|
+
那一半仍然二义 —— 上一版的 `rebasePath` 尾注原话:「那是编码本身的歧义……归下一个 major」。
|
|
36
|
+
|
|
37
|
+
**修法(以点改面,规则数变少 —— 这是判它是正确抽象的第一判据)**:
|
|
38
|
+
|
|
39
|
+
> 坐标 = `ConfigPath = readonly (string | number)[]`。**字符串段 = 对象键(逐字,含 `.` 也逐字);
|
|
40
|
+
> 数字段 = 数组下标(回写后 = 原文档下标)。**
|
|
41
|
+
|
|
42
|
+
- 新增导出 `ConfigPath`(型)与 `formatConfigPath(p): string`(**唯一**的出门 stringify 点):段间 `.`,
|
|
43
|
+
数字段十进制,字符串段**逐字写出去读回来只能是它自己**时才逐字,否则按 JSON 字符串字面量加引号 ——
|
|
44
|
+
空串、含 `.` / `"` / 控制字符的,以及文本恰好是某个数字段样子的(规范十进制:`models."1".k`,
|
|
45
|
+
见下方 codex 复审一条)。一条判据,不是一串特例。**刻意不提供 parse 反函数** —— 2.1.0 起没有任何一处
|
|
46
|
+
把坐标读回来(回写走 `keptIndex` 那本账),给它反函数就是给下一个人一条「在串上做事」的路。
|
|
47
|
+
- **四个铸点**全部改段数组下推,零串拼接:`collectDropped`(数组 `[...prefix, i]` / 对象 `[...prefix, k]`)、
|
|
48
|
+
`scanCarried`(层级表改段形登记 `[[], …] / [["infraCostRates"], …]`,表驱动不变)、`salvageEntries`
|
|
49
|
+
(数组条目 `[field, i]`、Record 条目 `[field, redactSecrets(key)]` —— 脱敏仍在**段**上做,键是用户写的、
|
|
50
|
+
可能就是一条粘错位置的凭据)、`legacy-governance-lifted`(`Object.keys(lifted).map((k) => [k])`)。
|
|
51
|
+
- **回写律从两支收成一条**:`p[0]` 是字符串且在位移表里 ∧ `p[1]` 是**数字段** ⇔ 它是数组路径。
|
|
52
|
+
**删除**:`type PathGrammar`、`rebasePath(s)` 的 `grammar` 入参、段数门、规范十进制正则,以及
|
|
53
|
+
`scanCarried` 里「顶层 vs 嵌套」那两条分支。恒等纪律不变 —— 没有任何一段真的变(含表长外)⇒ 返回
|
|
54
|
+
**原引用**,数组与告警对象都不复制。`rebaseWarningPaths` 的穷举 `switch` 形不变。
|
|
55
|
+
- `EXTENSION_NAMESPACES.at` 从**父路径正则**改**段模式**,并新增导出 `ANY_INDEX`(`unique symbol`
|
|
56
|
+
通配哨兵 = 任一数组下标)与 `ExtensionNamespaceRule`(登记行的型):
|
|
57
|
+
`models: [{ at: ["models", ANY_INDEX], key: /^sema[A-Z]/ }]`。匹配 = 长度相等 ∧ 逐段全等
|
|
58
|
+
(哨兵段要求该位是**数字**段,字符串段逐字相等)。闭合因此是**形本身**的性质(没有正则可以锚歪),
|
|
59
|
+
测试里那条「`at` 首尾锚定」的表门随之改成「每段是合法字面段或哨兵」+ 一条机器反证(把每个字面段
|
|
60
|
+
加长一截,命中即说明它在做子串匹配)。
|
|
61
|
+
**通配为什么是 symbol 而不是约定字符串**(如 `"#"`):文档键只可能是 `string | number`
|
|
62
|
+
(`ConfigPath` 的值域),所以哨兵不可能与任何文档键相等 —— 「通配」与「一个字面叫 `#` 的键」零二义,
|
|
63
|
+
字面 `"#"` 仍是可登记的普通段;类型上也不塌(`readonly (string | "#")[]` 会被 TS 收成
|
|
64
|
+
`readonly string[]`,写错通配不编译红,`readonly (string | typeof ANY_INDEX)[]` 不会)。
|
|
65
|
+
|
|
66
|
+
**红先**(`test/structured-path-3.0.0.test.ts`,13 格):第一轮 ①②③ 三格三红 —— ① 同一份文档里的字面
|
|
67
|
+
顶层键与数组路径读出 `['models.1.k','models.1.k']` 两条同串;② 段形入参在旧 `rebasePath` 里走
|
|
68
|
+
`Array.prototype.indexOf`(恒 -1)⇒ 真数组路径没被回写;③ `isReservedExtensionKey(…, ["models",0], …)`
|
|
69
|
+
= false。第二轮补 ④ / 等式门 / 变异格后 12 格 8 红(`formatConfigPath is not a function` ×4;变异靶点
|
|
70
|
+
命中数 0)。改铸后 13 格全绿。
|
|
71
|
+
|
|
72
|
+
**等价矩阵**:v2.1.0 六份告警测试里的坐标断言(机器计数 56 条)逐条平移成段形,并加**一格机器等式门**
|
|
73
|
+
—— 34 行「旧串 ↔ 新段」(旧串逐字抄自 `git show v2.1.0:test/<file>.test.ts`,不手改),判据:对**不含
|
|
74
|
+
`.` 的键**,`formatConfigPath(新段) === 旧串`。刻意变的那一半单列一格:字面含 `.` 的顶层键
|
|
75
|
+
(`["hosts.0"]` → `"hosts.0"`)与同名数组路径(`["hosts",0]` → `hosts.0`)出门即可分辨 —— 那正是本版要
|
|
76
|
+
修的病。**负控保留**:S-323b 那条「字面顶层键不许被位移表挪位」今天由**段形**(`p[1]` 缺席)守住,
|
|
77
|
+
而不是 2.1.0 的段数门。2.1.0 留下的 🚧 现状钉随缺陷修好而**翻向**(旧读数 `models.1.typo` → 原引用不动)。
|
|
78
|
+
**变异格**(机器可跑):esbuild 真打包 `config-fns` → 把 `typeof p[1] === "number"` 换成 `p.length >= 2`
|
|
79
|
+
(= 2.1.0「两支文法合成一支」的等价物)→ 真 import 变异模块 ⇒ 它把键段 `"1"` 当成下标挪成
|
|
80
|
+
`["models",2,"k"]`(`[0,2]["1"] === 2`),生产实现返回原引用。
|
|
81
|
+
|
|
82
|
+
**迁移句(按消费方点名)**:
|
|
83
|
+
- **worker 服务**(两行,亲核坐标 `src/config-center/read-warnings.ts:33/57/59/61`):`keyList(prefix,
|
|
84
|
+
keys: readonly string[], …)` 的第二参改收 `readonly ConfigPath[]`、内部 `keys.map(formatConfigPath)`;
|
|
85
|
+
`entry-dropped` 那条的 `${w.path}` → `formatConfigPath(w.path)`。`foldEffectiveReadWarning` 的穷举形不变。
|
|
86
|
+
- **管理面**(两行,亲核坐标 `src/lib/config/effective-warnings.ts:71/72/86/88/90`):`warningFacts` 的
|
|
87
|
+
`names(a: string[])` / `name(s: string)` 两个脱敏辅助 —— `keys` 三臂改
|
|
88
|
+
`w.keys.map((p) => formatConfigPath(p.map((s) => typeof s === "string" ? redactSecrets(s) : s)))`,
|
|
89
|
+
`entry-dropped` 的 `path` 同形。**wire 形 `WireEffectiveWarning.keys: string[]` 保持串形不变**(它是
|
|
90
|
+
管理面自己的 wire 契约,且已持久化进发布快照 —— 硬 breaking 三句里「持久数据不能翻红」那条例外),
|
|
91
|
+
面板零改。⚠️ **先逐段脱敏再 format**:段是用户写的单位,对拼好的串做脱敏会把段界当词界
|
|
92
|
+
(今天的 `name()` 收的是整串,直接套上去就是这个错)。
|
|
93
|
+
- **CLI / 客户端内核**:零读点(亲核),**零动作**。
|
|
94
|
+
|
|
95
|
+
### ② S-321 删死出口 `./api/wire`(BREAKING)
|
|
96
|
+
|
|
97
|
+
`./api/wire` 是 2026-07-27 为「零依赖客户端运行期直取常量」拆出的子路径;那条消费腿自始至终没有出现,
|
|
98
|
+
四个消费仓对**现包名**零 import(唯一取值点在 sdk 的同源锚测试,走**退役包名** `registry-core` 的冻结版,
|
|
99
|
+
见上方「谁受伤」)。删 `src/api/wire.ts`、删 exports 表那一项、删只为它而活的两格打包纯度门。
|
|
100
|
+
常量与纯函数回到契约原处:auth 半场(`AUTH_V1_PATHS` / `DEVICE_GRANT_TYPE` / 四个 TTL /
|
|
101
|
+
`OAUTH_ERROR_CODES` / `DEVICE_AUTH_STATUSES` / `normalizeUserCode` / `nextPollInterval`)回 `./api/auth`,
|
|
102
|
+
scopes 半场(`SCOPES_V1_PATHS` / `SCOPE_CLAIM`)回 `./api/scopes`。**导出的名与值一个没动**(auth/scopes
|
|
103
|
+
此前就在 re-export 它们),变的只是它们不再有第二条 import 路径。出口表 21 → 20 项。
|
|
104
|
+
|
|
105
|
+
**迁移句**:`from "@sema-agent/settings-schema/api/wire"` → `from "@sema-agent/settings-schema/api/auth"`
|
|
106
|
+
(scopes 两件改 `/api/scopes`),或直接走根 barrel;引用相同,零行为改动。**点名 sdk**:
|
|
107
|
+
`sema-sdk/packages/sdk/test/registry-auth.test.ts:28` 那行 `@sema-agent/registry-core/api/wire` 今天不红
|
|
108
|
+
(退役包名的冻结版还带着这个出口),它在 sdk 把 devDep 换到 `@sema-agent/settings-schema` 那一拍按本句改
|
|
109
|
+
`./api/auth` —— `OAUTH_ERROR_CODES` 名与值一个没动。**红先**由既有门给出,不新造
|
|
110
|
+
特判钉:删源文件后 `test/package-surface.test.ts` 的「每个 subpath 都有对应的 src 源文件」报
|
|
111
|
+
`expected [ './api/wire' ] to deeply equal []`,清干净后 `npm pack --dry-run` 产物里 `api/wire` 命中数 0。
|
|
112
|
+
|
|
113
|
+
`migrate.ts` **本版不删**:管理面有三处真 import,其中 hosts 那条是**活读面**而不是一次性迁移,所以该
|
|
114
|
+
模块头注「窗口已过」那句对它不成立;ROADMAP 条目已按此改真话,去留候消费方表态后另裁。
|
|
115
|
+
|
|
116
|
+
### ③ S-332 wire 透传判据修原型链漏洞(行为面 bug)
|
|
117
|
+
|
|
118
|
+
`readEffectiveWire` 判「这个顶层键是不是已知域」用的是 `k in built`,而 `in` 会一路问到 `Object.prototype`
|
|
119
|
+
—— 于是一份 JSON 载荷里合法出现的 `constructor` / `toString` / `hasOwnProperty` / `__proto__` 四个顶层键
|
|
120
|
+
被判成「已知域」而整条吞掉,open-world 的承诺(本包不认识的键**原样送达**)对它们恰好失效,而且无声。
|
|
121
|
+
修法两处,都是「键就是键」这一条律的落实、零特判:判据改 `Object.prototype.hasOwnProperty.call(built, k)`
|
|
122
|
+
(与同文件另两处自有键判据同律);累积 passthrough 从逐键 `passthrough[k] = v` 改 `Object.fromEntries(...)`
|
|
123
|
+
—— 前者对 `"__proto__"` 走的是**原型 setter**(改掉对象的原型,而且不产生自有键)。红先:改前四个键在
|
|
124
|
+
返回值上全部缺席;改后四个都是**自有键**、值逐字节相同,且返回对象的原型仍是 `Object.prototype`。
|
|
125
|
+
|
|
126
|
+
### ④ 跨仓一致性门 conformance kit(新 subpath `./conformance`,additive)
|
|
127
|
+
|
|
128
|
+
**病**:2.0.0 / 2.1.0 两版的正确性靠「表态 + 黑盒测试 + 各仓提货时各自红先」——三样都是**单仓视角**。
|
|
129
|
+
真正的跨仓分歧一直是被提货过程**碰巧**撞出来的,而碰巧不是门。写侧(管理面)判断哪条坏、整域退不退,
|
|
130
|
+
读侧(worker / CLI)逐条容错,此前没有任何一格把两侧放在同一份文档上对过;本版又恰好改铸了告警坐标,
|
|
131
|
+
是最容易让几方读法悄悄分叉的一版。
|
|
132
|
+
|
|
133
|
+
**修法**:契约仓自带**金样语料 + 比对器**,随包发(`files` 新增 `conformance`);每个消费方把**自己的
|
|
134
|
+
生产读腿**塞进来跑同一套语料。规范化(canonical JSON、告警投影、坐标结构比对)在 kit 内**单铸**,
|
|
135
|
+
消费方零复述 —— 一份被各自复述的规范化就是第二份真源,而两份真源的分歧正是本门要抓的病。
|
|
136
|
+
|
|
137
|
+
- **接线三步**:①造一个 `ConformanceAdapter`(`provenance` = 你**实际加载到**的那份契约包的
|
|
138
|
+
`{packageJsonPath, version, integrity}`;`legs` = 你自己的生产读腿,每条带 `entry{module,export}`);
|
|
139
|
+
②`await runConformance(adapter, { mode: "release" })`;③断言 `report.ok`,不绿就读每格的 `diff`
|
|
140
|
+
(effective 的 JSON patch、告警**多重集**差、元数据差,三面分开)。
|
|
141
|
+
- **两种模式**:`release`(版本三方对齐 + 每条腿指向真存在且不在契约包 `node_modules` 之下的生产入口 +
|
|
142
|
+
禁 `only` + 禁归一器 + **至少登记一条腿** + **登记的腿必须跑**)与 `historical`(对旧版包跑,只记行为
|
|
143
|
+
diff,可挂一只**自陈有损**的坐标归一器)。**未登记的腿不算违例** —— 它只逐格记 `skipped: no adapter`
|
|
144
|
+
(覆盖矩阵看得见它没跑):一个结构上就没有某条读腿的消费方(worker 服务的生产代码里没有 `buildEffective`
|
|
145
|
+
调用点)照样接得进这道门,而这正是 `docs/CONFORMANCE.md §1` 一直写着的口径 —— 建门批的实现与它打架,
|
|
146
|
+
以档为准。
|
|
147
|
+
- **已知分歧账本** `ConformanceAdapter.knownDivergences`(`KnownDivergence[]`):消费方对金样的**合法**
|
|
148
|
+
差异(`kind:"debt"` 临时欠账 / `kind:"declared"` 成文语义)登记成机器可核的一行(`leg` + 可选 `cases`
|
|
149
|
+
+ `pathPrefix` + `ref` + `flipWhen`)。命中的格记新状态 `diff-ledgered`(不阻塞,单独计数,报告的
|
|
150
|
+
`ledger` 按 `ref` 列出命中数);**只收 effective 的差** —— 告警差与元数据差永不可入账(它们是这道门的
|
|
151
|
+
承重面);**逐坐标**白名单而不是整格豁免;**棘轮只降不升** —— 账本里一条**从未命中**的登记本身就是违例
|
|
152
|
+
(`stale ledger entry`),`pathPrefix` 必须点名至少一个顶层键、`ref`/`flipWhen` 非空,三者都是违例。
|
|
153
|
+
契约仓自证**不挂账本**(金样的作者给自己开豁免 = 把门关了)。账本另有一条**结局形**臂
|
|
154
|
+
`{ kind:"debt", outcome:{leg,cases,expected,actual}, ref, flipWhen }`:收「契约期望 `rejected{stage}`、
|
|
155
|
+
消费方读成 `effective`(降级 + 诊断)」这类**没有 effective patch** 的差(坐标形按 `pathPrefix` 够不着它,
|
|
156
|
+
于是消费方 `ok` 恒 false,而它恰是门最该逼着修的一类)。两条硬约束:`cases` **必填且非空**(不许按前缀
|
|
157
|
+
大包一整条腿的拒绝面;坏形的一条登记谁都不命中,fail-closed)、**只能是 `debt`**(契约说拒、消费方说
|
|
158
|
+
不拒,不是「成文语义」盖得住的,写成 `declared` 是违例)。judge 对结局形不一致的四条判决改附**结构化**
|
|
159
|
+
`diff.outcome = { expected, actual, stage? }` —— 靠 `detail` 文案分辨结局形的差等于没有判据。
|
|
160
|
+
- **资产出口 `"./package.json"`**:exports 表一旦在场就挡住所有没登记的子路径,于是
|
|
161
|
+
`require.resolve("@sema-agent/settings-schema/package.json")`(§1 接线配方拿 provenance 的第一行)在
|
|
162
|
+
建门批实跑抛 `ERR_PACKAGE_PATH_NOT_EXPORTED` —— 配方自己跑不通。放行它,出口表 21 → 22;
|
|
163
|
+
`package-surface` 的三格门随之认识「资产出口」这第二种登记形(值是字符串 ⇒ 核的是包内那个文件真在盘上,
|
|
164
|
+
不走 `./dist/<模块>.js` 约定),判据仍是一条:**每个 subpath 指向包里一个真东西**。
|
|
165
|
+
- **语料贡献形**:真源是 `domains`(各域原始文档),`wire` / `local-root` 两腿的入参与期望由**登记在案的
|
|
166
|
+
五条表示变换**派生 —— 凡不能由表解释的差异一定显示成 `diff`,于是「有没有第六条变换没登记」不再靠人
|
|
167
|
+
回忆。加一条语料 = 写 `input.json` + `meta.json`(`claim` 写清它想打谁)+ `expected.json` 骨架,
|
|
168
|
+
再跑 `npm run conformance:bless` / `npm run conformance:historical` 填金样与 `firstRedOn`。
|
|
169
|
+
- **四律**(缺一不算门):对抗律(`claim` 非空、`firstRedOn` 只能真跑写回)、变异律(十个靶各一处变异
|
|
170
|
+
必红 —— 读路径八个铸点,外加打在 **kit 自己身上**的两个:比对器、派生用的内容寻址)、覆盖律(消费方 ×
|
|
171
|
+
腿 × 域 × 结局矩阵 + 三张闭集表逐员下限,新告警 kind 不表态即编译红)、来源律(release 核 provenance
|
|
172
|
+
与生产入口)。契约仓自己也当一个消费方跑全套,自证 `buildEffective` / `readEffectiveWire` /
|
|
173
|
+
`loadLocalConfig` 三腿同源(此前只钉 delegation,不钉读数)。
|
|
174
|
+
- 新增出口(`./conformance`):`runConformance` / `materializeLocalRoot` / `resolveLegExpectation` /
|
|
175
|
+
`createContractAdapter` / `loadCorpus` / 五条变换表 `DERIVATION_TRANSFORMS` / 规范化与投影原语
|
|
176
|
+
(`canonicalize` / `deepEqual` / `diffJson` / `projectWarning` / `diffWarningMultiset` / `findSecretLeaks`)
|
|
177
|
+
与全套型面。**Node-only**(语料在磁盘上,local-root 腿要落盘),不进主 barrel。
|
|
178
|
+
- 契约与口径:`docs/CONFORMANCE.md`(含**三条如实登记的边界**:消费方半场的 `firstRedOn` 测不到、
|
|
179
|
+
有损归一器会抹平真差异、来源律不能证明非同义反复)。
|
|
180
|
+
|
|
181
|
+
**本版自证 + 对抗复审抓到的五处真缺陷(都在 kit 内,逐条红先复现后修)**:
|
|
182
|
+
①规范化与派生两处在建对象时用逐键赋值,于是一个叫 `__proto__` 的顶层键在**期望侧与实际侧被同样抹掉**
|
|
183
|
+
—— 比对器对这一类全盲,而那正是同批 ③ 要修的那类病(改前:`canonicalize` 产物 `__proto__` 自有键缺席
|
|
184
|
+
且返回对象原型被污染;修法与 ③ 同一条律 `Object.fromEntries`,零特判)。
|
|
185
|
+
②来源律只核「`provenance.packageJsonPath` 是不是绝对路径」,一个指向不存在目录的伪造来源照样全绿;
|
|
186
|
+
入口甚至可以是 `package.json` 这种非模块文件。改成:那份 package.json 必须真在磁盘上、`name` 是本包、
|
|
187
|
+
`version` 与自报值相等;入口必须是模块文件,且解软链后不在契约包的 `node_modules` 之下。
|
|
188
|
+
③**双向抵消假绿**:wire 入参与 wire 期望都走同一只 `toManifestDoc`(唯一算新值的那条变换),把
|
|
189
|
+
`contentHash` 算错会两侧同样错,整套 wire 语料照样全绿。改成:该变换非恒等的 case,kit **fail-loud 拒绝
|
|
190
|
+
派生**、必须写显式金样(入库即冻结),并加第十个变异靶压着这只手。
|
|
191
|
+
④告警里的 `keys` / `droppedNames` 按序列比,消费方只要换个未知键扫描次序就会在读数完全相同的情况下把
|
|
192
|
+
发版门顶红(纯假红)。改成按**袋**比(重数仍保留;一条 `ConfigPath` 内部的段序仍是序列)—— 规则更齐,
|
|
193
|
+
不是更多。
|
|
194
|
+
⑤`remote-exec.json` 是 `config.d/` 里的**专用文件**(有自己的读取与校验路径),隐藏文件则被扫描忽略,
|
|
195
|
+
两者都不该报 `not-a-domain` —— 这是登记表漏掉的第六条变换(T6 文件名分类),补登记并从
|
|
196
|
+
`NON_DOMAIN_CONFIG_FILES`(本版起导出)派生,零手抄。
|
|
197
|
+
|
|
198
|
+
**发前补复审三条(09-19 补修,同属本节 ④ 的 kit;v2.1.0 无此码 ⇒ 都是本版新引入,不是历史欠账)**:
|
|
199
|
+
① **比对器读到了原型上的继承值**(`src/conformance/canonical.ts`):`diffJson` 的对象分支用裸下标取值,
|
|
200
|
+
`__proto__` / `constructor` / `toString` / `hasOwnProperty` 这四个名字在**缺席的那一侧**会读到
|
|
201
|
+
`Object.prototype`。`{"__proto__":{}}`(JSON.parse 得自有键)对 `{}` 于是既不 add 也不 remove、递归进
|
|
202
|
+
`diffJson({}, Object.prototype)` 又深相等 ⇒ **`deepEqual` 说不等而 `diffJson` 返回空数组**,而 judge 正是
|
|
203
|
+
按 `effectivePatch.length === 0` 判 pass —— **假绿**,掩掉的恰好是同批 ③(S-332)要防的那类丢键。
|
|
204
|
+
**红先读数**(`test/conformance-comparator.test.ts`,7 格):改前 3 红 —— `diffJson({"__proto__":{}}, {})`
|
|
205
|
+
`= []`;四个原型名键里 `__proto__` 两向空数组、另三个报成 `replace` 且 `actual` 里塞进宿主函数
|
|
206
|
+
(`{__proto__:{z:1}}` vs `{}` 报出 `/__proto__/z` 这条**不存在的坐标**);不变式格在 `__proto__` 两向红。
|
|
207
|
+
**修法(类修,规则变少)**:比对器里「键在不在 / 取键的值」收成唯一一处 `ownValue`(自有键 +
|
|
208
|
+
`undefined` 即不在场),`canonicalize` / `deepEqual` / `diffJson` 三处共用 —— 与 ③ 同一条「键就是键」的律,
|
|
209
|
+
零特判。另立**结构不变式**一格钉住承重面:`deepEqual(e,a) === false ⇒ diffJson(e,a).length > 0`
|
|
210
|
+
(对语料全集 × baseline + 相邻对 + 四个原型名键的 17 个标本两两全对做性质断言)。
|
|
211
|
+
② **语料落盘的文件名未校验**(`src/conformance/run.ts` `materializeLocalRoot`):`join(dir, name)` 直接落盘,
|
|
212
|
+
而 name 来自仓外贡献面(case 的 `localFiles` 键 / `deriveLocalInput` 从 **domains 顶层键**派生的
|
|
213
|
+
`<域名>.json`)—— 一个 `"../../x.json"` 写到临时根之外、覆盖宿主文件,`cleanup()` 还删不到它。
|
|
214
|
+
**红先读数**(`test/conformance-local-root.test.ts`,4 格):改前 3 红 —— `../../<名>.json` 不抛且
|
|
215
|
+
`os.tmpdir()/<名>.json` 真被写出来;九个坏形名字(`.` / `..` / 空串 / 子目录 / 反斜杠 / NUL / 绝对路径 /
|
|
216
|
+
`./x` / `../x`)全部不被拒(`.` 那格抛的是 node 的 `EISDIR`,不是判据);`deriveLocalInput({"../../x": …})`
|
|
217
|
+
派生出的文件名照样落盘。**修法(单铸点类修)**:落盘处一道 `assertBareFileName` 闸 —— 非空、不是 `.` /
|
|
218
|
+
`..`、无 NUL、无 `/` 与 `\`、`basename(name) === name`,并在写之前断言 `resolve(p)` 仍在 `dir` 之内
|
|
219
|
+
(违例清掉临时根再抛)。闸**先于**任何 fs 动作,于是坏名字连临时根都建不出来;错形沿用 kit 既有的
|
|
220
|
+
harness 错形(`conformance: …`,经适配器腿记成 `harness-error`),不新造错误族。
|
|
221
|
+
③ **账本 `pathPrefix` 没有段边界**(`ledgerIndexFor`):`patchPath.startsWith(prefix)` 让登记
|
|
222
|
+
`/limits/infraCostRates` 顺带豁免 `/limits/infraCostRatesInjected`、`/models/1` 顺带豁免 `/models/10` ——
|
|
223
|
+
账本是**逐坐标**白名单(棘轮),一条登记悄悄盖住没登记的相邻坐标就等于绕开它自己那条律。
|
|
224
|
+
**红先读数**(`test/conformance-legs-and-ledger.test.ts` ⑤,3 格):改前 2 红 —— 相邻键与下标 1/10 两格
|
|
225
|
+
都读到 `diff-ledgered = 1`、`diff = 0`、`ok = true`(假绿)。**修法**:`patchPath === prefix ||
|
|
226
|
+
patchPath.startsWith(prefix + "/")`(`prefix = ""` 表根,自然成立);负控两格钉住「段前缀本身与其子坐标
|
|
227
|
+
照常命中」。`docs/CONFORMANCE.md §9` 与 `PathDivergence.pathPrefix` 的表述同步改成「JSON Pointer 段前缀」。
|
|
228
|
+
|
|
229
|
+
### 门读数(09-19 补修后重跑,四门亲跑)
|
|
230
|
+
|
|
231
|
+
`npx tsc -p tsconfig.build.json --noEmit` 与 `npx tsc --noEmit` 各 **0 错**;`npm run build` 成功;
|
|
232
|
+
全量 `npx vitest run` **61 文件 895 格全绿**(补修前 59 文件 881 格,本批 +2 文件 +14 格);
|
|
233
|
+
`npm pack --dry-run` **226 文件**,产物里 `api/wire` 命中数 **0**、`conformance/cases/` 在列
|
|
234
|
+
**147 行 = 49 条语料 × 三文件**。
|
|
235
|
+
(注:`test/package-surface.test.ts` 有两格读 `dist/`,在**没跑过 build 的干净工作树**上会 ENOENT ——
|
|
236
|
+
门序就是 `prepublishOnly` 的 `build && test`,先 build 再全量。)
|
|
237
|
+
|
|
9
238
|
## 2.1.0 — 2026-09-15 — 告警点名**原文档的下标**:每个压缩点自带位移表,哪一层压缩哪一层回写
|
|
10
239
|
|
|
11
240
|
> **版号裁定(发布方)**:本批新增两个导出(`rebaseWarningPaths` / `EntryKeptIndex`)与两个接口新键
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
> **`@sema-agent/registry-core`(最后一版 `0.19.0`)**,更早还曾是 `@sema-ai/registry-core`。
|
|
5
5
|
> **这是一次纯改名,不加料**:`0.19.0` → `1.0.0` 之间**零语义变更**——没有字段增删、没有校验收紧
|
|
6
6
|
> (无 `.strict()` 化)、没有默认值改动、没有行为变化;`exports` 的 **21 个 subpath 一个不动**
|
|
7
|
-
> (`.` / `./types` / `./node` / `./api/auth`
|
|
7
|
+
> (`.` / `./types` / `./node` / `./api/auth` …… 逐条 1:1 平移,只换包名前缀)。
|
|
8
8
|
> 版号跳到 `1.0.0` **不是**「契约进入稳定期」的语义信号——改名需要一个不与旧 `0.x` 段混淆的新起点而已
|
|
9
9
|
> (但自 `1.0.0` 起本包按标准 semver 发版:破坏性 = major,见下文「发版纪律」)。
|
|
10
10
|
>
|
|
@@ -110,9 +110,17 @@ sound). `npm ls --prod` therefore shows only `zod`. Node built-ins only (`node:c
|
|
|
110
110
|
and any top-level key a domain schema strips are both NAMED through `onWarning`
|
|
111
111
|
(`unread-config-file` / `unknown-keys-dropped`) instead of vanishing silently. **2.0.0** adds per-ENTRY
|
|
112
112
|
tolerance on the same read path: one malformed catalog entry is dropped on its own (named through
|
|
113
|
-
`onWarning` as `entry-dropped
|
|
113
|
+
`onWarning` as `entry-dropped`) and its siblings survive, instead of the whole domain falling to
|
|
114
114
|
its schema default. It is the SAME `DOMAIN_READ_FALLBACK` table that decides where this applies — gate
|
|
115
|
-
domains keep failing loud, entry by entry included.
|
|
115
|
+
domains keep failing loud, entry by entry included. **3.0.0** re-casts every coordinate these warnings
|
|
116
|
+
carry (`entry-dropped.path`, `unknown-keys-*.keys`) from a dot-joined STRING to a structured
|
|
117
|
+
`ConfigPath = readonly (string | number)[]` — a string segment is an object key (verbatim, `.` included),
|
|
118
|
+
a number segment is an array index — because the string form was a LOSSY encoding: a key literally named
|
|
119
|
+
`models.1.k` and the unknown key `k` inside `models[1]` collapsed to the same string. `formatConfigPath`
|
|
120
|
+
is the ONE place that turns a path into text for a log or a UI: a string segment goes out verbatim only
|
|
121
|
+
when reading that text back can only yield the segment itself — an empty one, one holding `.` / `"` / a
|
|
122
|
+
control character, and one whose text is exactly what a number segment would print (`models."1".k`) all
|
|
123
|
+
come out quoted. There is deliberately no parse inverse.
|
|
116
124
|
- **Hooks contract** (`hooks.ts`, subpath `./hooks`): the CC-parity hook surface — `HOOK_EVENTS` (33 events:
|
|
117
125
|
the CC 2.1.198 set of 27 plus `CwdChanged` / `FileChanged` / `MessageDisplay` / `DirectoryAdded` and, from
|
|
118
126
|
2.0.0, the model-switch pair `PreModelSwitch` / `PostModelSwitch`), the single-owner map
|
|
@@ -137,6 +145,29 @@ sound). `npm ls --prod` therefore shows only `zod`. Node built-ins only (`node:c
|
|
|
137
145
|
`models`). They are still stripped, but they are NOT reported as unknown keys — intent is declared at the
|
|
138
146
|
registration site, so every remaining unknown key is a typo, with no per-consumer special-casing.
|
|
139
147
|
|
|
148
|
+
## Cross-repo conformance gate (`./conformance`, 3.0.0)
|
|
149
|
+
|
|
150
|
+
契约仓自带**金样语料 + 比对器**,随包发(`conformance/cases/**`)。每个消费方把**自己的生产读腿**塞给
|
|
151
|
+
kit 跑一遍 ⇒ 同一份 settings 语料在配置中心、worker、管理面、契约仓自身读出的 effective 逐字节一致、
|
|
152
|
+
告警多重集一致。
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { runConformance } from "@sema-agent/settings-schema/conformance";
|
|
156
|
+
const report = await runConformance(myAdapter, { mode: "release" });
|
|
157
|
+
if (!report.ok) throw new Error(report.violations.join("\n"));
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
- **适配器**带 `provenance`(你**实际加载到**的那份契约包)与每条腿的 `entry{module,export}`
|
|
161
|
+
(**生产代码**的入口 —— 在测试里把契约包函数本身当读腿,门证明的只是「包等于包」)。
|
|
162
|
+
- **两种模式**:`release`(版本三方对齐 + 生产入口核验 + 禁 `only`/归一器 + 至少登记一条腿 + **登记的腿
|
|
163
|
+
必须跑**;未登记的腿只记 `skipped: no adapter`,不算违例)与 `historical`(对旧版包跑,只记行为 diff)。
|
|
164
|
+
- **四律**:对抗律 / 变异律 / 覆盖律 / 来源律 —— 缺一不算「门」。
|
|
165
|
+
- **已知分歧账本** `knownDivergences`:消费方对金样的**合法**差异(临时欠账 / 成文语义)登记成机器可核的
|
|
166
|
+
一行,命中记 `diff-ledgered` 不阻塞;**告警差与元数据差永不可入账**,而**从未命中的一条登记本身就是
|
|
167
|
+
违例**(棘轮只降不升,逼着到期翻转)。契约仓自证不许挂账本。
|
|
168
|
+
- 契约形、报告形、语料贡献形、以及**三条如实登记的边界**见 `docs/CONFORMANCE.md`。
|
|
169
|
+
- Node-only(语料在磁盘上,local-root 腿要落盘),不进主 barrel。
|
|
170
|
+
|
|
140
171
|
## Secret boundary
|
|
141
172
|
|
|
142
173
|
Every secret field is an **env-NAME**, never a value. The `ENV_NAME` regex (`/^[A-Z_][A-Z0-9_]*$/`) rejects a
|
|
@@ -157,7 +188,7 @@ local `.env`). This package never carries a credential.
|
|
|
157
188
|
Fleet-only domains (`workers`, `hosts`, `systems`) are omitted on a single machine — they resolve to schema
|
|
158
189
|
defaults. Each `config.d/<domain>.json` is exactly that domain's zod object.
|
|
159
190
|
|
|
160
|
-
## 发版纪律(semver,1.x)
|
|
191
|
+
## 发版纪律(semver,1.x 起)
|
|
161
192
|
|
|
162
193
|
自 `1.0.0`(改名)起本包按**标准 semver** 发版;`0.x` 时代的「破坏性变更必 bump minor」规矩**已撤**
|
|
163
194
|
(末条仅作历史注记)。判档看**消费方可见性**,不看 diff 大小:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0.0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"collab": {
|
|
3
|
+
"templates": []
|
|
4
|
+
},
|
|
5
|
+
"entitlement": {
|
|
6
|
+
"budgetGroups": [],
|
|
7
|
+
"groupBindings": [],
|
|
8
|
+
"subjects": [],
|
|
9
|
+
"tiers": []
|
|
10
|
+
},
|
|
11
|
+
"execution": {
|
|
12
|
+
"allowedLanes": [
|
|
13
|
+
"host"
|
|
14
|
+
],
|
|
15
|
+
"required": false
|
|
16
|
+
},
|
|
17
|
+
"governance": {},
|
|
18
|
+
"hosts": {
|
|
19
|
+
"hosts": []
|
|
20
|
+
},
|
|
21
|
+
"limits": {},
|
|
22
|
+
"mcp": {
|
|
23
|
+
"servers": []
|
|
24
|
+
},
|
|
25
|
+
"models": {
|
|
26
|
+
"models": [],
|
|
27
|
+
"roles": {},
|
|
28
|
+
"tierGroups": []
|
|
29
|
+
},
|
|
30
|
+
"plugins": {
|
|
31
|
+
"plugins": []
|
|
32
|
+
},
|
|
33
|
+
"projects": {
|
|
34
|
+
"projects": {}
|
|
35
|
+
},
|
|
36
|
+
"prompts": {
|
|
37
|
+
"bindings": []
|
|
38
|
+
},
|
|
39
|
+
"rosters": {
|
|
40
|
+
"rosters": []
|
|
41
|
+
},
|
|
42
|
+
"runtime": {},
|
|
43
|
+
"scenarios": {
|
|
44
|
+
"scenarios": []
|
|
45
|
+
},
|
|
46
|
+
"skills": {
|
|
47
|
+
"skills": []
|
|
48
|
+
},
|
|
49
|
+
"systems": {
|
|
50
|
+
"systems": []
|
|
51
|
+
},
|
|
52
|
+
"workers": {
|
|
53
|
+
"workers": []
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "effective",
|
|
4
|
+
"effective": {
|
|
5
|
+
"collab": {
|
|
6
|
+
"templates": []
|
|
7
|
+
},
|
|
8
|
+
"entitlement": {
|
|
9
|
+
"budgetGroups": [],
|
|
10
|
+
"groupBindings": [],
|
|
11
|
+
"subjects": [],
|
|
12
|
+
"tiers": []
|
|
13
|
+
},
|
|
14
|
+
"execution": {
|
|
15
|
+
"allowedLanes": [
|
|
16
|
+
"host"
|
|
17
|
+
],
|
|
18
|
+
"required": false
|
|
19
|
+
},
|
|
20
|
+
"governance": {},
|
|
21
|
+
"hosts": {
|
|
22
|
+
"hosts": []
|
|
23
|
+
},
|
|
24
|
+
"limits": {},
|
|
25
|
+
"mcp": {
|
|
26
|
+
"servers": []
|
|
27
|
+
},
|
|
28
|
+
"models": {
|
|
29
|
+
"models": [
|
|
30
|
+
{
|
|
31
|
+
"api": "openai-completions",
|
|
32
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"id": "good-id",
|
|
35
|
+
"name": "good",
|
|
36
|
+
"provider": "openai",
|
|
37
|
+
"quotaWeight": 1,
|
|
38
|
+
"reasoning": false,
|
|
39
|
+
"tier": "standard",
|
|
40
|
+
"vision": false
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"roles": {},
|
|
44
|
+
"tierGroups": []
|
|
45
|
+
},
|
|
46
|
+
"plugins": {
|
|
47
|
+
"plugins": []
|
|
48
|
+
},
|
|
49
|
+
"projects": {
|
|
50
|
+
"projects": {}
|
|
51
|
+
},
|
|
52
|
+
"prompts": {
|
|
53
|
+
"bindings": []
|
|
54
|
+
},
|
|
55
|
+
"rosters": {
|
|
56
|
+
"rosters": []
|
|
57
|
+
},
|
|
58
|
+
"runtime": {},
|
|
59
|
+
"scenarios": {
|
|
60
|
+
"scenarios": []
|
|
61
|
+
},
|
|
62
|
+
"skills": {
|
|
63
|
+
"skills": []
|
|
64
|
+
},
|
|
65
|
+
"systems": {
|
|
66
|
+
"systems": []
|
|
67
|
+
},
|
|
68
|
+
"workers": {
|
|
69
|
+
"workers": []
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"warnings": [
|
|
73
|
+
{
|
|
74
|
+
"domain": "models",
|
|
75
|
+
"kind": "entry-dropped",
|
|
76
|
+
"path": [
|
|
77
|
+
"models",
|
|
78
|
+
0
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"domain": "models",
|
|
83
|
+
"keys": [
|
|
84
|
+
[
|
|
85
|
+
"models",
|
|
86
|
+
1,
|
|
87
|
+
"typo"
|
|
88
|
+
]
|
|
89
|
+
],
|
|
90
|
+
"kind": "unknown-keys-dropped"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"metadata": {
|
|
94
|
+
"version": 7,
|
|
95
|
+
"updatedAt": "2026-09-16T00:00:00.000Z"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"wire": {
|
|
99
|
+
"derive": true
|
|
100
|
+
},
|
|
101
|
+
"localRoot": {
|
|
102
|
+
"derive": true,
|
|
103
|
+
"localVersion": 654437760217277
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 7,
|
|
4
|
+
"updatedAt": "2026-09-16T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"models": {
|
|
8
|
+
"models": [
|
|
9
|
+
{
|
|
10
|
+
"name": "broken-no-provider"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "good",
|
|
14
|
+
"provider": "openai",
|
|
15
|
+
"id": "good-id",
|
|
16
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
17
|
+
"typo": 1
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "抢救剔掉坏条目后,后续的剥键扫描报的是**压缩后**的下标 —— 谁不回写,谁就让运维照着告警去改原文档的另一条(S-323 消费方真案)。三腿必须同样报**原文档**坐标 ['models',1,'typo'],而不是 ['models',0,'typo']。",
|
|
4
|
+
"firstRedOn": [
|
|
5
|
+
"settings-schema@1.0.0",
|
|
6
|
+
"settings-schema@1.10.0",
|
|
7
|
+
"settings-schema@1.5.0",
|
|
8
|
+
"settings-schema@2.0.0"
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"domains": {
|
|
3
|
+
"outcome": "effective",
|
|
4
|
+
"effective": {
|
|
5
|
+
"collab": {
|
|
6
|
+
"templates": []
|
|
7
|
+
},
|
|
8
|
+
"entitlement": {
|
|
9
|
+
"budgetGroups": [],
|
|
10
|
+
"groupBindings": [],
|
|
11
|
+
"subjects": [],
|
|
12
|
+
"tiers": []
|
|
13
|
+
},
|
|
14
|
+
"execution": {
|
|
15
|
+
"allowedLanes": [
|
|
16
|
+
"host"
|
|
17
|
+
],
|
|
18
|
+
"required": false
|
|
19
|
+
},
|
|
20
|
+
"governance": {},
|
|
21
|
+
"hosts": {
|
|
22
|
+
"hosts": [
|
|
23
|
+
{
|
|
24
|
+
"approved": false,
|
|
25
|
+
"drain": false,
|
|
26
|
+
"enabled": true,
|
|
27
|
+
"labels": [],
|
|
28
|
+
"name": "keep-me"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"limits": {},
|
|
33
|
+
"mcp": {
|
|
34
|
+
"servers": []
|
|
35
|
+
},
|
|
36
|
+
"models": {
|
|
37
|
+
"models": [],
|
|
38
|
+
"roles": {},
|
|
39
|
+
"tierGroups": []
|
|
40
|
+
},
|
|
41
|
+
"plugins": {
|
|
42
|
+
"plugins": []
|
|
43
|
+
},
|
|
44
|
+
"projects": {
|
|
45
|
+
"projects": {}
|
|
46
|
+
},
|
|
47
|
+
"prompts": {
|
|
48
|
+
"bindings": []
|
|
49
|
+
},
|
|
50
|
+
"rosters": {
|
|
51
|
+
"rosters": []
|
|
52
|
+
},
|
|
53
|
+
"runtime": {},
|
|
54
|
+
"scenarios": {
|
|
55
|
+
"scenarios": []
|
|
56
|
+
},
|
|
57
|
+
"skills": {
|
|
58
|
+
"skills": []
|
|
59
|
+
},
|
|
60
|
+
"systems": {
|
|
61
|
+
"systems": []
|
|
62
|
+
},
|
|
63
|
+
"workers": {
|
|
64
|
+
"workers": []
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"warnings": [
|
|
68
|
+
{
|
|
69
|
+
"domain": "hosts",
|
|
70
|
+
"droppedNames": [
|
|
71
|
+
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx…"
|
|
72
|
+
],
|
|
73
|
+
"kind": "hosts-grandfathered"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"domain": "hosts",
|
|
77
|
+
"kind": "entry-dropped",
|
|
78
|
+
"path": [
|
|
79
|
+
"hosts",
|
|
80
|
+
2
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"metadata": {
|
|
85
|
+
"version": 7,
|
|
86
|
+
"updatedAt": "2026-09-16T00:00:00.000Z"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"wire": {
|
|
90
|
+
"derive": true
|
|
91
|
+
},
|
|
92
|
+
"localRoot": {
|
|
93
|
+
"derive": true,
|
|
94
|
+
"localVersion": 2617555914511015
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 7,
|
|
4
|
+
"updatedAt": "2026-09-16T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"hosts": {
|
|
8
|
+
"hosts": [
|
|
9
|
+
{
|
|
10
|
+
"name": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "keep-me"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "UPPER-BAD"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "读路径上有两个压缩点(hosts 的按名夹紧 + 逐条抢救)。两层叠加时,内层铸的 entry-dropped 坐标要过外层的位移表一次才是原文档坐标(S-323b)。少回写一层,告警就指向第三条别人的记录。",
|
|
4
|
+
"firstRedOn": [
|
|
5
|
+
"settings-schema@1.0.0",
|
|
6
|
+
"settings-schema@1.10.0",
|
|
7
|
+
"settings-schema@1.5.0",
|
|
8
|
+
"settings-schema@2.0.0"
|
|
9
|
+
]
|
|
10
|
+
}
|