✅ 已完成 —— packages/spec/dual-source-exports.baseline.json 现为 entries: []
52 → 0,历时两天、17 簇、17 个 PR。最后一簇 C7(#4741 → PR #4789)于 2026-08-03 07:5xZ 合并,门禁实报 0 accepted dual-source (baseline)。
#4446 的 gate(#4506)守住「不再新增」;本单偿清了存量。这份账目从此只应是 0——任何新增都会被门禁在 PR 上拦下,不需要再开清账单。
问题是什么
同一个名字在两个入口解析到不同声明,消费者拿到哪个类型只取决于 import 路径 —— #4411 陷阱。两侧都不 .strict() 时,把一侧的文档粘到另一侧不报错,只静默剥掉全部外来键(ADR-0104 silent-strip 类)。52 条这样的名字曾同时存在于发布契约里。
最终账目
| 批次 |
条数 |
时间 |
说明 |
| 第一批 |
52 → 13 |
2026-08-02 ~ 08-03 |
A1/A2/A3/B/C1–C5/C8/C9/C11/C12/C14,共 39 条 |
| 第二批 |
13 → 0 |
2026-08-03 |
C6/C10/C13/C15/C16/C17/C7,共 13 条,维护者裁决全部纳入 v17 窗口 |
第二批逐簇(维护者 2026-08-03 裁决:13 条全入 v17)
| 簇 |
名字 |
子 issue → PR |
基线 |
路线 |
| C6 |
Event |
#4658 → #4745 |
13 → 12 |
死侧删除:automation 侧是零引用 XState 信号孤儿,从未接线 |
| C16 |
TenantPlan |
#4739 → #4752 |
12 → 10 |
./cloud 5 值词表为唯一真源;system/provisioning.zod.ts 六 def 全族 + 两个 contracts 整文件退役(21 文件 +271/−939)。词表 3→5 拓宽如实写进 changeset |
| C13+C15 |
DataSyncConfig / ConflictResolution |
#4738 → #4760 |
10 → 6 |
整删 automation/sync.zod.ts(L1「Simple Sync」叙事层,17 导出名 / 8 def / 39 key,三仓零消费者);integration 侧改名 ConnectorConflictResolution;./ui 一字未动 |
| C10 |
EnvironmentArtifact |
#4740 → #4767 |
6 → 3 |
收敛到线上 wire 形状(唯一 runtime 消费者 metadata/plugin.ts 已在解析的形状),./cloud 纯 re-export;v0 家族 16 名 / 9 def 退役。checksum 对象→字符串是 #4666 盲区内的类型变更,显式承载 + parse pin 钉住 |
| C17 |
ActionLocationSchema |
#4737 → #4768 |
3 → 2 |
改名 studio 侧 ActionContributionLocationSchema + 补类型导出(顺带消掉 docs-import-surface 例外行);ui 侧一字未动 |
| C7 |
PackageDependency |
#4741 → #4789 |
2 → 0 |
两侧键集完全不相交(声明形 vs 解析器形),改名 kernel 侧 ResolvedPackageDependency;4 key 全承接 |
沉淀下来的东西(比账目本身更值钱)
1. RENAMED_DEFS 承接表 —— def 改名的正规通道
packages/spec/scripts/lib/renamed-defs.ts,C9(PR #4695)首创、C12(PR #4710)加固。五条不变式,任一违反即红:
- 旧 def 名下每个 key 都必须在新 def 名下存在(否则是「披着改名外衣的删除」);
- target 必须被本次 build 产出;
- source 必须不再被产出 —— 两个都在是复制而非改名,而复制正是这张表绝不能洗白的 dual-source 形状;
- 两个 source 不许指向同一个 target(合并两个 def 是真变更);
- 链式改名(A → B → C)按名报错。
表内现有 6 条(C9 / C12 ×2 / C15 / C17 / C7)。def 改名一律走这条通道;真退役一律不许走(那张表的不变式正是「没有 key 离开契约」)。
2. #4650 删行自证门禁(PR #4726)—— 基线不能再手编
被删基线行必须在门禁内自证,merge-base 锚定(CI 不空转),三条合法路径:aged-out tombstone(≥2 majors)/ 从 24 个元数据根真 Zod 图 BFS 不可达 / 整 def 不再发出(归 manifest ratchet + check:api-surface 裁决)。另加 --check 对整文件的规范形字节比对(#4663 加固法),手编即红。
实证补充:整文件/整族删除走的都是路径 3,per-key 可达性判定不适用 —— 以门禁实跑输出为准,不要按静态推断写 PR。
3. 类型级 pin 的唯一有效形态(#4642 的解药)
tsconfig exclude 掉 test、vitest 未开 typecheck.enabled ⇒ 编译期条件类型 pin 空转。有效形态是:TypeScript compiler API 在 src/ 上做符号身份解析,从 package.json exports map 枚举全部入口(新入口无法逃逸),带防空转守卫(module symbol 必解析、表面非平凡),holders 用精确相等断言。
为什么必须精确相等:C17 与 C7 各自实证了一条对 dual-source 门禁全绿、但语义说谎的路线 —— 在错误的入口 re-export 同一声明。C7 更把它量化:用含 sabotage 的源码重建 dist 后实跑门禁,读数从 173 re-exported 变 175,门禁结构性看不见。拦住它的是 pin 的精确相等断言,以及 RENAMED_DEFS 不变式 3 —— 后者更早在 build 阶段即拒绝。
4. 定级要据实,五种形状五种论证(不许跨簇照抄)
| 形状 |
定级 |
实例 |
| FROM ≡ TO |
patch |
C11 |
| def 改名 |
major,零元数据迁移 |
C9 / C12 / C17 / C7 |
| 已发布导出名移除 |
major(TS2305),零元数据迁移 |
C14 / C6 / C16 / C10 |
| 收敛致词表拓宽 |
major + changeset 显式警示 |
C16(3→5) |
| 收敛致字段类型变更 |
major + 警示 + parse pin(#4666 盲区) |
C10(checksum 对象→字符串) |
「major 且零迁移」对真退役不成立(#4651 那类有迁移)。谎报破坏与漏报破坏同样污染升级指南。
5. ⚠️ 入队纪律:同步 main 的三个坑(2026-08-03 全部实证)
a. 用 git merge,不用 rebase + force-push。 AGENTS.md §3 禁止 --force/--force-with-lease —— 仓规不因 PM 指令而失效(PM 曾下达错误指令,实施 agent 拒绝执行并改走 merge 是正确处置)。merge=os-regen 驱动正为此而设。
b. 静默回退有三处,第三处最隐蔽:
| 文件 |
归属 |
合并时表现 |
暴露方式 |
dual-source-exports.baseline.json |
手管 ratchet |
产生冲突 |
冲突标记 |
authorable-surface.json / docs-import-surface.baseline.json |
手管 ratchet |
产生冲突 |
冲突标记 |
json-schema.manifest.json |
merge driver 托管 |
无冲突标记,静默合并 |
只有 gen:schema 实跑暴露 |
C17 与 #4634 各踩一次:manifest 无声复活了 C10 蓄意删除的 9 个键 / 文本 auto-merge 复活了 46 行 authorable-surface。唯一可靠处置:四张 ratchet 一律 git checkout origin/main -- <file> 后只重施自己的那一处改动,再全量重跑生成器,零文本合并(#4783 做法,重放后与 main 逐字节一致)。
c. renamed-defs.ts 的合并冲突必须让两条改名条目并存,不能二选一。 C7 实证:承接表是累积台账,冲突里选一条就等于把别人已合并的改名从台账抹掉 —— 而不变式 1 只在本次 build 产出时校验,被抹掉的那条不会报红。这类静默丢失只能靠人判断拦住。
6. 判不出来就升级,不要猜
分析本身就是交付物。#4653 / #4658 / #4661 都是这样处理的。四仓零 importer ≠ 有死侧可删(#4653 实证);C7 同理:两侧各自被真实 schema 嵌入、都活着,所以是改名而非删除。
派生工单(留维护者排期,均非窗口限时)
门禁洞
| # |
内容 |
优先级建议 |
| #4666 |
门禁对默认值 / 约束变更完全不可见 —— 改一个字符的 .default(),check:authorable-surface 全绿 |
最高:元数据即 API,默认值就是 API 的一部分。C8/C10/#4634 三次实证 |
| #4725 |
manifest 删键是 #4650 那个洞上移一层 |
高 |
| #4659 |
检查 (b) 按 leaf name 匹配 conversion surface,无关 conversion 即可蒙混 |
中(与 #4726 检查 (c) 同词表,一起修) |
| #4642 |
编译期条件类型 pin 空转 |
中(本单已给出有效形态,可作修复参考) |
| #4675 / #4676 |
生成物冲突 —— #4676 才是对合并队列有效的那个 |
排期待定 |
文档管道(双源的第三类受害者)
| # |
内容 |
| #4696 |
build-docs.ts 按裸 schema 名做全局索引,同名跨 category 互相覆盖产出幽灵页 —— 本单四次实证(幽灵页随改名/删除自愈消失) |
| #4759 |
references/index.mdx 根索引被生成器「保留不重生」,烂尾无 gate |
| #4781 |
runtime-capabilities.mdx 整页描述已于 #3605 删除的 schema |
其他
#4686(两份 RateLimitConfig 全仓零 runtime reader,C9 落地不使其失效)、#4782(测试 mock 写满 off-spec 键)、#4723。
跨仓下游
| # |
内容 |
紧迫性 |
| objectui#3235 |
C14 下游:packages/types 的 type-only 一行迁移(HttpMethodType as HttpMethod) |
下个 rc 前不处理会 TS2305 断链 |
| cloud#1027 |
C16 下游:手拷 5 值 plan 并集 |
低 |
| cloud#1028 |
#4634 下游:TursoDriver 死位 + off-spec fallback 清理 |
低(不破编译,纯死重) |
协作方式记录
本单第二批由 PM 会话 session_0176qgxgCXTJCUv4YFLtusP9 协调,os-dev agent 并行实施。两条关键协议:
- 不并行入队(2026-08-02 三次生成物冲突返工的教训 → 08-03 收窄):def 文件/入口区域不相交的簇可并行实施,但入队严格串行(merge main + 四张 ratchet 取 main 版重施 + 重生成 + 复验后逐个进队)。
- 认领 = assign + claim 评论(含 session ID 与分支名):所有 agent 共用一个 GitHub 身份,assignee 字段无法区分是谁的认领,开工前必须重读评论。
关联:#4411(先例)、#4446 / #4506(gate 本体)、#4650 / PR #4726(删行自证门禁)、#4663、#4711 / PR #4724、ADR-0049、ADR-0059 §5、ADR-0087、ADR-0104、ADR-0112
问题是什么
同一个名字在两个入口解析到不同声明,消费者拿到哪个类型只取决于 import 路径 —— #4411 陷阱。两侧都不
.strict()时,把一侧的文档粘到另一侧不报错,只静默剥掉全部外来键(ADR-0104 silent-strip 类)。52 条这样的名字曾同时存在于发布契约里。最终账目
第二批逐簇(维护者 2026-08-03 裁决:13 条全入 v17)
EventTenantPlan./cloud5 值词表为唯一真源;system/provisioning.zod.ts六 def 全族 + 两个 contracts 整文件退役(21 文件 +271/−939)。词表 3→5 拓宽如实写进 changesetDataSyncConfig/ConflictResolutionautomation/sync.zod.ts(L1「Simple Sync」叙事层,17 导出名 / 8 def / 39 key,三仓零消费者);integration 侧改名ConnectorConflictResolution;./ui一字未动EnvironmentArtifactmetadata/plugin.ts已在解析的形状),./cloud纯 re-export;v0 家族 16 名 / 9 def 退役。checksum 对象→字符串是 #4666 盲区内的类型变更,显式承载 + parse pin 钉住ActionLocationSchemaActionContributionLocationSchema+ 补类型导出(顺带消掉 docs-import-surface 例外行);ui 侧一字未动PackageDependencyResolvedPackageDependency;4 key 全承接沉淀下来的东西(比账目本身更值钱)
1.
RENAMED_DEFS承接表 —— def 改名的正规通道packages/spec/scripts/lib/renamed-defs.ts,C9(PR #4695)首创、C12(PR #4710)加固。五条不变式,任一违反即红:表内现有 6 条(C9 / C12 ×2 / C15 / C17 / C7)。def 改名一律走这条通道;真退役一律不许走(那张表的不变式正是「没有 key 离开契约」)。
2. #4650 删行自证门禁(PR #4726)—— 基线不能再手编
被删基线行必须在门禁内自证,merge-base 锚定(CI 不空转),三条合法路径:aged-out tombstone(≥2 majors)/ 从 24 个元数据根真 Zod 图 BFS 不可达 / 整 def 不再发出(归 manifest ratchet +
check:api-surface裁决)。另加--check对整文件的规范形字节比对(#4663 加固法),手编即红。实证补充:整文件/整族删除走的都是路径 3,per-key 可达性判定不适用 —— 以门禁实跑输出为准,不要按静态推断写 PR。
3. 类型级 pin 的唯一有效形态(#4642 的解药)
tsconfigexclude 掉 test、vitest 未开typecheck.enabled⇒ 编译期条件类型 pin 空转。有效形态是:TypeScript compiler API 在src/上做符号身份解析,从package.jsonexports map 枚举全部入口(新入口无法逃逸),带防空转守卫(module symbol 必解析、表面非平凡),holders 用精确相等断言。为什么必须精确相等:C17 与 C7 各自实证了一条对 dual-source 门禁全绿、但语义说谎的路线 —— 在错误的入口
re-export同一声明。C7 更把它量化:用含 sabotage 的源码重建 dist 后实跑门禁,读数从173 re-exported变175,门禁结构性看不见。拦住它的是 pin 的精确相等断言,以及RENAMED_DEFS不变式 3 —— 后者更早在 build 阶段即拒绝。4. 定级要据实,五种形状五种论证(不许跨簇照抄)
「major 且零迁移」对真退役不成立(#4651 那类有迁移)。谎报破坏与漏报破坏同样污染升级指南。
5.⚠️ 入队纪律:同步 main 的三个坑(2026-08-03 全部实证)
a. 用
git merge,不用 rebase + force-push。 AGENTS.md §3 禁止--force/--force-with-lease—— 仓规不因 PM 指令而失效(PM 曾下达错误指令,实施 agent 拒绝执行并改走 merge 是正确处置)。merge=os-regen驱动正为此而设。b. 静默回退有三处,第三处最隐蔽:
dual-source-exports.baseline.jsonauthorable-surface.json/docs-import-surface.baseline.jsonjson-schema.manifest.jsongen:schema实跑暴露C17 与 #4634 各踩一次:manifest 无声复活了 C10 蓄意删除的 9 个键 / 文本 auto-merge 复活了 46 行 authorable-surface。唯一可靠处置:四张 ratchet 一律
git checkout origin/main -- <file>后只重施自己的那一处改动,再全量重跑生成器,零文本合并(#4783 做法,重放后与 main 逐字节一致)。c.
renamed-defs.ts的合并冲突必须让两条改名条目并存,不能二选一。 C7 实证:承接表是累积台账,冲突里选一条就等于把别人已合并的改名从台账抹掉 —— 而不变式 1 只在本次 build 产出时校验,被抹掉的那条不会报红。这类静默丢失只能靠人判断拦住。6. 判不出来就升级,不要猜
分析本身就是交付物。#4653 / #4658 / #4661 都是这样处理的。四仓零 importer ≠ 有死侧可删(#4653 实证);C7 同理:两侧各自被真实 schema 嵌入、都活着,所以是改名而非删除。
派生工单(留维护者排期,均非窗口限时)
门禁洞
.default(),check:authorable-surface全绿文档管道(双源的第三类受害者)
build-docs.ts按裸 schema 名做全局索引,同名跨 category 互相覆盖产出幽灵页 —— 本单四次实证(幽灵页随改名/删除自愈消失)references/index.mdx根索引被生成器「保留不重生」,烂尾无 gateruntime-capabilities.mdx整页描述已于 #3605 删除的 schema其他
#4686(两份
RateLimitConfig全仓零 runtime reader,C9 落地不使其失效)、#4782(测试 mock 写满 off-spec 键)、#4723。跨仓下游
packages/types的 type-only 一行迁移(HttpMethodType as HttpMethod)协作方式记录
本单第二批由 PM 会话
session_0176qgxgCXTJCUv4YFLtusP9协调,os-dev agent 并行实施。两条关键协议:关联:#4411(先例)、#4446 / #4506(gate 本体)、#4650 / PR #4726(删行自证门禁)、#4663、#4711 / PR #4724、ADR-0049、ADR-0059 §5、ADR-0087、ADR-0104、ADR-0112