@sema-agent/settings-schema 6.3.0 → 7.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 +207 -0
- package/README.md +40 -5
- package/bin/settings-schema.mjs +22 -0
- package/conformance/VERSION +1 -1
- package/conformance/cases/c48-s935-model-headers-transported/expected.json +115 -0
- package/conformance/cases/c48-s935-model-headers-transported/input.json +37 -0
- package/conformance/cases/c48-s935-model-headers-transported/meta.json +6 -0
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +98 -0
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/input.json +28 -0
- package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/meta.json +9 -0
- package/conformance/cases/c50-s784-lane-host-legal/expected.json +102 -0
- package/conformance/cases/c50-s784-lane-host-legal/input.json +29 -0
- package/conformance/cases/c50-s784-lane-host-legal/meta.json +5 -0
- package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +104 -0
- package/conformance/cases/c51-s784-lane-e2b-legal/input.json +32 -0
- package/conformance/cases/c51-s784-lane-e2b-legal/meta.json +5 -0
- package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +106 -0
- package/conformance/cases/c52-s784-lane-k8s-legal/input.json +34 -0
- package/conformance/cases/c52-s784-lane-k8s-legal/meta.json +5 -0
- package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +106 -0
- package/conformance/cases/c53-s784-lane-ssh-legal/input.json +34 -0
- package/conformance/cases/c53-s784-lane-ssh-legal/meta.json +5 -0
- package/conformance/cases/c54-s784-lane-adb-legal/expected.json +102 -0
- package/conformance/cases/c54-s784-lane-adb-legal/input.json +29 -0
- package/conformance/cases/c54-s784-lane-adb-legal/meta.json +5 -0
- package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +103 -0
- package/conformance/cases/c55-s784-lane-local-docker-legal/input.json +30 -0
- package/conformance/cases/c55-s784-lane-local-docker-legal/meta.json +5 -0
- package/conformance/cases/c56-s784-lane-device-legal/expected.json +109 -0
- package/conformance/cases/c56-s784-lane-device-legal/input.json +36 -0
- package/conformance/cases/c56-s784-lane-device-legal/meta.json +5 -0
- package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +83 -0
- package/conformance/cases/c57-s784-g1-enabled-no-lane/input.json +23 -0
- package/conformance/cases/c57-s784-g1-enabled-no-lane/meta.json +5 -0
- package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +83 -0
- package/conformance/cases/c58-s784-g2-multitenant-host/input.json +34 -0
- package/conformance/cases/c58-s784-g2-multitenant-host/meta.json +5 -0
- package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +83 -0
- package/conformance/cases/c59-s784-g3-k8s-missing-image/input.json +26 -0
- package/conformance/cases/c59-s784-g3-k8s-missing-image/meta.json +5 -0
- package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +83 -0
- package/conformance/cases/c60-s784-g3-e2b-missing-key/input.json +26 -0
- package/conformance/cases/c60-s784-g3-e2b-missing-key/meta.json +5 -0
- package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +83 -0
- package/conformance/cases/c61-s784-g3-other-lane-key/input.json +30 -0
- package/conformance/cases/c61-s784-g3-other-lane-key/meta.json +5 -0
- package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +83 -0
- package/conformance/cases/c62-s784-g7a-session-tidb/input.json +27 -0
- package/conformance/cases/c62-s784-g7a-session-tidb/meta.json +5 -0
- package/conformance/cases/c63-s784-host-two-replicas/expected.json +83 -0
- package/conformance/cases/c63-s784-host-two-replicas/input.json +27 -0
- package/conformance/cases/c63-s784-host-two-replicas/meta.json +5 -0
- package/conformance/cases/c64-s784-multitenant-local-store/expected.json +83 -0
- package/conformance/cases/c64-s784-multitenant-local-store/input.json +30 -0
- package/conformance/cases/c64-s784-multitenant-local-store/meta.json +5 -0
- package/conformance/cases/c65-s784-pg-without-db/expected.json +83 -0
- package/conformance/cases/c65-s784-pg-without-db/input.json +27 -0
- package/conformance/cases/c65-s784-pg-without-db/meta.json +5 -0
- package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +83 -0
- package/conformance/cases/c66-s784-memory-backend-mismatch/input.json +36 -0
- package/conformance/cases/c66-s784-memory-backend-mismatch/meta.json +5 -0
- package/conformance/cases/c67-s784-retired-field-loud/expected.json +83 -0
- package/conformance/cases/c67-s784-retired-field-loud/input.json +22 -0
- package/conformance/cases/c67-s784-retired-field-loud/meta.json +5 -0
- package/conformance/cases/c68-s784-device-local-store/expected.json +83 -0
- package/conformance/cases/c68-s784-device-local-store/input.json +26 -0
- package/conformance/cases/c68-s784-device-local-store/meta.json +5 -0
- package/conformance/cases/cli04-env-value-with-newline/expected.json +13 -2
- package/conformance/cases/cli04-env-value-with-newline/input.json +8 -1
- package/conformance/cases/cli04-env-value-with-newline/meta.json +1 -1
- package/conformance/migrate-workers/m01-g5-k8s-env-lifted/expected.json +49 -0
- package/conformance/migrate-workers/m01-g5-k8s-env-lifted/input.json +26 -0
- package/conformance/migrate-workers/m01-g5-k8s-env-lifted/meta.json +4 -0
- package/conformance/migrate-workers/m02-g5-idempotent/expected.json +38 -0
- package/conformance/migrate-workers/m02-g5-idempotent/input.json +33 -0
- package/conformance/migrate-workers/m02-g5-idempotent/meta.json +5 -0
- package/conformance/migrate-workers/m03-g5-refused-no-lane/expected.json +71 -0
- package/conformance/migrate-workers/m03-g5-refused-no-lane/input.json +42 -0
- package/conformance/migrate-workers/m03-g5-refused-no-lane/meta.json +4 -0
- package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/expected.json +52 -0
- package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/input.json +30 -0
- package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/meta.json +4 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +70 -0
- package/dist/execution-lane-index.d.ts +19 -0
- package/dist/execution-lane-index.js +23 -0
- package/dist/execution-lanes.d.ts +64 -0
- package/dist/execution-lanes.js +152 -0
- package/dist/file-edit.js +26 -21
- package/dist/hash.d.ts +3 -3
- package/dist/hash.js +3 -3
- package/dist/hooks.d.ts +12 -12
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/migrate-workers.d.ts +63 -0
- package/dist/migrate-workers.js +331 -0
- package/dist/remote-exec.d.ts +23 -64
- package/dist/remote-exec.js +20 -71
- package/dist/secret-refs.d.ts +7 -1
- package/dist/secret-refs.js +9 -3
- package/dist/types.d.ts +1382 -430
- package/dist/types.js +298 -76
- package/package.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,213 @@
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 7.0.0 — 2026-10-03 — M-R2 WorkerSpec 结构块:执行车道 `runtime.execution` + 存储 `runtime.store`,词表单正本 `EXECUTION_LANES` 等六个导出,一次性迁移 `migrateWorkersDomain`(BREAKING)
|
|
12
|
+
|
|
13
|
+
> **判档 = major**(README「发版纪律」:删除字段、校验收紧、保留键表加词让存量行读到即拒,都是破坏性)。设计稿 = server design/327 v1.1
|
|
14
|
+
> (板上写的「6.4.0」是版本标签,不是范围;6.4.0 已另发 `headers`)。台账 S-784;web-admin WA-49 / WA-50 的契约半场。
|
|
15
|
+
|
|
16
|
+
### 病(6.4.0 及更早)
|
|
17
|
+
|
|
18
|
+
- **车道没有结构位**:编排器只能靠 `worker.env.REMOTE_EXEC`。漏写 ⇒ 执行体落进程内 stub ⇒ 手带工具一件不挂 ⇒ 任务照回 `completed`(WA-49)。
|
|
19
|
+
- **店的三处词表不齐**:`sessionBackend` 收 `tidb`(引擎见之拒启)、缺省 `auto` 且只有 MySQL 族坐标 `coords.tidb*`(PG 部署无坐标可写);
|
|
20
|
+
`memoryBackend` 渲成引擎从不读的死名 `MEMORY_BACKEND`(记忆持久面根本声明不了);`DB_BACKEND` 无位,引擎靠 SQL 信号猜(WA-50)。
|
|
21
|
+
- **词表四处手抄**:车道词(引擎能力表 / 部署面车道清单 / 中心表单 / 本包 `RemoteExecSpec`,后者还多一个引擎零读点的 `remote-docker`)、
|
|
22
|
+
存储词、租户分离位 —— 任何一处改了别处不红。`RESERVED_WORKER_ENV` 与它的「归属字段」映射是两张要人记得同步的表。
|
|
23
|
+
|
|
24
|
+
### 修(规则变少:一张表,三处读)
|
|
25
|
+
|
|
26
|
+
- **新导出(`src/execution-lanes.ts`,主桶,纯数据)**:`EXECUTION_LANE_WORDS` / `ExecutionLane`(`host | e2b | k8s | ssh | adb | local-docker | device`,
|
|
27
|
+
= 引擎 `REMOTE_EXEC` 收的词逐字同序;**不含** `in-process` 与 `remote-docker`)、`EXECUTION_LANES`(每行 `lane / tenantSeparation / requiredEnv /
|
|
28
|
+
requiredSecretEnv / optionalEnv / optionalSecretEnv`,深冻结)、`TENANT_SEPARATION_WORDS`、`STORE_BACKENDS` / `SESSION_BACKENDS` /
|
|
29
|
+
`MEMORY_ENGINE_BACKENDS`(各带同名单数类型)。行内容逐格抄自 server 7.112.0 树,坐标写在每行 JSDoc(必需键 = `REQUIRED_ENVS_BY_LANE`;
|
|
30
|
+
`tenantSeparation` = 能力表那一位;可选键 = `REMOTE_EXEC` 三元链该车道那一臂读的名,别的域也读的 `MINIO_*` 不收;按引擎目录值类型
|
|
31
|
+
`secret` / `opaque` 分进密钥栏)。
|
|
32
|
+
- **与稿的一处差异(主会话裁定 1:采)**:表行多一栏 `optionalSecretEnv`。稿的五栏里没有「可选的密钥」,而 k8s 的 `K8S_TOKEN` / `K8S_CA_CERT_B64`、
|
|
33
|
+
e2b 的 `E2B_SANDBOX_ENV`、local-docker 的 `DOCKER_SANDBOX_ENV` 正是这一类 —— 没有这一栏,它们要么写不进结构块(k8s 显式令牌部署声明不了),
|
|
34
|
+
要么留在 `secretEnv` 逃生口(车道配置两把尺)。
|
|
35
|
+
- **`WorkerSpec.runtime.execution`**(可选;enabled 的 worker 必填):`lane` + `coords`(非密坐标,字面值)+ `secretRefs`(密钥,宿主 env-NAME)。
|
|
36
|
+
键 ⊆ 表[lane] 的对应栏;必需键在场且非空串(引擎把空串读作未设);别车道的键拒并点名它属于哪条车道;密钥写进 coords / 坐标写进 secretRefs
|
|
37
|
+
拒并指路另一栏;坐标值过与 `env` 同一条密钥形判据。
|
|
38
|
+
- **`WorkerSpec.runtime.store`**(可选;enabled 的 worker 必填):`backend`(必填,`STORE_BACKENDS`)/ `session`(缺省 `auto`)/
|
|
39
|
+
`memory {engine on|off 缺省 on, backend 缺省 file}` / `db {host, port, user, database}`(可选)+ `secretRefs.dbPasswordEnv`。
|
|
40
|
+
- **跨字段判据(WorkerSpec 层,每条一个 zod issue,`path` 指到要改的字段,拒因带出路)**:
|
|
41
|
+
① enabled 无 `runtime.execution` ⇒ 拒(`runtime.execution.lane`,列全部车道词;没有「无手」词)/ 无 `runtime.store` ⇒ 拒(`runtime.store.backend`);
|
|
42
|
+
② `requirePrincipal` ∧ 车道 `tenantSeparation === "single-user-only"` ⇒ 拒,出路 = 表里 `supported` 的车道**现算**(`e2b / k8s / local-docker / device`);
|
|
43
|
+
③ `host` 车道 ∧ 最多副本数 > 1 ⇒ 拒 —— 副本数有两个旋钮,`replicas` 与 `autoscaling.maxReplicas` 同一条规则(稿只写了 `replicas`,补全这一类);
|
|
44
|
+
④ SQL 坐标(`runtime.store.db` + `secretRefs.dbPasswordEnv`)在场 ⇔ `store.backend` ∈ {mysql, pg}(稿的①②两条是同一条规则的两面);
|
|
45
|
+
⑤ `store.memory.backend` pg ⇒ 店 pg,tidb ⇒ 店 mysql;⑥ `requirePrincipal` ⇒ 店 ∈ {mysql, pg};
|
|
46
|
+
⑦ `device` 车道 ⇒ 店 ∈ {mysql, pg} 且 `session` ≠ memory(= 引擎 `device-durable-store`:设备注册簿 / 绑定 / 审计都在 SQL 里,`SESSION_BACKEND=memory`
|
|
47
|
+
一块坐标都不铸;稿没列这一条,gpt-6 腿 F2 逮到「写闸放行、引擎拒启」,与 ② 同族补上)。同族的 `device-durable-approval` 读 `DURABLE_APPROVAL`
|
|
48
|
+
(逃生口里的 env + 姿态缺省),不在结构字段上,写闸判不了 —— 只在起服拒(如实登记);
|
|
49
|
+
⑧ `store.backend` memory ∧ `session` mysql ⇒ 拒(引擎 `plugins/session-store.ts:17`:durable 会话店要一只店,memory 后端一只都不建);
|
|
50
|
+
⑨ 记忆引擎开 ∧ `memory.backend` ∈ {pg, tidb} ∧ `session` memory ⇒ 拒(引擎 `boot/stores.ts:232 / :300`:记忆面绑 SQL 池,session memory 时池不开)。
|
|
51
|
+
⑧⑨ 是主会话裁定的核项:逐个读引擎(server 79de35f8)起服对 session × backend 各组合的处置,**起服拒的写闸同拒,起服放的不加** ——
|
|
52
|
+
local + session mysql(LocalBackend 自带会话店)、SQL + session memory(声明不用坐标、跑内存)、memory + auto / memory 都放。
|
|
53
|
+
同样读出、但**写闸判不了**的一条:SQL 店还要对象存储(`MINIO_*` 三键,或 `SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true`)否则起服拒
|
|
54
|
+
(`plugins/store-backend.ts:476`)—— 那几个键在 `env` / `secretEnv` 逃生口里,不在结构字段上,只在起服拒(如实登记)。
|
|
55
|
+
写闸 = `WorkerSpec.safeParse` / `DOMAIN_SCHEMAS.workers.safeParse`;**不另导出拒因函数**(schema 是唯一判据)。
|
|
56
|
+
- **`RESERVED_WORKER_ENV`**:改由「保留名 → 唯一写位」一张表派生(以前是两张手写表)。**加** `REMOTE_EXEC` / `REQUIRE_EXECUTION_LANE` /
|
|
57
|
+
`DB_BACKEND` / `MEMORY_ENGINE` / `MEMORY_ENGINE_BACKEND` 与车道表里全部名(拒因指到 `runtime.execution.coords.K8S_SANDBOX_IMAGE` 这种形)——
|
|
58
|
+
反转 0.1.30「执行基座键不保留」:当年没有结构位,如今有了,逃生口再留就是两把尺。**删** `MEMORY_BACKEND`(死名)与 `TIDB_*` 族(结构字段不再产出它们;
|
|
59
|
+
引擎的墓碑表见之拒启)。`MYSQL_*` / `PG_*` 归 `runtime.store.db.*` 与 `secretRefs.dbPasswordEnv`。`MINIO_*` / `LOG_LEVEL` / `REMOTE_EXEC_HOME_DIR` 照旧不保留。
|
|
60
|
+
- **删除项读到即响亮拒**(不被 zod 静默剥成「什么都没声明」):`runtime.sessionBackend` / `runtime.memoryBackend` / `runtime.db` /
|
|
61
|
+
`coords.tidbHost|tidbPort|tidbUser` / `secretRefs.tidbPasswordEnv` 在场 ⇒ 每个一条 issue,拒因指路迁移命令(停用的 worker 也拒)。迁移窗口代码。
|
|
62
|
+
- **一次性迁移 `migrateWorkersDomain(doc) → { doc, changed, dropped, refused }`**(主桶;纯函数、幂等;读前抬升 —— 对**原始** workers 文档在
|
|
63
|
+
`parseDomain` 之前跑)。每个旧键恰好一种去处:搬进结构块 / 引擎本就不读 ⇒ `dropped`(通知)/ 表达不了 ⇒ `refused`(该 worker 不进 `doc`,
|
|
64
|
+
`field` 点名要人改的那一格,`original` = 输入里那一行逐字 —— **写回 `doc` 之前必须把 `refused[].original` 按 `index` 放回或另存**,
|
|
65
|
+
否则运维的 spec 随写回消失;`doc` ∪ `refused[].original` 覆盖输入全部 worker,有钉)。enabled 且无 `env.REMOTE_EXEC` ⇒ refused(不替运维猜车道);`sessionBackend: "tidb"` ⇒ `store.session/backend: "mysql"`;
|
|
66
|
+
`memoryBackend` ⇒ dropped;`coords.tidbHost` 在 ⇒ mysql 店 + `store.db`(缺端口 ⇒ 3306),不在 ⇒ local 店;env 里的 `DB_BACKEND` /
|
|
67
|
+
`MEMORY_ENGINE*` 搬进 store。终判 = 7.0.0 `WorkerSpec`(迁移不复述写闸规则)。`dropped` / `refused` 的形比稿多 `index`(`refused` 再多
|
|
68
|
+
`original`),`field` 是 `ConfigPath`(本包 3.0.0 起坐标一律结构化)。
|
|
69
|
+
- **`WORKER_NAME`**(新导出):worker 名字的唯一判据。`WorkerSpec` 不再是普通对象 schema,`WorkerSpec.shape.name` 没了 —— 中心在租约 /
|
|
70
|
+
用量 / discovery `?worker=` 上借上游名字判据的五处改读它(查漏轮读 web-admin `origin/main` 逮到)。
|
|
71
|
+
- **子路径 `./execution-lanes`**(照 `./secret-refs` 现形):只要词表的消费方(中心客户端组件)不必经主桶;导出与主桶**同一个模块实例**
|
|
72
|
+
(有钉:真走 Node 的 exports 解析,两处取到的 `EXECUTION_LANES` 是同一对象)。
|
|
73
|
+
- **CLI**:`settings-schema migrate-workers <workers.json> [--check]`(`package.json` 新增 `bin`;入口 `bin/settings-schema.mjs` 是本包唯一用
|
|
74
|
+
`node:fs` 写文件的地方,逻辑在 `src/cli.ts`,不碰 fs)。有 refused ⇒ 一字不写、退出 1;`--check` 有改动 ⇒ 退出 3;stdout 一行
|
|
75
|
+
`workers_domain_migrated` JSON 报告(只点名字段)。
|
|
76
|
+
- **`RemoteExecSpec` 删 `remote-docker` 变体**(零别名)—— 取证见下;远端 docker 守护进程 = `local-docker` 车道 + `DOCKER_HOST`。
|
|
77
|
+
`listRequiredEnvNames` 的 provider 分支改穷举 `switch`(新 provider 不表态 = 编译红)。
|
|
78
|
+
- **消费面跟上**:`workersReferencingSecret`(批量轮换)与 `collectEnvRefs`(密钥清单)看得见 `runtime.execution.secretRefs` 与 `dbPasswordEnv` ——
|
|
79
|
+
否则迁移把 `E2B_API_KEY` 从 `secretEnv` 搬走之后,轮换 E2B 密钥不再重建引用它的 worker(静默,旧值留在跑着的 pod 里)。
|
|
80
|
+
|
|
81
|
+
### remote-docker 取证(裁 = 删)
|
|
82
|
+
|
|
83
|
+
- core(server 树装的 7.38.3 dist):零命中。cli `src/`:零命中。web-admin `src/`:零命中(执行域标签表本就没有它)。
|
|
84
|
+
- server `src/`:有一只适配器工厂 `remoteDockerExecutionEnvFactory`(`plugins/remote-env-host.ts`),**生产代码零调用**(只有它自己的单测引用);
|
|
85
|
+
`AppConfig.remoteExec` 联合没有 `remote-docker` 臂(`config-types.ts` 注:配置面「remaining follow-up」);`REQUIRED_ENVS_BY_LANE` /
|
|
86
|
+
`REMOTE_EXEC_PROVIDER_WORDS` 没有它 ⇒ `REMOTE_EXEC=remote-docker` 起服即拒;`config.d/remote-exec.json` 写它 ⇒ 只告警「未接线」、env 车道照旧。
|
|
87
|
+
- 结论:没有任何读点能把这个词变成一条在跑的车道 ⇒ 删。远端守护进程的真形今天就是 `local-docker` + `DOCKER_HOST`(server `config.ts` 读点),
|
|
88
|
+
本包表里 `DOCKER_HOST` 在 local-docker 的可选栏。
|
|
89
|
+
|
|
90
|
+
### 用户可见行为变化(逐条;主会话裁定 5「采」)
|
|
91
|
+
|
|
92
|
+
1. **6.x 没有 SQL 坐标的 worker,迁移后变成文件持久**:6.x 渲染器恒渲 `SESSION_BACKEND=auto`,引擎把它当 SQL 信号、`DB_BACKEND` 标 mysql
|
|
93
|
+
却什么都不建 ⇒ 实际跑**内存**(重启即丢 run / 会话);迁移写 `store.backend: local`,渲染器改真后渲 `DB_BACKEND=local` ⇒ 跑**本机文件店**
|
|
94
|
+
(容器内持久,重建容器才丢)。与引擎裸 boot 的缺省同源(无 SQL 信号 ⇒ local)。
|
|
95
|
+
2. **6.x 多租户(`requirePrincipal`)而没有 SQL 坐标的 worker,迁移 refused**:它今天跑内存(引擎对多租户裸 boot 落 memory + notice);
|
|
96
|
+
7.0.0 多租户必须 mysql | pg 店(判据 ⑥)。出路 = 补 `runtime.store.db` + `secretRefs.dbPasswordEnv`,或关掉 `requirePrincipal`。
|
|
97
|
+
3. **SQL 店的口令引用必填(主会话裁定 4:不放宽)**:无口令的 SQL 服务器(开发用 TiDB root 空口令)声明不了 —— 编排舰队是部署形,无口令 SQL
|
|
98
|
+
不是合法声明;引擎侧接受空口令(`MYSQL_PASSWORD` 缺省 `""`),但写闸不收。6.x 行「有 `coords.tidbHost`、无 `tidbPasswordEnv`」迁移 refused,
|
|
99
|
+
拒因点名 `secretRefs.dbPasswordEnv`(出路就在字段上)。
|
|
100
|
+
4. **`DOCKER_HOST` 全局保留(主会话裁定 7)**:它是 local-docker 车道的坐标(远端守护进程 = `local-docker` + `coords.DOCKER_HOST`),保留集一直是
|
|
101
|
+
全局闭集、不按车道豁免 ⇒ host 车道的 worker 想给 **agent 自己的 docker CLI** 经 `env.DOCKER_HOST` 指远端守护进程,这条路没了。
|
|
102
|
+
5. **enabled 而没写车道的 worker 不再「无手照回 completed」**:写闸拒、迁移 refused(WA-49 病例本身)。
|
|
103
|
+
6. **`remote-docker` 写进 `config.d/remote-exec.json` 的本机部署**:以前告警「未接线」、照用 env 车道;7.0.0 起读文件即拒(fail-closed)。
|
|
104
|
+
|
|
105
|
+
### BREAKING 逐条(消费方 tsc 红 / 读到即拒即通知)
|
|
106
|
+
|
|
107
|
+
1. `WorkerSpec.runtime.sessionBackend` / `.memoryBackend` / `.db`、`WorkerSpec.coords.tidbHost` / `.tidbPort` / `.tidbUser`、
|
|
108
|
+
`WorkerSpec.secretRefs.tidbPasswordEnv` 删除 —— 类型上消失(读它们 tsc 红),数据里出现即拒(指路迁移)。
|
|
109
|
+
2. enabled 的 worker 必须声明 `runtime.execution` 与 `runtime.store`(6.x 的 `runtime: {}` 最小形读到即拒)。
|
|
110
|
+
3. `RESERVED_WORKER_ENV` 加词:存量 `env.REMOTE_EXEC` / `K8S_*` / `E2B_*` / `SSH_*` / `ADB_*` / `DOCKER_*` / `DEVICE_*` / `DB_BACKEND` /
|
|
111
|
+
`MEMORY_ENGINE*` 透传行读到即拒(迁移搬进结构块);删 `MEMORY_BACKEND` / `TIDB_*`(不再被本表拒,由引擎墓碑表拒)。
|
|
112
|
+
4. `RemoteExecSpec` 删 `remote-docker` 变体:`config.d/remote-exec.json` 写它 ⇒ `loadRemoteExec` / `validateRemoteExec` 拒(以前:读过、引擎告警未接线)。
|
|
113
|
+
5. `WorkerSpec` 从 `ZodObject` 变成 `ZodEffects`(预处理 + 跨字段判据):`WorkerSpec.shape` / `.extend` / `.pick` 不再可用 —— web-admin
|
|
114
|
+
`origin/main` 有五处读 `WorkerSpec.shape.name`(`api/fleet/leases`、`api/fleet/usage`、`api/v1/scenarios/builtin`、`api/v1/scenarios/detail/[name]` ×2),
|
|
115
|
+
改读新导出 `WORKER_NAME`(同一只判据);`z.input<typeof WorkerSpec>` 变成 `unknown`(普查零用法)。
|
|
116
|
+
|
|
117
|
+
### 红先 / 门
|
|
118
|
+
|
|
119
|
+
- 红先提交 `e8f4520`(只有测试)。修前读数:A 组(新模块不存在)三个新文件收集即红,`remote-exec` 1 格红(remote-docker 曾合法的三形)、
|
|
120
|
+
`reserved-worker-env` 2 格红;B 组(只放词表数据、规则未写)`execution-lanes` + `worker-execution-store` 两文件 44 红 / 48 绿
|
|
121
|
+
(绿 = 表内容钉 33 + 正控 15)。消费面两格(`workersReferencingSecret` / `collectEnvRefs`)对 6.4.0 的 `secret-refs.ts` 2 红;`WORKER_NAME` 1 红;
|
|
122
|
+
gpt-6 腿两条 [high] 各自红先(F1 迁移 1 红、F2 写闸 2 红)再修。
|
|
123
|
+
- 新文件:`test/execution-lanes-7.0.0.test.ts`(表门:词序、逐行 = 引擎真码、栏不交、深冻结、`RemoteExecSpec.provider ⊆ EXECUTION_LANE_WORDS`
|
|
124
|
+
运行期 + 编译期)、`test/worker-execution-store-7.0.0.test.ts`(写闸判据 + 绕法:别车道键 / 大小写 / 空串 / 密钥形 / 错栏)、
|
|
125
|
+
`test/migrate-workers-7.0.0.test.ts`(迁移规则逐条 + 幂等 + 纯 + CLI 内存 io 与真 bin)、`test/conformance-workers-7.0.0.test.ts`。
|
|
126
|
+
- 旧测试按意图改:`reserved-worker-env`(0.1.30 反向门按设计反转;`MINIO_*` / `LOG_LEVEL` 仍不保留那半留着)、`remote-exec`、`file-edit`
|
|
127
|
+
(R16 端口门挪到 `runtime.store.db.port`)、七个测试文件的 worker 夹具补两块(提货成本)、`deprecation-hygiene` 豁免表删一行陈旧条目、
|
|
128
|
+
`docs-hygiene` 外部版本白名单加 `7.112.0`(server 树版本,表行坐标出处)。
|
|
129
|
+
- conformance:新语料 `c50–c56`(七条车道各一份合法 spec,三腿零告警)、`c57–c68`(十二条拒因:G1 / G2 / G3 三形 / G7a / host∧两副本 /
|
|
130
|
+
多租户∧local / pg 缺 db / 记忆后端不配 / 删除项响亮拒)+ `c68`(device ∧ local 店,gpt-6 腿 F2;`c56` 的 device 合法样随之用 pg 店),`firstRedOn` 留空(historical 阶梯证据真跑于入库之前,不手填,c41 同口径;对 6.4.0
|
|
131
|
+
这 19 条都会红:合法 7 条两块被剥、拒因 12 条被放行)。`cli04` 的输入改成 7.0.0 形(显式声明车道与店;6.x 原输入是 enabled 无车道的 WA-49 形,
|
|
132
|
+
迁移对它是 refused,本条要打的是 env 值承运,与车道无关)并重加冕;其余既有语料、`baseline.json` 全量重加冕零 diff。
|
|
133
|
+
迁移金样 `conformance/migrate-workers/m01–m04`(G5 正臂 / 幂等 / refused / G7b),加冕脚本同一个(`npm run conformance:bless`)。
|
|
134
|
+
|
|
135
|
+
### 消费方(@ 点名,迁移句)
|
|
136
|
+
|
|
137
|
+
- **@web-admin**(中心 / 编排器,10-17 窗):删除项 ⇒ 渲染器 `workerToServiceEnv` tsc 红即通知,按 `runtime.execution` / `runtime.store` 改真
|
|
138
|
+
(`REMOTE_EXEC` + `REQUIRE_EXECUTION_LANE=true` + coords / secretRefs 逐键;`DB_BACKEND` / `SESSION_BACKEND` / `MEMORY_ENGINE` /
|
|
139
|
+
`MEMORY_ENGINE_BACKEND` 恒渲;按 `backend` 选 `MYSQL_*` / `PG_*` 名族;`MEMORY_BACKEND` 不再产出)。workers 唯一读口在 `parseDomain` 之前跑
|
|
140
|
+
`migrateWorkersDomain`,写回 `doc`、日志 `workers_domain_migrated {from, changed, dropped}` 一行、UI 横幅;`refused` 的 worker 不加载、列表标红
|
|
141
|
+
点名 `field`(它不在输出 `doc` 里 —— 写回时用 `index` 从原文档保住那一行,别把它删了)。写闸零新代码:`DOMAIN_SCHEMAS.workers.safeParse`
|
|
142
|
+
已带全部判据。五处 `WorkerSpec.shape.name` 改 `WORKER_NAME`;编排器 `warnSharedDb` 读 `runtime.db` 改 `runtime.store.db.database`;向导建出的
|
|
143
|
+
`runtime: {}` 要补两块(否则写闸拒)。执行域(`allowedLanes`,开放词)的标签表:可声明车道取 `EXECUTION_LANE_WORDS`(今天手抄的那张缺 `device`);
|
|
144
|
+
`in-process` 是引擎「没有 remoteExec」的状态名、不在可声明表里 —— 那一行要留就单独写明来源。`RESERVED_WORKER_ENV` 派生的保留集自动跟上。
|
|
145
|
+
- **@server**(7.113.0 提货):`REMOTE_EXEC_PROVIDER_WORDS` / `REQUIRED_ENVS_BY_LANE` / `tenantSeparation` 改从 `EXECUTION_LANES` 派生
|
|
146
|
+
(运行期事实留在按导入联合穷举的 switch 里);`DB_BACKEND` / `SESSION_BACKEND` / `MEMORY_ENGINE_BACKEND` 三处 `enumEnv` 词表改读导出常量;
|
|
147
|
+
加一格「运行期事实与表不矛盾」;对表:ssh / adb / local-docker / device 的可选栏是按 7.112.0 三元链各臂抄的,请对一遍。
|
|
148
|
+
`config.d/remote-exec.json` 写 `remote-docker` 的本机部署,提货后读文件即拒启(以前告警未接线)。
|
|
149
|
+
- **@cli**:不 import `WorkerSpec` / `RemoteExecSpec`(普查零用法),零改动;`engineEnvGroups.ts` 的 `REQUIRED_ENVS_BY_LANE` 镜像可改从
|
|
150
|
+
`EXECUTION_LANES` 派生(可选)。
|
|
151
|
+
- **@deploy**:`deploy/sema-up/lib/lanes.json` 的 `users` / `env` 列从 `EXECUTION_LANES` 生成(server 自决,design/327 已决)。
|
|
152
|
+
|
|
153
|
+
### 车内对抗复审(gpt-6-astra 一轮)
|
|
154
|
+
|
|
155
|
+
两条 [high],都亲读代码复现后红先修:**F1** 迁移在「运维已手填 `secretRefs.dbPasswordEnv`、旧 `tidbPasswordEnv` 还在、`runtime.store` 未写」时
|
|
156
|
+
用旧引用静默覆盖新引用(两形并存检查只看了 `runtime.store`)⇒ 新形店字段 = `runtime.store` ∪ `secretRefs.dbPasswordEnv`,任一在场 ∧ 有旧店字段 ⇒ refused;
|
|
157
|
+
**F2** device 车道配非 SQL 店过闸而引擎拒启 ⇒ 判据 ⑦。
|
|
158
|
+
|
|
159
|
+
### 主会话裁定(9 条候裁)
|
|
160
|
+
|
|
161
|
+
1 第 6 栏 `optionalSecretEnv` 采 · 2 host 多副本同看 `autoscaling.maxReplicas` 采 · 3 device ⇒ SQL 店 采 · 4 `dbPasswordEnv` 必填不放宽(见「用户可见行为变化」3)·
|
|
162
|
+
5 「无坐标 ⇒ local」与多租户无坐标 refused 采(同上 1、2)· 6 refused 行带原条目回传(`refused[].original`,本版改)· 7 `DOCKER_HOST` 全局保留 采(同上 4)·
|
|
163
|
+
8 加子路径 `./execution-lanes`(本版改)· 9 `WorkerSpec` 成 ZodEffects 采。核项 session × backend ⇒ 判据 ⑧⑨。
|
|
164
|
+
|
|
165
|
+
### 迁移代码删除窗
|
|
166
|
+
|
|
167
|
+
`migrateWorkersDomain`、`settings-schema migrate-workers`、删除项「读到即拒」的预处理 —— 在 web-admin 10-17 落地(中心读口接上迁移)后的
|
|
168
|
+
**下一版**删除(主会话开 DEBTS 票跟踪)。
|
|
169
|
+
|
|
170
|
+
## 6.4.0 — 2026-10-01 — `models.models[].headers` 解析透明键(S-935;与 `compat` 同一只变换)
|
|
171
|
+
|
|
172
|
+
> **判档 = minor**(新键 = additive,README「发版纪律」)。缺席 = 键不铸 = 6.3.0 行为,零迁移;不带 `headers` 的文档读出来逐字节不变
|
|
173
|
+
> (conformance 全语料重加冕:既有 61 条 case、`baseline.json`、`VERSION` 零 diff)。
|
|
174
|
+
|
|
175
|
+
### 病(6.3.0 及更早)
|
|
176
|
+
|
|
177
|
+
sema-server 7.108.0(S-931)给模型目录条目加了 `headers`(部署 ↔ 供应商的 per-model 附加请求头,例 `{"anthropic-beta":"context-1m-2025-08-07"}`
|
|
178
|
+
开 1M 上下文)。本包 `ModelEntry` 没有这个键 ⇒ 每一条按域 schema 解析的读口都把它剥掉并报 `unknown-keys-dropped`
|
|
179
|
+
(实测:`[{"domain":"models","kind":"unknown-keys-dropped","keys":[["models",0,"headers"]]}]`)—— 远端 `readEffectiveWire`、`buildEffective`、
|
|
180
|
+
文件腿 `FileConfigStore.getEffective()`(严格 / `{tolerant:true}` 两形,`loadLocalConfig` 走严格形)、`FileConfigStore.getDomain`
|
|
181
|
+
(`exportBundle` 的读法);写腿 `writeDomainFile` / `validateDomain` 同样剥,且连告警都没有。经生产配置通道写下的 `headers`
|
|
182
|
+
到不了 server 目录,只有绕过读腿的输入(盘上 LKG / 手写 effective)到得了。
|
|
183
|
+
|
|
184
|
+
### 修
|
|
185
|
+
|
|
186
|
+
- `ModelEntry.headers?`(`src/types.ts`):`z.unknown().optional().transform(createFreeFormTransform("headers"))` —— 与 `compat` **同一只**
|
|
187
|
+
变换(本版把 `compat` 那段内联闭包提成包内私有的 `createFreeFormTransform(field)`,两键共用,不再各写一份):缺席不铸键;其余只过
|
|
188
|
+
`vetFreeFormJson` 自由形安全判(密钥形键 / 值、访问器、环、非 JSON、深于 `MAX_EXTRA_BODY_DEPTH`),拒句与 `compat` 逐字同形、只换字段名。
|
|
189
|
+
- **不做形校验**:字符串 / 数组 / 数字 / `null` / 非规范大小写的名(`Anthropic-Beta`)/ 白名单外的名 / 非字符串值 / 写在不读它的线路上,
|
|
190
|
+
本包一律逐字过。头名闭集白名单 × 读它的线路 × 值形的判据**唯一属主是 sema-server**(坏声明 ⇒ 该条目整条不可用),本包复述一份必漂。
|
|
191
|
+
- 登记进 `PARSE_TRANSPARENT_KEYS`(`models[].headers`,`since: "6.4.0"`,`validatedBy: "consumer"`)。`ParseTransparentValidator` 的
|
|
192
|
+
`consumer` 词注去掉了「丢掉坏的那一个键、保留宿主条目」这句处置描述 —— 坏值怎么处置是执法点自己的契约(`headers` 的执法点整条
|
|
193
|
+
条目不可用,`mcp.servers[].source` 的只丢标签),写在各登记行的 `why` 里,本包不替它定(规则少一条,不加新词)。
|
|
194
|
+
- 同深度上限:`src/hash.ts` `MAX_EXTRA_BODY_DEPTH` 注文补 `headers`(与 `extraBody` / `compat` 同一个包裹深度,同一个上限)。
|
|
195
|
+
- 文档:README「Declared-but-unvalidated keys」、`llms.txt` 解析透明键登记表段(4 员 → 5 员)、`llms-full.txt` 补 `headers`。README 同句
|
|
196
|
+
顺手订正:它把 `models[].extraBody` 列成解析透明键、把「the key's own guard」列成第三种校验方 —— 两处都与实现不符(`extraBody`
|
|
197
|
+
有自己的形门,不在登记表里;校验方闭集只有 `engine-ingest` / `consumer` 两词),改成与 `src/types.ts` 一致。
|
|
198
|
+
|
|
199
|
+
### 红先 / 门
|
|
200
|
+
|
|
201
|
+
- `test/model-headers-6.4.0.test.ts` 16 格,修前 15 红 1 绿(绿的是 ③ 负控):① 五条读腿逐字交出、零告警 ①b 写腿逐字落盘
|
|
202
|
+
② 密钥形值 / 键(`sk-ant-…` / 私钥 PEM / `Bearer …` / 密钥形键 / 数组里的嵌套值)拒,拒句 = `compat` 拒句换字段名 ②b 五条读腿上与
|
|
203
|
+
`compat` 同一个处置(经 `buildEffective` 的四条腿逐条丢 `entry-dropped`、兄弟幸存;`getDomain` 整域净化后抛)、零回显
|
|
204
|
+
③ 负控:不带 `headers` 的文档 effective / wire 的 `stableHash` 与 6.3.0 实测金样逐位相同 ④ 不做形校验 ⑤ `stableHash` 键序无关、
|
|
205
|
+
声明 / 换值改变哈希、恰在 `MAX_EXTRA_BODY_DEPTH` 收且包进 effective 可哈希、超一层拒(与 `compat` 同层)⑥ 登记行。
|
|
206
|
+
- 解析透明键登记表门(`test/parse-transparent-keys.test.ts`,从 `DOMAIN_SCHEMAS` 行为派生、双向对拍)随新键自动覆盖。
|
|
207
|
+
- conformance 两条新语料(`npm run conformance:bless` 加冕):`c48-s935-model-headers-transported`(三腿逐字交出、零告警;openai 线路上的
|
|
208
|
+
数组形 `headers` 照样过;无 `headers` 的条目不铸键)、`c49-s935-model-headers-secret-entry-dropped`(密钥形值 ⇒ 条目逐条丢、零回显,
|
|
209
|
+
`secrets` 已登记)。对 6.3.0 源码实测三腿同红(c48:2 处 effective 差 + 1 条多出的 `unknown-keys-dropped`;c49:6 处 effective 差、
|
|
210
|
+
缺 1 条 `entry-dropped`、多 1 条 `unknown-keys-dropped`);`firstRedOn` 留空(historical 阶梯证据真跑于入库之前,不手填,c41 同口径)。
|
|
211
|
+
|
|
212
|
+
### 消费方
|
|
213
|
+
|
|
214
|
+
- **sema-server 7.109.0 提货**:`config-provider.ts` `mapToServiceEffective` 加一行过境 `headers`,并把 `test/catalog-entry-headers.test.ts`
|
|
215
|
+
末段 🚧 S-931-schema 两格(「两条读腿今天剥掉 `headers`」)翻成「读腿逐字交出 `headers`」的正向钉、删该段 🚧。
|
|
216
|
+
- center / TOC:`ModelEntry` 的推断类型多一个 `headers?: unknown`;不读它的消费方零改动。
|
|
217
|
+
|
|
11
218
|
## 6.3.0 — 2026-09-27 — 安全修(codex gpt-6-astra 对 v6.1.0 复审 [high],回填 D-4):可披露身份改白名单闭形 `DISCLOSABLE_IDENTITY_RE` · `redactSecrets` 整串判套在一处归一化上 · 告警坐标出门一道
|
|
12
219
|
|
|
13
220
|
> **判档 = minor**(发版方裁,2026-09-27;原排 6.2.1 当日补丁):按 README「发版纪律」,新导出 `DISCLOSABLE_IDENTITY_RE` = minor
|
package/README.md
CHANGED
|
@@ -68,8 +68,36 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
68
68
|
- **Secret inventory** (`secret-refs.ts`): `collectEnvRefs` — every referenced env-NAME.
|
|
69
69
|
- **The narrow reader** (`reader.ts`): `ConfigReader` (3 methods) — the config-center 产品's fat `ConfigStore`
|
|
70
70
|
`extends` it; a local file source / test fixture implements it without stubbing ~32 methods.
|
|
71
|
-
- **`remoteExec` contract** (`remote-exec.ts`): the execution-substrate
|
|
72
|
-
|
|
71
|
+
- **`remoteExec` contract** (`remote-exec.ts`): the per-machine `config.d/remote-exec.json` execution-substrate
|
|
72
|
+
schema (`host` / `local-docker` / `e2b` / `k8s` / `ssh` / `adb`), discriminated on `provider`; every secret an
|
|
73
|
+
env-NAME ref. Every `provider` word is an execution-lane word (`EXECUTION_LANE_WORDS`, pinned at runtime and at
|
|
74
|
+
compile time). **7.0.0** deleted the `remote-docker` variant: no engine read point ever ran it; a remote docker
|
|
75
|
+
daemon is the `local-docker` lane pointed at it (`DOCKER_HOST`).
|
|
76
|
+
- **WorkerSpec execution lane + store (7.0.0, M-R2)** (`execution-lanes.ts`, also subpath `./execution-lanes`, + `types.ts`): the lane / store
|
|
77
|
+
vocabulary has ONE source — the exported data `EXECUTION_LANE_WORDS`, `EXECUTION_LANES` (per lane:
|
|
78
|
+
`tenantSeparation` + the env names it reads, in four columns `requiredEnv` / `requiredSecretEnv` / `optionalEnv` /
|
|
79
|
+
`optionalSecretEnv`, copied from the engine with per-row coordinates), `STORE_BACKENDS`, `SESSION_BACKENDS`,
|
|
80
|
+
`MEMORY_ENGINE_BACKENDS`. The center's write gate (this package's `WorkerSpec.safeParse`), the center's env
|
|
81
|
+
renderer and the engine's boot checks all read that one table, so they cannot drift. A worker declares
|
|
82
|
+
`runtime.execution = { lane, coords, secretRefs }` (non-secret coordinates as literals, secrets as host env-NAMEs,
|
|
83
|
+
keys ⊆ that lane's columns, required ones present and non-empty) and `runtime.store = { backend, session, memory,
|
|
84
|
+
db? }` (+ `secretRefs.dbPasswordEnv`); an enabled worker must declare both. Cross-field refusals live in the
|
|
85
|
+
schema as zod issues whose `path` names the field to change and whose message carries the way out: a
|
|
86
|
+
multi-tenant worker (`requirePrincipal`) on a lane that does not separate tenants (outlets computed from the
|
|
87
|
+
table), the `host` lane with more than one replica (`replicas` or `autoscaling.maxReplicas`), the `device` lane
|
|
88
|
+
without a SQL store that actually builds its coordinates (the engine's `device-durable-store`), SQL coordinates
|
|
89
|
+
without a SQL store (or the reverse), a memory backend that does not match the store, a multi-tenant worker
|
|
90
|
+
without a SQL store, and the two session × store combinations the engine refuses at boot (`session: mysql` on a
|
|
91
|
+
`memory` store; a pg / tidb memory engine with `session: memory`). `WorkerSpec` is no longer a plain object schema — the worker-name rule is exported on its
|
|
92
|
+
own as `WORKER_NAME`. `RESERVED_WORKER_ENV` (derived from a name → owning-field table) now reserves every
|
|
93
|
+
env name those blocks produce, so the `env` / `secretEnv` escape hatches can no longer set a lane or a store.
|
|
94
|
+
Stored 6.x rows are lifted ONCE by `migrateWorkersDomain(doc)` (pure, idempotent; run it on the RAW workers
|
|
95
|
+
document before `parseDomain` — the 6.x fields are refused loudly by the 7.0.0 schema, not silently stripped)
|
|
96
|
+
or its file form `npx @sema-agent/settings-schema migrate-workers <workers.json> [--check]` (the package's
|
|
97
|
+
`bin`; writes only when every worker migrates). Workers it cannot lift (an enabled worker with no
|
|
98
|
+
`env.REMOTE_EXEC` — the migration never guesses a lane) come back in `refused` with the field to fix and the
|
|
99
|
+
`original` row verbatim — they are NOT in the migrated `doc`, so a caller that writes `doc` back must put each
|
|
100
|
+
`refused[].original` back at its `index` (or store it aside), or that worker's spec disappears.
|
|
73
101
|
- **Safety merge-spec** (`safety-merge-spec.ts`, subpath `./safety-merge-spec`): `SAFETY_MERGE_SPEC`, the ONE
|
|
74
102
|
per-category merge/enforcement table every settings resolver reads (`mergeShape` / `minTrust` / `tighten` /
|
|
75
103
|
`enforcement` / `fail`) — no consumer re-implements the merge law. 1.1.0 adds **member-level admission**:
|
|
@@ -209,9 +237,12 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
209
237
|
rule the dropped-entry identity on read warnings already uses: the `DISCLOSABLE_IDENTITY_RE` allowlist ∧ not
|
|
210
238
|
secret-shaped, 6.3.0).
|
|
211
239
|
- **Declared-but-unvalidated keys** (`PARSE_TRANSPARENT_KEYS`, 2.0.0): the ONE registry of keys this package
|
|
212
|
-
carries verbatim WITHOUT checking their shape, each row naming who does check it (the engine's ingest side
|
|
213
|
-
a consumer's
|
|
214
|
-
`mcp.servers[].source` (1.7.2), `mcp.servers[].toolFaces`
|
|
240
|
+
carries verbatim WITHOUT checking their shape, each row naming who does check it (the engine's ingest side or
|
|
241
|
+
a consumer's enforcement point). Today: `models[].compat` (1.10.0), `models[].headers` (6.4.0; the header-name
|
|
242
|
+
allowlist × lane is sema-server's, not restated here), `mcp.servers[].source` (1.7.2), `mcp.servers[].toolFaces`
|
|
243
|
+
(1.9.0), and an entitlement override's `value`. `models[].extraBody` is NOT one of them — it has its own shape
|
|
244
|
+
gate (a plain JSON object); what it leaves open is the key vocabulary inside. `compat` / `headers` / `extraBody`
|
|
245
|
+
still clear the one free-form safety judgment (secret-shaped key/value, accessor, cycle, non-JSON, too deep ⇒ rejected).
|
|
215
246
|
- **Extension namespaces** (`EXTENSION_NAMESPACES`, 1.5.0): keys another writer puts in a domain document by
|
|
216
247
|
contract and this package deliberately does not model (today: the shell's entry-level `sema*` fields on
|
|
217
248
|
`models`). They are still stripped, but they are NOT reported as unknown keys — intent is declared at the
|
|
@@ -280,6 +311,10 @@ defaults. Each `config.d/<domain>.json` is exactly that domain's zod object.
|
|
|
280
311
|
「修 bug」若改变了合法输入的解析结果,按上两档判,不按 patch。
|
|
281
312
|
- 契约破坏面动之前先盘 center / server / CLI 三方消费点;commit message 的 `feat!`/`BREAKING` 标记照旧,
|
|
282
313
|
但标记不豁免版号义务。每版 CHANGELOG 一节,git tag `v<version>` 同名。
|
|
314
|
+
- **持久数据面的破坏性变更(例:7.0.0)**:类型 / API 面直接删改、零别名(消费方 tsc 红即通知);**存下来的数据**不会自己红,
|
|
315
|
+
所以同版配三件:读到旧形即**响亮拒**(拒因指路迁移命令,不是被 zod 静默剥掉)、一只**一次性迁移**(纯函数、幂等、
|
|
316
|
+
表达不了就 refused 点名,不替运维猜)、以及一个**写明的删除窗**(7.0.0 的 `migrateWorkersDomain` 在中心接上迁移后的下一版删除)——
|
|
317
|
+
绝不长成长命双读。
|
|
283
318
|
- **历史注记(0.x 时代)**:0.x 下 `^0.7.0` 这类 range 只自动收 patch,故当年规矩是「破坏性必 bump
|
|
284
319
|
minor,patch 只装 additive/修 bug/文档」。0.7.1(2026-07-10)曾携带两件预协调 BREAKING(撤 governance
|
|
285
320
|
effective 双写镜像、撤 QuotaLease 0.5 `tokens` 别名 shim),名义上违反该条;当时下游(center/service
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `settings-schema` — this package's command line (7.0.0: `migrate-workers <workers.json> [--check]`).
|
|
3
|
+
// The ONLY place the package writes files with node:fs; the logic is `runSettingsSchemaCli` (dist/cli.js), which never
|
|
4
|
+
// touches the filesystem itself — this entry injects real file I/O into it.
|
|
5
|
+
import { readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
6
|
+
import { runSettingsSchemaCli } from "../dist/cli.js";
|
|
7
|
+
|
|
8
|
+
const io = {
|
|
9
|
+
readFile: (path) => readFile(path, "utf8"),
|
|
10
|
+
// atomic: write a sibling temp file (same mode as the original), then rename over it — a half-written workers
|
|
11
|
+
// document is worse than the old one.
|
|
12
|
+
writeFileAtomic: async (path, text) => {
|
|
13
|
+
const { mode } = await stat(path);
|
|
14
|
+
const tmp = `${path}.migrate-${process.pid}.tmp`;
|
|
15
|
+
await writeFile(tmp, text, { encoding: "utf8", mode: mode & 0o777 });
|
|
16
|
+
await rename(tmp, path);
|
|
17
|
+
},
|
|
18
|
+
stdout: (text) => process.stdout.write(text),
|
|
19
|
+
stderr: (text) => process.stderr.write(text),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
process.exitCode = await runSettingsSchemaCli(process.argv.slice(2), io);
|
package/conformance/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
7.0.0
|
|
@@ -0,0 +1,115 @@
|
|
|
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": "anthropic-messages",
|
|
32
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY",
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"headers": {
|
|
35
|
+
"anthropic-beta": "context-1m-2025-08-07"
|
|
36
|
+
},
|
|
37
|
+
"id": "claude-x",
|
|
38
|
+
"name": "claude-1m",
|
|
39
|
+
"provider": "anthropic",
|
|
40
|
+
"quotaWeight": 1,
|
|
41
|
+
"reasoning": false,
|
|
42
|
+
"tier": "standard",
|
|
43
|
+
"vision": false
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"api": "openai-completions",
|
|
47
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
48
|
+
"enabled": true,
|
|
49
|
+
"headers": [
|
|
50
|
+
"Anthropic-Beta: not-a-header-bag"
|
|
51
|
+
],
|
|
52
|
+
"id": "gw-id",
|
|
53
|
+
"name": "gw",
|
|
54
|
+
"provider": "openai",
|
|
55
|
+
"quotaWeight": 1,
|
|
56
|
+
"reasoning": false,
|
|
57
|
+
"tier": "standard",
|
|
58
|
+
"vision": false
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"api": "openai-completions",
|
|
62
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"id": "plain-id",
|
|
65
|
+
"name": "plain",
|
|
66
|
+
"provider": "openai",
|
|
67
|
+
"quotaWeight": 1,
|
|
68
|
+
"reasoning": false,
|
|
69
|
+
"tier": "standard",
|
|
70
|
+
"vision": false
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"roles": {},
|
|
74
|
+
"tierGroups": []
|
|
75
|
+
},
|
|
76
|
+
"plugins": {
|
|
77
|
+
"plugins": []
|
|
78
|
+
},
|
|
79
|
+
"projects": {
|
|
80
|
+
"projects": {}
|
|
81
|
+
},
|
|
82
|
+
"prompts": {
|
|
83
|
+
"bindings": []
|
|
84
|
+
},
|
|
85
|
+
"rosters": {
|
|
86
|
+
"rosters": []
|
|
87
|
+
},
|
|
88
|
+
"runtime": {},
|
|
89
|
+
"scenarios": {
|
|
90
|
+
"scenarios": []
|
|
91
|
+
},
|
|
92
|
+
"skills": {
|
|
93
|
+
"skills": []
|
|
94
|
+
},
|
|
95
|
+
"systems": {
|
|
96
|
+
"systems": []
|
|
97
|
+
},
|
|
98
|
+
"workers": {
|
|
99
|
+
"workers": []
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"warnings": [],
|
|
103
|
+
"metadata": {
|
|
104
|
+
"version": 7,
|
|
105
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"wire": {
|
|
109
|
+
"derive": true
|
|
110
|
+
},
|
|
111
|
+
"localRoot": {
|
|
112
|
+
"derive": true,
|
|
113
|
+
"localVersion": 1883250445565322
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 7,
|
|
4
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"models": {
|
|
8
|
+
"models": [
|
|
9
|
+
{
|
|
10
|
+
"name": "claude-1m",
|
|
11
|
+
"provider": "anthropic",
|
|
12
|
+
"api": "anthropic-messages",
|
|
13
|
+
"id": "claude-x",
|
|
14
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY",
|
|
15
|
+
"headers": {
|
|
16
|
+
"anthropic-beta": "context-1m-2025-08-07"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "gw",
|
|
21
|
+
"provider": "openai",
|
|
22
|
+
"id": "gw-id",
|
|
23
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
24
|
+
"headers": [
|
|
25
|
+
"Anthropic-Beta: not-a-header-bag"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "plain",
|
|
30
|
+
"provider": "openai",
|
|
31
|
+
"id": "plain-id",
|
|
32
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "S-935(6.4.0):`models[].headers` 是解析透明键(与 `compat` 同一只变换)⇒ 三读腿**逐字交出、零告警**,不剥、不报 `unknown-keys-dropped`;并且本包**不做形校验** —— 写在 openai 线路上的数组形 `headers`(非规范大小写的名、根本不是头袋)照样逐字过,形与线路归 sema-server 的目录条目判据。任一腿把它剥掉,经生产配置通道写下的附加请求头(开 1M 上下文的 `anthropic-beta`)就到不了 server 目录且零告警;任一腿对它做形校验,就是本包复述了 server 的白名单(两个写者)。第三条不带 `headers` 的条目是负控:不铸键。",
|
|
4
|
+
"firstRedOn": [],
|
|
5
|
+
"note": "车SL(2026-10-01)红先:6.3.0 读腿在本条上三腿同红 —— 两条带 `headers` 的条目都被剥掉该键,`unknown-keys-dropped` 点名 `[\"models\",0,\"headers\"]` / `[\"models\",1,\"headers\"]`(实测读数见车SL 收车档)。firstRedOn 为空:`conformance/historical/` 的阶梯证据(2.1.0 及更早)真跑于本条入库之前,没有本条的读数,那一栏只收 historical 真跑,不手填(c41 同口径)。"
|
|
6
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
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": "gw-id",
|
|
35
|
+
"name": "gw",
|
|
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
|
+
"identity": {
|
|
76
|
+
"id": "claude-x",
|
|
77
|
+
"name": "claude-1m"
|
|
78
|
+
},
|
|
79
|
+
"kind": "entry-dropped",
|
|
80
|
+
"path": [
|
|
81
|
+
"models",
|
|
82
|
+
0
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"metadata": {
|
|
87
|
+
"version": 7,
|
|
88
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"wire": {
|
|
92
|
+
"derive": true
|
|
93
|
+
},
|
|
94
|
+
"localRoot": {
|
|
95
|
+
"derive": true,
|
|
96
|
+
"localVersion": 496785931148953
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"version": 7,
|
|
4
|
+
"updatedAt": "2026-10-01T00:00:00.000Z"
|
|
5
|
+
},
|
|
6
|
+
"domains": {
|
|
7
|
+
"models": {
|
|
8
|
+
"models": [
|
|
9
|
+
{
|
|
10
|
+
"name": "claude-1m",
|
|
11
|
+
"provider": "anthropic",
|
|
12
|
+
"api": "anthropic-messages",
|
|
13
|
+
"id": "claude-x",
|
|
14
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY",
|
|
15
|
+
"headers": {
|
|
16
|
+
"x-api-key": "sk-ant-api03-FAKES935CORPUS000000000000000000"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "gw",
|
|
21
|
+
"provider": "openai",
|
|
22
|
+
"id": "gw-id",
|
|
23
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "S-935(6.4.0):`models[].headers` 里粘了一把密钥形值(`x-api-key: sk-ant-…`)⇒ 与 `compat` 同一只自由形安全判据拒 ⇒ 该条目**逐条丢**(`entry-dropped`,坐标 `[\"models\",0]`)、兄弟条目幸存、告警面零回显那把钥匙。打的是两种读错:① 腿把 `headers` 当未知键剥掉(6.3.0 形)⇒ 条目带着「看起来干净」的形幸存,明文凭据却已经进了持久层且没人拒;② 腿对 `headers` 另起一套判据(或把拒句拼上值)⇒ 告警面带出密钥。",
|
|
4
|
+
"firstRedOn": [],
|
|
5
|
+
"secrets": [
|
|
6
|
+
"sk-ant-api03-FAKES935CORPUS000000000000000000"
|
|
7
|
+
],
|
|
8
|
+
"note": "车SL(2026-10-01)红先:6.3.0 读腿在本条上三腿同红 —— 条目幸存(`headers` 被剥)+ `unknown-keys-dropped` 点名 `[\"models\",0,\"headers\"]`,没有 `entry-dropped`(实测读数见车SL 收车档)。firstRedOn 为空:同 c48 / c41 口径(historical 阶梯证据真跑于本条入库之前,不手填)。"
|
|
9
|
+
}
|