@sema-agent/settings-schema 8.1.0 → 8.3.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 +160 -0
- package/README.md +49 -3
- package/conformance/VERSION +1 -1
- package/conformance/migrate-workers/m05-row-verdict-reserved-env/expected.json +82 -0
- package/conformance/migrate-workers/m05-row-verdict-reserved-env/input.json +68 -0
- package/conformance/migrate-workers/m05-row-verdict-reserved-env/meta.json +4 -0
- package/dist/cli.js +4 -3
- package/dist/fleet-paths.json +14 -0
- package/dist/fleet.d.ts +157 -18
- package/dist/fleet.js +151 -40
- package/dist/issue-text.d.ts +10 -0
- package/dist/issue-text.js +8 -0
- package/dist/migrate-workers.d.ts +12 -4
- package/dist/migrate-workers.js +39 -15
- package/dist/remote-exec.d.ts +2 -2
- package/dist/types.d.ts +26 -26
- package/dist/types.js +3 -2
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,166 @@
|
|
|
6
6
|
> `@sema-agent/registry-core`(更早还曾是 `@sema-ai/registry-core`)。本档 `0.19.0` 以下各节里的
|
|
7
7
|
> 包名是**历史记录**,如实保留不追改。
|
|
8
8
|
|
|
9
|
+
## 8.3.0 — 2026-10-08 — fleet 成员所属租户 scope 的 env 名常量 `FLEET_SCOPE_ENV`(additive)
|
|
10
|
+
|
|
11
|
+
> **判档 = minor**(README「发版纪律」:新键 / 新导出 = minor)。新导出 1 名(`FLEET_SCOPE_ENV`,`.` 与 `./fleet` 各 +1)与一个新保留 env 名;
|
|
12
|
+
> 无新运行期行为、无新 wire 形。导出面登记表只多名字行,无删、无改形。
|
|
13
|
+
|
|
14
|
+
### 一、`FLEET_SCOPE_ENV = "FLEET_SCOPE"`
|
|
15
|
+
|
|
16
|
+
与 `FLEET_GENERATION_ENV` 同一处登记(`src/fleet.ts`)。配置渲染器把引擎所属租户 scope 渲进这个 env(与该成员 per-worker 令牌绑定的 scope 同值);
|
|
17
|
+
引擎读它作**自身身份的 scope**:排空口里拿 `DrainRequest.scope` 比对的那一格、续租体 `ServingLeaseRequest.scope`、心跳的 `?scope=`。
|
|
18
|
+
**一个事实一个源**:scope 由渲染器给,引擎**不从令牌的格式反推**(令牌对引擎是不透明串,格式猜测就是会与中心绑定值分歧的第二个源)。
|
|
19
|
+
**缺席 = 默认 scope**:值的唯一正本是 `GLOBAL_SCOPE`(`api/scopes`),与中心「请求里没有任何东西点名 scope」时读的是同一个缺省;常量头注只指向 `GLOBAL_SCOPE`,不复述字面量。
|
|
20
|
+
|
|
21
|
+
它同时进了保留 env 名表(`RESERVED_WORKER_ENV`):`WorkerSpec.env` / `secretEnv` 设它即被拒,拒因指路「set by the config renderer from the worker's scope — not configurable」;
|
|
22
|
+
渲染器是唯一写手。两侧都 import 常量,不各自拼字符串(整个 `src/` 里这个字面量只出现一次,有源码文本钉)。
|
|
23
|
+
|
|
24
|
+
### 用户可见变化(谁受影响 / 怎么改 / 不改会怎样)
|
|
25
|
+
|
|
26
|
+
1. **只用 schema / 读写 helper、不碰 fleet 的消费方**:零变化。
|
|
27
|
+
2. **配置渲染器(管理面)**:给 fleet 成员渲 env 时,用 `FLEET_SCOPE_ENV` 写该成员 per-worker 令牌绑定的 scope;不改会怎样:引擎读不到 scope,按上面的缺省读法把自己当 `GLOBAL_SCOPE` ——
|
|
28
|
+
非 `global` 租户的成员的身份 scope 与令牌绑定的 scope 不一致(续租体「在场必须相等」的规则下会被拒)。
|
|
29
|
+
3. **引擎(server)**:读 `FLEET_SCOPE_ENV` 作自身身份的 scope,缺席用 `GLOBAL_SCOPE`;不要从令牌格式反推。
|
|
30
|
+
4. **在 `WorkerSpec.env` / `secretEnv` 里设了 `FLEET_SCOPE` 的**:现在被拒(保留名),`migrateWorkersDomain` 对这样的行进 `refused`(8.2.0 起逐行终判)。
|
|
31
|
+
这个名字是本版才出现的,本包此前没有它;设过的删掉那一行,由渲染器写。**持有 `RESERVED_WORKER_ENV` 总数 / 名单断言的测试**要 +1(本仓的历史钉就是两例)。
|
|
32
|
+
|
|
33
|
+
### 红先 / 门
|
|
34
|
+
|
|
35
|
+
- 先写钉、对着改前的树跑红,再实现:`test/fleet-scope-env-8.3.0.test.ts` 七格(名逐字 + 两入口同值 + 字面量类型 / 保留表两直通面 + 拒因指路 + fleet 保留名恰两个 /
|
|
36
|
+
字面量在 `src/` 里恰一处 / 头注指向 `GLOBAL_SCOPE` 且不复述字面量、写清三件事)+ 两处既有钉的新读数(`test/engine-signal-8.1.0.test.ts` 保留 fleet 名单、
|
|
37
|
+
`test/migration-signpost-7.0.1.test.ts` 7.0.0 之后的增词表)⇒ 8 红;实装后全绿。
|
|
38
|
+
- 变异自证(七个,每个都使预期那一格红):常量值改字 / 删保留表那一行 / `src/` 里多一处字面量 / 头注写进 `"global"` / 头注删掉 `GLOBAL_SCOPE` / 头注删掉「不从令牌格式反推」句 /
|
|
39
|
+
导出面登记表删一行。
|
|
40
|
+
- 全量:build rc 0 · typecheck rc 0 · vitest 85 files / 1508 tests rc 0 · e2e rc 0 · `npm pack --dry-run` rc 0(360 文件,含 `dist/fleet-paths.json`,无 docs / scripts / test / src)。
|
|
41
|
+
- 导出面登记表(`docs/API-SURFACE.md`)重生成:`.` 与 `./fleet` 各 +1 名(`FLEET_SCOPE_ENV` — value),无删无改形。
|
|
42
|
+
|
|
43
|
+
### 未闭环(如实)
|
|
44
|
+
|
|
45
|
+
- **本包只定名与缺省,不含渲染器与引擎的实现**:「渲染器写、引擎读」的两端落地在各自仓,本包没有取它们源码的通道,两端是否都 import 这只常量没有机器门看。
|
|
46
|
+
- **`FLEET_SCOPE` 与令牌绑定的 scope 同值是渲染器的义务**:本包不判、也判不了(令牌不在本包);不一致时按各口既有的规则表现为拒(续租体 scope 在场必须与令牌绑定的相等)/ 比对不上,而不是静默错归属。
|
|
47
|
+
|
|
48
|
+
## 8.2.0 — 2026-10-08 — 迁移器逐行终判(行为改真)· fleet 端点常量与活性路由组 · 心跳三键收型 · 中心能力位的承载键 · 两处注释改真
|
|
49
|
+
|
|
50
|
+
> **判档 = minor**(README「发版纪律」:新键 / 新导出 = minor)。新导出 6 名(`LEASE_STATES` / `LeaseState` / `FLEET_PATHS` / `FLEET_LIVE_PATHS` /
|
|
51
|
+
> `HEARTBEAT_REPLY_CAPABILITIES_KEY`,`.` 与 `./fleet` 各 +5;`LeaseState` 是值 + 类型)+ 一个资产出口 `./fleet-paths.json`;`EngineSignal` 与 `InstanceAnnouncement`
|
|
52
|
+
> 各多可选键(无默认)。**唯一一处行为改真**是第一节的迁移器:它改变的是**读侧本来就拒**的文档的迁移结局(多一类 `refused` 行),合法文档的迁移结局与
|
|
53
|
+
> 读数一字不变(金样 m01–m04 与全部语料零 diff)。导出面登记表只多名字行,无删、无改形。
|
|
54
|
+
|
|
55
|
+
### 一、`migrateWorkersDomain` 逐行终判(行为改真:多一类 refused 行)
|
|
56
|
+
|
|
57
|
+
**病**(管理面实测):一份已是 7.x 形、三行都不需要迁的 workers 文档里,一台在 `env` 里设了 `FLEET_GENERATION`(8.1.0 起的保留名)——
|
|
58
|
+
迁移回 `changed: []` / `refused: []`,随后 `parseDomain("workers")` 整域抛:管理面 workers 唯一读口整域读不出,一行坏把整份舰队清单拖黑;
|
|
59
|
+
CLI 对同一份文件报 `outcome=noop` / 退出 0。根因:迁移的终判(`WorkerSpec.safeParse`)只对**它改写过的行**跑,没动的行直接放行 ——
|
|
60
|
+
于是迁移与读侧对同一行各说各话,任何「存下来时合法、后来被收紧的判据拒掉」的行(保留名表变长只是其中一例)都走这条缝。
|
|
61
|
+
|
|
62
|
+
**修**(规则替换,不是加一条):终判**逐行**,迁过的行与没动的行同一只 —— 每一只认得出名字(字符串 `name`)的 worker 都过读侧自己的判据:
|
|
63
|
+
**只含这一行的 workers 域**读不读得进(`WorkersConfig`,就是 `parseDomain("workers")` 用的那一只 schema;逐行的规则写在 `WorkerSpec` 里的、
|
|
64
|
+
写在域层的(`replicas` 与 `autoscaling` 互斥)都在,跨行规则一行时不触发)。读不进 ⇒ `refused`(`name` + `field` = schema issue 相对该行的路径 +
|
|
65
|
+
`reason` = schema 自己的原句,前缀说明是迁出形 `after migration the worker …` 还是存储形 `the stored worker …`;`original` 照旧逐字带回)。
|
|
66
|
+
迁移不复述任何一条写闸规则、不另抄保留名表。整域读侧仍是最后围栏,只剩两类归它:认不出名字的条目(迁移不判形,原样留在 `doc`)与跨行规则
|
|
67
|
+
(名字 / 路由前缀唯一)。迁过的行的终判拒因原句从 `after migration the worker is not a valid 7.0.0 WorkerSpec — …` 改成 `… is not a valid WorkerSpec — …`
|
|
68
|
+
(判据是当前版本的 schema,8.1.0 的保留名也在里面,「7.0.0」已不准)。
|
|
69
|
+
|
|
70
|
+
**拒因不回显输入值**(车内对抗复审的发现,修在同一版):zod 自带的枚举拒句以 `, received '<填的值>'` 收尾 —— 迁过的行的终判拒因与 CLI 整域终判的报告
|
|
71
|
+
早就会带出它(8.1.0 已有),逐行终判又把没动的行也接到这条路上。现在 issue 一律经同一只渲染(内部 `issueText`,不在任何子路径上):
|
|
72
|
+
枚举拒句只按它的闭集重写成 `Invalid enum value. Expected 'a' | 'b'`,其余 issue 的句子照旧(zod 的其余默认句只说期望的形,不带输入)。
|
|
73
|
+
迁移的 `refused[].reason`、CLI 报告的 `refused[].reason` 与 stderr 结论句三处同用。
|
|
74
|
+
|
|
75
|
+
### 二、心跳三键收型:`LEASE_STATES` / `LeaseState` · `EngineSignal.leaseState?` · `InstanceAnnouncement` 不再剥三键(additive)
|
|
76
|
+
|
|
77
|
+
- **`LEASE_STATES = ["none", "granted", "expired", "denied"]`**(+ zod `LeaseState` 与同名类型)—— 引擎持有的服务租约四态,闭集在这里定一次(引擎的词表逐字同序):
|
|
78
|
+
`none` = 租约不生效(中心没宣告 `servingLease` 位;行为与没有租约的引擎逐字同)· `granted` = 持有租约(`leaseUntil` 说到何时)·
|
|
79
|
+
`expired` = 租约生效但此刻没有有效授予(中心不可达 / 答 `unknown` / 尚未首授;照常服务直到引擎自己的不可达上限,不是被拒)·
|
|
80
|
+
`denied` = 中心凭正面证据拒了本实例(黏性,已排空、到期自停)。只有 fleet 成员说它;非成员没有这个键(没有第五个词表示「非成员」,缺席就是)。
|
|
81
|
+
- **`EngineSignal.leaseState?`**:闭形多一键(引的就是 `LeaseState` 那一只 schema);`leaseUntil` 的注改准为「在场 ⇔ `leaseState` 是 `granted`」。
|
|
82
|
+
`readEngineSignal` 原样读出;集外词按 `EngineSignal` 既有的律整只 `undefined`。
|
|
83
|
+
- **`InstanceAnnouncement` 加 `generation?` / `leaseState?` / `leaseUntil?`**(心跳此前把这三键 strip 掉 —— 引擎早已在每拍心跳上平铺它们,中心读不到):
|
|
84
|
+
三键各自**引用** `EngineSignal` 上同名键的那一只 schema(规范代际串 / `LeaseState` / 非负整数 ms),不抄第二份;存下来的行(`InstanceRegistration`)随之带着。
|
|
85
|
+
**失败方向随含义**:三键是中心留存的证据、不是路由输入 —— 形坏的那一键落成缺席(`.catch`,与 `modelRefusals` 同姿势),心跳照收、可路由性不变;
|
|
86
|
+
所以引擎以后多一个租约词,老中心不会因此拒掉它的每一拍心跳。三键之间的在场律(成员 ⇒ `generation` + `leaseState`;`leaseUntil` ⇔ `granted`)是引擎的律,本形不跨键判。
|
|
87
|
+
- 金样:引擎今天真发的心跳体(成员 · granted / expired 两拍、单机形)入 `test/fleet-8.2.0.test.ts`。
|
|
88
|
+
|
|
89
|
+
### 三、两处注释改真(零行为)
|
|
90
|
+
|
|
91
|
+
- **`EngineSignal` 头注**:8.1.0 写的「心跳与 `/health` 携带同名键、同值,平铺在体上,`readEngineSignal` 读哪一个都行」(本档 8.1.0 第二节同句)**不成立**,
|
|
92
|
+
且与同一份注里「心跳 / `InstanceAnnouncement` 的 `draining` 是布尔」自相矛盾。照实改为:两出口今天都不整只承载这只信号 ——
|
|
93
|
+
① 心跳恒带布尔 `draining`(含 `false`),`/health` 只在排空时带 `draining: true`;② `/health` 只在**未**就绪时带 `ready`;③ 引擎把 `configTargetVersion` /
|
|
94
|
+
`configAppliedVersion` 写成数,本形是串。所以 `readEngineSignal` 对今天任何心跳体恒 `undefined`,对 `/health` 体在三条任一成立时 `undefined`;两出口同名同值平铺的
|
|
95
|
+
只有 `restart` / `instanceId` / `generation` / `leaseState` / `leaseUntil`(心跳上读解析后的 `InstanceAnnouncement`)。下一个 major 退布尔对、两出口整只承载、两只路由谓词改吃它。
|
|
96
|
+
`readEngineSignal` 的注同步(不再说「两出口键都平铺、哪个都能读」)。README / llms-full 的同句一并改。
|
|
97
|
+
- **`ServingLeaseRequest.scope` 注**:8.1.0 写「缺席 = 单 scope 部署」。改成续租的令牌规则一句话:续租**只收 per-worker 令牌**(凭证绑定 (scope, worker)),
|
|
98
|
+
所以 scope 由凭证定、本字段只能附和 —— 缺席 = 令牌绑定的 scope;在场必须与之相等(不符即拒,两头都不改写);**共享令牌不得续租**(中心答 403)。
|
|
99
|
+
- **心跳一侧的 scope 规则写在 `InstanceAnnouncement` 注上**:心跳体**没有** `scope` 键(本形没有这个键,发了也被 strip);行落在凭证点名的 scope ——
|
|
100
|
+
per-worker 令牌 = 令牌绑定的 scope(给了 `?scope=` 就必须相等);共享令牌 = `?scope=`,缺席 ⇒ `"global"`。这条是心跳的,不是续租的。
|
|
101
|
+
- 钉:`test/fleet-8.2.0.test.ts` ③ —— 四格注释文本钉(续租注不许出现 `?scope=` / `"global"`;在改前的注上红)+ 两格行为钉(引擎今天真发的心跳 / `/health` 金样上
|
|
102
|
+
`readEngineSignal` 的读数,本来就绿:注改的是话,不是行为);心跳注那一格顺带钉「心跳体里的 `scope` 被 strip」。
|
|
103
|
+
|
|
104
|
+
### 四、fleet 端点常量:`FLEET_PATHS` · `FLEET_LIVE_PATHS` · 随包的 `fleet-paths.json`(additive)
|
|
105
|
+
|
|
106
|
+
**病**:fleet 端点路径两仓各拼一份,已经对不上 —— 引擎续租打 `/api/fleet/serving-lease`,管理面活性组预留的是 `/api/fleet/live/serving-lease`
|
|
107
|
+
(中心一宣告 `servingLease` 位,全舰队续租就 404);心跳 / 用量 / 配额租约三条也是两侧手写字面。
|
|
108
|
+
|
|
109
|
+
- **`FLEET_PATHS`**(`as const`,形照 `AUTH_V1_PATHS` 先例)—— 中心外部按路径打到的 `/api/fleet/*` 端点,一种拼法:
|
|
110
|
+
`instances: "/api/fleet/instances"`(心跳 `POST` / 告别 `DELETE`)· `usage: "/api/fleet/usage"` · `quotaLeases: "/api/fleet/leases"` ·
|
|
111
|
+
`servingLease: "/api/fleet/live/serving-lease"` · `hostPlanner: "/api/fleet/live/host-planner/{host}"`(执行器读一台 host 的规划记录;体是中心与执行器的契约,
|
|
112
|
+
不在本包 —— 它在这里是因为部署要把它当活性组成员路由)。成员律:本包定形其体的端点 ∪ 活性组成员;中心内部路由不在。
|
|
113
|
+
记法:值是路径**模板**,参数只以整段 `{name}` 出现(只有 `hostPlanner` 有);前缀路由(Ingress)取第一个 `{` 之前的部分。
|
|
114
|
+
**没有能力读口端点**:中心能力位的唯一载体是心跳 2xx 答复体(见第五节)。
|
|
115
|
+
- **`FLEET_LIVE_PATHS`** = `[instances, servingLease, hostPlanner]` —— 活性路由组:中心不经就绪门、不经配置治理门作答的那组(不读配置域、只收服务凭证),
|
|
116
|
+
部署把它们路由过就绪门(Kubernetes:第二个 `publishNotReadyAddresses` 的 Service,Ingress 规则指向它)。**组是这张表,不是路径前缀**(心跳早于 `/api/fleet/live/`
|
|
117
|
+
前缀);`FLEET_PATHS` 里 `/api/fleet/live/` 下的每一条都在组里;配额租约与用量不在。值就是 `FLEET_PATHS` 里那几只串,不是第二份拼写。
|
|
118
|
+
- **`@sema-agent/settings-schema/fleet-paths.json`**(新资产出口 → `dist/fleet-paths.json`)= `{ "FLEET_PATHS": …, "FLEET_LIVE_PATHS": … }`:给 import 不了 TS 的工具
|
|
119
|
+
(Helm 模板、冒烟脚本)对表。`npm run build` 在 tsc 之后由 `scripts/gen-fleet-paths.mjs` 从**构建出的** `dist/fleet.js` 写出(脚本里没有路径字面),不手改;
|
|
120
|
+
钉它与常量逐字同(常量改了没重建 ⇒ 红)。导出面登记表表头的资产出口清单改成从 exports 表派生(原先手写只有 `./package.json`)。
|
|
121
|
+
- 钉:`src/` 里 `"/api/fleet/` 起头的字面量只出现在 `FLEET_PATHS` 那几行(第二处拼写 ⇒ 红)。
|
|
122
|
+
|
|
123
|
+
### 五、中心能力位的承载键:`HEARTBEAT_REPLY_CAPABILITIES_KEY = "capabilities"`(additive)+ `CenterCapabilities` 注改真
|
|
124
|
+
|
|
125
|
+
- 中心把 `CenterCapabilities` 放在**心跳 2xx 答复体**的哪个键下 —— 这是能力对象的**唯一载体**(没有独立的能力读口;一事实一载体)。中心写
|
|
126
|
+
`{ …, [HEARTBEAT_REPLY_CAPABILITIES_KEY]: caps }`,引擎读 `readCenterCapabilities(reply[HEARTBEAT_REPLY_CAPABILITIES_KEY])`,且只在 2xx 时读;嵌套不平铺
|
|
127
|
+
(答复体自己的键与能力位不共享命名空间);答复体没有这个键 = 老中心,什么位都没说。两仓不再各写字面(`src/` 里这个键名字面量只出现在常量那一行,有钉)。
|
|
128
|
+
- `CenterCapabilities` 注:撤 8.1.0 的「本包只定形与读器、不定哪个中心端点承载」;改为「唯一载体 = 心跳 2xx 答复体的这个键」,并加一句
|
|
129
|
+
**位按调用方凭证答**:per-worker 令牌按中心实际支持的答;共享令牌下 `servingLease` 恒缺席(续租端点只收 per-worker 令牌,对共享令牌宣告只会把它推进不可达臂)。
|
|
130
|
+
- 金样:老中心 `{ ok: true }` ⇒ `undefined`;`{ ok: true, capabilities: {} }` ⇒ `{}`;`{ ok: true, capabilities: { servingLease: true } }` ⇒ 启用;位平铺在答复体上不算。
|
|
131
|
+
|
|
132
|
+
### 用户可见变化(谁受影响 / 怎么改 / 不改会怎样)
|
|
133
|
+
|
|
134
|
+
1. **管理面的 workers 读口(调 `migrateWorkersDomain` 的)**:一行设了保留名(或别的逐行读不进的形)的文档,以前整域读失败,现在那一行进 `refused`、其余照常加载。
|
|
135
|
+
按契约「`refused` 行保住它正在跑的负载、不当删除」处理的,零动作;不改会怎样:没这样处理的编排器会把那一行当成缺席。
|
|
136
|
+
2. **`migrate-workers` CLI 的脚本**:上面那类文件以前 `outcome=noop` / 退出 0,现在 `outcome=refused` / 退出 1、一字不写;读 `refused[].reason` 原句的,
|
|
137
|
+
迁过的行的终判拒因少了「7.0.0」,没动的行的拒因以 `the stored worker` 起头;枚举拒句不再带 `received '<值>'`。
|
|
138
|
+
3. **引擎(续租客户端)**:续租路径改 import `FLEET_PATHS.servingLease`(`/api/fleet/live/serving-lease`);不改会怎样:中心按包常量注册续租路由后,手写
|
|
139
|
+
`/api/fleet/serving-lease` 的引擎续租得 404(走不可达臂)。心跳答复体的能力对象改读 `reply[HEARTBEAT_REPLY_CAPABILITIES_KEY]`。
|
|
140
|
+
4. **中心**:心跳 / 用量 / 配额租约 / 续租 / HostPlanner 的路由路径与活性组表从 `FLEET_PATHS` / `FLEET_LIVE_PATHS` 取;能力对象写在
|
|
141
|
+
`HEARTBEAT_REPLY_CAPABILITIES_KEY` 下;心跳解析结果里现在有 `generation` / `leaseState` / `leaseUntil`(存行 `InstanceRegistration` 随之)。
|
|
142
|
+
5. **部署(Helm / 冒烟)**:活性组路由与对表读 `@sema-agent/settings-schema/fleet-paths.json`(`FLEET_LIVE_PATHS`;`{host}` 是路径参数,前缀路由取 `{` 之前)。
|
|
143
|
+
6. **对 `EngineSignal` / `InstanceAnnouncement` 的键做穷举的**:多出的键编译红(提货成本,补一行)。**持 `LEASE_STATES` 穷举的**:以后加词同理。
|
|
144
|
+
|
|
145
|
+
### 红先 / 门
|
|
146
|
+
|
|
147
|
+
- 每节先写钉、对着改前的树跑红,再实现:第一节 `test/migrate-workers-row-verdict-8.2.0.test.ts` 20 格(基线 14 红;6 绿是干净文档幂等、两格最后围栏、
|
|
148
|
+
整域读侧对照等反向格;其中 3 格「拒因不回显值」是复审后补的,在复审前的树上红)+ 金样 m05;第二节 `test/fleet-8.2.0.test.ts` ④ 12 格(8 红;4 绿 = 旧形不铸键、失败方向、类型面等反向格);第三节 ③ 4 格注释文本钉
|
|
149
|
+
(改前的注上红;其中心跳注那一格顺带钉「心跳体里的 `scope` 被 strip」)+ 2 格行为钉(本来就绿:注改的是话);第四节 ② 11 格(常量格在缺常量的树上红,
|
|
150
|
+
JSON 三格随生成器同提交、以变异自证咬合);第五节 ⑤ 4 格(基线全红)。
|
|
151
|
+
`test/engine-signal-8.1.0.test.ts` 两格键集钉随 additive 加键改;`test/conformance-workers-7.0.0.test.ts` 金样清单四份 → 五份。
|
|
152
|
+
- 变异自证(26 个变异,每个都至少使预期那一格红):没动的行跳过终判 / 判据退回 `WorkerSpec` / 手抄保留名表 / `field` 不去前缀 / 拒因措辞对调 / `original` 被拷贝;
|
|
153
|
+
心跳 `leaseState` 严判 / 抄第二份 / 改词 / `EngineSignal.leaseState` 收任意串 / 心跳 `generation` 不判规范 / 丢 `leaseUntil` / `EngineSignal` 无 `leaseState`;
|
|
154
|
+
能力端点回来 / 活性组二次拼写 / 少 HostPlanner / 多配额租约 / 引擎侧旧续租拼法 / 冒号参数记法 / JSON 过期;键名改字 / 第二处字面 / 能力位注回旧句。
|
|
155
|
+
- 全量:build rc 0 · typecheck rc 0 · vitest 84 files / 1501 tests rc 0 · e2e rc 0 · `npm pack --dry-run` rc 0(360 文件,含 `dist/fleet-paths.json`,无 docs / scripts / test / src)。
|
|
156
|
+
- 导出面登记表(`docs/API-SURFACE.md`)重生成:`.` 与 `./fleet` 相对 8.1.0 各 +5 名,无删无改形;表头的资产出口清单改为从 exports 表派生。
|
|
157
|
+
|
|
158
|
+
### 未闭环(如实)
|
|
159
|
+
|
|
160
|
+
- **`EngineSignal` 今天在两个出口上都读不出**(第三节):心跳的布尔 `draining`、`/health` 就绪时缺 `ready`、引擎把世代账两键写成数而本形是串 ——
|
|
161
|
+
第三条是契约与引擎的形不一致,本版只照实写进注,不改形(改 `configTargetVersion` / `configAppliedVersion` 的型是收紧 = major);收口在下一个 major
|
|
162
|
+
与引擎同版翻转。
|
|
163
|
+
- **心跳三键之间的在场律不判**(成员 ⇒ `generation` + `leaseState`;`leaseUntil` ⇔ `granted`):是引擎的律,本形逐键判、不跨键判。
|
|
164
|
+
- **`LEASE_STATES` 与引擎词表的对齐是人读的**:本仓没有取引擎源码的通道,词表逐字照引擎今天的四词定,没有机器门看「引擎加词而本包没跟」。
|
|
165
|
+
- **迁移器的 `field` 粒度随读侧 issue 路径**:保留名拒的 `field` 是 `["env"]` / `["secretEnv"]`(读侧的保留名判据挂在整张表上),键名在 `reason` 里;
|
|
166
|
+
要指到 `["env", <键>]` 得改读侧的 issue 路径(诊断面,另一件)。
|
|
167
|
+
- **CLI 的 `noop` 不跑整域终判**:一份不需要迁、逐行都读得进、但跨行冲突(名字重复)的文件仍报 `noop` / 退出 0(既有行为,本版未动)。
|
|
168
|
+
|
|
9
169
|
## 8.1.0 — 2026-10-08 — 引擎自铸信号的共享型:`RestartSignal.withheld` · `EngineSignal` · 服务租约 API 型与中心能力位 · 排空请求 / 回执型 · fleet env 名常量(全部 additive)
|
|
10
170
|
|
|
11
171
|
> **判档 = minor**(README「发版纪律」:新键 / 新导出 = minor)。本版只加**型与契约**,零行为:既有字段的语义、`InstanceHealth` / `InstanceAnnouncement`
|
package/README.md
CHANGED
|
@@ -48,13 +48,46 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
48
48
|
> a zod-3 host (today the config-center product) still dedups to one instance. Moving this package to zod 4 is a major
|
|
49
49
|
> of its own (S-777); 6.2.0 does not touch the dependency or peer range.
|
|
50
50
|
|
|
51
|
+
## 升级指引:8.2.0 → 8.3.0(additive,零动作可升)
|
|
52
|
+
|
|
53
|
+
`./fleet`(与主入口)多一个 env 名常量 `FLEET_SCOPE_ENV = "FLEET_SCOPE"`:成员所属租户 scope,渲染器写、引擎读(缺席 = `GLOBAL_SCOPE`),同时进 `RESERVED_WORKER_ENV`(`worker.env` / `secretEnv` 设它被拒)。逐条见 CHANGELOG 8.3.0。
|
|
54
|
+
|
|
55
|
+
## 升级指引:8.1.0 → 8.2.0(additive + 迁移器一处行为改真)
|
|
56
|
+
|
|
57
|
+
**行为改真(一处)—— `migrateWorkersDomain` 终判逐行**:每一只有字符串名字的 worker(迁过的、没动的一样)都要读得进「只含它一行的 workers 域」
|
|
58
|
+
(读侧的 `WorkersConfig`,不另抄保留名表),读不进就进 `refused`;以前只判迁过的行,没动的行直接放行。
|
|
59
|
+
|
|
60
|
+
- **谁需要**:管理面的 workers 唯一读口 —— 以前一份已是 7.x 形的文档里只要一行在 `env` 里设了保留名(例:8.1.0 起的 `FLEET_GENERATION`),迁移报零变化,
|
|
61
|
+
随后 `parseDomain("workers")` 整域抛,整份舰队清单读不出;现在那一行进 `refused`(名字 + `field` + 读侧原句),其余行照常加载。文件后端 / 离线的
|
|
62
|
+
`migrate-workers` CLI 同理:那份文件以前报 `outcome=noop` / 退出 0(说「没事」),现在报 `outcome=refused` / 退出 1、一字不写、`refused[]` 点名那一行。
|
|
63
|
+
- **谁受伤**:① 读口把 `refused` 当「不加载」的消费方 —— 一行以前让整域读失败(什么都不加载),现在只有它不加载;按「`refused` 行保住它正在跑的负载、不当删除」
|
|
64
|
+
处理的编排器(契约要求,见 `WorkersMigrationRefusal.original`)不受影响,没这样处理的会把这一行当成缺席。② 把 `migrate-workers` 退出 0 当「文件可用」的脚本:
|
|
65
|
+
这类文件现在退出 1。③ 读 `refused[].reason` 原句的:迁过的行的终判拒因从 `… not a valid 7.0.0 WorkerSpec — …` 改成 `… not a valid WorkerSpec — …`,
|
|
66
|
+
没动的行的拒因前缀是 `the stored worker …`。
|
|
67
|
+
- **补偿**:`refused[]` 逐条带 `name` / `index` / `field` / `reason` 与原行逐字(`original`),写回前按 `index` 放回 —— 运维的 spec 不丢;修法 = 改掉 `field` 指的那一格
|
|
68
|
+
(保留名:删掉 `env` / `secretEnv` 里那一键,由它的唯一写位产出)。整域读侧仍是最后围栏,只剩两类归它:没有字符串名字的条目与跨行唯一性(名字 / 路由前缀)。
|
|
69
|
+
|
|
70
|
+
**additive(零动作可升)**,全在 `./fleet`(与主入口)上:
|
|
71
|
+
|
|
72
|
+
- `LEASE_STATES` / `LeaseState` —— 引擎持有的服务租约四态闭集 `none | granted | expired | denied`。
|
|
73
|
+
- `EngineSignal.leaseState?`;`InstanceAnnouncement` 不再剥 `generation?` / `leaseState?` / `leaseUntil?`(引 `EngineSignal` 同名键那一只 schema;形坏的那一键落成缺席,心跳照收)。
|
|
74
|
+
- `FLEET_PATHS`(`instances` / `usage` / `quotaLeases` / `servingLease` = `/api/fleet/live/serving-lease` / `hostPlanner` = `/api/fleet/live/host-planner/{host}`)、
|
|
75
|
+
`FLEET_LIVE_PATHS`(活性路由组:心跳 / 续租 / HostPlanner 读口)与新资产出口 `@sema-agent/settings-schema/fleet-paths.json`(同两只常量的 JSON,构建时写)。
|
|
76
|
+
**引擎侧注意**:续租路径以 `FLEET_PATHS.servingLease` 为准(`/api/fleet/live/serving-lease`),不是 `/api/fleet/serving-lease`。
|
|
77
|
+
- `HEARTBEAT_REPLY_CAPABILITIES_KEY = "capabilities"` —— `CenterCapabilities` 的唯一载体是心跳 2xx 答复体的这个键;位按调用方凭证答(共享令牌看不到 `servingLease`)。
|
|
78
|
+
- 注释改真:`EngineSignal`(今天的心跳与 `/health` 都不整只承载它 —— 心跳恒带布尔 `draining`,`readEngineSignal` 读今天的心跳体恒 `undefined`)、
|
|
79
|
+
`ServingLeaseRequest.scope`(续租只收 per-worker 令牌;缺席 = 令牌的 scope,在场必须相等;共享令牌不得续租)。
|
|
80
|
+
|
|
81
|
+
提货成本:对 `EngineSignal` / `InstanceAnnouncement` 的键做穷举的消费方会因多出的键编译红;对 `LEASE_STATES` 穷举的,以后加词同理。逐条见 CHANGELOG 8.2.0。
|
|
82
|
+
|
|
51
83
|
## 升级指引:8.0.0 → 8.1.0(全部 additive,零动作可升)
|
|
52
84
|
|
|
53
85
|
8.1.0 只在 `./fleet`(与主入口)上**加**型与契约,零行为:既有字段的语义、`InstanceHealth` / `InstanceAnnouncement` 的形、两个就绪谓词一字未动。新增清单:
|
|
54
86
|
|
|
55
87
|
- `RestartSignal.withheld?` —— 可选布尔,引擎自判「这一拍不该被换代」;缺席 = `false`,读出形不铸键。
|
|
56
88
|
- `EngineSignal`(+ `EngineDraining`)与 `readEngineSignal(health)` —— 引擎自铸信号的**闭形**(`ready` 必填,`draining?` / `restart?` / `generation?` / `instanceId?` /
|
|
57
|
-
`leaseUntil?` / `configTargetVersion?` / `configAppliedVersion?` 可选)
|
|
89
|
+
`leaseUntil?` / `configTargetVersion?` / `configAppliedVersion?` 可选);与既有读器走同一只受保护读口。⚠️ 8.2.0 订正:今天的心跳与 `/health` 都不整只
|
|
90
|
+
承载它(心跳恒带布尔 `draining`、`/health` 就绪时不带 `ready`、世代账两键是数),`readEngineSignal` 对今天的心跳体恒 `undefined` —— 见 8.2.0 升级指引。
|
|
58
91
|
`undefined` = 没有这只信号,**不是就绪**;布尔 `draining` 的旧方言体读不出它(两个就绪谓词的输入仍是布尔方言,下一个 major 收)。
|
|
59
92
|
- 代际 —— `generation` 是非负整数的**规范十进制串**(`"7"`,不是 `"07"`、不是数字型),判别器 `isCanonicalGeneration`、数值比较 `compareGeneration`;三处 wire 形共用这一条判据。
|
|
60
93
|
- 服务租约 API 型 —— `ServingLeaseRequest`、`ServingLeaseResponse`(`granted { ttlMs }` / `denied { reason: superseded | retired }` / `unknown` 三词闭集,
|
|
@@ -128,7 +161,11 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
128
161
|
`bin`; writes only when every worker migrates). Workers it cannot lift (an enabled worker with no
|
|
129
162
|
`env.REMOTE_EXEC` — the migration never guesses a lane) come back in `refused` with the field to fix and the
|
|
130
163
|
`original` row verbatim — they are NOT in the migrated `doc`, so a caller that writes `doc` back must put each
|
|
131
|
-
`refused[].original` back at its `index` (or store it aside), or that worker's spec disappears.
|
|
164
|
+
`refused[].original` back at its `index` (or store it aside), or that worker's spec disappears. The final judgement
|
|
165
|
+
is per row (since 8.2.0 the same one for rows it rewrote and rows it left alone): every worker with a string name must read
|
|
166
|
+
as a one-row workers domain under the read side's own `WorkersConfig`, or it goes to `refused` — so each row of `doc`
|
|
167
|
+
reads on its own; what the whole-domain read can still refuse is a nameless entry (left as is) and the cross-row rules
|
|
168
|
+
(unique names / route prefixes).
|
|
132
169
|
- **`migrate-workers` CLI: report shape + rejection signposts (7.0.1)** (`bin/settings-schema.mjs`, core in `cli.ts`):
|
|
133
170
|
`npx @sema-agent/settings-schema migrate-workers <workers.json> [--check]` prints exactly two lines on stdout (exit 0 / 1 / 3): line 1 is the
|
|
134
171
|
ONE conclusion line `outcome=<refused|applied|noop|pending> written=<true|false>`, line 2 is the JSON report (`event: "workers_domain_migrated"`,
|
|
@@ -294,7 +331,7 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
294
331
|
optional `withheld` ("the engine says this beat must not be handed to a new generation"; absent ≡ false);
|
|
295
332
|
`EngineSignal` (`{ ready, draining?: EngineDraining, restart?, generation?, instanceId?, leaseUntil?,
|
|
296
333
|
configTargetVersion?, configAppliedVersion? }`) is the closed form of the engine-minted subset of the /health
|
|
297
|
-
self-description (
|
|
334
|
+
self-description (`InstanceHealth` stays the open record; neither exit carries it whole yet — see its doc comment) and
|
|
298
335
|
`readEngineSignal(health)` reads it through the same guarded reader as `readRestartSignal` / `readModelRefusals` —
|
|
299
336
|
`undefined` means "no such signal", never "ready", and a body carrying the boolean `draining` of the 8.0 dialect is not
|
|
300
337
|
one. The serving-lease wire (`ServingLeaseRequest` / `ServingLeaseResponse`: `granted { ttlMs }` | `denied { reason:
|
|
@@ -304,6 +341,15 @@ therefore shows only `zod`. Node built-ins only (`node:crypto`, `node:fs`).
|
|
|
304
341
|
(`servingLease?: true` — absent means the center has no lease, so the engine neither renews nor is fenced), the drain
|
|
305
342
|
endpoint's `DrainRequest` / `DrainReceipt`, one reader per wire shape, and the env name `FLEET_GENERATION_ENV` are defined
|
|
306
343
|
here once for the renderer and the engine (an instance's id is minted by the engine per process — it has no env name).
|
|
344
|
+
**8.2.0** (additive) adds the engine's lease vocabulary `LEASE_STATES` (`none | granted | expired | denied`) as
|
|
345
|
+
`EngineSignal.leaseState?`, keeps `generation` / `leaseState` / `leaseUntil` on the heartbeat (`InstanceAnnouncement` no longer
|
|
346
|
+
strips them; a malformed one drops to absent, the heartbeat still lands), spells the center's fleet endpoints once —
|
|
347
|
+
`FLEET_PATHS` (heartbeat, usage, quota leases, serving lease `/api/fleet/live/serving-lease`, host planner
|
|
348
|
+
`/api/fleet/live/host-planner/{host}`) and the liveness group `FLEET_LIVE_PATHS` (heartbeat, serving lease, host planner), also
|
|
349
|
+
shipped as `@sema-agent/settings-schema/fleet-paths.json` for tooling that cannot import TypeScript — and names the one carrier of
|
|
350
|
+
the center's capability bits: `HEARTBEAT_REPLY_CAPABILITIES_KEY` (`"capabilities"`) on the heartbeat's 2xx reply.
|
|
351
|
+
**8.3.0** (additive) adds the env name `FLEET_SCOPE_ENV` (`"FLEET_SCOPE"`) — the tenant scope a fleet member belongs to, set by the
|
|
352
|
+
config renderer and read by the engine as its own identity's scope (absent ⇒ `GLOBAL_SCOPE`); a reserved worker env name.
|
|
307
353
|
- **Declared-but-unvalidated keys** (`PARSE_TRANSPARENT_KEYS`, 2.0.0): the ONE registry of keys this package
|
|
308
354
|
carries verbatim WITHOUT checking their shape, each row naming who does check it (the engine's ingest side or
|
|
309
355
|
a consumer's enforcement point). Today: `models[].compat` (1.10.0), `models[].headers` (6.4.0; the header-name
|
package/conformance/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.
|
|
1
|
+
8.3.0
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"doc": {
|
|
3
|
+
"workers": [
|
|
4
|
+
{
|
|
5
|
+
"name": "alpha",
|
|
6
|
+
"enabled": true,
|
|
7
|
+
"host": "default",
|
|
8
|
+
"image": "sema-server:latest",
|
|
9
|
+
"secretRefs": {
|
|
10
|
+
"apiKeyEnv": "MODEL_KEY"
|
|
11
|
+
},
|
|
12
|
+
"runtime": {
|
|
13
|
+
"requirePrincipal": false,
|
|
14
|
+
"rateLimitRpm": 0,
|
|
15
|
+
"execution": {
|
|
16
|
+
"lane": "host",
|
|
17
|
+
"coords": {},
|
|
18
|
+
"secretRefs": {}
|
|
19
|
+
},
|
|
20
|
+
"store": {
|
|
21
|
+
"backend": "local",
|
|
22
|
+
"session": "auto"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"coords": {}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "gamma",
|
|
29
|
+
"enabled": false,
|
|
30
|
+
"host": "default",
|
|
31
|
+
"image": "sema-server:latest",
|
|
32
|
+
"secretRefs": {
|
|
33
|
+
"apiKeyEnv": "MODEL_KEY"
|
|
34
|
+
},
|
|
35
|
+
"runtime": {
|
|
36
|
+
"requirePrincipal": false,
|
|
37
|
+
"rateLimitRpm": 0
|
|
38
|
+
},
|
|
39
|
+
"coords": {}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"changed": [],
|
|
44
|
+
"dropped": [],
|
|
45
|
+
"refused": [
|
|
46
|
+
{
|
|
47
|
+
"name": "beta",
|
|
48
|
+
"index": 1,
|
|
49
|
+
"field": [
|
|
50
|
+
"env"
|
|
51
|
+
],
|
|
52
|
+
"reason": "the stored worker is not a valid WorkerSpec — env: env cannot set reserved key \"FLEET_GENERATION\" — set it via (set by the config renderer from the worker's generation — not configurable)",
|
|
53
|
+
"original": {
|
|
54
|
+
"name": "beta",
|
|
55
|
+
"enabled": true,
|
|
56
|
+
"host": "default",
|
|
57
|
+
"image": "sema-server:latest",
|
|
58
|
+
"secretRefs": {
|
|
59
|
+
"apiKeyEnv": "MODEL_KEY"
|
|
60
|
+
},
|
|
61
|
+
"runtime": {
|
|
62
|
+
"requirePrincipal": false,
|
|
63
|
+
"rateLimitRpm": 0,
|
|
64
|
+
"execution": {
|
|
65
|
+
"lane": "host",
|
|
66
|
+
"coords": {},
|
|
67
|
+
"secretRefs": {}
|
|
68
|
+
},
|
|
69
|
+
"store": {
|
|
70
|
+
"backend": "local",
|
|
71
|
+
"session": "auto"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"coords": {},
|
|
75
|
+
"env": {
|
|
76
|
+
"FLEET_GENERATION": "7",
|
|
77
|
+
"LOG_LEVEL": "debug"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"workers": [
|
|
3
|
+
{
|
|
4
|
+
"name": "alpha",
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"host": "default",
|
|
7
|
+
"image": "sema-server:latest",
|
|
8
|
+
"secretRefs": {
|
|
9
|
+
"apiKeyEnv": "MODEL_KEY"
|
|
10
|
+
},
|
|
11
|
+
"runtime": {
|
|
12
|
+
"requirePrincipal": false,
|
|
13
|
+
"rateLimitRpm": 0,
|
|
14
|
+
"execution": {
|
|
15
|
+
"lane": "host",
|
|
16
|
+
"coords": {},
|
|
17
|
+
"secretRefs": {}
|
|
18
|
+
},
|
|
19
|
+
"store": {
|
|
20
|
+
"backend": "local",
|
|
21
|
+
"session": "auto"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"coords": {}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "beta",
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"host": "default",
|
|
30
|
+
"image": "sema-server:latest",
|
|
31
|
+
"secretRefs": {
|
|
32
|
+
"apiKeyEnv": "MODEL_KEY"
|
|
33
|
+
},
|
|
34
|
+
"runtime": {
|
|
35
|
+
"requirePrincipal": false,
|
|
36
|
+
"rateLimitRpm": 0,
|
|
37
|
+
"execution": {
|
|
38
|
+
"lane": "host",
|
|
39
|
+
"coords": {},
|
|
40
|
+
"secretRefs": {}
|
|
41
|
+
},
|
|
42
|
+
"store": {
|
|
43
|
+
"backend": "local",
|
|
44
|
+
"session": "auto"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"coords": {},
|
|
48
|
+
"env": {
|
|
49
|
+
"FLEET_GENERATION": "7",
|
|
50
|
+
"LOG_LEVEL": "debug"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "gamma",
|
|
55
|
+
"enabled": false,
|
|
56
|
+
"host": "default",
|
|
57
|
+
"image": "sema-server:latest",
|
|
58
|
+
"secretRefs": {
|
|
59
|
+
"apiKeyEnv": "MODEL_KEY"
|
|
60
|
+
},
|
|
61
|
+
"runtime": {
|
|
62
|
+
"requirePrincipal": false,
|
|
63
|
+
"rateLimitRpm": 0
|
|
64
|
+
},
|
|
65
|
+
"coords": {}
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contributor": "contract",
|
|
3
|
+
"claim": "8.2.0 逐行终判:一份已是 7.x 形的 workers 文档(三行都不需要迁),其中 beta 在 env 里设了保留名 FLEET_GENERATION(渲染器是它的唯一写手)⇒ beta 进 refused(field = env,拒因是读侧自己那句,点名保留键与它的唯一写位),alpha / gamma 原样留在 doc,changed / dropped 为空;过滤后的 doc 整域读得进。8.1.0 及以前这份文档迁移回零变化、随后整域读抛。"
|
|
4
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { formatConfigPath, sanitizeZodError } from "./config-fns.js";
|
|
21
21
|
import { MIGRATE_WORKERS_COMMAND } from "./execution-lane-index.js";
|
|
22
|
+
import { issueText } from "./issue-text.js";
|
|
22
23
|
import { migrateWorkersDomain } from "./migrate-workers.js";
|
|
23
24
|
import { DOMAIN_SCHEMAS } from "./types.js";
|
|
24
25
|
const USAGE = [
|
|
@@ -69,11 +70,11 @@ function verdictOf(m) {
|
|
|
69
70
|
refused: issues.map((i) => {
|
|
70
71
|
const [head, index, ...rest] = i.path;
|
|
71
72
|
if (head !== "workers" || typeof index !== "number")
|
|
72
|
-
return { name: null, field: i.path, reason: i
|
|
73
|
+
return { name: null, field: i.path, reason: issueText(i) };
|
|
73
74
|
const entry = workers[index];
|
|
74
|
-
return { name: isRecord(entry) && typeof entry.name === "string" ? entry.name : null, field: rest, reason: i
|
|
75
|
+
return { name: isRecord(entry) && typeof entry.name === "string" ? entry.name : null, field: rest, reason: issueText(i) };
|
|
75
76
|
}),
|
|
76
|
-
why: `the migrated document does not read as a 7.0.0 workers domain — ${issues.map((i) => `${formatConfigPath(i.path)}: ${i
|
|
77
|
+
why: `the migrated document does not read as a 7.0.0 workers domain — ${issues.map((i) => `${formatConfigPath(i.path)}: ${issueText(i)}`).join("; ")}`,
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
const isRecord = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"FLEET_PATHS": {
|
|
3
|
+
"instances": "/api/fleet/instances",
|
|
4
|
+
"usage": "/api/fleet/usage",
|
|
5
|
+
"quotaLeases": "/api/fleet/leases",
|
|
6
|
+
"servingLease": "/api/fleet/live/serving-lease",
|
|
7
|
+
"hostPlanner": "/api/fleet/live/host-planner/{host}"
|
|
8
|
+
},
|
|
9
|
+
"FLEET_LIVE_PATHS": [
|
|
10
|
+
"/api/fleet/instances",
|
|
11
|
+
"/api/fleet/live/serving-lease",
|
|
12
|
+
"/api/fleet/live/host-planner/{host}"
|
|
13
|
+
]
|
|
14
|
+
}
|