# 触发器 T 存量覆盖面探针 —— 实施计划

> **For agentic workers:** 本计划按 `superpowers:writing-plans` 写就。步骤用 `- [ ]` 勾选。
> ⛔ **本计划含预注册常量，必须「先 commit 再跑」**（§30.5 N80.1 纪律）。
> ⛔ **控制组不全绿，不许跑正式面**（fail closed，见 Task 3）。

**Goal:** DS 于 2026-08-31 10:57（`6ac56de2`）落地**触发器 T**「给产物定了会增长的性质，就按满载态
定结构」。它目前**只有 1 个实证案例、纯自陈、零机器闸**，而它自己第 (B) 条写着「用同一判据把整个产物
扫一遍」—— **判据给了，没人扫过存量**。本探针产出 T 在 DS 存量 `.md` 上的违规面读数与判据精确率，
供 owner 判「T 要不要配机器闸 / 存量要不要修」。

**Architecture:** 新增 `metrics/container-extensibility.mjs`。把 T 的硬要求（「加一个条目 = 追加一个
单元、不动任何已有单元」）操作化成两条 lab 自己的**结构判据**，双臂扫描：臂 A 读产物的**增长自述**、
臂 B 测**跨段条目横切**，命中 = A ∧ B。控制组用 LCD 那份文档的**重构前 / 后两版**做互证。

**Tech Stack:** 纯 Node ESM、零依赖（D4）。只读 pin worktree。

**Spec:** DS `docs/meta-rules.md` 触发器 T（commit `6ac56de2`）；
本 session 商定的两段切法（第一段＝本探针，第二段＝据读数再决定是否建元机制）。

---

## Global Constraints

- **lab 只审查、不裁定**（`AGENTS.md` §8）⇒ 产出读数与候选清单，⛔ 不推荐「该不该建闸」。
- **只在 pin 住的 worktree 上测量**；pin dirty ⇒ **fail closed** 抛错，⛔ 不许 `allowDirty`。
  跑完验 `git status` 为空。
- **预注册先行**：`PREREG` 常量写死进源码，**先 commit 再跑**；⛔ 不许拿同一份读数反复调阈值到通过（N80.1）。
- **lab 事先不知道的量 ⛔ 不设期望值，显式写 `null`** —— DS 面的违规数从未测过，设任何值都是编的。
- **每条 `must-not-hit` 必须配同构 `must-hit` 阴性对照**（N79.2）；
  **`must-hit` 一样会恒真** ⇒ 每条控制都要回答「它和谁比，那个『谁』是不是同源」（N81.1）。
- **比 id 集合，⛔ 不比总数**（N80.2）—— 候选集用文件路径集合比对，不比命中数。
- **⛔ 不复制 DS 闸里未导出的正则**（副本会漂，而控制测的是副本）⇒ 判据用**通用 markdown 结构**，
  并在报告里明示「这是 lab 的判据，不是 DS 闸的判据」。
- **凡引用分母必带口径名**（`AGENTS.md` §2.4）⇒ 一律写 `N（ds-tracked-md@6ac56de2 口径）`。
- **⛔ 读数只对 `.md` 面成立，不得外推到 Figma 面**（§2.7：单一形态的估计不外推）——
  T 的催生案例恰恰在 Figma，这个缺口必须在报告里显式写出，⛔ 不许沉默。
- 取退出码 ⛔ 不接管道（zsh 下 `${PIPESTATUS[0]}` 是空的）⇒ 一律 `cmd; echo "exit=$?"`。

### ⛔ 本计划不碰的文件（并行 session 隔离）

同期另有一条 lab 侧工作线（N81.1 回改 `unclassified-fix-triage.mjs`）与 DS 侧 session。本计划：

- **只新增文件**，⛔ 不修改任何已有 `metrics/*.mjs`。
- ⛔ **不碰 [`docs/round2-status.md`](./round2-status.md)** —— 那是 round2 中央状态文件，
  另一条线要往里登记 N82。本探针的登记**留到读数出来后单独一次**，且需先 `git pull`。
- ⛔ **不写 DS 仓**（`AGENTS.md` §1 只读边界）。DS HEAD 在本 session 期间已动过
  （`f3537a4d → 6ac56de2`）⇒ 动手前先看一眼 HEAD。

---

## 判据定义（lab 自己的判据）

触发器 T 的硬要求逐字：**「加一个条目 = 追加一个单元、不动任何已有单元。⛔ 禁按层横切（内容 / 规则 /
出处各一段），那是『一次性』的形态」**。它是 authoring-time 的动作，事后扫不到「起手时想没想」，
**只能扫结构后果**。故拆成两条可测判据：

### D1 · 增长自述 `growthClaim`（臂 A）

T 第三条边界逐字：**「⛔ 性质是我写的，不是猜的」** ⇒ **扫描器不许猜某份文档该不该增长**，
只读它的自述。判据：文件的 **H1 标题 / frontmatter `description` / 首段**（正文前 400 字）
命中冻结词表。

```js
const GROWTH_WORDS = [
  '常驻', '登记', '总表', '索引', '汇总', '清单', '词表', '目录', '花名册',
  '往这加', '后续都', '持续', '逐轮', '累加', '每次都',
  'registry', 'catalog', 'inventory', 'roster',
]
```

⚠️ **`changelog` / `log` 族刻意不入表**：它们按时间单向追加、天然自包含，收进来是已知假阳源。
这是**边界，不是 TODO**。

### D2 · 跨段横切 `crossCutting`（臂 B）

存在 **≥2 个顶层段**，各自列举的**条目名集合**满足：各自 ≥2 项，且重叠率 ≥50%。
⇒ 同一批条目被切在多个段里 ⇒ 加一个条目要动多处 ⇒ 违反 T 的硬要求。

顶层段 = H2/H3。条目名按**通用 markdown 结构**抽取（⛔ 不复制任何闸的正则）：

- 表格：第一列各单元格的文本
- 列表项：`- **X**` / `- X：` / `- X:` 的 `X`
- H4 子标题的文本

重叠率 = `|A ∩ B| / min(|A|, |B|)`。

### 命中

`hit = D1 && D2`。臂 B 独有（有横切、无自述）**不算违规** —— 按 T 第三条边界，性质没写下来就
没有判据。但**必须单独报**：它对应 T 的另一个缺口（「该定性质而没定」），是 owner 的决策输入。

---

## 控制组（`--self-check`）

| id | 输入 | 期望 | 它和谁比 / 是否同源（N81.1） |
|---|---|:-:|---|
| `must-hit-0/lcd-before` | TVU Pack `83db51d:docs/specs/lcd-message-copy.md`（重构**前**，横切三卡） | 🔴 命中 | 和判据比。**非同源**：与 `must-not-hit-0` 是同一文档的两个时点，内容真的不同 |
| `must-not-hit-0/lcd-after` | TVU Pack `d885d72:docs/specs/lcd-message-strings.md`（重构**后**，自包含场景） | 🟢 不命中 | 同上。**两条互为对方的判别力证明**：判据恒红则本条挂，恒绿则 `must-hit-0` 挂 |
| `must-not-hit-1/oneshot-intact` | 一份一次性交付产物原样（`docs/2026-08-31-f4-denominator-branches-plan.md`，自述是单轮计划、无增长词） | 🟢 不命中 | 和判据比。⚠️ **单独看恒真**（它可能因为结构上根本不可能横切而绿）⇒ 必须配下一条 |
| `must-hit-1/oneshot-perturbed` | 同一份文件，**注入扰动**：把两个 H2 段各自改成列举同一批条目（重叠 100%），并在 H1 加「常驻登记」 | 🔴 命中 | 扰动臂。证明 `must-not-hit-1` 的绿是**判据判出来的**，不是输入面恒空 |

- ⛔ **skip 的控制不计为绿**（N79.2）。
- ⛔ **控制组不全绿，不许跑正式面**（Task 3 fail closed）。
- 扰动样本用 `--fixture` 从内存构造，⛔ 不落盘、不改动真实文件。

---

## 预注册常量

```js
const PREREG = {
  // ⛔ DS 面从未测过 —— 设任何期望值都是编的（N80.1）
  dsHitCount: null,
  dsPrecision: null,

  // 控制组：可证伪，写死
  controls: { 'must-hit-0': true, 'must-not-hit-0': false,
              'must-not-hit-1': false, 'must-hit-1': true },

  // 判定阈值 —— 跑前冻结，⛔ 不许跑完再调
  thresholds: {
    // 真命中 = 人判核实后确认违反 T 的文件数；精确率 = 真命中 / 脚本命中
    supportsGate:    { minTrueHits: 3, minPrecision: 0.50 },
    criterionNeedsRewrite: { minTrueHits: 3, maxPrecision: 0.50 },
    selfAttestationSuffices: { maxTrueHits: 2 },
  },
}
```

**三种判定互斥且穷尽**，跑完直接落格，⛔ 不许新造第四种解释。

---

## Task 1：新建 pin @ `6ac56de2` + 预注册先 commit

**Files:**
- Modify: `subjects/tvu-ds/subject.json`（只往 `pinHistory` **追加**，⛔ 不改 `pinnedShaShort`）

**Interfaces:**
- Produces: pin worktree 路径 `~/.ai-ds-lab/pins/tvu-ds-6ac56de2`，供 Task 4 只读扫描

- [ ] **Step 1: 确认 DS HEAD 与目标 sha 一致**

```bash
DS=~/Documents/AICoding/VS_Code/tvu-design-system
git -C "$DS" log --oneline -1; echo "exit=$?"
```

Expected: 输出含 `6ac56de2`。若 HEAD 已前进，**仍 pin `6ac56de2`**（T 落地的那一刻就是要测的时点），
并在报告里记下「pin 时 HEAD 已是 X」。

- [ ] **Step 2: 建 pin worktree（⛔ 落在 DS 工作树之外）**

```bash
DS=~/Documents/AICoding/VS_Code/tvu-design-system
W=~/.ai-ds-lab/pins/tvu-ds-6ac56de2
git -C "$DS" worktree add --detach "$W" 6ac56de2; echo "exit=$?"
```

Expected: exit=0。⛔ 不拆任何旧 pin（README 纪律：旧 pin 是既有读数的主键）。

- [ ] **Step 3: 验 pin 干净 + 触发器 T 确实在里面**

```bash
W=~/.ai-ds-lab/pins/tvu-ds-6ac56de2
git -C "$W" status --short; echo "status-exit=$?"
grep -c "触发器 T" "$W/docs/meta-rules.md"; echo "grep-exit=$?"
```

Expected: status 无输出；grep 计数 ≥1。任一不满足 ⇒ **停止**，不要继续。

- [ ] **Step 4: 往 `pinHistory` 追加一条**

在 `subjects/tvu-ds/subject.json` 的 `pinHistory` 数组追加一条，**字段名照现有条目**
（`sha` / `short` / `role` / `worktree` / `pinnedAt` / `keep` / `whyKeep`，⛔ 别凭印象写）：

```json
{ "sha": "6ac56de225828ec4bdf56781a95e95815b7159ab", "short": "6ac56de2",
  "role": "P7 — 触发器 T 落地当次 commit；本探针的唯一基线",
  "worktree": "~/.ai-ds-lab/pins/tvu-ds-6ac56de2",
  "pinnedAt": "2026-08-31", "keep": true,
  "whyKeep": "…（写清为什么刻意不按 repinProtocol.pinTarget，见下）" }
```

⛔ 不动 `pinnedShaShort`（那是 round2 的主 pin，另一条线在用）。

⚠️ **本次 pin 目标刻意不按 `repinProtocol.pinTarget`**：那条规定 pin 到「本轮处方线的最后一个
commit」，前提是「测处方落地效果」。本探针测的是**一条新规则落地那一刻的存量违规面** ⇒ 基线只能是
规则落地的那个 commit 本身，取更晚的会把 T 落地后的修补算进存量。**这个偏离必须写进 `whyKeep`**，
否则下一轮会被当成「漏 re-pin」修掉。

- [ ] **Step 5: 预注册先 commit（⛔ 跑之前）**

```bash
git add docs/2026-08-31-trigger-t-coverage-probe-plan.md subjects/tvu-ds/subject.json
git commit -m "docs(probe): 触发器 T 存量覆盖面探针计划 + 预注册阈值（先提交，⛔ 不许跑完调）"
echo "exit=$?"
```

---

## Task 2：扫描器 + 控制组

**Files:**
- Create: `metrics/container-extensibility.mjs`

**Interfaces:**
- Produces:
  - `parseSections(md: string) → Array<{ heading: string, items: string[] }>`
  - `hasGrowthClaim(md: string) → { hit: boolean, matched: string[] }`
  - `isCrossCutting(sections) → { hit: boolean, pairs: Array<{a,b,overlap:number}> }`
  - `judge(md) → { growthClaim, crossCutting, hit }`
  - CLI: `--self-check` / `--scan <dir>` / `--md <out>` / `--json`

- [ ] **Step 1: 写脚本头（覆盖边界写在最前，AGENTS §3.4）**

```js
#!/usr/bin/env node
// container-extensibility.mjs — 触发器 T（DS meta-rules, 6ac56de2）的存量违规面探针
//
// 算什么：双臂扫 pin 住的 DS .md 面 ——
//         臂 A `growthClaim`：产物**自述**会增长（⛔ 不猜，T 第三条边界「性质是我写的」）
//         臂 B `crossCutting`：同一批条目被横切在 ≥2 个顶层段里
//         命中 = A ∧ B
// 回答：T 只有 1 个实证、纯自陈、零机器闸；它自己第 (B) 条要求「用同一判据扫一遍整个产物」，
//       但没人扫过存量。本器给存量违规面的**候选清单**，供 owner 判 T 要不要配闸。
//
// 纯 Node、零依赖（D4）。只读。
//
// ════════════════════════════════════════════════════════════════════
// 覆盖边界（**这是边界，不是 TODO**）
// ════════════════════════════════════════════════════════════════════
//  ① **这是 lab 的判据，不是 DS 闸的判据。** ⛔ 未复制任何闸的正则（副本会漂）；
//     段落切分与条目抽取走通用 markdown 结构。
//  ② **只测结构后果，⛔ 测不到 authoring 动作。** T 要求「定结构前输出三行块」，
//     那是过程产物、事后不可见。本器报的是「结构长成了横切」，
//     ⇒ 命中 = **该产物违反 T 的硬要求**，⛔ 不等于「作者没做三行块」。
//  ③ **`changelog` / `log` 族刻意不入增长词表** —— 按时间单向追加，天然自包含。
//  ④ **只覆盖 `.md` 面。** T 的催生案例在 Figma，Figma 面本器**完全没测** ——
//     ⛔ 读数不得外推到 Figma（§2.7）。
//  ⑤ **臂 B 独有（有横切无自述）不算违规**，按 T 第三条边界单独报。
```

- [ ] **Step 2: 实现 `parseSections` + 三种条目抽取**

```js
export function parseSections(md) {
  const lines = md.split('\n')
  const sections = []
  let cur = null
  let inFence = false
  for (const line of lines) {
    if (/^\s*```/.test(line)) { inFence = !inFence; continue }
    if (inFence) { if (cur) cur.raw.push(line); continue }
    const h = line.match(/^(#{2,3})\s+(.*)$/)
    if (h) { cur = { heading: h[2].trim(), raw: [] }; sections.push(cur); continue }
    if (cur) cur.raw.push(line)
  }
  return sections.map((s) => ({ heading: s.heading, items: extractItems(s.raw) }))
}

function extractItems(raw) {
  const items = []
  for (const line of raw) {
    const row = line.match(/^\s*\|([^|]+)\|/)
    if (row) { const c = clean(row[1]); if (c && !/^[-: ]+$/.test(c)) items.push(c); continue }
    const li = line.match(/^\s*[-*]\s+\*\*(.+?)\*\*/) || line.match(/^\s*[-*]\s+([^：:]{1,40})[：:]/)
    if (li) { const c = clean(li[1]); if (c) items.push(c); continue }
    const h4 = line.match(/^#{4,}\s+(.*)$/)
    if (h4) { const c = clean(h4[1]); if (c) items.push(c) }
  }
  return [...new Set(items)]
}

const clean = (s) => s.replace(/[`*_~]/g, '').replace(/\[(.+?)\]\(.*?\)/g, '$1').trim()
```

- [ ] **Step 3: 实现两条判据 + `judge`**

```js
const GROWTH_WORDS = ['常驻','登记','总表','索引','汇总','清单','词表','目录','花名册',
  '往这加','后续都','持续','逐轮','累加','每次都','registry','catalog','inventory','roster']

export function hasGrowthClaim(md) {
  const head = md.slice(0, 400) + '\n' + (md.match(/^#\s+.*$/m)?.[0] ?? '')
  const matched = GROWTH_WORDS.filter((w) => head.toLowerCase().includes(w.toLowerCase()))
  return { hit: matched.length > 0, matched }
}

export function isCrossCutting(sections) {
  const eligible = sections.filter((s) => s.items.length >= 2)
  const pairs = []
  for (let i = 0; i < eligible.length; i++) {
    for (let j = i + 1; j < eligible.length; j++) {
      const A = new Set(eligible[i].items), B = new Set(eligible[j].items)
      const inter = [...A].filter((x) => B.has(x)).length
      const overlap = inter / Math.min(A.size, B.size)
      if (overlap >= 0.5) pairs.push({ a: eligible[i].heading, b: eligible[j].heading, overlap, inter })
    }
  }
  return { hit: pairs.length > 0, pairs }
}

export function judge(md) {
  const g = hasGrowthClaim(md)
  const c = isCrossCutting(parseSections(md))
  return { growthClaim: g, crossCutting: c, hit: g.hit && c.hit }
}
```

- [ ] **Step 4: 写控制组（先跑，必须失败）**

```js
const CONTROLS = [
  { id: 'must-hit-0/lcd-before', expect: true,
    why: 'LCD 重构前版：文案/规则/出处三段横切同一批场景 + 自述「常驻登记处」',
    load: () => gitShow(PACK, '83db51d', 'docs/specs/lcd-message-copy.md') },
  { id: 'must-not-hit-0/lcd-after', expect: false,
    why: '同一文档重构后版：每类场景一张自包含卡 ⇒ 判据必须转绿。与上条互为判别力证明（N81.1）',
    load: () => gitShow(PACK, 'd885d72', 'docs/specs/lcd-message-strings.md') },
  { id: 'must-not-hit-1/oneshot-intact', expect: false,
    why: '一次性计划原样。⚠️ 单独看恒真 ⇒ 必配下面的扰动臂',
    load: () => readFileSync('docs/2026-08-31-f4-denominator-branches-plan.md', 'utf8') },
  { id: 'must-hit-1/oneshot-perturbed', expect: true,
    why: '同一份文件注入横切 + 增长自述 ⇒ 证明上条的绿是判出来的，不是输入面恒空',
    load: () => perturb(readFileSync('docs/2026-08-31-f4-denominator-branches-plan.md', 'utf8')) },
]

function perturb(md) {
  const items = ['条目甲', '条目乙', '条目丙']
  return `# 常驻登记总表（探针扰动样本）\n\n` + md +
    `\n\n## 文案\n\n` + items.map((x) => `- **${x}**：内容`).join('\n') +
    `\n\n## 出处\n\n` + items.map((x) => `- **${x}**：来源`).join('\n') + '\n'
}
```

- [ ] **Step 5: 运行控制组，确认它失败**

```bash
node metrics/container-extensibility.mjs --self-check; echo "exit=$?"
```

Expected: FAIL —— 此时 `gitShow` 尚未实现。这一步是为了确认控制组**真的会红**，
⛔ 不许跳过（否则无法区分「控制通过」与「控制没跑」）。

- [ ] **Step 6: 实现 `gitShow` 与 CLI，commit**

```js
import { execFileSync } from 'node:child_process'
const PACK = `${process.env.HOME}/Documents/AICoding/VS_Code/TVU Pack`
function gitShow(repo, sha, path) {
  return execFileSync('git', ['-C', repo, 'show', `${sha}:${path}`], { encoding: 'utf8', maxBuffer: 1 << 26 })
}
```

```bash
git add metrics/container-extensibility.mjs
git commit -m "feat(metrics): 触发器 T 存量违规面探针 —— 双臂判据 + 4 条控制（含扰动臂）"
echo "exit=$?"
```

---

## Task 3：控制组必须全绿（fail closed 闸）

**Files:** 无（只跑）

- [ ] **Step 1: 跑控制组**

```bash
node metrics/container-extensibility.mjs --self-check; echo "exit=$?"
```

Expected: 4/4 绿，exit=0。

- [ ] **Step 2: 逐条核对期望，⛔ 不看总数**

对照预注册表逐条比对 `must-hit-0=true / must-not-hit-0=false / must-not-hit-1=false /
must-hit-1=true`。**skip 不计为绿**。

- [ ] **Step 3: 任一条红 ⇒ 停止，登记为判据缺陷**

⛔ **不许调阈值让它绿**（N80.1）。特别地：
- `must-hit-0` 红不了 ⇒ 判据抓不住已知阳性 ⇒ **判据不成立**，本探针到此为止，如实登记。
- `must-not-hit-0` 绿不了 ⇒ 判据恒红 ⇒ 同上。
- `must-hit-1` 红不了 ⇒ 扰动臂无效 ⇒ `must-not-hit-1` 的绿**不可信**，重新设计扰动。

---

## Task 4：正式面实跑

**Files:**
- Create: `subjects/tvu-ds/inventory/container-extensibility-6ac56de2.json`

- [ ] **Step 1: 扫 pin 全面**

```bash
W=~/.ai-ds-lab/pins/tvu-ds-6ac56de2
node metrics/container-extensibility.mjs --scan "$W" \
  --json > subjects/tvu-ds/inventory/container-extensibility-6ac56de2.json
echo "exit=$?"
```

- [ ] **Step 2: 记全三元组主键 + 双臂分母（§5.2）**

产物 JSON 必须含：`subjectSha=6ac56de2`、`modelId=n/a`、`promptTemplateVersion=n/a`（T1 确定性
指标，⛔ 显式记 `n/a` 不留空）、`scanFiles`（扫描面文件数）、`armA`（自述臂分母）、`armB`（形态臂
分母）、`intersection`（命中集）、`armBOnly`（有横切无自述）。

- [ ] **Step 3: `_archive/` 分开报**

归档产物的可扩展性缺陷不算实害 ⇒ 分两栏：`live` / `archived`。⛔ 不合并成一个数。

- [ ] **Step 4: 跑完验 pin 仍干净**

```bash
git -C ~/.ai-ds-lab/pins/tvu-ds-6ac56de2 status --short; echo "exit=$?"
```

Expected: 无输出。

---

## Task 5：亲验逐条（⛔ 不外包结论）

**Files:** 无（人判，结论进 Task 6 报告）

> **纪律**：subagent 的「完成 / N 项通过」文字总结 ⛔ 不得直接采信 —— 本 Task 的读数会驱动
> 「要不要建闸」的决定，必须拿到可复核证据（逐条打开文件、实际数触碰单元数）。
> 批量**读取**可外包给 subagent，**判定必须自己做**。

- [ ] **Step 1: 逐条打开命中文件，实测 `appendCost`**

对每个命中文件，回答：「往它加**一个同类新条目**，需要编辑几个已有单元？」
- `0` ⇒ **假阳**（结构其实自包含，判据误判）
- `≥1` ⇒ **真命中**，记下具体要改哪几段

- [ ] **Step 2: 假阳归因分类**

每个假阳标一个原因：`增长词误命中`（如「目录」指的是文件夹）/ `条目名巧合重叠` /
`该产物其实是一次性的` / `其他`。这决定 Task 6 里「判据要怎么改」。

- [ ] **Step 3: 算精确率**

`precision = 真命中 / 脚本命中`。⛔ 分母写 `N（脚本命中，ds-tracked-md@6ac56de2 口径）`。

- [ ] **Step 4: 比 id 集合**

把真命中的**文件路径集合**逐条列出，⛔ 不只报个数（N80.2）。

---

## Task 6：读数报告 + 落判定

**Files:**
- Create: `reports/2026-08-31-trigger-t-coverage.md`

- [ ] **Step 1: 写读数报告**

必含：双臂分母（带口径名）、命中集（列路径）、精确率、假阳归因分布、`armBOnly` 清单、
**以及「Figma 面完全未测」这句显式声明**。

- [ ] **Step 2: 对照预注册阈值落格**

三选一，⛔ 不新造第四种：
- 真命中 ≥3 且精确率 ≥50% ⇒ **读数支持「T 配机器闸」**
- 真命中 ≥3 且精确率 <50% ⇒ **判据表述需重写**，⛔ 不得据此建闸
- 真命中 ≤2 ⇒ **读数支持「T 靠自陈即可」**

⛔ lab 只报落在哪格，**不推荐 owner 选哪个**（`AGENTS.md` §8）。

- [ ] **Step 3: 回答本探针的立项问题**

用同一份读数回答第二段的三个问题：
1. **「判据跨域迁移」值不值得机制化** —— 真命中数就是答案
2. **判据要怎么写才可迁移** —— 假阳归因分布就是答案
3. **「主动扫盲区」回路的成本画像** —— 记下实际耗时与假阳率

- [ ] **Step 4: commit**

```bash
git add reports/2026-08-31-trigger-t-coverage.md \
        subjects/tvu-ds/inventory/container-extensibility-6ac56de2.json
git commit -m "feat(metrics): 触发器 T 存量覆盖面读数 @6ac56de2"
echo "exit=$?"
```

- [ ] **Step 5: 登记进 status（⛔ 先 pull）**

```bash
git pull --rebase; echo "exit=$?"
```

确认另一条线的 N82 是否已落，再往 `docs/round2-status.md` §30.5 追加本探针条目，**编号顺延**。

---

## Task 7（可选，需 owner 点头）：Figma 面抽样

> **为什么单列且可选**：T 的催生案例在 Figma，但 Figma 面**无法程序化扫**（要 `use_figma`
> 逐页勘察），成本远高于 `.md` 面。⛔ 抽样读数**不进精确率计算**，只做形态验证。

- [ ] **Step 1: 抽 5 个自述为「常驻 / 总表 / 登记」的 Figma 页**
- [ ] **Step 2: 逐页人判 `appendCost`**
- [ ] **Step 3: 报形态结论，⛔ 显式标注 `N=5，不外推`**（§2.7：离散型小 N 估计一律不外推）

---

## 自检（写完计划后跑一遍）

- [x] **无占位符**：无 TBD / TODO / 「类似 Task N」。
- [x] **类型一致**：`judge` / `parseSections` / `hasGrowthClaim` / `isCrossCutting` 在 Task 2
      定义，Task 4 与控制组用的是同名同签名。
- [x] **预注册在跑之前**：Task 1 Step 5 commit，Task 4 才实跑。
- [x] **每条 `must-not-hit` 配同构 `must-hit`**：`must-not-hit-1` ↔ `must-hit-1`（扰动臂）；
      `must-not-hit-0` ↔ `must-hit-0`（同文档两版）。
- [x] **每条控制回答了「和谁比、同源吗」**：见控制组表末列。
- [x] **分母带口径名**：`ds-tracked-md@6ac56de2`。
- [x] **不外推声明**：Global Constraints 与 Task 6 Step 1 各一处。
- [x] **并行隔离**：不碰 `round2-status.md`（除 Task 6 Step 5 且先 pull）、不改已有 metrics、不写 DS。
