# DS 瘦身 + 优化（Claude Code 单工具范围）实施计划

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 按「自动化 Agent 设计 / 检查 / 角色测试」目标，把 DS 里为其它 AI 工具准备的第 1 层适配件归档，把三个量出的真缺口（牙的分布 · upstream-gate 零产出 · agent 化只 2 个）各推进一步，并留下一份多维审查报告。

**Architecture:** 三层判位（谁在跑 / 留下什么 / 哪里拦）决定每个对象的去留：只动第 1 层里绑 Codex / claude.ai 的件，第 2、3 层一律不动。牙的补法不加新规则、不进 CI、不要 Figma 凭据进 CI，只把已存在的 Stop hook 的判定面补齐一块（「写了却一次机检没跑」）。upstream-gate 用**追溯回填**的历史需求 V4-2333 让 validator 第一次非 no-op。agent 化优先接线（pipeline → 现有只读 agent），只新增一个真正需要干净 context 的 `upstream-research` agent。

**Tech Stack:** bash hook（Claude Code hooks 契约，已 2026-09-09 逐字核 docs + 无头探针实测）· node ESM zero-dep validator · markdown skill / agent 文件 · vitest（基线 3367 passed）

**Spec:** 用户 2026-09-09 的任务描述（本 session 首条消息）+ [`docs/2026-09-09-ds-automation-architecture-readings.md`](2026-09-09-ds-automation-architecture-readings.md) + [`docs/decision-queue.md`](decision-queue.md) 顶部 6 条 / §1.1

## Global Constraints

- 范围只做 **Claude Code**；Codex / claude.ai 支持继续 DEFER（不新建、也不拆在用的通道）。
- ⛔ 不动第 2、3 层：git hook · `.gitea/workflows/pr-checks.yml` · `scripts/validate-*.mjs` / `audit-*.mjs` · artifact 规范 · `templates/consumer-product/.githooks/`。
- 归档优先于删除；归档落点 = live 路径镜像（`docs/internal/_prompts` → `docs/_archive/_prompts`；`docs/superpowers/specs` → `docs/_archive/superpowers/specs`）；一律 `git mv`；⛔ 不留墓碑文件；入站指针改写成归档后路径。
- 扩豁免 / 降判据 / 放宽任何闸 = C4 ⇒ ⛔ agent 不自批。
- 闸一律不带管道单跑读 `$?`；macOS 无 `timeout`。
- 改判据后必跑 7 闸：`acceptance-gate-coverage · stale-anchors · rule-inventory · doc-shape · gate-mount-declaration · rule-load-map · gate-ci-parity` + 全量 `pnpm test`（基线 **3367 passed / 14 skipped**）。
- ⛔ `--no-verify` · ⛔ `git stash` · ⛔ `add -A`；DS 提交前 `git pull`；两个开工前就脏的文件（`docs/internal/render-coverage-gaps.md` · `playground/docs/data/a11y-token-contrast.json`）⛔ 不提交；两个 stash ⛔ 不动。
- Σ 只数顶层 checklist 的 `·` 份数 ⇒ 改规则正文只加缩进续行（本计划不改 mockup-conventions 等规则正文）。
- 绿灯不算证据：每条新判定面都要造故障验它会红并点名，还原后 `cmp`。

## 基线读数（2026-09-09 11:50 现取，⛔ 别抄，执行时重取）

| 项 | 值 |
|---|---|
| DS HEAD | `d9cd4aa5`（clean，除上述两个脏文件） |
| lab HEAD | `fd71e7a` |
| 棘轮 | `unclassified 36 · gated 47 · nmc 50 · 合计 133`，`EXIT=0` |
| `pnpm audit:upstream-gate` | `no-op PASS EXIT=0`；8 个仓 `upstream-gate.*.md` 全 0 |
| `pnpm test` | `3367 passed / 14 skipped`，`EXIT=0` |
| Stop hook 无头探针 | Claude Code **2.1.251**（nvm）`claude -p`：Stop 触发 2 次、第 1 次 `exit 2` 被尊重（`num_turns 2`，模型按 stderr 回 `PROBE-ACK`）、输入含 `stop_hook_active`（首次 `false`，续行 `true`）。⚠️ ds-autofix 的 launchd 用的是 ServBay 的 **2.1.89**，两个二进制并存 |
| ds-autofix | 09-09 10:17 有一次跑到 `verdict` 阶段（`exitCode 1`，needsHuman）⇒ 「仍零成功」那句已过期：不再卡在 pull |
| ds-metrics | `ds-dimensions.jsonl` **3 行**（09-08 · 09-09 · 09-09） |

---

### Task 1: 归档 4 份第 1 层跨工具适配件（DS）

**Files:**
- Move: `docs/internal/_prompts/upstream-gate-codex.prompt.md` → `docs/_archive/_prompts/upstream-gate-codex.prompt.md`
- Move: `docs/internal/_prompts/2026-07-23-ds-merge-phase2-foundation-cards.prompt.md` → `docs/_archive/_prompts/`
- Move: `docs/superpowers/specs/2026-07-17-trig-03-pipeline-orchestration-tool-agnostic-tracking-design.md` → `docs/_archive/superpowers/specs/`
- Move: `docs/superpowers/specs/2026-06-25-cross-ai-authoring-gate-design.md` → `docs/_archive/superpowers/specs/`
- Modify（入站指针改写为归档路径）: `scripts/lib/foundation-card-template.mjs:6` · `skills/tvu-design-pipeline/SKILL.md:12` · `tests/audit-upstream-gate-cli.test.ts:40` · `docs/internal/backlog.md`（`upstream-gate-codex.prompt` 与 TRIG-03 路径的出现处）· `docs/internal/STATUS-CHANGELOG.md`（同上，只改路径串）· `docs/superpowers/specs/2026-08-05-infra-f96-lifecycle-scan-face-extension-design.md:79` · `docs/superpowers/specs/2026-06-25-mockup-conventions-restructure-design.md:6`

**三层判位（每件先标）：**

| 件 | 层 | 绑哪个工具 | 为什么可归档 |
|---|---|---|---|
| `upstream-gate-codex.prompt.md` | 1 | Codex | 契约真源是 `scripts/upstream-gate.schema.json` + `validate-upstream-gate.mjs`（更厚、留着）；本件只是 L2 入口；live 入链全是注释 / 字符串 fixture / 历史叙述，无硬接线 |
| `…phase2-foundation-cards.prompt.md` | 1 | Codex（一次性 executor prompt） | 契约已固化进 `scripts/lib/foundation-card-template.mjs`；孪生件 Phase 3 早已归档，本件漏网 |
| TRIG-03 spec | 混合，主体是第 1 层的跨工具论证 | 跨工具 | 状态逐字 DEFERRED；唯一 live 入链是 pipeline skill 的防重造指针 ⇒ 指针改写后保留其价值 |
| cross-ai-authoring-gate spec | 混合，Part 1 是历史诊断 | 跨工具 | 内容被 `docs/internal/full-lifecycle-assessment-2026-07-08.md` 接续更新；唯一 live 入链是同日兄弟 spec 的溯源句 |

**本轮刻意不动（写进审查报告）：** `docs/internal/upstream-gate-l1-instructions.md`（硬接线：`export-claude-design-bundle.mjs:77` + `claude-design-reference-registry.json` "16" + `.husky/pre-commit:247`；30 行收益≈0）· `docs/docs-site-dx-parity-spec.md`（live 入链 0 但 §1「五段固定顺序」是唯一副本且无机检 ⇒ 先安置再归档，本轮跳过）· `docs/superpowers/specs/2026-07-09-pillar4-upstream-gate-design.md`（三层都占，是 schema+validator 的设计真源）· `docs/internal/icon-naming-convention.md`（第 2 层 + husky 硬接线，Codex 只是反模式点名）。

- [ ] **Step 1: 重扫入站引用（执行时现取，⛔ 别抄本计划）**

```bash
cd ~/Documents/AICoding/VS_Code/tvu-design-system
for b in upstream-gate-codex.prompt.md 2026-07-23-ds-merge-phase2-foundation-cards.prompt.md 2026-07-17-trig-03-pipeline-orchestration-tool-agnostic-tracking-design.md 2026-06-25-cross-ai-authoring-gate-design.md; do
  echo "== $b"; grep -rn --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=dist-wc --exclude-dir=playground-dist --exclude-dir=_archive "$b" . 
done
```

- [ ] **Step 2: 改指针（每处把 `docs/internal/_prompts/` → `docs/_archive/_prompts/`，`docs/superpowers/specs/` → `docs/_archive/superpowers/specs/`；相对链接同步改 `../../docs/_archive/superpowers/specs/...`）**

- [ ] **Step 3: `git mv`**

```bash
mkdir -p docs/_archive/superpowers/specs
git mv docs/internal/_prompts/upstream-gate-codex.prompt.md docs/_archive/_prompts/
git mv docs/internal/_prompts/2026-07-23-ds-merge-phase2-foundation-cards.prompt.md docs/_archive/_prompts/
git mv docs/superpowers/specs/2026-07-17-trig-03-pipeline-orchestration-tool-agnostic-tracking-design.md docs/_archive/superpowers/specs/
git mv docs/superpowers/specs/2026-06-25-cross-ai-authoring-gate-design.md docs/_archive/superpowers/specs/
```

- [ ] **Step 4: 三闸 + 零残留**

```bash
pnpm -s audit:stale-anchors > /tmp/x1 2>&1; echo EXIT=$?
pnpm -s lint-skills > /tmp/x2 2>&1; echo EXIT=$?
pnpm -s audit:plan-lifecycle > /tmp/x3 2>&1; echo EXIT=$?
grep -rn --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=_archive 'docs/internal/_prompts/upstream-gate-codex\|docs/superpowers/specs/2026-07-17-trig-03\|docs/superpowers/specs/2026-06-25-cross-ai' . ; echo "residue grep EXIT=$? (1 = 零残留)"
```
Expected: 三个 `EXIT=0`；残留 grep `EXIT=1`。

- [ ] **Step 5: Commit（pathspec）**

```bash
git add docs/_archive docs/internal/_prompts docs/superpowers/specs scripts/lib/foundation-card-template.mjs skills/tvu-design-pipeline/SKILL.md tests/audit-upstream-gate-cli.test.ts docs/internal/backlog.md docs/internal/STATUS-CHANGELOG.md
git commit -m "chore(slim): 归档 4 份为 Codex / 跨工具准备的第 1 层适配件（指针改写，零删除）"
```

---

### Task 2: Stop hook —— 更正头注释 + 堵「写了却零机检」的洞

**Files:**
- Modify: `.claude/hooks/post-figma-write.sh:103-106`（两条「没有自动跑机检」分支）+ `:110-135`（发起分支清 marker）
- Modify: `.claude/hooks/stop-figma-conformance.sh:18-23`（头注释）+ `:112-115`（新增第 ③ 段）
- Modify: `.claude/hooks/stop-figma-conformance.selftest.sh`（新增 MH5 / MH5′ / MN5）
- Create: `.claude/hooks/post-figma-write.selftest.sh`

**Interfaces:**
- Produces: 状态文件 `$STATE_DIR/unchecked-writes`（每次未机检的写操作追加一行 `<epoch> <scope>`），由 post-figma-write 写、由 stop hook 消费为 `unchecked-writes.consumed`；发起一次真实 run 时 `rm -f` 它。

**为什么这不是 C1（新增阻塞闸）而是 A/B：** Stop hook 的阻塞已由 owner 2026-09-07 拍 Q6 `fix-last-round-blindspot` 上线；它守的规则逐字是「报 done 前必跑写后机检」。现状：写操作发生但因缺 fileKey/仓库而**一次机检都没跑**时，post-figma-write 只 systemMessage 一句、Stop 静默放行 ⇒ 同一条规则的另一个盲区。补它 = 把已有闸的判定面补齐，不加规则、不进 CI；仍消费一次 + 有界。⚠️ 若 owner 判它属 C1，回滚点是 `stop-figma-conformance.sh` 第 ③ 段。

- [ ] **Step 1: 写 `post-figma-write.selftest.sh`（先红）**

```bash
#!/bin/bash
# 自测 post-figma-write.sh 的「未机检的写」marker。只测不发起后台 run 的分支（无 fileKey）。
set -u
HOOK="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/post-figma-write.sh"
PASS=0; FAIL=0
check(){ if [ "$2" -eq 0 ]; then PASS=$((PASS+1)); echo "  ✓ $1"; else FAIL=$((FAIL+1)); echo "  ✗ $1"; fi; }
run_hook(){ # $1 session $2 code
  printf '{"session_id":"%s","hook_event_name":"PostToolUse","tool_input":{"code":%s}}' "$1" "$2" \
    | env -u CLAUDE_PROJECT_DIR -u TVU_DESIGN_SYSTEM_PATH bash "$HOOK" > /dev/null 2>&1
  EC=$?
}
S="selftest-pfw-$$"; SD="${TMPDIR:-/tmp}/tvu-mockup-conformance/$S"; rm -rf "$SD"
echo "▶ 自测 post-figma-write.sh"
run_hook "$S" '"const n = figma.getNodeById(\"1:2\"); console.log(n.name)"'
check "PN1 只读 code ⇒ exit 0" "$([ "$EC" -eq 0 ] && echo 0 || echo 1)"
check "PN1′ 且不写 marker" "$([ ! -f "$SD/unchecked-writes" ] && echo 0 || echo 1)"
run_hook "$S" '"const f = figma.createFrame(); f.name = \"x\""'
check "PH1 写 code + 无 fileKey ⇒ exit 0（PostToolUse 不拦）" "$([ "$EC" -eq 0 ] && echo 0 || echo 1)"
check "PH1′ 且 marker 1 行" "$([ -f "$SD/unchecked-writes" ] && [ "$(wc -l < "$SD/unchecked-writes" | tr -d ' ')" = "1" ] && echo 0 || echo 1)"
run_hook "$S" '"figma.getNodeById(\"3:4\").resize(10,10)"'
check "PH2 第二次写 ⇒ marker 2 行" "$([ "$(wc -l < "$SD/unchecked-writes" | tr -d ' ')" = "2" ] && echo 0 || echo 1)"
rm -rf "$SD"
echo "▶ 自测：$PASS 过 / $FAIL 失败"; [ "$FAIL" -eq 0 ] || exit 1; exit 0
```

- [ ] **Step 2: 跑它，预期 PH1′ / PH2 红**（`bash .claude/hooks/post-figma-write.selftest.sh; echo EXIT=$?` ⇒ `EXIT=1`）

- [ ] **Step 3: 改 `post-figma-write.sh`** —— 在两条「没有自动跑机检」分支里各加一行：

```bash
  echo "$(date +%s) $scope_desc_or_reason" >> "$STATE_DIR/unchecked-writes"
```
（`REPO` 为空 ⇒ `no-repo`；`file_key` 为空 ⇒ `no-filekey`。）在真正 `nohup … &` 发起分支里加 `rm -f "$STATE_DIR/unchecked-writes"`。⚠️ 「上一轮仍在跑」那条分支**不**追加、也不清（那次写会被 pending run 之后的 Stop 段 ① 兜住的是上一轮的范围，如实起见把它也追加为 `stacked`）。

- [ ] **Step 4: 跑 selftest 全绿**（`EXIT=0`）

- [ ] **Step 5: `stop-figma-conformance.selftest.sh` 加三例（先红）**

```bash
# ── MH5 有未机检的写 ⇒ exit 2 并点出次数 ──
S="selftest-unchecked-$$"; SD=$(mkstate "$S")
printf '1 no-filekey\n2 no-filekey\n3 no-repo\n' > "$SD/unchecked-writes"
run_hook "$S"
check "MH5 有未机检的写 ⇒ exit 2" "$([ "$EC" -eq 2 ] && echo 0 || echo 1)"
check "MH5′ 且点出次数 3" "$(grep -q '3 次' "$ERRFILE" && echo 0 || echo 1)"
check "MH5″ 且 marker 已消费" "$([ ! -f "$SD/unchecked-writes" ] && [ -f "$SD/unchecked-writes.consumed" ] && echo 0 || echo 1)"
run_hook "$S"
check "MH5‴ 第二次 Stop ⇒ exit 0（消费一次）" "$([ "$EC" -eq 0 ] && echo 0 || echo 1)"
# ── MN5 marker 文件存在但为空 ⇒ 不挡、不崩 ──
S="selftest-emptyunchecked-$$"; SD=$(mkstate "$S")
: > "$SD/unchecked-writes"
run_hook "$S"
check "MN5 空 marker ⇒ exit 0" "$([ "$EC" -eq 0 ] && echo 0 || echo 1)"
```
并把 cleanup 循环加上 `unchecked emptyunchecked`。

- [ ] **Step 6: 跑，预期 MH5 / MH5′ / MH5″ 红**

- [ ] **Step 7: 改 `stop-figma-conformance.sh`**：在「没有 pending、也没有未消费的结果」之前加第 ③ 段：

```bash
# ── ③ 写了却一次机检都没跑（缺 fileKey / 仓库）⇒ 挡一次，点出次数 ──────────
if [ -s "$STATE_DIR/unchecked-writes" ]; then
  n=$(wc -l < "$STATE_DIR/unchecked-writes" | tr -dc '0-9')
  mv "$STATE_DIR/unchecked-writes" "$STATE_DIR/unchecked-writes.consumed" 2>/dev/null || true
  emit_and_block "⛔ §M-LIFECYCLE 第②时点：本 session 有 ${n} 次 Figma 写操作**没有任何机检跑过**（post-figma-write 因缺 fileKey 或未定位仓库而没发起）。
下一步（⛔ 别报 done）：贴一次该文件的 figma.com/design/<key> URL 让后续写操作自动机检，或手工跑
  pnpm audit:mockup-conformance --file <key> --node <触碰节点>
明细：${STATE_DIR}/unchecked-writes.consumed（每行 = 一次写的时间与原因）。本提醒只挡一次。"
fi
```
头注释 `:18-23` 改为（逐字）：
```
# ── 契约取自活源 + 实测 (2026-09-09 复核，订正 09-07 那版) ──────────────────
#   · 阻塞机制是**退出码 2**，消息取 **stderr**（docs: "decision: block prevents Claude from stopping";
#     exit 2 路由同 reason）。JSON `{"decision":"block","reason":…}` 亦有效，本 hook 用 exit 2。
#   · 输入**有** `stop_hook_active` 字段（docs 逐字：true when Claude Code is already continuing as a
#     result of a stop hook）。2026-09-09 用 `claude -p` + 探针 hook 实测 Claude Code 2.1.251：
#     Stop 触发两次，首次 false、续行 true，exit 2 被尊重。09-07 那版写「没有这个字段」是错的。
#   · 本 hook **仍不拿它防循环**（它只说明「这是续行」，不说明「该不该再挡」），防循环靠下面两条。
```

- [ ] **Step 8: 两个 selftest 全绿；造故障：注释掉第 ③ 段整块 ⇒ 恰好 MH5 / MH5′ / MH5″ 转红、其余不动；还原后 `cmp`**

- [ ] **Step 9: Commit**

```bash
git add .claude/hooks/post-figma-write.sh .claude/hooks/post-figma-write.selftest.sh .claude/hooks/stop-figma-conformance.sh .claude/hooks/stop-figma-conformance.selftest.sh
git commit -m "fix(hooks): Stop 闸补「写了却零机检」盲区 + 订正 stop_hook_active 断言（2.1.251 无头实测）"
```

---

### Task 3: 把只读 agent 接进流水线的常用路径（skills + hook 注入 + settings）

**Files:**
- Modify: `skills/tvu-design-pipeline/SKILL.md:26-35`（流水线表）
- Modify: `skills/design-qa-loop/SKILL.md:18-27`（Phase 1 加执行形态段，与 `:60-63` 同形）
- Modify: `.claude/hooks/detect-figma-task.sh:112`（mockup-write 注入的第 4 条【走查】句）
- Modify: `.claude/settings.json:22`（删 `"Bash(cat >> *)"`）

**依据（已亲验）：** pipeline Stage 5 逐字只写 `design-qa-loop Phase 2`，全文无 agent 字样；spawn 指令只在 `design-qa-loop:60-63`（Phase 2）与 `design-walkthrough:15`（「建议」）；Phase 1 无执行形态段；`detect-figma-task.sh:147` 只点名 `affordance-search`；`design-review.md:46-47` 场景 C/D 已覆盖 F2-early / F2-late ⇒ **不需要新建 persona agent**，接线即可。

- [ ] **Step 1: pipeline 表改三行 + 加一行**

```markdown
| 前置 | 上游理解-分析 gate | `upstream-gate`（步骤 1–6 派发只读 agent `upstream-research`，写盘 + validator 留主线） | `docs/specs/upstream-gate.<feature>.md` 确定层 `pnpm audit:upstream-gate` PASS；已有 artifact 且需求没变则复用 |
| 2 | IA 验证 | `design-qa-loop` Phase 1 (F2-early) —— 派发只读 agent [`design-review`](../../.claude/agents/design-review.md) 场景 C | 0 🔴 缺口、🟡 均有决策才进下一步 |
| 5 | 设计走查 + 角色测试 | `design-qa-loop` Phase 2 —— F1 + F2-late 派发只读 agent [`design-review`](../../.claude/agents/design-review.md) 场景 A + D；**auto-fix 留主线** | F1 + F2-late 均 0 🔴 |
```

- [ ] **Step 2: design-qa-loop Phase 1 加段（放 `### Loop` 之前）**

```markdown
> **执行形态（Claude Code）**：F2-early 那一步派发只读 subagent
> [`.claude/agents/design-review.md`](../../.claude/agents/design-review.md)（场景 C，读
> [`persona-simulation`](../persona-simulation/SKILL.md) F2-early 模式）跑，拿回缺口清单；
> **改 IA / feature list 那一步留在主线**（agent 无写权限）。
```

- [ ] **Step 3: detect-figma-task.sh:112 【走查】句尾追加**：`；F1 走查派发只读 agent design-review (Agent 工具, subagent_type=design-review)，auto-fix 留主线`

- [ ] **Step 4: settings.json 删第 22 行 `"Bash(cat >> *)",`**（wl-append.sh 已替代它；它是任何拿到 Bash 的只读 agent 的写洞）

- [ ] **Step 5: 验**：`pnpm -s lint-skills; echo EXIT=$?` ⇒ 0；`bash -n .claude/hooks/detect-figma-task.sh`；`node -e 'JSON.parse(require("fs").readFileSync(".claude/settings.json","utf8"))'`；用含「走查」+ figma URL 的 prompt 喂 hook 看注入含 `design-review`：

```bash
printf '{"session_id":"t","prompt":"走查 https://figma.com/design/abc123XYZ/x"}' | .claude/hooks/detect-figma-task.sh > /tmp/dft.json; echo EXIT=$?; grep -c 'design-review' /tmp/dft.json
```

- [ ] **Step 6: Commit**

```bash
git add skills/tvu-design-pipeline/SKILL.md skills/design-qa-loop/SKILL.md .claude/hooks/detect-figma-task.sh .claude/settings.json
git commit -m "feat(pipeline): 只读 agent 接进 Stage 前置/2/5 的常用路径；hook 注入点名 design-review；删 cat>> 写洞"
```

---

### Task 4: 新 agent `upstream-research`（只读调研）+ 修 `affordance-search` 工具表

**Files:**
- Create: `.claude/agents/upstream-research.md`
- Modify: `.claude/agents/affordance-search.md:4`（tools 加两套前缀的 `search_design_system`）
- Modify: `skills/upstream-gate/SKILL.md:14-22`（加「执行形态（Claude Code）」段）

**Interfaces:**
- 输入契约：`feature`（kebab）· 需求原文 / Jira / PRD（inline 或路径）· 消费仓绝对路径 · `docs/product-context.md` 路径（若有）
- 输出：一段可直接粘进 `docs/specs/upstream-gate.<feature>.md` 的 front-matter（7 个必填字段，复杂字段 JSON-inline）+ 5 节正文草稿；每条 competitive 带 `http:` 实测状态；拿不到的写 `UNVERIFIED`，⛔ 不写 validator 结论。

- [ ] **Step 1: 写 agent 文件**

```markdown
---
name: upstream-research
description: 支柱④ 上游理解-分析 gate 的只读调研半环（upstream-gate skill 步骤 1–6）。主线在「做产品设计 / 画 mockup / 加新 feature」动手前派发本 agent，拿回一份可直接落进 docs/specs/upstream-gate.<feature>.md 的 front-matter + 正文草稿。本 agent 只读不写：无 Write/Edit/Bash/use_figma ⇒ 结构上写不了 artifact、跑不了 validator，那两步留主线。
tools: Read, Grep, Glob, WebSearch, WebFetch
---

# Upstream Research Agent（上游调研 · 只读）

你是 `skills/upstream-gate/SKILL.md` 步骤 1–6 的执行器，不是规则真源：字段契约在
`scripts/upstream-gate.schema.json`，流程在那份 skill 里。**本文件只写「拿什么 / 做什么 / 交回什么」。**

> **为什么是 subagent**：① 竞品检索会拉进大量网页正文，不该撑爆主线 context；
> ② 没有 Write / Edit / Bash ⇒ 你交回的是草稿，不是 artifact —— 「确定层 PASS」这句话只能由主线跑 validator 后说；
> ③ 规则不搬家：skill 与 schema 仍是真源。

## 1. 输入契约（缺哪条问一次，⛔ 别猜）
- `feature`（kebab slug）· 需求原文（Jira / PRD / 用户话，inline 或路径）· 消费仓绝对路径 ·
  `docs/product-context.md` 路径（没有就明说「无」，data_feasibility 会降 SKIP）

## 2. 做什么（按 upstream-gate skill 步骤 1–6，逐条读那份 skill 再动）
1. 需求复述 → `understanding`（摘要 + 正文完整复述；把你**不确定**的点单列，交主线向用户确认）
2. 读真源 → `sources_read`：每条 `path#anchor`，anchor 用 GitHub slug；**写之前 Read 那个文件确认标题存在**
3. 竞品实时检索 → `competitive`：每条 `{vendor,url,finding}`；url 必须是你 WebFetch **成功过**的页面，
   并在正文里附 `http: <状态码>` 与一句逐字引用；打不开的写 `UNVERIFIED`，⛔ 禁脑补、⛔ 禁 example.com
4. persona / IA → `persona_ia`
5. 数据可行性 → `data_feasibility.fields`（对照 product-context 的 `available_data_fields`；没有就如实标「未对照」）
6. MVP scope → `mvp_scope`

## 3. 交回什么（返回值 = 草稿本身）
按 `templates/consumer-product/docs/specs/_upstream-gate.template.md` 的形状：front-matter 7 个必填字段
（复杂字段 JSON-inline，validator 靠 `JSON.parse` 读）+ 5 节正文。末尾固定两行：
```
主线下一步: 写入 <消费仓>/docs/specs/upstream-gate.<feature>.md，然后跑
  node <DS>/scripts/validate-upstream-gate.mjs --repo-root=<消费仓>  （读 EXIT，⛔ 不带管道）
```

## 4. ⛔ 禁止
- 不说「确定层 PASS」—— 你没跑 validator。
- 不编 URL、不编引用、不把「没查到」写成「竞品没有」（写「未在公开资料中找到」）。
- 不改任何文件（你也没有工具改）。
```

- [ ] **Step 2: affordance-search.md:4 改为**
`tools: Read, Grep, Bash, Glob, mcp__claude_ai_Figma__search_design_system, mcp__plugin_figma_figma__search_design_system`
（正文 `:66` 逐字要求调 `search_design_system`，原工具表没有 ⇒ 那条路径结构上跑不通。）

- [ ] **Step 3: upstream-gate SKILL.md 在「## 流程」标题下加**

```markdown
> **执行形态（Claude Code）**：步骤 1–6 派发只读 subagent
> [`.claude/agents/upstream-research.md`](../../.claude/agents/upstream-research.md) 跑，拿回 front-matter + 正文草稿；
> **步骤 7（写 artifact + 跑 validator + user 校验）留在主线**（agent 无 Write / Bash）。
```

- [ ] **Step 4: 验** `pnpm -s lint-skills; echo EXIT=$?` ⇒ 0；两份 agent frontmatter 用 `head -5` 目检 `tools:` 单行。

- [ ] **Step 5: Commit**

```bash
git add .claude/agents/upstream-research.md .claude/agents/affordance-search.md skills/upstream-gate/SKILL.md
git commit -m "feat(agents): 新增只读 upstream-research agent；affordance-search 工具表补 search_design_system"
```

---

### Task 5: 追溯回填 V4-2333 的 upstream-gate artifact（TVU Pack）+ 验量具两侧

**Files:**
- Create: `/Users/nancy/Documents/AICoding/VS_Code/TVU Pack/docs/specs/upstream-gate.v4-2333-transmission-test.md`
- 真源：`TVU Pack/docs/specs/2026-07-09-v4-2333-transmission-test-design-record.md`（slug 已算：`1-问题与根因` · `2-scope--non-goals` · `4-设计--状态与指示模型` · `6-决策记录`）· `TVU Pack/docs/PRODUCT_INTRODUCTION.md#32-lcd-直播状态样式参考standby--live--online--offline`
- 竞品（2026-09-09 追溯检索，agent 实测 200）：Teradek `https://teradek.com/products/cube-605`（有 test pattern generator，逐字 "A configurable test pattern generator allows you to test your stream without connecting a video source"）· LiveU `https://www.liveu.tv/products/create/lu300s`（未在公开资料找到）· Dejero `https://www.dejero.com/quick-start-guide-engo-family/engo-3/`（未在公开资料找到）

- [ ] **Step 1: 写 artifact**，头部**必须**两条边界：① 追溯填写（2026-09-09），⛔ 不声称流程当时走过；② 验的是量具能不能跑，⛔ 不是规则被遵守。front-matter：

```yaml
feature: v4-2333-transmission-test
understanding: RPS One 无音视频输入时，操作员无法在开播前验证「背包 → MCR」链路；本期加一键 Test Signal（固定 HD SMPTE 彩条 + 1kHz），推流中给 LIVE 视觉 + 遥测 + Stop Test；scope 以 FB-9937 为准
sources_read: ["docs/specs/2026-07-09-v4-2333-transmission-test-design-record.md#1-问题与根因", "docs/specs/2026-07-09-v4-2333-transmission-test-design-record.md#2-scope--non-goals", "docs/specs/2026-07-09-v4-2333-transmission-test-design-record.md#4-设计--状态与指示模型", "docs/specs/2026-07-09-v4-2333-transmission-test-design-record.md#6-决策记录", "docs/PRODUCT_INTRODUCTION.md#32-lcd-直播状态样式参考standby--live--online--offline"]
competitive: [{"vendor": "Teradek (Cube 605)", "url": "https://teradek.com/products/cube-605", "finding": "产品页明写可配置 test pattern generator：无视频源时测推流、视频失锁时防中断（固定式编码器，非蜂窝背包）"}, {"vendor": "LiveU (LU300S)", "url": "https://www.liveu.tv/products/create/lu300s", "finding": "未在公开产品页找到 test-signal / color bars 类开播前自检；support 知识库对抓取 403，未核对手册"}, {"vendor": "Dejero (EnGo 3)", "url": "https://www.dejero.com/quick-start-guide-engo-family/engo-3/", "finding": "QSG 描述开机进 Preview、按 Go Live；未在公开资料找到 test pattern / connection test 功能"}]
persona_ia: 现场操作员（无源态开播前自检）· MCR 接收端值班；IA = Online idle 屏加 Test Signal 主按钮 → 测试推流屏（LIVE 色带 + 源字段「NO INPUT · Test Pattern / 1kHz」+ Receiver/Bitrate/Delay + Stop Test）
data_feasibility: {"fields": ["receiver", "bitrate", "delay", "running_timecode"]}
mvp_scope: 做：单入口 + 固定 HD 彩条 + 1kHz + 遥测 + Stop Test；不做：多图案类型 / 可配参数 / Config-T / 视频区 TEST 标签（后经 Trevor 评论改为方案 B 整屏蓝 TEST 身份）
```

- [ ] **Step 2: 跑 validator（读 EXIT，不带管道）**

```bash
cd ~/Documents/AICoding/VS_Code/tvu-design-system
node scripts/validate-upstream-gate.mjs --repo-root="/Users/nancy/Documents/AICoding/VS_Code/TVU Pack" > /tmp/ug-real.txt 2>&1; echo EXIT=$?; cat /tmp/ug-real.txt
```
Expected: `── docs/specs/upstream-gate.v4-2333-transmission-test.md ──` · `✓ 确定层 PASS` · degradation `[SKIP] data_feasibility —— 无 product-context` · `EXIT=0`。URL 若超时 ⇒ `[UNVERIFIED]`，不算 FAIL，如实记。

- [ ] **Step 3: 造故障三例（scratch 副本，`--artifact=`）**
  - (a) 把 Teradek url 换成 `https://example.com/x` ⇒ 预期 `EXIT=1`，`[competitive[0].url] 占位/示例域名：example.com`
  - (b) 把第一条 anchor 改成 `#1-问题与根因X` ⇒ `EXIT=1`，`[sources_read: …] heading slug 不存在`
  - (c) 删 `mvp_scope:` 行 ⇒ `EXIT=1`，`[schema.mvp_scope] 必填字段缺失或为空`
  三例各自**只多出那一条** finding。

- [ ] **Step 4: TVU Pack 提交 + push**

```bash
cd "/Users/nancy/Documents/AICoding/VS_Code/TVU Pack" && git pull --ff-only && git add docs/specs/upstream-gate.v4-2333-transmission-test.md && git commit -m "docs(specs): 追溯回填 V4-2333 upstream-gate artifact —— 让 validator 第一次非 no-op（⛔ 不声称流程当时走过）" && git push
```

---

### Task 6: lab 侧落盘 —— 审查报告 · 架构读数更正 · decision-queue · 计划勾选

**Files:**
- Create: `ai-ds-lab/docs/2026-09-09-ds-slim-optimize-review.md`
- Modify: `ai-ds-lab/docs/2026-09-09-ds-automation-architecture-readings.md`（§1.1 表「前置」行是错的：pipeline 表**没有**这一行，upstream-gate 全文零命中；§1.3 Stop 行「未观测」→ 已观测 2.1.251）
- Modify: `ai-ds-lab/docs/decision-queue.md` 顶部表：加 1 条 C1「TVU Pack 要不要挂 `templates/upstream-gate-workflow.yml`（消费仓 CI）」；⚠️ 先过 §1.1 自查：TVU Pack 无 package.json / 无 CI，runner 有没有 node 是只有 owner 知道的输入 ⇒ 真进
- Modify: 本计划文件勾选

审查报告结构：§0 一句话 · §1 基线与探针读数 · §2 瘦身账本（每件：层 / 动作 / 理由 / 入链处理；含 4 件刻意不动）· §3 三个缺口各做了什么 + 两侧证据 · §4 四维审查（UX：跨产品一致性只在规则层被 M21.4 划为「止于产品」、无跨产品走查轴 —— 引用 cross-product 盘点 agent 的证据；PM：upstream-gate 缺席流水线、W 档分流；项目管理：两个 claude 二进制 / ds-autofix 首次到 verdict / 3 个点仍不成趋势；QA：hook 三事件的牙分布表 + `Bash` 仍是只读 agent 的写洞）· §5 本轮不能说的话 · §6 下一轮

- [ ] **Step 1–4: 写三份 + 勾选；lab commit**

```bash
cd ~/Documents/AICoding/VS_Code/ai-ds-lab && git add docs/2026-09-09-ds-slim-optimize-plan.md docs/2026-09-09-ds-slim-optimize-review.md docs/2026-09-09-ds-automation-architecture-readings.md docs/decision-queue.md && git commit -m "docs(slim): DS 瘦身+优化一轮的计划、审查报告与读数更正" && git push
```

---

### 执行记录（2026-09-09 下午，inline 执行）

| Task | 状态 | 落点 | 与计划的偏差（如实） |
|---|---|---|---|
| 1 归档 4 件 | ✅ | DS `bdb9ae31` | 两处「残留」是正则 fixture / 形态示例，非指针，保留；F96 §3「specs 不归档」冲突 ⇒ Q12 |
| 2 Stop 盲区 + 头注释 | ✅ | DS `1c93c285` | 「上一轮仍在跑」分支**没**追加 `stacked` marker —— 那会让第 ③ 段的文案「没有任何机检跑过」变假；该情形由段 ① 兜住 |
| 3 pipeline 接线 | ✅ | DS `91de6018` | 无 |
| 4 新 agent + 修工具表 | ✅ | DS `6dc34197` | 无 |
| 5 追溯 artifact | ✅ | TVU Pack `38febf3`（已 push） | 故障 (a) 首跑用了 `--no-network` 而绿 ⇒ **探针错一半、量具露一缝**；派生 Task 5b |
| **5b validator `--no-network` 漏判占位**（计划外） | ✅ | DS `d506abb9` | 收紧非放宽；先红后绿 51 passed |
| 6 lab 三份 | ✅ | 本文件 · review · arch 读数 · decision-queue Q12/Q13 | 无 |
| 7 全量验证 + push | ✅ | DS `d506abb9` 已 push | test 3369 = 3367 + 2 |

### Task 7: DS 全量验证 + push + 收尾

- [x] 7 闸逐个单跑读 EXIT（全 0）+ `pnpm -s test`（**3369 passed / 14 skipped**）
- [x] 棘轮仍 `36 / 47 / 50`
- [x] `git pull --ff-only` 后 `git push`（`d9cd4aa5..d506abb9`）；两个脏文件与两个 stash 未触碰
- [x] work-log 走 `~/.claude/hooks/wl-append.sh`；memory `measure-negative-claims-too` 加两例（Stop hook 字段断言 · 架构读数「前置」行）
