{
  "taskId": "GT-002",
  "slug": "ndi-source-type-form",
  "archetype": "form-flow",
  "archetypeLabel": "表单流",
  "taskSetVersion": "v1",

  "provenance": {
    "kind": "real-requirement",
    "pinnedSha": "4a68e02d3d695cee3c39d255ea5d20f7f2bf9b8c",
    "citations": [
      {
        "path": "docs/internal/_metrics/phase0-ledger.md",
        "mustContain": "V4-1827 Round 3",
        "why": "真 Jira 需求：RPS One 支持 NDI 作为 Live Input（Config-T `rJJjWWs51n2iFOlCIC7aYG`）。⚠️ **2026-08-26 换出处（`lab:N37` 到期）** —— 原出处 `docs/_archive/_design-kickoffs/v4-1827-ndi-into-ipsource.md` 已被 DS 在 commit `483e3feb` 连同整个 `_archive/_design-kickoffs/` 目录删除。ledger 是 append-only 台账（与 GT-003 同源），无删除动机。"
      },
      {
        "path": "docs/internal/_metrics/phase0-ledger.md",
        "mustContain": "radio 三选一互斥",
        "why": "增量契约成文的凭据：该行（2026-07-21 V4-1827 Round 3）逐字记着「NDI 归入现有 IP Source 页、`Type of source` radio 三选一互斥（HDMI/SDI/USB · IP Source · NDI）、per-Tx、三态内容区」+「AFTER 三帧（IP 6卡 / NDI 单源表单 / HDMI 居中提示）+ 分隔线(`--line-light`)+ 状态 caption」⇒ **逐条覆盖本任务 prompt 的四条要求**（三选一互斥 / 三态内容区 / 分隔线 / 不新增页签）。"
      }
    ]
  },

  "prompt": {
    "templateVersion": "pt-v1",
    "text": "请用 TVU 设计系统，为一个既有的设备本地设置页做**增量设计**，产出**单文件 HTML** 高保真 mockup。\n\n背景：产品原本的「Type of source:」是二选一互斥（`HDMI/SDI/USB` 与 `IP Source`）。现在产品新增了对 NDI 作为直播输入源的支持。\n\n要改的：\n\n1. 「Type of source:」从二选一变成**三选一互斥**，新增第三项 `NDI`\n2. 选中项决定下方内容区：选 `IP Source` 时保持既有的来源卡片网格（含预览、IP、目标接收端、应用按钮）；选 `NDI` 时内容区切换成 NDI 专属表单\n3. 选择行与内容区之间加一条视觉分隔\n4. 顶部导航**不新增页签** —— NDI 不是一个新的导航项\n\n三种选中态都要能在产出里看到（可用同页多帧或明确的状态标注）。\n\n约束：单文件、可直接在浏览器打开、不引外部 CDN。"
  },

  "outputContract": {
    "form": "single-file-html",
    "path": "runs/<runId>/GT-002.html",
    "mustNotRequire": ["network", "FIGMA_TOKEN", "build step"]
  },

  "graders": [
    {
      "id": "ds-html-conformance",
      "kind": "T1",
      "judgeSource": "DS gate",
      "script": "scripts/audit-mockup-html-conformance.mjs",
      "caliper": "5 规则口径（同 GT-001）",
      "expectedDiscrimination": "表单面主要打 unconstrained-svg 与 hardcoded-color；不含确认弹窗 ⇒ **popupbox-for-confirm 在本条上应恒不命中**，可作为跨任务的 must-not-hit 对照。"
    },
    {
      "id": "lab-escape-rate",
      "kind": "T1",
      "judgeSource": "lab 自写",
      "script": "metrics/escape-rate.mjs",
      "caliper": "字面色值/间距口径（同 GT-001）"
    }
  ],

  "whyThisTask": "三条里唯一形态是「互斥单选驱动条件内容区」的一条 —— 3-way 实验完全没覆盖这类。且它的增量契约成文，转写不需要我编需求。",

  "boundaries": [
    "⛔ 形态转写同 GT-001：原需求交付物是 Figma（Config-T `rJJjWWs51n2iFOlCIC7aYG`），本任务要 HTML。",
    "⛔ 原 kickoff 卡里带 Figma node id（`7862:1729` 等），**prompt 里刻意不给** —— 给了就变成「照着节点抄」，测不出选型能力。",
    "⚠️ **本条的 citation 出处正在 `archive-triage` 桶三（真删）清单上** —— 该处方 §2 逐字列着「`_archive/_design-kickoffs` | 2 | 210」，判据是「0 外部入站」。而 lab 的引用在 **DS 仓外**，DS 的 `ds-doc-graph` 结构上看不见它。",
    "但这**不会破坏已冻结的 v1**：冻结物钉死在 `4a68e02d`，而 pin worktree 是 detached 的不可变快照 —— DS 在 master 上删了，pin 上照旧在。⇒ v1 的 citation 校验**永远可复现**。真正的影响在**下一次 re-pin**：新 pin 上定位不到 ⇒ 校验器 fail ⇒ 触发 §7.5 的 set 升级流程。这正是 §7.5 没写全的那个升级触发条件（它只写了「需求变了」，没写「出处被删了」）。",
    "✅ **上一条边界已于 2026-08-26 兑现并结清（`lab:N37`）** —— 出处已换成 `docs/internal/_metrics/phase0-ledger.md`，⛔ 上一条原文逐字保留不删（被推翻/已兑现的框架要留痕，否则下轮会照旧措辞再引一次）。⚠️ 注意兑现方式与预测**不同**：预测说「re-pin 时校验器 fail ⇒ 触发 §7.5 升级流程」，实际是**在 re-pin 之前主动换出处**，且换出处**不触发 §7.5** —— 因为 `prompt` 与 `outputContract` 一个字节未动（`subjectSha256` 逐位不变，由 `golden-set-freeze` 的三分档实测钉住）。⇒ **「出处被删」这个升级触发条件，实际上可以被「换一个等价出处」提前拆掉，不必真走 set 升级。**",
    "⚠️ **换出处的性质，⛔ 别读错**：本条 prompt 是冻结时照 kickoff 卡的 `Baseline / Delta Contract` 段（**事前契约**，Keep/Change 逐条成文）转写的；新出处 `phase0-ledger.md`（2026-07-21 V4-1827 Round 3 行）是**事后流水记录**。两者都能逐条支撑 prompt 的四条要求（已逐条对拍），但**形态不同** ⇒ 本条应读作「**为同一段已冻结的 prompt 重新找一个可定位的凭据**」，⛔ **不是**「照新出处重新转写了 prompt」。",
    "⚠️ **换出处引入一处单点风险，如实登记**：GT-002 与 GT-003 现在引的是**同一份文件** `docs/internal/_metrics/phase0-ledger.md` ⇒ 该文件若被删/被搬，**两条 task 同时失去凭据**。取舍理由：它是 append-only 台账（DS 侧无删除动机），而原 `_archive/` 那条路已实证会被清理。⛔ 不假装没有。"
  ]
}
