feat(spec): preview/trial 的 discovery 折叠改为显式声明,折叠表对 EnvironmentType 穷尽 (#6287) - #6610
Merged
Merged
Conversation
#6287) `EnvironmentTypeSchema` 有七个成员,`NODE_ENV_TO_DISCOVERY_ENVIRONMENT` (`packages/spec/src/api/discovery.zod.ts`)只为其中五个写了条目。`preview` 与 `trial` 一直靠 `resolveDiscoveryEnvironment` 末行的 `?? 'development'` 兜底落到 `development` —— 不是一条被写下来的决定,而是掉出表尾的副作用。 这张表的注释本来就写明它是给后来者读的,读表的人会以为它是全的;#6554 刚把 unset 一行收进这个 mapper,留下的正是这最后一条隐式边。 折叠目标 = `sandbox`(两者皆是),三条理据 —— 它们既不是 absent(宿主拒答) 也不是未识别拼写(猜测),而是**已声明的一等成员**,属第三类: 1. 本仓语义:environment 是被开通的运行容器(独立数据库、规范主机名、套餐档位、 按环境 RBAC,见 `cloud/environment.zod.ts`)。`preview` / `trial` 是这种东西, 不是 `development` / `dev` / `test` 描述的开发机与 CI 的一次性运行; `sandbox` 正是枚举里「已开通的准生产」那一档,`staging` 已按同样理由折在此处。 2. 姿态按收紧方向:`trial` 装着评估中客户的真实业务数据,答 `development` 是低报姿态 —— 与 #5673 / #5936 把 unset 翻成 `production` 所避免的是同类错误, 只低一档。两者都不是 `production`,报 `production` 会朝另一个方向答错。 3. 保住作者的区分:把环境标成 `preview` 的人手里本就有 `development` 和 `test` 而没有选;折到 `development` 会抹平这个选择携带的唯一信息。 漏补条目从此不编译:七行分组在 `satisfies Record<EnvironmentType, DiscoveryEnvironment>` 之后(operator 便利拼写 `prod` / `dev` 留在组外,否则穷尽标注写不出来)。逆向验证(方向先判后跑,两条都实读): 删 `preview` 行 → TS1360 `Property 'preview' is missing`;加非成员键 `qa` → TS2353 `'qa' does not exist in type`。选编译期而非运行期断言,是因为运行期断言看不见这个缺陷 —— 兜底与三条已声明的行都产出 `development`,一条运行期穷尽测试在坏状态下本来就是绿的。 `?? 'development'` 兜底保留,职责收窄并写进注释:只服务既非词表成员、也非 operator 简写的任意字符串(`qa`、`uat`、拼错)。#5936 的两条既有 pin(absent → `production`、 未识别 → `development`)规则未动且保持绿。 夹带的 fixture 三处按消费半径逐条重判(不是批量改写):`packages/spec`、 `packages/metadata-protocol`、`packages/runtime` 三个 test 都把 `preview` 当作「未识别拼写」的例子,而它现在是已声明成员 —— 规则保留,例子改成 真正未识别的 `uat`。其中 metadata-protocol 那条是 spec 范围的 sweep 看不到、 由消费者测试跑出来的(与 PR #5046 同一类)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
qq9340100
marked this pull request as ready for review
August 8, 2026 07:21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6287
前提复核(基于 #6554 落地后的
origin/main)复核通过,
premise_still_valid: true。在a36db28b7实读packages/spec/src/api/discovery.zod.ts:NODE_ENV_TO_DISCOVERY_ENVIRONMENT(#6554 之后移到
:341)确实只有五条 ——production/prod/sandbox/staging/development/dev/test,preview与trial无条目;resolveDiscoveryEnvironment末行的?? 'development'兜底仍在。一条比 issue 描述更硬的旁证:改动前源文件注释第 318 行把
preview写成「未识别拼写」的举例(
An unrecognised spelling (qa, preview)),三个包的测试也拿
preview当未识别拼写的 fixture。这正是本单要修的那个混淆 ——它是我们自己词表里的一等成员,不是没听说过的拼写。
#6554 建立的两分法(absent →
production是宿主拒答;未识别拼写 →development是猜测)原样保留,本 PR 不动它。折叠目标判定:两者皆
sandbox—— 否决窗口见下preview/trial既不是 absent 也不是未识别拼写,属第三类:已声明的一等成员,所以需要独立理据。三条:
独立数据库、规范主机名、套餐档位、按环境的 RBAC(
cloud/environment.zod.ts开头的定义)。
preview/trial是这种东西,不是development/dev/test所描述的开发机与 CI 的一次性运行。sandbox正是这个枚举里「已开通的准生产」那一档,而
staging早就按同样理由折在此处。trial尤其装着评估中客户的真实业务数据。environment是机器可读面,客户端读它决定要不要放宽破坏性操作的二次确认,答
development是低报姿态 —— 与 NODE_ENV 未设置时 /discovery 广播 environment=development,而 os start 默认 NODE_ENV=production、CLI doctor 也按 production 解析 #5673 / NODE_ENV 未设置时,第二个 /discovery 生产者(metadata-protocol 的 getDiscovery,经 @objectstack/rest)仍广播 environment=development #5936 把 unset 一行翻成production所要避免的是同一类错误,只是低一档。两者都不是production:它们按定义就不是客户的生产部署,报
production会让这个字段唯一要回答的问题朝另一个方向答错,也违反「机器可读面不得说谎」。
preview的人,手里本来就有development和test而没有选。折到development会把这个选择携带的唯一信息抹平;折到
sandbox在三成员枚举的分辨率内保住了它。这是行为变化,changeset 按
minor定并写明 FROM → TO:NODE_ENV(或任何 operator 提供的字符串)previewdevelopmentsandboxtrialdevelopmentsandbox兜底声明化 + 编译期穷尽检查
七行分组在
satisfies Record< EnvironmentType, DiscoveryEnvironment >之后;operator 便利拼写
prod/dev留在组外 —— 混进去的话每个简写都会被当成词表成员,穷尽标注就写不出来了。合并后仍是原来那张查找表,
resolveDiscoveryEnvironment的查找路径未变。EnvironmentType走import type,编译期擦除,不给api/→cloud/添运行时边。?? 'development'兜底保留(issue 的建议正确:它服务的是任意 operator字符串这一真实输入类),但职责收窄并写进注释:如今只对既非词表成员、也非
operator 简写的拼写生效(
qa、uat、拼错)。未来新增的桶再也够不到它 ——够不到的方式是根本编译不过。
为什么是编译期而非运行期断言
运行期断言看不见这个缺陷:兜底与三条已声明的行(
development/dev/test)都产出
'development',所以调resolveDiscoveryEnvironment('preview')在「有条目」与「
??现编」两种情况下返回完全一致。一条运行期穷尽测试在#6287 报告的那个坏状态下本来就是绿的。
tsc比的是键集合,那才是真正的主张。逆向验证(方向先判后跑,两条都是实读)
preview行error TS1360: … Property 'preview' is missing in type … but required in type 'Record< "test" ¦ "development" ¦ "production" ¦ "preview" ¦ "staging" ¦ "sandbox" ¦ "trial", … >'qaerror TS2353: Object literal may only specify known properties, and 'qa' does not exist in type 'Record< … >'trial成员TS2353;测试:TS2578: Unused '@ts-expect-error' directive第三行是负向控制的负向控制 —— 它证明那条
@ts-expect-error不是空过的。packages/spec的测试层确实被 tsc 编译(tsconfig.test.json,自 #5286 起写进
typecheck脚本),且discovery.test.ts不在test-typecheck-debt.json里(该账本只有 2 个文件),所以这条 pin 是活的,不是 AGENTS.md 警告的那种幽灵检查。
一处如实修正:我最初在测试注释里写这条 pin「双向失败,包括源表标注被放宽时」。
不成立 —— 测试里的 pin 用的是它自己的
Record< EnvironmentType, … >,源表标注被改宽它是不会红的(表未导出,为测试导出它等于把一个私有查找表
放上本包公开面)。注释已改成如实陈述覆盖与不覆盖的范围。
Fixture 三处逐条重判(按消费半径,不是批量改写)
preview从「未识别拼写」的例子里毕业,三处 fixture 各自重判 —— 规则一概保留,只换例子:
packages/spec/src/api/discovery.test.ts['qa', 'preview', 'nonsense']→['qa', 'uat', 'nonsense']packages/metadata-protocol/src/discovery-schema-conformance.test.tspackages/runtime/src/discovery-schema-conformance.test.ts['qa', 'preview', 'uat', 'nonsense']→ 去掉preview留着不改的话,它们会断言出与 mapper 决定相反的事实,而且会因为
「已声明的答案恰好等于兜底的答案」而继续绿 —— 正是这次要消灭的那种绿。
其中 metadata-protocol 那条是 spec 范围的 sweep 看不到、由消费者测试跑出来的
(先红后修,与 PR #5046 同一类:改在 A 包,坏的 fixture 在 B 包)。
验证
pnpm --filter @objectstack/spec test—— 全量 342 files / 8790 tests 全绿;定向复跑
discovery.test.ts+discovery-environment-subset.pin.test.ts:86 passedpnpm --filter @objectstack/spec typecheck—— 绿(含check:scripts-typecheck与
check:test-typecheck:测试层在tsconfig.test.json下编译通过)pnpm --filter @objectstack/spec check:generated—— ✓ All 10 generated artifacts are up to datepnpm check:spec-parsed-alias——--self-test18 assertions passed;1443 bare z.input aliases, 749 pinned isomorphic, 694 paired with an XParsed. OKmetadata-protocoldiscovery 一致性 19 passed(修 fixture 前 1 failed,实读
expected 'sandbox' to be 'development');runtimediscovery + http-dispatcher258 passed
eslint(5 个改动文件,--no-inline-config)rc=0node scripts/check-nul-bytes.mjs—— OK(6163 个文件);改动文件另做grep -naP控制字符自扫,cleanpnpm check:empty-changeset—— self-test 48 assertions 通过packages/metadata-protocol无typecheck脚本(类型检查覆盖率账本内的既有状态),故该包只跑测试。
Generated by Claude Code