# Prompt — audit:translation-completeness section boundary fix

> **触发方式**：用户 → executor：`请按 docs/internal/_prompts/audit-translation-completeness-h2-boundary-fix.prompt.md 执行`
> **角色**：executor
> **plan owner**：Claude Code（已诊断 + 写本 prompt）
> **关联**：v0.4.0 baseline 红的根因；不修无法起步 Phase 6.6 sprint。

---

## 1. 背景（plan owner 已诊断完）

`pnpm run audit:translation-completeness` 报 2 个 active-stale findings：

```
- active-stale:docs/internal/retrospection/design-spec-canonical-alignment-tracker.md#Phase 6.3@5539
  Active section in tracker references Phase 6.3, but divergences-decisions.json marks it resolved
  (id: notification-success-deletion)
- active-stale:docs/internal/retrospection/design-spec-canonical-alignment-tracker.md#Phase 6.3@5539
  …(id: notification-type-deletion)
```

**Root cause** — [`figma-sync/audit-translation-completeness.mjs:407`](../../../figma-sync/audit-translation-completeness.mjs) `auditActiveVsResolved` 函数：

```js
const sectionRe = /^###\s+.*?v\d+\.\d+\.\d+/gm
// ...
for (let i = 0; i < matches.length; i += 1) {
  const start = matches[i].index
  const end = matches[i + 1]?.index ?? content.length  // <-- BUG
  const section = content.slice(start, end)
  // ...
}
```

Section 边界只用 next `### vX.Y.Z` h3 match。tracker.md 里 `### v1.0.0（**稳定承诺**）` 是最后一个 v-pattern h3，导致 v1.0.0 section 一直延伸到文件末尾，把 `## 轨道 A — CANONICAL 系列 → ### 已完成` timeline 表（line 149: "Phase 6.3 stale active 修正" wrap-up entry）误判为 v1.0.0 active 段内的 stale 引用。

**实际**：line 149 是 timeline 历史记录（"已做过 Phase 6.3 stale active 修正"），跟 v1.0.0 没关系。

---

## 2. 修复任务

修 [`figma-sync/audit-translation-completeness.mjs`](../../../figma-sync/audit-translation-completeness.mjs) 的 `auditActiveVsResolved` 函数，让 section 边界除了 next h3 v-match，**也在下一个 `^## ` h2 header 处截断**。

### 精确 patch

`figma-sync/audit-translation-completeness.mjs` line 414-419 附近：

```js
// before
for (const { path, content } of sources) {
  const matches = [...content.matchAll(sectionRe)]
  for (let i = 0; i < matches.length; i += 1) {
    const start = matches[i].index
    const end = matches[i + 1]?.index ?? content.length
    const section = content.slice(start, end)

// after
const h2BoundaryRe = /^##\s+(?!#)/gm  // h2 only (not h3+); used as section terminator
for (const { path, content } of sources) {
  const matches = [...content.matchAll(sectionRe)]
  for (let i = 0; i < matches.length; i += 1) {
    const start = matches[i].index
    const nextH3 = matches[i + 1]?.index ?? content.length
    // Section also ends at next ## h2 (e.g. "## 轨道 A" after "### v1.0.0")
    // to prevent track/timeline tables from polluting the last release section.
    h2BoundaryRe.lastIndex = start + 1
    const nextH2Match = h2BoundaryRe.exec(content)
    const nextH2 = nextH2Match ? nextH2Match.index : content.length
    const end = Math.min(nextH3, nextH2)
    const section = content.slice(start, end)
```

**关键点**：
- `h2BoundaryRe = /^##\s+(?!#)/gm` — `(?!#)` negative lookahead 保证只匹配 `## ` 不匹配 `### ` 或 `#### `
- `lastIndex = start + 1` 跳过当前 section 自己的 h3 header（避免被自匹配）
- `Math.min(nextH3, nextH2)` 取较小边界
- regex `/g` flag + `lastIndex` 重置：因为 `h2BoundaryRe` 在 outer loop 复用，每次 inner iteration 必须 reset

**禁止偷工**：
- 不要改 `sectionRe` 本身
- 不要碰 `archivedRe` / `inlineAckRe` 逻辑
- 不要改 `auditActiveVsResolved` 外的任何函数
- 不要 reformat 该函数的其它代码（最小 diff）
- 不要改 tracker.md / status.md（这才是审计的对象，本 prompt 是审计脚本 fix）

---

## 3. Verify

跑下面命令，逐项核验：

```bash
# 1. audit 必须 pass，0 active findings
pnpm run audit:translation-completeness
# Expected exit 0；输出 byType 不含 active-stale；activeFindings = 0；allowlistedFindings = 9

# 2. 整套 release pipeline 必须 pass
pnpm run prepublishOnly
# Expected exit 0；10 strict gates 全通过

# 3. vitest 跑通（应该不动 test，只防回归）
pnpm test
# Expected 108 passed | 1 skipped

# 4. vue-tsc 跑通
pnpm exec vue-tsc --noEmit
# Expected 0 errors
```

任一不绿 → STOP，列出失败 stdout / stderr，**不要继续 commit**。

---

## 4. 边界 case 自查（人脑跑一遍，不必写 test）

确认下面 3 个场景输出符合直觉：

| 场景 | tracker.md 长这样 | 期望行为 |
|---|---|---|
| A | `### v0.5.0（active）` 后 100 行内有 `### v0.6.0` h3 | v0.5.0 section 在 v0.6.0 处结束（原行为，nextH3 < nextH2） |
| B | `### v1.0.0（active）` 是最后一个 h3，后面紧跟 `## 轨道 A` | v1.0.0 section 在 `## 轨道 A` 处结束（新行为，nextH2 < nextH3=EOF） |
| C | `### v0.3.0（active）` 后只有 `### v0.4.0`，无 `## ` 介入 | v0.3.0 section 仍在 v0.4.0 处结束（nextH3 < EOF=nextH2） |

如果觉得任一场景可能不符合，先 STOP 跟 plan owner 沟通，不擅自扩 patch。

---

## 5. Commit message

verify 4 项全绿后，commit：

```
fix(audit-translation-completeness): section boundary at next ^## h2

Active version sections were extending past file end when no later
### vX.Y.Z h3 existed, polluting v1.0.0 section with track timeline
tables. Fix: section.end = min(nextH3, nextH2).

Unblocks v0.4.0 baseline (Phase 6.3 false-positive active-stale x2
cleared after fix).
```

---

## 6. STOP + 报告

完成后 STOP，**不要**继续做 Sprint A 或任何其它任务。给 plan owner 报：

1. 改动文件 + 行数（应该 ~6 line diff）
2. `pnpm run audit:translation-completeness` 完整 stdout（含 byType + findings 列表）
3. `pnpm run prepublishOnly` exit code + 最后 20 行 stdout
4. commit SHA
5. 任何"我犹豫了但没改"的边界 case（如有）

plan owner 复审后才进 Sprint A（Phase 6.6 FormItem.label dual-form）。

---

## 7. Fallback (B) — 如果 patch 写不通 / verify 不绿

跟 plan owner 报"路径 A patch 不通过"，**不要自行降级到路径 B**（allowlist）。allowlist 是治标方案，plan owner 拍板才能上。

allowlist 路径 B 仅作为最后手段记录在此（参考，**不执行**）：
- 编辑 `figma-sync/audit-allowlist/translation-completeness.json`
- 新增 `activeStale` array（顶层加 key）+ 2 个 entry
- key 形如 `active-stale:docs/internal/retrospection/design-spec-canonical-alignment-tracker.md#Phase 6.3@5539`
- 需检查 `audit-translation-completeness.mjs` 的 `flattenAllowlist` 是否支持 `activeStale` channel — 不支持的话要额外加，scope 比想象大，**不要做**

---

完。
