#4535 的 HttpMethod 簇。原排在 v18,维护者 2026-08-02 裁定并进 v17 。基线行:
HttpMethod — [./api, ./shared (type)] ≠ [./ui (type)]
⚠️ 派发前 PM 已做过定位复核,推翻了「与 C11 同形、一行即可」的初判。 请先读下面这节再动手 —— C11(#4688 / PR #4689 )的结论不适用于本簇 。
这两个 HttpMethod 是真的不同类型
packages/spec/src/shared/http.zod.ts 里并存两个 HTTP 方法枚举(行号对 origin/main @ 7d21581,开工请自行复核):
位置
声明
取值
shared/http.zod.ts:20 + :30
export const HttpMethod / export type HttpMethod
7 值 — GET POST PUT DELETE PATCH HEAD OPTIONS
shared/http.zod.ts:37
export const HttpMethodSchema = lazySchema(…)
5 值 — GET POST PUT PATCH DELETE
shared/http.zod.ts:39
export type HttpMethodType = z.infer<typeof HttpMethodSchema>
5 值(就是 ./ui 那个类型,只是叫别的名 )
ui/view.zod.ts:2040
export type HttpMethod = z.infer<typeof HttpMethodSchema>
5 值,却叫 HttpMethod
:37 的注释自己写明了它的身份:"HTTP Method Schema (subset for UI/View data sources)" 。
所以 ./shared / ./api 的 HttpMethod 是 7 值,./ui 的 HttpMethod 是 5 值真子集 。同一个名字,两个不同类型 —— 这正是 #4411 陷阱最恶劣的形态(C11 那簇只是符号身份不同、形状相同;本簇形状也不同)。
⛔ 因此「让 ./ui re-export ./shared 的 HttpMethod」是错的
那会把 ./ui 的 HttpMethod 从 5 值悄悄放宽到 7 值 ,而 HttpRequestSchema.method(shared/http.zod.ts:48)用的是 5 值的 HttpMethodSchema 。结果是类型说 HEAD / OPTIONS 合法、运行时 .parse() 直接抛 —— 类型开始对运行时说谎 。这比双源本身更糟,不要为了清一行基线换来这个。
推荐路线(PM 分析,实施者需复核;复核结论若与此矛盾请升级而不是硬做)
让 ./ui 不再导出 HttpMethod 这个名字 ,冲突即消失(名字只剩 ./api + ./shared 的那一个声明),且类型保持诚实的 5 值。
删 ui/view.zod.ts:2040 的 export type HttpMethod = z.infer<typeof HttpMethodSchema>。
需要给 ./ui 保留一个可用的方法类型名的话:export type { HttpMethodType } from '../shared/http.zod'(纯新增,安全)。./ui 本来就 re-export 了 HttpMethodSchema(ui/view.zod.ts:37),消费者也可自行 z.infer。
迁移指引:import type { HttpMethod } from '@objectstack/spec/ui' → import type { HttpMethodType } from '@objectstack/spec/shared'(同一个类型,零形状变化 )。
风险面 —— PM 已实测,仓内为零
全仓没有任何地方从 ./ui 导入 HttpMethod。 唯一的跨包消费者 packages/rest/src/route-manager.ts:9 用的是 Shared.HttpMethod(7 值那个),不受影响。
HttpMethodType 目前零消费者 (只有 :39 的声明本身)。
但它仍是已发布的 API 表面 ,外部消费者不可见 → api-surface.json 会变,changeset 定 major ,写清 FROM → TO。
不是 authorable key,不需要 ADR-0087 tombstone / conversion。 若你的实现产生了任何一个,说明走偏了,停下来升级。
纪律(#4535 §1–§4 + 手册 6/7/8)
⛔ 禁止手编 packages/spec/authorable-surface.json (authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 )。
⚠️ 门禁绿 ≠ 登记正确 (build-schemas.ts 检查 (b) 用叶名匹配 conversion surface —— 无关簇的 .type 就能让一个 tombstone 冒充「已登记迁移」 #4659 ):自己枚举核对,别信 leaf-name 匹配。
回归 pin 必须能真的红。 packages/spec 的「编译期 pin」是失效的:tsconfig 排除了 *.test.ts,vitest 也不做类型检查 #4642 已证本包编译期 pin 空转 (tsconfig.json 排除 **/*.test.ts、vitest 不开 typecheck)。HttpMethod 是类型 ,运行时看不见 —— 直接抄 PR refactor(spec): 双源 C11 收敛 — HttpRequest 类型别名改为 re-export ./shared 的唯一声明 (#4688) #4689 在 ui/view.test.ts 里那条用 TypeScript compiler API 在 src/ 上做符号身份解析 的断言(含它的防空转守卫 expect(moduleSym).toBeTruthy()),那是本仓目前唯一有效的类型级 pin 形态。必须 sabotage 验证并贴实际输出。
本簇额外要求一条值域 pin :钉住 ./shared 的 HttpMethod 是 7 值、HttpMethodSchema 是 5 值,且 HttpRequestSchema.parse({url, method:'HEAD'}) 抛错 。这条防的是将来有人「顺手统一」两个枚举而不自知。
⚠️ 生成物冲突只能靠重新生成 (手册第 7 条)。推之前重新 git fetch origin main;spec-changes.json 是对象数组,必须跑 gen:spec-changes ,集合合并会丢条目。
⛔ 不要碰 content/docs/releases/ 。
验收
顺带记录,本簇不处理
HttpMethodType(5 值)零消费者、HttpMethod(7 值)与它并存且命名无法自解释("Type" 后缀是噪音,而且它是更窄 的那个)。按 ADR-0049 enforce-or-remove 与 ADR-0112 D9(a)「给领域专用的那一侧改名」,更彻底的收敛是把 5 值那对改成 ViewHttpMethod / ViewHttpMethodSchema 之类自解释的名。但那超出清一行基线的范围,范围由维护者定 —— 想做请单独立单,不要搭本簇顺风车。
关联:#4535 (主单)、#4688 / PR #4689 (C11,同文件相邻行,但结论不适用 本簇)、#4642 (pin 空转)、#4650 / #4659 (门禁洞)、#4675 (生成物冲突)、ADR-0049、ADR-0087、ADR-0112
#4535 的 HttpMethod 簇。原排在 v18,维护者 2026-08-02 裁定并进 v17。基线行:
这两个
HttpMethod是真的不同类型packages/spec/src/shared/http.zod.ts里并存两个 HTTP 方法枚举(行号对origin/main@7d21581,开工请自行复核):shared/http.zod.ts:20+:30export const HttpMethod/export type HttpMethodshared/http.zod.ts:37export const HttpMethodSchema = lazySchema(…)shared/http.zod.ts:39export type HttpMethodType = z.infer<typeof HttpMethodSchema>./ui那个类型,只是叫别的名)ui/view.zod.ts:2040export type HttpMethod = z.infer<typeof HttpMethodSchema>HttpMethod:37的注释自己写明了它的身份:"HTTP Method Schema (subset for UI/View data sources)"。所以
./shared/./api的HttpMethod是 7 值,./ui的HttpMethod是 5 值真子集。同一个名字,两个不同类型 —— 这正是 #4411 陷阱最恶劣的形态(C11 那簇只是符号身份不同、形状相同;本簇形状也不同)。⛔ 因此「让 ./ui re-export ./shared 的 HttpMethod」是错的
那会把
./ui的HttpMethod从 5 值悄悄放宽到 7 值,而HttpRequestSchema.method(shared/http.zod.ts:48)用的是 5 值的HttpMethodSchema。结果是类型说HEAD/OPTIONS合法、运行时.parse()直接抛 —— 类型开始对运行时说谎。这比双源本身更糟,不要为了清一行基线换来这个。推荐路线(PM 分析,实施者需复核;复核结论若与此矛盾请升级而不是硬做)
让
./ui不再导出HttpMethod这个名字,冲突即消失(名字只剩./api+./shared的那一个声明),且类型保持诚实的 5 值。ui/view.zod.ts:2040的export type HttpMethod = z.infer<typeof HttpMethodSchema>。./ui保留一个可用的方法类型名的话:export type { HttpMethodType } from '../shared/http.zod'(纯新增,安全)。./ui本来就 re-export 了HttpMethodSchema(ui/view.zod.ts:37),消费者也可自行z.infer。import type { HttpMethod } from '@objectstack/spec/ui'→import type { HttpMethodType } from '@objectstack/spec/shared'(同一个类型,零形状变化)。风险面 —— PM 已实测,仓内为零
./ui导入HttpMethod。 唯一的跨包消费者packages/rest/src/route-manager.ts:9用的是Shared.HttpMethod(7 值那个),不受影响。HttpMethodType目前零消费者(只有:39的声明本身)。api-surface.json会变,changeset 定 major,写清 FROM → TO。纪律(#4535 §1–§4 + 手册 6/7/8)
packages/spec/authorable-surface.json(authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650)。.type就能让一个 tombstone 冒充「已登记迁移」 #4659):自己枚举核对,别信 leaf-name 匹配。tsconfig.json排除**/*.test.ts、vitest 不开typecheck)。HttpMethod是类型,运行时看不见 —— 直接抄 PR refactor(spec): 双源 C11 收敛 — HttpRequest 类型别名改为 re-export ./shared 的唯一声明 (#4688) #4689 在ui/view.test.ts里那条用 TypeScript compiler API 在src/上做符号身份解析的断言(含它的防空转守卫expect(moduleSym).toBeTruthy()),那是本仓目前唯一有效的类型级 pin 形态。必须 sabotage 验证并贴实际输出。./shared的HttpMethod是 7 值、HttpMethodSchema是 5 值,且HttpRequestSchema.parse({url, method:'HEAD'})抛错。这条防的是将来有人「顺手统一」两个枚举而不自知。git fetch origin main;spec-changes.json是对象数组,必须跑gen:spec-changes,集合合并会丢条目。content/docs/releases/。验收
HttpMethod那 1 行,只减不增(其余行一字不动)。./ui不再导出HttpMethod;./api/./shared的 7 值声明原样不动。build、check:dual-source-exports、check:generated、test,加源码审计组(check:liveness/check:strictness-ledger/check:empty-state/check:variant-docs/check:exported-any/check:skill-examples),以及全仓pnpm typecheck。@objectstack/specmajor,含 FROM → TO 与迁移指引。顺带记录,本簇不处理
HttpMethodType(5 值)零消费者、HttpMethod(7 值)与它并存且命名无法自解释("Type" 后缀是噪音,而且它是更窄的那个)。按 ADR-0049 enforce-or-remove 与 ADR-0112 D9(a)「给领域专用的那一侧改名」,更彻底的收敛是把 5 值那对改成ViewHttpMethod/ViewHttpMethodSchema之类自解释的名。但那超出清一行基线的范围,范围由维护者定 —— 想做请单独立单,不要搭本簇顺风车。关联:#4535(主单)、#4688 / PR #4689(C11,同文件相邻行,但结论不适用本簇)、#4642(pin 空转)、#4650 / #4659(门禁洞)、#4675(生成物冲突)、ADR-0049、ADR-0087、ADR-0112