@@ -391,6 +391,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
391391> `probe.mjs`(C12 五个文件的官方行数 + 真值锚,逐条自证)· `probe2.mjs`(`useViewMemory` 落点 + 三道门禁的自动捡拾面)· `probe3.mjs` / `probe4.mjs`(其余锚与消费者普查)· `probe5.mjs`(`App.tsx` / toast 三测试 / `tsconfig` 的 `noUnusedLocals`)· `probe6.mjs`(定向复核 T7/T18/T19 的落点行)· **`anchors-baseline.mjs`(文件类锚 165 条 × 基线逐条核对,带正控/负控)** · **`windows.mjs --compact`(同上的可读铺开版)** · **`bare.mjs`(裸 `:NN` 锚 386 条 × 上下文文件解析)** · `scan-plan.mjs`(计划全文错锚与归属句扫描)。
392392> **复现命令**:`node .superpowers/sdd/2026-09-12-frontend-redesign-batch7-unwired/tmp/e1/anchors-baseline.mjs`(+ `bare.mjs`;两者都可用 `--dump <file>` 落盘)。
393393> **仪器自证**:**正控 = PASS**(`line-limits.mjs` 含 `countLines`)· **负控 = PASS**(`zzz_no_such_symbol_zzz` **0 命中**)。
394+ > 🔴 **锚点裁定纪律(§C17.3,本表 E-25 的教训)**:**「某变异体的期望红点」这类锚必须由实跑裁定** —— 在**导出树**里注入变异体(**自证注入恰 1 次**)、跑具名测试、把**实际变红的 `文件:行:断言名`** 抄下来。**不许**由阅读推断。**先例**:`FROZEN_NATIVE_BUTTON_TOTAL 393 → 394` ⇒ CONTROL **15/15 绿** · MUTANT **14/15**,唯一红点 **`buttonMigration.test.ts:272:93`**(证据 `tmp/e1/e25-control.json` / `e25-mutant.json`)。
394395> **本节的定位**:`### 表 6` 的 X2/X3 是**勘误的来源记录**;**本节是逐条的真值表**。🔴 **本计划全文已按本节逐处改正**(受影响位点列给出落点)。
395396
396397**(a)官方行数(E1 实测,`countLines()`)与控制方 §C12 表逐条对拍**
@@ -444,7 +445,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
444445|---|---|---|---|---|---|
445446| **E-23** | **控制方第 14 例**:控制方派发语逐字「**不要碰 `App/src/pages/SessionsPage.tsx` 的 prop(那是 T17 的活)**」 | 🔴 **与计划 `T1` 的 Step 6 冲突**(该步明确要求 T1 给 `SessionsPage` 加两个可选 props 并在 `App.tsx` 透传) | **派发语该句作废**,**以计划 T1 卡为准**:**T1 = 加类型 + `App.tsx` 两行透传 + `SessionsPage` 解构转交;消费逻辑留 T17**。理由(机器可判):`app/tsconfig.json` 的 **`noUnusedLocals: true`** + **`noUnusedParameters: true`** ⇒ **不加那两行透传(或不接收/不使用)`tsc` 必红**(TS6133;控制方实测探针 **exit 2**) | `app/tsconfig.json`(`probe5.mjs` ⇒ `"noUnusedLocals": true`)· `App.tsx`(**599**)· `pages/SessionsPage.tsx` | **T1** 的 Step 6(已写入「以本卡为准」的作废声明)· 本节 |
446447| **E-24** | **计划方第 2 例错误**:`### 表 5` 的 **Y2** 行把 `toastMigration.test.tsx:146`(`toContain("durationMs={3500}")`)判为「**不改**」 | 🔴 **判错**:`durationMs={3500}` 在 **`AiToast` 的定义体内**(`App.tsx:198`)⇒ T1 把 `AiToast` 搬去 `shell/aiToast.tsx` ⇒ **该断言必红**(原行的"零改动反向声明"对本条不成立) | **Y2 行已改写为勘误并保留原文**;🔴 **新增四处授权改写**:`toastMigration.test.tsx:146`(**必改**,换被读文件)· `:126`(`barrelNames(App.tsx)` 含 `Toast` ≠ 搬走后)· `shell/TopBar.test.tsx:276`(`APP_CODE` 含 `placement="belowNav"`)· `shell/ShellFallback.test.tsx:174-175`(在 `App.tsx` 里 `indexOf("function PageSlot(")` 再切定义体);`:117`(`App.tsx` 含 `<AiToast`)**确实不改**(调用点在 `App.tsx:549`) | `App.tsx`(**599**)`:50` / `:160` / `:186` / `:198` / `:199` / `:549` · `toastMigration.test.tsx`(**235**)`:117` / `:126` / `:146` · `TopBar.test.tsx`(**298**)`:276` · `ShellFallback.test.tsx`(**208**)`:174-175`(全部由 `probe5.mjs` 逐行打印复核) | **`### 表 5` 的 Y2 行(勘误)+ Y2-A/Y2-B/Y2-C/Y2-D 四行(新增授权)** · **T1** 的 Files / Step 2b / 诚实边界 |
447- | **E-25** | `nativeButton.ratchet.test.ts:268-273`(出现于 `## Global Constraints` 的 §C5.1 行 / **T10 的 V1** / **`## 陷阱` B4** 三处) | 🔴 **越界**:该文件**只有 265 行**(`countLines()`) | 真锚 = **`:199-200`**(`expect(SCAN.buttonTotal, …).toBeLessThanOrEqual(FROZEN_NATIVE_BUTTON_TOTAL)` = 「常量 == Σ entries」的牙);同文件的另两条牙 = 逐文件表 **`:203-214`**(✓ 本就正确)、`const *Btn*` 族 **`:255-263`**(✓ 本就正确) | `nativeButton.ratchet.test.ts`(**265**)· `probe6.mjs`(逐行打印 `:200-265`;并全文件扫 `FROZEN_NATIVE_BUTTON_TOTAL` ⇒ 仅 `:35` / `:199` / `:200`)· 出处 = **控制方 §C9.7 与 §C5.1 的引述**(控制方侧同一错锚) | `## Global Constraints` 的 C5.1 行 · **T9 的 Step 3 表** · **T10 的 V1(M1)** · `## 陷阱` B4 |
448+ | **E-25** | **🔴 跨文件改锚(控制方 §C17 复核更正了 E1 的第一版修法)**:原引 `nativeButton.ratchet.test.ts:268-273`(出现于 `## Global Constraints` 的 §C5.1 行 / **T10 的 V1** / **`## 陷阱` B4**) | 🔴 **原锚越界**(该文件**只有 265 行**);🔴 **且 E1 的第一版真锚 `:199-200` 也是错的** —— 那是 **① 总量只减不增**(`:196-201`,语义 = **`总量 ≤ 常量`**),**不是** `常量 == Σ entries`。🔴 **这是「引错文件」而不是「引错行」** | ✅ **真锚 = `app/src/ui/primitives/buttonMigration.test.ts:268-273`**(该文件 **280** 行):`:268` = `it("基线常量 == 逐文件 entries 之和(只改常量腾预算必红)", …)` · `:271` = 键数 `toBe(114)` · **`:272` = `expect(FROZEN_NATIVE_BUTTON_TOTAL, …).toBe(sum)`**。🔴 **变异体裁定(§C17.3,E1 在导出树实跑)**:`FROZEN_NATIVE_BUTTON_TOTAL 393 → 394` ⇒ **CONTROL 15/15 绿**、**MUTANT 14/15**,**唯一红点 = `buttonMigration.test.ts:272:93`**(「基线常量 394 ≠ 逐文件之和 393」),`nativeButton.ratchet.test.ts` **保持绿**(总量 392 ≤ 394)⇒ **旧写法会让变异体不红**并导致「判据没牙」的**错误结论** | `buttonMigration.test.ts`(**280**)· `nativeButton.ratchet.test.ts`(**265**)· `nativeButtonBaseline.ts:47`(常量)· 证据 = `tmp/e1/e25-control.json` / `tmp/e1/e25-mutant.json`(vitest `--reporter=json`)+ `tmp/e1/mutate-e25.mjs`(注入点自证恰 1 次)· 出处 = **控制方 §C17**(控制方第 16 例 = 原引越界;E1 第 1 版修法 = 引错文件) | `## Global Constraints` 的 C5.1 行 · **T9 的 Step 3 表** · **T10 的 V1(M1)** · `## 陷阱` B4 |
448449| **E-26** | `SessionScreenCards.tsx:96`(出现于 §C9.4 的「真·可解锁 4 处」引述 + 计划 T7 的两处) | 🔴 **偏 2 行** | `:96` 是 `id={\`ocr-…\`}` 行;**整圈边框在 `:98`**(`border: "1px solid #e5e7eb"`,style 块 `:97-103`,`background: "#fafafa"` 在 `:102`) | `session-detail/SessionScreenCards.tsx`(**193**)· `probe6.mjs`(逐行打印 `:88-104`)· 出处 = **控制方 §C9.4 的三处行号引述**(控制方侧同一错锚) | **T7** 的 `FROZEN_BORDER_TOTAL` 行 · **T7** 的迁移逐处表 |
449450| **E-27** | **计划方第 3 例错误**:T3 卡 Step 3 要求「`lowConfidenceClass` 的用例**已由 T2 搬到** `utils/lowConfidence.test.ts`」 | 🔴 **T2 卡没有这个文件、T2 也(正确地)没建它** ⇒ 原措辞会让 T3 依赖一个不存在的产物 | 🔴 **控制方 2026-09-13 裁决:授权 T3 自建** `app/src/utils/lowConfidence.test.ts`(内容 = `structuredBlocks.test.ts:82` 的**那 1 个 `it`**,内含 4 条 `expect` = `:86-89`);理由 = **删除与迁移必须在同一单元内完成**(否则中间态丢用例) | `structuredBlocks.test.ts`(**92**,`it(` = `:14/:21/:31/:38/:49/:59/:68/:82`)· `probe4.mjs` · 出处 = **控制方追加裁决 2026-09-13** | **T3** 的 Files(新增该文件)· **T3** 的 Step 3 · **T3** 的冻结值预算表(用例数行) · **T3** 的 V4/M4 |
450451| **E-28** | **计划方第 4 例错误**:原计划把「改文件」(T1/T6/T7)与「补豁免表行数」(T11 集中做)**拆给不同单元** | 🔴 **设计缺陷**:`line-limits.mjs --full` 的 **(e) 判据 = 工作树实测 == 登记值**,而 husky pre-commit 扫**工作树** ⇒ **每一个中间提交都必然撞钩子** ⇒ 等于**强制全员 `--no-verify`**(把门禁变成形式)。**T2 与 T8 各自独立撞上,读数一致** | 🔴 **控制方 §C14 裁决**:**豁免表的行数列改由「改文件的那个单元」在同一提交里更新**;**T11 缩为只做非行数类维护**(拆法说明列 / 记录文案);另给 **`--no-verify` 的条件式授权**(四条 + 「❌ 其余钩子失败 ⇒ STOP」,见 `## Global Constraints` 的「提交纪律」节),**权威证据 = T12/T22 在最终树上的串行八闸** | `.husky/pre-commit`(**20** 行,三条具名脚本,实测)· `scripts/line-limits.mjs`(**300**)的 (e) 判据 · 出处 = **控制方 §C14**(T2/T8 实测触发) | **T11** 的标题/目标/预算表/Files/Step 1–2/V1/V3/V6′/诚实边界 · **`### 段 7a 任务一览`** 的 T1/T6/T7/T10/T11 行 · **`> 🔴 热点文件的单写者约束`** 的豁免表行 · **`## Global Constraints` 的「提交纪律」节**(新增条件式授权) |
@@ -1358,7 +1359,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
13581359 | ` surface ` 的 ` <Surface> ` 调用点 | ** 普查** (标签数/ 条目数) | ** 已经是三连通严格相等** (` FROZEN == Σ登记 == Σ实测 ` ) | ** 已经是等式** ⇒ 无需转换 |
13591360 | ` loading ` 的 ` FROZEN_LOADING_TEXT_TOTAL ` | ** 棘轮** | 保留 ` <= ` | ** 不转换** |
13601361 | ` loading ` 的 ` MIGRATED_FILES ` (迁移面** 下界** ) | ** 普查** | 已有下界判据 + 残留面上界 | ** 不转换** (改等式会砸掉" 下界" 语义) |
1361- | ` nativeButton ` 的总量 | 🔴 ** 刻意设计的棘轮** (` :9-11 ` 逐字解释:拆件会让逐行 key 假红,故用计数 + ` SPLIT_MOVES ` 守恒) | 保留 ` <= ` | 🔴 ** 不得改成等式** ;它的** 等式牙齿已经在 ** :逐文件表( ` :203-214 ` ) + 常量 == Σ entries ( ** 真值 ` :199-200 ` ** —— 🔴 §C9 .7 原引的 ` :268-273 ` ** 越界 ** (该文件 ** 265 ** 行),见 ` ### 表 6b ` 的 ** E - 25 ** ) |
1362+ | ` nativeButton ` 的总量 | 🔴 ** 刻意设计的棘轮** (` :9-11 ` 逐字解释:拆件会让逐行 key 假红,故用计数 + ` SPLIT_MOVES ` 守恒) | 保留 ` <= ` | 🔴 ** 不得改成等式** ;它的** 等式牙齿在另一个文件 ** :** ` buttonMigration.test.ts:268-273 ` ** ( ` :272 ` = ` 常量 == 逐文件 entries 之和 ` ) —— 🔴 ** §C9 .7 原引的 ` :268-273 ` 是「引错文件」 ** ( ` nativeButton.ratchet.test.ts ` 只有 265 行、且它自己的 ` :196-201 ` 是 ` 总量 ≤ 常量 ` ); ** 变异体裁定见 ` ### 表 6b ` 的 E - 25 ** 。🔴 ** ` nativeButton.ratchet.test.ts ` 自己的牙 = ① ` 总量 ≤ 常量 ` ` :196-201 ` · ② 逐文件 ` :203-214 ` · ④ ` SPLIT_MOVES ` 守恒 ` :228-253 ` · ⑤ ` const *Btn* ` 族 ` :255-263 ` ** ( ** 四件都不是等号判据 ** ) |
13621363 | 新增的懒侧三判据 | ** 棘轮** (族上限 + 总上限) | ` <= ` | — |
13631364 ⇒ 上表** 逐字进报告** (C9 .7 的「逐处声明」要求)。
13641365
@@ -1445,7 +1446,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
14451446- [ ] ** Step 2 : 自证「只改散文」**
14461447 探针:` git diff -U0 ` 的新增行** 逐行断言** ` ^\+ \* ` 或 ` ^\+ describe\( ` 或 ` ^\+ > ` (Markdown 引用块)。
14471448 🔴 ** ` describe( ` 的标题串算不算" 散文" ?** ⇒ 🔴 ** 已裁(§C11 .6 ):算散文,可改** (Vitest ** 不按标题匹配** ,它只影响报告可读性)。** 但附加四条硬条件(§C11 .6 逐字,防「改散文改出事」)** :
1448- 1. 🔴 ** 该提交只改字符串** —— ** 任何断言、计数、常数一律不动** (` nativeButton.ratchet.test.ts ` 的 ` FROZEN_* ` / `* _BY_FILE` / ` SPLIT_MOVES ` / 「常量 == Σ entries 」全在冻结面内 );
1449+ 1. 🔴 ** 该提交只改字符串** —— ** 任何断言、计数、常数一律不动** (` nativeButton.ratchet.test.ts ` 的 ` FROZEN_* ` / `* _BY_FILE` / ` SPLIT_MOVES ` 全在冻结面内;🔴 ** 「常量 == 逐文件 entries 之和」的牙在 ` buttonMigration.test.ts:272 ` ** ,同样一个字不许动 —— 见 ` ### 表 6b ` 的 ** E - 25 ** );
14491450 2. 🔴 ** 改前必须在全仓 grep 该标题原文** (` 基线随迁移只降不升(T12 后 394 处 / 114 文件) ` 这一整串),确认** 没有** 任何测试 / 脚本 / 文档按它匹配或引用 —— ** 有 ⇒ STOP 报控制方** (判据要把命令与输出写进报告);
14501451 3. 🔴 ** 评审须以 diff 逐字核对「只有标题串变了」** (` git diff -U0 ` 的新增行** 只有** ` describe( ` 那一行);
14511452 4. 🔴 ** 该文件的门禁读数与该文件自身的用例数前后逐字相同** (` nativeButton.ratchet.test.ts ` 的 ` --reporter=json ` 用例数 before == after ;` --full ` 读数同)。
@@ -1461,7 +1462,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
14611462
14621463| # | 判据 | 变异体(专属) | 期望 |
14631464| -- - | -- - | -- - | -- - |
1464- | ** V1 ** | ** 三支棘轮判据全绿** · ` --full ` ** exit 0 ** · ` docs-check ` ** exit 0 ** | ** M1 ** :把 ` FROZEN_NATIVE_BUTTON_TOTAL ` 从 393 改成 394 (** 动常数** ) | ** M1 后期望** :` nativeButton.ratchet. test.ts` 的「常量 == Σ entries 」红 —— 🔴 ** 真值 = ` :199-200 ` ** (` expect(SCAN.buttonTotal , …).toBeLessThanOrEqual(FROZEN_NATIVE_BUTTON_TOTAL) ` );原写 ` :268-273 ` ** 越界 ** (该文件 ** 265 ** 行)⇒ 见 ` ### 表 6b ` 的 ** E - 25 ** 。** 证明" 只改散文" 这条边界真的被判** |
1465+ | ** V1 ** | ** 三支棘轮判据全绿** · ` --full ` ** exit 0 ** · ` docs-check ` ** exit 0 ** | ** M1 ** :把 ` FROZEN_NATIVE_BUTTON_TOTAL ` 从 393 改成 394 (** 动常数** ) | 🔴 ** M1 后期望(变异体裁定,§ C17 . 3 ; E1 在导出树实跑) ** :红在 ** ` buttonMigration. test.ts:272:93 ` ** (` expect(FROZEN_NATIVE_BUTTON_TOTAL , …).toBe(sum) ` ⇒ 「基线常量 394 ≠ 逐文件之和 393 」); ** ` nativeButton.ratchet.test.ts ` 的「总量 ≤ 常量」保持绿 ** ( 392 ≤ 394 )⇒ 🔴 ** 不得 ** 把期望红点写成 ` nativeButton.ratchet.test.ts ` (那是 ** 引错文件 ** ; 见 ` ### 表 6b ` 的 ** E - 25 ** ,证据 ` tmp/e1/e25-mutant.json ` ) 。** 证明" 只改散文" 这条边界真的被判** |
14651466| ** V2 ** | ** 行数逐字不变** :` textBaseline.ts ` = ** 297 ** (改前后);` nativeButton.ratchet.test.ts ` = ** 265 ** ;` surfaceBaseline.ts ` = ** 261 ** | ** M2 ** :把 ` textBaseline.ts:25 ` 的那一行拆成两行 | ** M2 后期望** :` lines.mjs ` 报 ** 298 ** ⇒ 红 |
14661467| ** V3 ** | ** 逐行 diff 全在注释/ 引用块内** | ** M3 ** :顺手把 ` FROZEN_MUTED_GRAY_TOTAL ` 从 63 改成 64 | ** M3 后期望** :diff 里出现非注释行 ⇒ 红 |
14671468| ** V4 ** | ** ` docs-check ` 的扫描/ 检查数与基线逐字相同** (280 / 180 )+ 五项全 ✅ | — | 逐字读数 |
@@ -2450,7 +2451,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
24502451### B4 · 棘轮与冻结值
24512452- **① C9.12 的预算法是**硬要求**:算不出「触碰的冻结键 + 现值 + 上限 + 是否变红」⇒ **计划不合格**。
24522453- **② 只许降或持平**(C5.1):抬任何 `FROZEN_*` 都违规(`<Surface>` 登记制是**唯一**例外,且只许按 C9.5 三步 + C9.8 的实测登记)。
2453- - **③ 禁止只改常量不动逐文件表**(`nativeButton.ratchet.test.ts:203-214` 的逐文件表 + **`:199-200 `** 的「常量 == Σ entries」是守卫已有的牙;🔴 §C5.1 原引的 `:268-273` **越界**,见 ` ### 表 6b` 的 ** E-25**)。
2454+ - **③ 禁止只改常量不动逐文件表**(`nativeButton.ratchet.test.ts:203-214` 的逐文件表 + **`buttonMigration.test.ts:272 `** 的「常量 == 逐文件 entries 之和 」是守卫已有的牙;🔴 ** §C5.1 原引的 `nativeButton.ratchet.test.ts :268-273` 是「引错文件 + 越界」** —— 该文件只有 **265** 行、且它自己的 `:196-201` 只是 `总量 ≤ 常量`;**变异体裁定见 ` ### 表 6b` 的 E-25**)。
24542455- **④ `<Surface>` 的 9 行 legacy「只许降」**(C9.5 逐字)。
24552456- **⑤ `nativeButton` 的总量断言不得改成等号**(C9.7 逐字:会砸掉 `SPLIT_MOVES` 语义)。
24562457
@@ -2487,6 +2488,7 @@ surfaceBaseline.ts:49 → * 阴影 **24 → 24 处 / 24 文件(…)**
24872488
24882489- **B9-①(🔴 本批最贵的一条 · 行号锚的系统性偏移)**:编制期仪器 `tmp/plan-writer/sites.mjs` 的 `stripComments` **把块注释整段删除**(`s.replace(/\/\*[\s\S]*?\*\//g, "")`)而不是抹成等长空白 ⇒ **它打印的 `:N` 是「剥注释后的行号」** ⇒ **凡引用它的锚一律偏移**(本批已知 24 条,见 `### 表 6b`)。**正确做法**:① 自测行号时**抹注释为等长空白保行号**(先例 `tmp/t2/census.mjs`、`tmp/e1/anchors-baseline.mjs`);② 一切锚以**冻结提交树**(`git show <BASE>:<path>`)为基准(工作树有在飞改动);③ 读数口径 `countLines()`;④ 仪器必带**正控 + 负控**。
24892490- **B9-②(🔴 豁免表行数的职责)**:`--full` 的 (e) 判据读**工作树**、husky 也读**工作树** ⇒ **行数列必须由改文件的那个单元在自己提交里更新**(§C14),否则**每个中间提交都撞钩子** ⇒ 会逼出全员 `--no-verify`。`--no-verify` 只在 §C14.3 的四条全成立时可用,**其余钩子失败 ⇒ STOP**。
2491+ - **B9-③(🔴 锚点由变异体裁定,不由推理裁定 —— §C17.3)**:**凡写「某变异体的期望红点」这类锚,必须在导出树里真跑那个变异体**,把**实际变红的 `文件:行`** 抄进计划/报告;🔴 **不许**由「哪条断言看起来像」推断。**本批已因此修错两次**(控制方 §C5.1/§C9.7 把 `nativeButton.ratchet.test.ts:268-273` 当等号牙 = 引错文件;E1 第 1 版把它改成同文件 `:199-200` = 也错,那是 `总量 ≤ 常量`)⇒ 真身在 **`buttonMigration.test.ts:272`**(实跑证据:CONTROL 15/15 绿 · MUTANT 14/15,唯一红点 `buttonMigration.test.ts:272:93`)。**做法**:导出树 → 注入(**自证恰 1 次**)→ 跑 → 抄 `文件:行:断言名`;**`ran > 0` 只是旁证**。
24902492- **① 🔴 C9.15 与 C10.1 的形态不同** ⇒ **本计划按 C10.1**;任何实施者若按 C9.15 的"换成 react-markdown"做 ⇒ **违反 C10.1 的"禁止"**。
24912493- **② `NotePreviewView.renderMarkdown` 是**非导出**函数** ⇒ 补表征测试**必须先解决可达性**(T16 选 `export function renderMarkdown`,+0 行)。
24922494- **③ `setViewKey` 会写视图记忆**(`useViewMemory` 写 localStorage)⇒ 自动切三轨**有持久副作用**(见 `## 待控制方裁决` #2)。
0 commit comments