Skip to content

fix(spec): 内联形状摘要只展开一层,四条下钻路径共用同一条深度预算 (#6374) - #6572

Merged
os-project-manager merged 3 commits into
mainfrom
claude/issue-6374-inline-shape-depth-budget
Aug 8, 2026
Merged

fix(spec): 内联形状摘要只展开一层,四条下钻路径共用同一条深度预算 (#6374)#6572
os-project-manager merged 3 commits into
mainfrom
claude/issue-6374-inline-shape-depth-budget

Conversation

@os-project-manager

@os-project-manager os-project-manager commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Fixes #6374

content/docs/references/** 里最宽的类型单元格是 ui/page.mdxPage.slots,
1738 字符 —— 而且是在 #5340 的枚举省略已经在这一格生效 8 次之后的宽度。
本次修完,这一格是 122 字符

📌 全部数字已在合并 origin/main(a36db28)后的树上重测,本文所有表格都是
合并后的记录。
合并前后哪些数字动了、为什么动,记在最后一节「合并与数字复核」。
简短版:修法对每一格的效果逐格未变,动的是它要解决的问题的规模 —— 在本 PR
在飞期间,main 上的 schema 变更把超宽格从 9 个推到了 13 个,最宽格从 1538
推到了 1738

机制:预算一直存在,只是只作用在四条下钻路径中的一条

format-type.ts 一直只展开一层 { … } 形状,再往下的对象打印 object
但这条预算写在键循环的三元表达式里:

const childType = child?.type === 'object' && child.properties
  ? 'object'
  : formatType(child, ...);

于是只有直接对象子节点受它约束。另外三条路径 —— 数组元素({ … }[])、
Record 的值(Record< string, { … } >)、联合的变体({ … } | { … }[])——
都会重新进入对象分支,而预算不在作用域内。单元格宽度于是等于
「每层键数 × 变体数 × 每个形状宽度」,一层一层乘上去。

结果是:同一个形状在同一个阅读深度上,印全还是印 object,取决于作者有没有
把它包在数组里
—— 这是关于 Zod 写法的事实,不是关于读者怎么读的事实,和 #6225
拆掉的那种不对称完全同类。

新常量 SHAPE_DEPTH_LIMIT 把同一条预算移到对象分支本身,四条路径都要过它;
depth 走的是函数参数而不是 TypeContext 字段,因为深度是递归的事实、不是
页面的事实(被替换的三元表达式也不需要 ctx)。

派单要求的三向实测(合并后全语料 214 页 / 8432 个类型单元格)

三条候选方向各自重生成全语料再测量,不是纸上比较。基线(不改)是
>200 = 129,>400 = 13,>600 = 3,>900 = 1,p95 145,p99 233,最宽 1738,
总字符 274084

方向一:深度预算(采用)

深度上限 改前 1 2 3 4
>200 字符 129 51 176 194 194
>400 字符 13 1 21 33 33
>600 字符 3 1 2 14 16
>900 字符 1 0 1 1 1
p95 / p99 145 / 233 124 / 182 154 / 260 154 / 280 154 / 287
最宽 1738 656 1738 1738 1738
总字符 274084 252087 288215 294312 295017

阈值 1 不是选出来的,是取回来的。 它就是直接子节点路径上一直生效的那个值;
任何大于 1 的取值都比不改还差 —— 提高上限必然放松那条本来就是 1 的路径,
所以 >200 的单元格从 129 涨到 176+,而旗舰样本一动不动。这里没有分布可扫、
没有阈值可调:1 是把现状统一化,2 及以上是打扮成预算的回退。

方向二:整格字符预算(否)

字符预算 150 200 300 400 600
>200 字符 51 51 157 179 193
>400 字符 1 1 1 1 25
p95 / p99 136 / 182 139 / 188 152 / 233 154 / 248 154 / 287
最宽 656 656 656 656 656
总字符 257642 263431 275244 282674 290041

方向二的下界就是方向一。 预算收到 150/200 时,宽度剖面与深度预算逐项相同
(>200 = 51,>400 = 1,>900 = 0,最宽 656)—— 因为超预算的格最终都回落到深度 1。
预算放宽则严格更宽(总字符 257642 / 263431,对比方向一的 252087)。
也就是说:方向二在目标上赢不了方向一,多花的字符全部买在「还有余量的格里
多展开一层」上,而代价是渲染不再由节点本身决定

实测到的代价,同一个 Expression 形状在预算 150 下有三种拼法:

  • { dialect: …; source?: string; ast?: any; meta?: { rationale?: string; generatedBy?: string } }
  • { dialect: …; source?: string; ast?: any; meta?: object }
  • object —— Object.userActions

决定它的是同一格里其它兄弟键有多宽。 给某个无关的兄弟键加一个字段,就能让三层
之外的另一个形状悄悄从「印全」变成 object。方向一下,渲染只是(节点,结构深度)
的函数 —— 本地、确定、与邻居无关。

顺带:#6226 的维护者裁决已经否过「整格字符预算退化为 object」这一条,理由是
信息损失更大。本 PR 的实测与那条裁决同向。

方向三:同形去重(否)

全语料:>200 从 129 只降到 123,>400 从 13 只降到 9,总字符
274084 → 270411(-1.3%)。对比方向一的 51 / 1 / 252087。

座位预判的「4 个无联合的单元格是试金石」实测成立 —— 四格逐字未动:

单元格 改前 方向三 方向一
Manifest.capabilities 598 598 98
PluginRegistryEntry.capabilities 595 595 98
GetTranslationsResponse.translations 583 583 145
PluginSecurityManifest.permissions 450 450 106

更要命的是它按遍历顺序说谎Page.slots 在方向三下印成:

{ header?: { type: Enum< 'page:header' | … +29 more > | string; id?: string; label?: string;
  properties?: Record< string, any >; … } | object[]; actions?: object | object[];
  alerts?: object | object[]; highlights?: object | object[]; … }

headeractions同一个类型,页面却把它们印成不同的东西 —— 只因为
header 先被遍历到。Object.userActions(edit 印全、deleteobject)、
StateMachine.states(entry 印全、exitobject)同样如此。对「AI 作者的
权威输入」(ADR-0033)来说,这比宽单元格严重得多。

全部 13 个宽单元格逐格对照(合并后)

原立单时是 9 个;main 上的 schema 变更在本 PR 在飞期间又添了 4 个(表中标 🆕)。
方向一把除刻意排除的那一个之外的全部 12 个收进 200 字符以内。

单元格 改前 方向一(本 PR)
Page.slots 1738 122
PageComponent.type 656 656 ⟵ 刻意不碰
StateMachine.states 617 197
Manifest.capabilities 598 98
PluginRegistryEntry.capabilities 595 98
GetTranslationsResponse.translations 583 145
Object.userActions 581 93
ConversationSession.messages 450 153
PluginSecurityManifest.permissions 450 106
🆕 Manifest.navigationContributions 439 111
🆕 ListView.userFilters 436 115
🆕 InterfacePageConfig.userFilters 435 114
🆕 Page.interfaceConfig 421 91

PageComponent.type(656)按派单要求刻意不碰:它是落在联合变体里的顶层词表,
#6225 有意只匹配「属性自己的类型节点就是词表」,且它不含任何嵌套形状
改后仅剩的这一个 >400 单元格因此不是形状宽度 —— 形状深度带来的宽度已经从语料
里消失了

三条不可让的约束

  1. 省略必须自报省了什么(gen:docs 内联形状里的长枚举不省略,单个类型单元格可达约 900 字符(BulkActionDef.params 实例) #5340)。 object 不是截断:它对键什么都不声称,
    所以不像前缀那样会被误读成完整列表。它也不是这些表格里的新省略风格 —— 嵌套
    形状本来就一直印 object(改前的 Manifest.capabilities 里就有 protocol: object)。
    完整形状仍在原处:生成器为它出页时是它自己的 ## Schema 一节,任何情况下都在
    json-schema/ 里。
  2. 标记必须挣回自己的位置(fix(spec): 参考文档顶层长枚举移入 Allowed Values,联合变体印数量 (#6225, #6226) #6377 实测)。 本 PR 不新增任何标记,共享守卫原样
    保留,并在深度预算下继续正确工作(见下面 gen:docs 深度预算落地后,11 个单元格出现 object | object | object | object —— 同形变体是否该去重,落在 #6226 的裁决面上 #6569)。
  3. 4 个无联合的单元格是试金石。 逐格数据见方向三那节:方向一把它们从
    598/595/583/450 降到 98/98/145/106;方向三对它们完全无效

#5340 / #6226 的标记都还活着

深度预算在它们上游,所以会吸收掉一部分出现位置,但两条都没有被关掉:

改前 改后
枚举标记(#5340 / #6225) 173 152
变体标记(#6226) 20 12

#6226 的旗舰样本 App.navigation 在深度 0,逐字未变(377 字符)。

测试

新增 formatType — one shape level, whichever way down (#6374),10 条:四条下钻
路径各一条(旗舰 Page.slots 真实节点、数组元素、Record 值、联合变体)、
「直接对象子节点本来就不透明」(被统一的那条既有规则)、「包装器不花预算,所以
格子顶层的 { … }[]Record< string, { … } > 仍开一层」、「无键的 Record
不是形状」、「无 ctx 也生效」、「本来就只有一层的格逐字未变」,以及同形变体的
元数 pin(见下)。

空洞性守卫:旗舰那条断言 rendered.length === 122not.toContain('Enum<')
—— 预算一撤,这个节点会把同一份 PageComponent 摘要印 8 遍,两条断言同时以一个
数量级的差距失败。(该夹具是自带的真实节点快照,所以合并后依旧是 122 —— 而活的
Page.slots 也仍是 122:深度预算把第一层以下全收掉了,main 新加的嵌套键因此
够不到这一格的宽度。这正是这条修法的稳健性。)

反向验证 —— 方向在跑之前就写死了

撤销 = 删掉 depth >= SHAPE_DEPTH_LIMIT 守卫并把三元表达式放回去。
方向不是全红,而这正是本块的要点:本次修的是让一条既有规则统一,所以那些钉住
「本来就存在的那条限制」的用例必须在撤销下保持绿,否则它们钉的就不是一致性。

预测(写在运行之前,已落在测试块注释里):6 红 / 4 绿

  • 红:object 经由数组 / Record 值 / 联合变体到达的每一条,加上 no-ctx 那条。
  • 绿:「直接对象子节点本来就不透明」、两条「包装器不花预算」、「无键 Record
    不是形状」。

实测:逐条吻合。 该块 6 红 4 绿,4 条绿的正是预测的那 4 条。
块外另有 1 红,是被重新指向的 #6226 夹具(见下),预测未涵盖它 —— 如实记录。

夹具分诊(2 条既有测试)

⚠️ 一处待裁决,已单独立案 #6569(不在本 PR 里改)

深度预算的后果之一:一个联合的多个变体如果都是对象,现在会渲染成同一个字符串,
于是出现 object | object | object | object全语料 11 格,改前 0 格。

本 PR 不折叠它们,三条理由:

  1. 折叠丢掉的是元数 —— 这一格还剩的唯一事实,而 gen:docs 联合类型的每个对象变体都印一遍完整摘要,一个单元格里出现近乎相同的形状 N 次(PageSlots.slots 1538 字符,枚举已省略后仍如此) #6226 的维护者裁决正是
    「省略必须自报数量」;
  2. 仓库已经有意在印这种重复:format-type.test.tsgen:docs 联合类型的每个对象变体都印一遍完整摘要,一个单元格里出现近乎相同的形状 N 次(PageSlots.slots 1538 字符,枚举已省略后仍如此) #6226 的现存 pin
    string | string | string | string | string 逐字保留,理由就是「标记比省下的
    还长」。object | object | object | object 只是同一条既有行为遇上新拼写;
  3. 折叠会覆盖 gen:docs 联合类型的每个对象变体都印一遍完整摘要,一个单元格里出现近乎相同的形状 N 次(PageSlots.slots 1538 字符,枚举已省略后仍如此) #6226Manifest.navigationContributions 那一格的渲染裁决 ——
    在维护者刚裁决过的面上单方面改口。

宽度上它无关紧要。行为已明确钉在
prints an identical variant once per variant 一条里并注明是待裁决项;
#6569 请维护者在 A(现状)/ B(折叠)/ C(折叠+自报元数)之间裁决,
裁决若选 B/C,改的是那一条 pin。

合并与数字复核

GitHub 报 mergeable_state: dirty冲突是纯机械的,不涉及本 PR 的源改动。

origin/main 上有三个提交改了 schema 并各自重生成了 content/docs/references/**,
与本分支的重生成在 13 个 .mdx 上相交:

main 上碰过 packages/spec/scripts/lib/format-type.ts 的提交数:0。
碰过 format-type.test.ts 的:0。碰过本 PR changeset 的:0。

所以这不是设计问题,是这条车道本就要串行的那一类碰撞。

.gitattributesmerge=os-regen 驱动按设计没有做文本合并,而是把这 13 个
文件标记为待重生成 —— 正是为了避免 #6224 那种「零冲突却落地陈旧组合」。
check-regen-pending 随即报了这 13 个文件;在合并后的树上跑
gen:schema && gen:docs 修正了其中 12 个(第 13 个恰好已正确),标记清除。
⛔ 无一处手改 .mdx

复核结论:修法对每一格的效果逐格未变,动的是问题本身的规模。

断言 合并前 合并后 变化
语料单元格数 8499 8432 退役 sweep 删了 schema
改前 >400 9 13 main 新添 4 格
改前最宽 1538 1738 Page.slots#6512 加宽
改后 >200 42 51 随语料变化
改后 >400 1 1 未变
改后 p99 180 182 随语料变化
Page.slots 改后 122 122 未变
改后最宽 = PageComponent.type 656 656 未变
枚举 / 变体标记 156 / 9 152 / 12 随语料变化

原 9 格的改后值全部逐字未变(122 / 656 / 197 / 98 / 98 / 145 / 93 / 153 / 106)。
三条方向的结论在合并后的树上全部复现,只有绝对数字随语料移动;上文所有表格
都已换成合并后的数字。

门禁(合并后的树上实测)

  • pnpm --filter @objectstack/spec check:generated —— 10 / 10 全绿
  • pnpm --filter @objectstack/spec test —— 342 files / 8796 tests passed
  • scripts/format-type.test.ts 单跑 —— 78 passed
  • typecheck / check:scripts-typecheck —— 通过
  • pnpm --filter @objectstack/docs build —— 全语料 MDX 站点构建通过
  • eslint 改动文件 —— exit 0;check:nul-bytes —— 通过
  • check-regen-pending —— 标记已清除

content/docs/references/** 全部由 gen:schema && gen:docs 重生成,无一处手改;未触碰 content/docs/releases/


🤖 Generated with Claude Code

https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o

`format-type.ts` 一直只展开一层 `{ … }` 形状,但这条预算写在键循环的三元
表达式里,于是只有直接对象子节点受它约束。数组元素、`Record` 的值、联合的
变体这三条路径都会重新进入对象分支而预算不在作用域内,单元格宽度于是等于
每层键数 × 变体数 × 每个形状宽度,一层一层乘上去。`ui/page.mdx` 的
`Page.slots` 因此是 1538 字符 —— 而且是在 #5340 的枚举省略已在该格生效
8 次之后的宽度。

新常量 `SHAPE_DEPTH_LIMIT` 把同一条预算移到对象分支本身,四条路径都要过它。
阈值 1 不是选出来的,是取回来的:它就是直接子节点路径上一直生效的那个值。
全语料实测(215 页 / 8499 个类型单元格),任何大于 1 的取值都比不改还差,
因为提高上限必然放松那条本来就是 1 的路径。

  深度上限   | 改前  |   1 |    2 |    3 |    4
  >200 字符  |  121 |  42 |  173 |  191 |  191
  >400 字符  |    9 |   1 |   19 |   35 |   35
  >900 字符  |    1 |   0 |    1 |    1 |    1
  最宽       | 1538 | 656 | 1538 | 1538 | 1538

改后仅剩的 >400 单元格是 `PageComponent.type`(656),落在联合变体里的顶层
词表,#6225 有意不收,且不含任何嵌套形状 —— 形状深度带来的宽度已经从语料
里消失。

`content/docs/references/**` 55 页由 `gen:schema && gen:docs` 重生成,
无一处手改。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 8, 2026 5:59am

Request Review

@github-actions github-actions Bot added the size/l label Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 8, 2026
@os-project-manager
os-project-manager marked this pull request as ready for review August 8, 2026 05:19

Copy link
Copy Markdown
Collaborator Author

PM 验收:通过,转 ready 并开启自动合并。(domain:spec-tooling 座位,session_01AZgRyPVwi1jLb1mNNuUQ9o,派单见 #6374)

边界:验收依据是 diff + 报告 + 已完成的检查;若 ESLint / TypeScript Type Check 仍在跑,自动合并会扣住直到全绿,红了不会合。

派单的裁决是「先量后裁」,三条方向都量了 —— 满足。 逐项复核:

1. 采纳的那条,阈值是「找回来」的而非选出来的。 渲染器一直有深度预算 = 1(键循环里那个三元式),但只作用在四条下钻路径的一条上;数组元素 / Record 值 / 联合变体各自绕开它重入对象分支。于是同一形状在读者看来同样的深度,会因作者有没有把它包进数组而时而不透明、时而全展开 —— 那是关于 Zod 写法的事实,不是关于阅读的事实,正是 #6225 在词表侧消掉的同一种不对称。扫描表把「调参」这个维度本身证伪了:任何 >1 的上限都比什么都不做更糟(>200 从 121 涨到 173+),因为放宽必然松开那条本就在 1 上的路径。

2. 否决 D2 的理由是本轮最硬的一条推理:D2 的下界就是 D1。 预算 150/200 时它的宽度剖面与深度预算逐项相同(>200=42、>400=1、>900=0、max 656),因为每个超预算的格本来就回落到深度 1;再往上只会更宽。所以 D2 在目标上不可能赢过 D1,多出的字符只买到「在本来就有余量的格里多展开一层」。而代价是实测出来的:预算 150 时同一个 Expression 形状在语料里渲染出三种样子,取决于外层对象里无关兄弟键有多宽 —— 126 行与 D1 的差异全在这上面。渲染不再是节点的函数,这对权威输入页是硬伤。另有 #6226 的既有裁决在先。

3. 我给的试金石按预言成立。 D3 对 4 个无联合的格逐字节未动(598→598、595→595、583→583、450→450)。更致命的是它按迭代顺序渲染:Page.slots 会把 header? 完整展开而把类型完全相同actions?/alerts?/highlights? 印成 object。对 ADR-0033 的权威输入页,这比宽单元格更糟。

4. 反向验证的形态是本轮最值得学的一条。 它没有硬套「全红」模板,而是先说明本单不该全红:这个修法是把既有规则统一化,所以钉「原本就存在的那条腿」的用例必须保持绿,否则它们钉的就不是统一性。预言 6 红 / 4 绿,实测恰好,且四条绿正是预言的四条。第 7 条红在块外、预言没点到 —— 它照实报告而不是塞进预言里。这与 #6497 的 dev 拒绝把误报下限凑进红集是同一种品质。

5. 两条既有用例的整体替换有据:#5340 那条钉的正是被移除的那条腿(261 成员枚举在两层形状之下),而 #5340 真正主张的是「省略沿包装器组合」—— 这一点仍然成立(预算挡的是重入对象分支,不是把 inShapeSummary 从数组/记录上切断),故换成数组套枚举的样本;#6226 那条若不换,断言的会变成「标记必须挣回位置」那条守卫而不是变体上限本身,故换成语料里唯一幸存的宽嵌套联合真实节点。

6. 上游未被关掉:深度预算位于两个既有省略之上,吸收了部分出现次数而非停用它们(枚举标记 178→156,变体标记 16→9),#6226 的旗舰 App.navigation 在深度 0、逐字节未变。

关于 #6569 的处理方式,我认可并想点名表扬:深度预算使全 object 的联合变体渲染成同一串(11 格,此前 0),它没有自行裁定,而是发了最保守的一支(保留 arity)、把它钉成一条测试、另立 #6569 交裁决 —— 于是改判 B/C 的代价恰好是一条测试。理由也是证据而非口味:仓库已经有一条 #6226 的活钉,断言 string | string | string | string | string 原样保留因为标记省不回自己的位置 —— 所以 object | object | object | object 是那条既有行为遇上新拼写,不是本单发明的行为;而宽度在此无关紧要(>200 仅 42→39,全语料约 259 字符),所以这纯粹是刚被裁决过的那个面上的可读性/契约取舍,不该由实施者单方面重定。

㉕ 申报:报告明写「无扩面」,与 diff 一致(只动 lib/format-type.ts + 其测试 + 生成物 + 一个 changeset,PageComponent.type 按派单未碰,content/docs/releases/ 未碰)。


Generated by Claude Code

claude added 2 commits August 8, 2026 05:42
`origin/main` 上有三个提交改了 schema 并各自重生成了
`content/docs/references/**`(#6512 i18n 标签契约、#6540 capability 注册、
#6526 ADR-0049 退役 sweep),与本分支的重生成在 13 个文件上相交。
`.gitattributes` 的 `merge=os-regen` 驱动按设计**没有做文本合并**,而是把这
13 个文件标记为「必须在合并后的树上重生成」—— 否则会落地 #6224 那种「零冲突
却陈旧」的组合。

本提交就是那次重生成:`gen:schema && gen:docs` 跑在合并后的树上,12 个文件
被修正,`check-regen-pending` 标记已清除。无一处手改 `.mdx`;
`packages/spec/scripts/lib/format-type.ts` 与其测试**逐字未动**(main 上没有
任何提交碰过这两个文件)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o

Copy link
Copy Markdown
Collaborator Author

PM 追加验收(解冲突轮):通过,自动合并已重开。

放行条件是我在派单里设的那条 —— PR 正文断言的每个数字必须在合并树上重核,因为这单的全部论证就是它的测量。已满足,且做法正确:

冲突性质:纯机械,不是设计问题。 main 上碰过 lib/format-type.ts / 其测试 / 本单 changeset 的提交数各为 0,所以我给的「若实质性冲突则停下上报」条件正确地未触发。相撞的是三条车道各自的重生成:#6512(i18n 标签契约,18 张)、#6540(capability 注册,3 张)、#6526(ADR-0049 退役 sweep,7 张,并删掉了 automation/etl.mdx),与本分支交于 13 张 .mdx

一处值得全仓记住的现场:文本合并 exit 0、零冲突标记,而 check-regen-pending 立刻点名全部 13 张 —— 即 merge=os-regen 驱动按设计拒绝文本合并、改判「必须在合并树上重生成」。若没有这个驱动,这次会静默落地成一个「零冲突却陈旧」的组合,正是 #6224 的失效形态 —— 这回是被现场复现,而不是被论证。

守住的数字:Page.slots 改后仍是 122 —— 而它的改前值从 1538 涨到了 1738(#6512PageComponent 加了嵌套键)。深度预算把第 1 层以下全部收掉,所以 main 新增的嵌套键够不到这一格的宽度。这不是运气,是这条修法的稳健性,已写进正文。同样守住:仅剩的 >400 格仍是 PageComponent.type(656);9 格的改后值逐字节不变;改后 >400=1、>900=0、p95=124;三条方向的结论全部复现(深度 1 仍是唯一可采值;D2 的下界仍恰为 D1;D3 对 4 个无联合格仍逐字节无效)。

移动并已改正文的数字:语料 8499 → 8432 格(退役 sweep 删了 schema);改前 >400:9 → 13 —— 在飞期间 main 上新长出 4 个宽格(Manifest.navigationContributions 439、ListView.userFilters 436、InterfacePageConfig.userFilters 435、Page.interfaceConfig 421),本修法把它们压到 111/115/114/91,正文的格表已扩到全部 13 格并标出新增;改前 max 1538 → 1738;改后 >200:42 → 51;标记计数 173→152 / 20→12。三张扫描表全部在合并树上重测并替换,正文另加了一节「合并与数字复核」明说哪些数字动了、为什么。

它自己抓到的测量错误值得单独表扬:重扫时它发现自己的脚手架有个假象 —— 把深度覆盖设成 99 会连原有的三元式一起去掉,那不等于「不修」,于是基线被读成 >400=33 而真值是 13。它改用真正的 merge-base 文件重测方向三,并在全文改用真基线。它主动点名的理由是「未改正的那一行会夸大本修法的效果」 —— 一个只会让自己好看的错误,由它自己找出来并说破,这是本会话最硬的一次自查。

测试口径的变化也如实交代:全量 343/8832 → 342/8796,原因是退役 sweep 在 main 上删掉了 etl 的 spec 测试,不是本单丢了用例。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants