refactor(spec): 双源 C11 收敛 — HttpRequest 类型别名改为 re-export ./shared 的唯一声明 (#4688) - #4689
Merged
Merged
Conversation
`@objectstack/spec/shared` and `@objectstack/spec/ui` both exported the name `HttpRequest` for DIFFERENT type declarations — a row on `dual-source-exports.baseline.json`, judged by symbol identity (#4411 trap). This cluster is the degenerate case of that trap. `HttpRequestSchema` was never duplicated: `ui/view.zod.ts` imports it from `shared/http.zod.ts` and re-exports it verbatim, which is why the baseline carries no `HttpRequestSchema` row. The only split was the local type alias at the bottom of view.zod.ts — `z.infer<typeof HttpRequestSchema>` over the very same schema object, so a second declaration symbol carrying an identical shape. It is now a re-export of shared's declaration, which the baseline header explicitly does not count. Baseline: 19 -> 18. NOT breaking, and deliberately not labelled so. #4535 calls the three v17 clusters breaking wholesale; this one is verified otherwise. FROM and TO infer from one schema object, and the compiler agrees: `Equal<PreFixUiHttpRequest, UiHttpRequest>` and `Equal<PreFixUiHttpRequest, SharedHttpRequest>` both hold, with a deliberately-false negative control erroring TS2344 to prove the pair is not vacuous. api-surface.json, authorable-surface.json and spec-changes.json are all byte-identical after a rebuild — zero authorable key movement, zero tombstone, zero conversion. Overstating breakage pollutes the upgrade guide as surely as understating it, so the changeset is patch. Regression pin: three RUNTIME assertions in ui/view.test.ts. #4642 established that a compile-time pin in this package is dead text (tsconfig excludes **/*.test.ts, vitest never type-checks), and that applies to the pre-existing `type HttpRequest` import in that file too — it is erased, so it never guaranteed the export survives. The third assertion closes that hole by resolving symbol identity through the TypeScript API over src/, the same measurement check:dual-source-exports makes over dist. All three sabotage-verified. `HttpMethod` on the next line is the identical shape and stays — #4535 scheduled it for v18, and scope is the maintainer's to set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9
…p-request-dual-source
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
August 2, 2026 18:07
This was referenced Aug 2, 2026
Merged
Closed
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 #4688
#4535 的 C11 簇,v17 收口三簇之二。基线 19 → 18,只减不增。
改了什么
HttpRequest这个名字过去在@objectstack/spec/shared和@objectstack/spec/ui解析到两份不同的类型声明(#4411 陷阱)。现在./uire-export./shared的那一份。派发单的定位表复核无误:
HttpRequestSchema从来只有一份声明(shared/http.zod.ts:46),ui/view.zod.ts:21import 进来、:37原样 re-export,所以基线里根本没有HttpRequestSchema行。唯一的双源点就是那个本地类型别名。处置后它变成基线表头明说不计的 "a re-export of one declaration from many entries"。构建产物可证收敛成功 —— 两个入口现在指向同一个 chunk 的同一个符号:
派发单要求「自己判,不要为了凑 major 而声称破坏」。结论:FROM 与 TO 是同一个类型,升级者无需做任何事。
两个别名
z.infer的是同一个 schema 对象,所以这不是推断,是编译器验过的(临时脚本,已删除):tsc --ignoreConfig --noEmit --strict输出 —— 只有负对照报错,证明前三条不是空转:配套证据(重新 build 后):
api-surface.json、authorable-surface.json、spec-changes.json全部零改动。零可作者化 key 消失、零 tombstone、零 ADR-0087 conversion。关于 #4684(C9)的门禁死结:确认未被惊动。本簇不改任何 def、不动
HttpRequestSchema声明,check:authorable-surface与 ratchet 全程无感,authorable-surface.json未被手编(#4650 纪律)。回归 pin(三条,全部 sabotage 验证)
src/ui/view.test.ts新增三条运行时断言。#4642 已证本包编译期 pin 空转(tsconfig.json排除**/*.test.ts、vitest 不开typecheck)—— 这条同样适用于该文件已有的type HttpRequest具名导入:它被 vitest transform 抹掉,从来就没有保障过这个导出还在。第三条断言正是来补这个洞的:用 TypeScript compiler API 在src/上做符号身份解析(check:dual-source-exports在 dist 上做的同一件事),因为HttpRequest是类型,运行时看不见,而它恰恰是本簇唯一改动的东西。AssertionError: expected 'src/ui/view.zod.ts:2056' to be 'src/shared/http.zod.ts:54'AssertionError: ./ui must still export the name `HttpRequest`: expected undefined to be truthy./ui重新声明第二份HttpRequestSchemaAssertionError: expected [Function] to be [Function] // Object.is equality第二条同时正是验收项「
ui/view.test.ts的既有具名类型导入继续可用」的守卫。验证
已合并
origin/main(含刚落地的 #4685),合并后重新 build 并重跑生成物门禁。pnpm typecheck全仓那次跑在合并前;合并后按手册第 10 条按重叠面收窄,重跑了 spec 的 build / check:generated / typecheck / test。⛔ 未纳入:紧挨着的
HttpMethod(留给维护者决定)ui/view.zod.ts下一行export type HttpMethod = z.infer< typeof HttpMethodSchema >我已确认是完全相同的形状 —— 同样只有 type 双源、同样从 import 进来的同一个HttpMethodSchemainfer、同样零 authorable key。基线行HttpMethod — [./api, ./shared (type)] ≠ [./ui (type)]仍在,一行改动即可清掉。但范围是维护者定的,#4535 已把它排进 v18,故本 PR 不动。若要并进来请直接说,改动约等于零。
一个差别值得记一笔:
HttpMethod比本簇多一层复杂度 ——shared/http.zod.ts里HttpMethod(7 值,:20)和HttpMethodSchema(5 值,:37)是两个不同的枚举,而./ui的HttpMethod类型 infer 自 5 值的那个。所以它不像本簇那样必然零类型差异,并进来时需要单独核 FROM → TO。🤖 Generated with Claude Code
https://claude.ai/code/session_0176qgxgCXTJCUv4YFLtusP9
Generated by Claude Code