# Task 2 对账 —— 处方 1 §5.1「分母恒定」（造故障：第 1 步失败）

**环境名 `wt-fault`** · 三元组 `(c1db57b8, n/a, n/a)`（T1 确定性）

## 1. 造故障形态（⛔ 改闸的输入，不改闸脚本）

`src/icons/catalog/generated/arrow.ts` 第一处 `fill="currentColor"/>` → `fill="#dbdbdb"/>`
—— **这正是该闸要抓的真 bug 形态**（`transformSvgCurrentColor` pipeline 漏了一个 icon）。
⛔ 未用 `process.exit(1)` 伪造 —— 那验的是 runner，不是分母恒定。

**判定面非空已先证**（`lab:N48`）：基线 `audit:icon-fill-currentcolor` = **0/644**
⇒ 644 个 icon entry 被判过、`#dbdbdb` 残留 0。

**故障态成立已先证**（⛔ 不带管道单跑，`lab:N47`）：`EXIT=1`，finding 逐字给出
`iconName: "arrow/double-down"` · `neutralHexCount: 1` · `totalPathFills: 1`。
`git status` = **1 行**（只有 arrow.ts）。

## 2. 预注册对账 —— **3 HIT / 0 MISS**

| # | 预测 | 结果 |
|---|---|---|
| **T2-P1** | 逐步表仍 **39 行**，第 2…39 行**每行都有 exit 与耗时** | **HIT** —— 39 / 39 / 39（见 §3） |
| **T2-P2** | runner 总退出码**非 0** | **HIT** —— 4 次全 `EXIT=1` |
| **T2-P3** | 失败行**只有第 1 行**，第 2…39 行 exit 全 0 | **HIT** —— `exit≠0` 集合 = **{1}** |

## 3. 程序化核逐步表（⛔ 不肉眼数）

节边界 = 表头行 `#  npm key  exit  ms  findings  checkedUnits  类型` 之后 →
汇总行 `本轮 N 步全部执行` 之前。⛔ 不跨到摘要段。

| 口径 | 全绿基线 r2 | 第 1 步失败 r2 |
|---|---:|---:|
| 逐步表行数 | **39** ✅ | **39** ✅ |
| 有 `exit` 的行数 | **39** ✅ | **39** ✅ |
| 有耗时（>0）的行数 | **39** ✅ | **39** ✅ |
| `exit≠0` 行号集合 | `{}` | **`{1}`** ✅ |
| 第 1 步 / 第 39 步 | `icon-fill-currentcolor`(0) / `figma-env-single-source`(0) | `icon-fill-currentcolor`(**1**) / `figma-env-single-source`(0) |
| 非闸行（E14） | `lint-skills` · `lint:ds` | 同 ✅ |

**逐位对账**：两份 39 个 `npmKey` **全同** ✅ · 第 2…39 步 exit **全同（都是 0）** ✅

⚠️ **解析器 fail-closed 实际救了一次**：表体里有一条 `───` 分隔线，
初版解析器**抛错而非静默跳过**（AGENTS §3.1）⇒ 改为**显式**排除分隔线、其余仍抛。
⛔ 若当初写成「解析不出就跳过」，行数会变成 38 而我不会知道。

## 4. 独立墙钟旁证 —— ⛔ 不依赖 runner 自称

处方 §5.1 逐字：「**⛔ 证据不是「runner 说它跑了」**」。
⇒ 用**同一把尺**（`/usr/bin/time -p` 的 `real`，全部 `wt-fault` 口径，各 4 次丢弃第一次）：

| 口径 | 均值 | σ |
|---|---:|---:|
| (a) 全绿全链 | **13,465 ms** | 102 |
| (b) 第 1 步失败全链 | **13,530 ms** | 73 |
| (c) 「改造前失败即停」等价 = 第 1 步单步 | **157 ms** | — |

- **(b) − (a) = +65 ms**，合并 **2σ = 177 ms** ⇒ **落在噪声地板以下，两者统计上无差异**
- **(b) / (c) = 86.2 倍** ⇒ 若仍 fail-fast，(b) 应 ≈ 157 ms
- ⇒ **后 38 步确实执行了，且其耗时被完整计入** —— 该结论**不依赖 runner 的逐步表**

**跨装置交叉验证**：(c) 的 157 ms 与 runner 逐步表自报的 **161 ms** 一致 ✅

⚠️ (c) 是**等价口径模拟**，⛔ **不是旧 runner 实跑** —— 旧形态是 39 步顶层 `&&`，
第 1 步非 0 即停 ⇒ 总耗时 ≈ 第 1 步耗时。本读数按此语义构造。

## 5. 🔴 顺带发现：摘要的 `stderr 尾部` 字段**结构性为空**

失败摘要原文：
```
   ── #1 audit:icon-fill-currentcolor  exit 1  (161 ms)
      (stderr 为空 —— 失败明细可能在 stdout，逐条跑该步看)
```

处方 §3.3 第 1 条要求摘要含「步号 + npmKey + **exit** + **stderr 尾部**」，
但 **stdout 契约 v1 要求闸把 JSON（含 `findings[]`）打到 stdout** ⇒
**闸的失败明细在 stdout，stderr 天然为空** ⇒ 摘要那一栏拿不到明细。

⇒ runner 已自觉处理（打了「失败明细可能在 stdout，逐条跑该步看」的提示，⛔ 不是静默留空），
但「失败可定位」这个语义**打了折扣**：还得**再跑一次**那一步才能看到明细。
⇒ **这是处方 §3.3 第 1 条与契约 v1 之间的一处张力**，⛔ 不是 runner 的实现缺陷。
⇒ Task 4（§5.3）会在**双故障**场景下复查这一栏。

## 6. 还原

`git checkout -- src/icons/catalog/generated/arrow.ts` ⇒ `dirty=0` ·
`#dbdbdb` 残留 **0** · 单跑第 1 步 **`EXIT=0`** ✅
