Skip to content

Commit dab62ea

Browse files
committed
docs(plan): 按变异体实跑更正常量等号牙齿的锚
1 parent d334ebd commit dab62ea

1 file changed

Lines changed: 7 additions & 5 deletions

File tree

‎docs/superpowers/plans/2026-09-13-frontend-redesign-batch7-unwired.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)