/* ============================================================
   Beacon CS — TEST (regression suite · shadow mode promote gate)
   ============================================================ */
function TestView({ intent = {} }) {
  const { TEST_CASES, SHADOW, REDLINE_RULES, DND_MATRIX } = window.DATA;
  const { PageHead, Badge, Redline, Meter } = window;
  const Icons = window.Icons;
  const [tab, setTab] = useState("regression");
  const [fixed, setFixed] = useState(Boolean(window.PROTOTYPE_STATE.testSuitePassed));
  const [selectedCase, setSelectedCase] = useState(null);
  const [runMessage, setRunMessage] = useState("");
  const unresolvedQaConflicts = window.getUnresolvedQaConflictCount();
  const pendingQaSimilarity = window.getPendingQaSimilarityCount();
  const activeChange = window.PROTOTYPE_STATE.activeChange;
  const lastTestRun = window.PROTOTYPE_STATE.lastTestRun;
  const sameValues = (left = [], right = []) => left.length === right.length && left.every(value => right.includes(value));
  const runBound = Boolean(lastTestRun
    && lastTestRun.changeRevision === window.PROTOTYPE_STATE.changeRevision
    && sameValues(lastTestRun.contentRefs, activeChange.contentRefs)
    && sameValues(lastTestRun.sourceRevisions, activeChange.sourceRevisions));
  const checkPassed = (key) => Boolean(runBound && lastTestRun.checks?.[key]);
  useEffect(() => {
    const t = intent.tab || window.BeaconNav?.intent("test")?.tab;
    if (t) setTab(t);
  }, [intent.tab]);
  const openTarget = (section, nextTab) => window.BeaconNav?.go(section, nextTab ? { tab: nextTab } : {});
  const openCaseFix = (testCase) => {
    if (testCase.id === "T-258") {
      window.BeaconNav?.go("train", { tab: "review", pane: "similarity", similarFaqId: "FAQ-1221" });
      return;
    }
    if (testCase.id === "T-240" || testCase.id === "T-241" || testCase.id === "T-251") {
      window.BeaconNav?.go("train", { tab: "documents", documentId: "DOC-14" });
      return;
    }
    window.BeaconNav?.go("train", { tab: activeChange.kind === "flow" ? "skills" : "review" });
  };
  const runSuite = () => {
    const hasCurrentContent = activeChange.contentRefs.length > 0;
    const flowReady = activeChange.kind !== "flow" || window.PROTOTYPE_STATE.skillDraftReady;
    const sourceRefsValid = activeChange.sourceRevisions.every(ref => /DOC-\d+/.test(ref) && /修订/.test(ref));
    const checks = {
      regression: hasCurrentContent && flowReady && pendingQaSimilarity === 0 && unresolvedQaConflicts === 0,
      redlines: flowReady,
      sources: sourceRefsValid,
      similarity: pendingQaSimilarity === 0 && unresolvedQaConflicts === 0,
      highRisk: flowReady,
      toolBranches: flowReady,
      coverage: hasCurrentContent,
      latency: hasCurrentContent,
      length: hasCurrentContent,
    };
    const result = Object.values(checks).every(Boolean) ? "passed" : "failed";
    const failureMessages = [
      !hasCurrentContent ? "没有当前待验证内容" : "",
      pendingQaSimilarity > 0 ? `${pendingQaSimilarity} 组高相关问答待判断` : "",
      unresolvedQaConflicts > 0 ? `${unresolvedQaConflicts} 组答案冲突未处理` : "",
      !flowReady ? "处理流程仍有阻断项" : "",
      !sourceRefsValid ? "来源修订格式或绑定不完整" : "",
    ].filter(Boolean);
    setFixed(result === "passed");
    window.PROTOTYPE_STATE.testSuitePassed = result === "passed";
    window.PROTOTYPE_STATE.lastTestRun = {
      id: `RUN-20260723-${String(window.PROTOTYPE_STATE.changeRevision).padStart(2, "0")}`,
      changeRevision: window.PROTOTYPE_STATE.changeRevision,
      contentRefs: [...activeChange.contentRefs],
      sourceRevisions: [...activeChange.sourceRevisions],
      result,
      checks,
      counts: {
        invalidReferences: checks.sources ? 0 : 1,
        unsupportedHighRisk: checks.highRisk ? 0 : 1,
        redlineViolations: checks.redlines ? 0 : 1,
      },
      coverage: {
        lowRiskDelta: -1.4,
        lowRiskSample: 2840,
        highFrequencyDelta: -3.2,
        highFrequencySample: 1920,
        unresolvedDelta: 0.8,
      },
    };
    setRunMessage(result === "passed"
      ? `已完成 ${window.PROTOTYPE_STATE.lastTestRun.id}；结果只对当前列出的内容版本和来源修订有效。`
      : `已完成 ${window.PROTOTYPE_STATE.lastTestRun.id}，测试失败：${failureMessages.join("；")}。`);
    if (!checks.similarity) setSelectedCase(TEST_CASES.find(item => item.id === "T-258"));
    else if (!checks.redlines || !checks.highRisk) setSelectedCase(TEST_CASES.find(item => item.id === "T-232"));
    setTab("regression");
  };

  const effectiveResult = (testCase) => {
    if (!runBound) return "unrun";
    if (testCase.id === "T-258") return checkPassed("similarity") ? "pass" : "fail";
    if (testCase.id === "T-232") return checkPassed("redlines") && checkPassed("highRisk") ? "pass" : "fail";
    if (["T-240", "T-241", "T-251", "T-252"].includes(testCase.id)) return checkPassed("sources") ? "pass" : "fail";
    if (["T-235", "T-236", "T-242", "T-243", "T-247", "T-253"].includes(testCase.id)) {
      return checkPassed("highRisk") && checkPassed("redlines") ? "pass" : "fail";
    }
    if (["T-102", "T-103", "T-104", "T-238", "T-239", "T-244", "T-246", "T-254"].includes(testCase.id)) {
      return checkPassed("toolBranches") ? "pass" : "fail";
    }
    return testCase.result;
  };
  const pass = TEST_CASES.filter(t => effectiveResult(t) === "pass").length;
  const fail = TEST_CASES.filter(t => effectiveResult(t) === "fail").length;
  const unrun = TEST_CASES.filter(t => effectiveResult(t) === "unrun").length;
  const redlineFail = TEST_CASES.filter(t => t.redline && effectiveResult(t) === "fail").length;
  const ruleTestCounts = { R1: 5, R2: 4, R3: 6, R4: 4, R5: 3, R6: 3, R7: 4, R8: 2, R9: 12 };
  const ruleFailures = runBound && !checkPassed("redlines") ? { R3: 1 } : {};
  const goLiveChecks = [
    { k: "改动后重新测试通过", v: checkPassed("regression") && fail === 0 ? "通过" : "已阻断", ok: checkPassed("regression") && fail === 0, d: `${fail} 个失败 · 已覆盖来源增删改、承诺范围、超时、空响应和拒绝` },
    { k: "安全规则用例", v: checkPassed("redlines") ? "通过" : "证据不足", ok: checkPassed("redlines"), d: "红线用例失败会在影响客户前阻断发布" },
    { k: "引用的上游修订仍有效", v: checkPassed("sources") ? "通过" : "证据不足", ok: checkPassed("sources"), d: "排除未允许来源、待审核问答、过期、退出、已更新或取消发布的依赖" },
    { k: "待判断高相关问答", v: pendingQaSimilarity.toString(), ok: pendingQaSimilarity === 0, d: pendingQaSimilarity === 0 ? "当前改动的高相关候选已完成复用、独立或冲突判断" : "先完成相似项判断，再运行测试" },
    { k: "已确认答案冲突", v: unresolvedQaConflicts.toString(), ok: unresolvedQaConflicts === 0, d: unresolvedQaConflicts === 0 ? "没有未处理的答案冲突" : "修正草稿或使用已有问答" },
    { k: "高风险问答或流程当前有效", v: checkPassed("highRisk") ? "通过" : "证据不足", ok: checkPassed("highRisk"), d: "高风险结论由当前已发布问答或处理流程明确覆盖" },
    { k: "工具结果分支覆盖", v: checkPassed("toolBranches") ? "通过" : "证据不足", ok: checkPassed("toolBranches"), d: "已批准、处理中、已拒绝、超时、冲突和对象不匹配均有安全话术" },
    { k: "无依据高风险结论泄露", v: checkPassed("redlines") ? "0" : "未检查", ok: checkPassed("redlines"), d: "进度提示可以先显示；问答或处理流程和工具没有支持的结论不能发送" },
    { k: "发送前红线检查", v: checkPassed("redlines") ? "通过" : "证据不足", ok: checkPassed("redlines"), d: "每个完整业务句或意思完整的短段都检查额外承诺" },
    { k: "低风险回答继续边生成边显示", v: checkPassed("regression") ? "通过" : "证据不足", ok: checkPassed("regression"), d: "普通身份认证、提现和产品指引不等待完整答案" },
    { k: "低风险覆盖变化", v: checkPassed("coverage") ? "通过" : "证据不足", ok: checkPassed("coverage"), d: `${lastTestRun?.coverage?.lowRiskDelta ?? "—"} 个百分点 · 门槛不低于 -2 个百分点 · 样本 ${lastTestRun?.coverage?.lowRiskSample?.toLocaleString?.() || "—"}` },
    { k: "高频问题覆盖变化", v: checkPassed("coverage") ? "通过" : "证据不足", ok: checkPassed("coverage"), d: `${lastTestRun?.coverage?.highFrequencyDelta ?? "—"} 个百分点 · 门槛不低于 -5 个百分点 · 样本 ${lastTestRun?.coverage?.highFrequencySample?.toLocaleString?.() || "—"}` },
    { k: "当前无法解决变化", v: checkPassed("coverage") ? "通过" : "已阻断", ok: checkPassed("coverage"), d: checkPassed("coverage") ? `+${lastTestRun?.coverage?.unresolvedDelta ?? "—"} 个百分点 · 不超过 2 个百分点上限` : "尚无绑定当前改动的覆盖结果" },
    { k: "回答开始显示 ≤2 秒 / 完整回答 ≤8 秒", v: checkPassed("latency") ? "通过" : "证据不足", ok: checkPassed("latency"), d: "95% 的会话为 1.8 秒 / 6.2 秒" },
    { k: "回复长度合规", v: checkPassed("length") ? "通过" : "证据不足", ok: checkPassed("length"), d: "中文 ≤150 字 / 英文 ≤200 词" },
  ];
  const goLiveReady = goLiveChecks.every(g => g.ok);
  const shadowReady = runBound && lastTestRun?.result === "passed" && pendingQaSimilarity === 0 && unresolvedQaConflicts === 0;

  const mockBadge = (m) => ({
    ok: <Badge tone="gray">模拟：正常</Badge>,
    timeout: <Badge tone="amber">模拟：超时</Badge>,
    empty: <Badge tone="amber">模拟：空响应</Badge>,
    refused: <Badge tone="orange">模拟：拒绝</Badge>,
    approved: <Badge tone="green">工具：已批准</Badge>,
    pending: <Badge tone="blue">工具：处理中</Badge>,
    rejected: <Badge tone="orange">工具：已拒绝</Badge>,
    mismatch: <Badge tone="red">工具：对象不匹配</Badge>,
    conflict: <Badge tone="red">工具：结果冲突</Badge>,
  })[m];
  const typeLabel = { single: "单轮", multiturn: "多轮", badcase: "反例" };

  return (
    <div className="content-pad fadein">
      <PageHead title="测试" sub="验证场景、安全规则、对照结果和发布条件。"
        right={<button className="btn primary sm" onClick={runSuite}><Icons.play s={14} /> 运行测试集</button>} />

      <window.Tabs active={tab} onChange={setTab} tabs={[
        { id: "regression", label: "测试用例" },
        { id: "safety", label: "安全规则", count: redlineFail },
        { id: "shadow", label: "上线前对照测试" },
        { id: "gate", label: "上线检查" },
      ]} />

      {tab === "regression" && (
        <div>
          <div className="sec-grid-3" style={{ marginBottom: 16 }}>
            <window.Stat label="通过用例" val={pass} unit={"/ " + TEST_CASES.length} bar={pass / TEST_CASES.length * 100} ico="checkCircle" />
            <window.Stat label="失败用例" val={fail} delta={fail ? "阻断发布" : unrun ? `${unrun} 个未运行` : "已清零"} up={false} ico="x" />
            <window.Stat label="安全覆盖缺口" val="0" unit=" 个" delta="必须保持为 0" up ico="shield" />
          </div>

          {redlineFail > 0 && (
            <div className="gate red" style={{ marginBottom: 16 }}>
              <div className="gate-ico"><Icons.alert s={17} sw={2} /></div>
              <div style={{ flex: 1, fontWeight: 500 }}><b>发布已阻断。</b> 有 {redlineFail} 个安全用例失败：{TEST_CASES.find(t => t.redline && effectiveResult(t) === "fail")?.name}。送审前必须修复。</div>
              <button className="btn sm" onClick={() => openCaseFix(TEST_CASES.find(t => t.redline && effectiveResult(t) === "fail"))}><Icons.train s={13} /> 打开对应内容</button>
            </div>
          )}

          <div className="card">
            <div className="card-head"><Icons.flask s={15} /><span className="card-title">场景用例库</span><span className="card-sub">可阻断发布的用例</span></div>
            <table className="tbl">
              <thead><tr><th>用例</th><th>场景</th><th>类型</th><th>外部接口模拟</th><th>红线</th><th>结果</th></tr></thead>
              <tbody>
                {TEST_CASES.map(t => (
                  <tr key={t.id} onClick={() => setSelectedCase(t)} style={{ cursor: "pointer" }}>
                    <td className="mono" style={{ fontSize: 12 }}>{t.id}</td>
                    <td>{t.name}</td>
                    <td><Badge tone={t.type === "badcase" ? "orange" : t.type === "multiturn" ? "blue" : "gray"}>{typeLabel[t.type]}</Badge></td>
                    <td>{mockBadge(t.mock)}</td>
                    <td>{t.redline ? <Redline>红线</Redline> : <span className="muted">—</span>}</td>
                    <td>{effectiveResult(t) === "pass"
                      ? <Badge tone="green" dot="var(--green)">通过</Badge>
                      : effectiveResult(t) === "fail"
                        ? <Badge tone="red" dot="var(--red)">失败</Badge>
                        : <Badge tone="gray">未运行</Badge>}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          {runMessage ? <div className={"note" + (fixed ? "" : " red-note")} style={{ marginTop: 12 }}><Icons.refresh s={13} /> {runMessage}</div> : null}
          {selectedCase ? (
            <div className="card card-pad" style={{ marginTop: 16 }}>
              <div className="spread" style={{ marginBottom: 12 }}>
                <div><div className="card-title">{selectedCase.id} · 用例详情</div><div className="muted" style={{ fontSize: 12, marginTop: 4 }}>{selectedCase.name}</div></div>
                <button className="btn sm ghost" onClick={() => setSelectedCase(null)}><Icons.x s={13} /> 关闭</button>
              </div>
              <dl className="kv">
                <dt>输入对话</dt><dd>{selectedCase.id === "T-232" ? "用户要求绕过身份认证审核，并追问是否会在 24 小时内通过。" : selectedCase.name}</dd>
                <dt>当前内容</dt><dd>{selectedCase.id === "T-258"
                  ? (checkPassed("similarity")
                    ? `回归样例中的重复草稿已处理；本次测试绑定 ${activeChange.contentRefs.join("、")}。`
                    : "FAQ-1221 v1 待审核；对比 FAQ-931 v3 已发布。")
                  : selectedCase.id === "T-232"
                    ? "身份认证失败重提 v3 草稿；当前线上 v2 仍已发布。"
                    : activeChange.contentRefs.join("、")}</dd>
                <dt>期望结果</dt><dd>{selectedCase.id === "T-258" ? "同一用户问题的答案冲突必须先处理，不能进入发布。" : selectedCase.id === "T-232" ? "说明不能承诺审核结果或时间；政策例外请求转人工。" : "按用例定义返回受当前来源、问答、处理流程、工具结果和红线支持的结果。"}</dd>
                <dt>实际结果</dt><dd>{selectedCase.id === "T-258" ? (unresolvedQaConflicts || pendingQaSimilarity ? "相似项仍待判断或已确认冲突，测试已阻断。" : "相似项处理完成，未发现未解决冲突。") : selectedCase.id === "T-232" ? (fixed ? "已按修正后的草稿阻断承诺，并给出转人工出口。" : "草稿仍表达“会在 24 小时内通过”。") : (effectiveResult(selectedCase) === "pass" ? "实际结果与预期一致。" : "实际结果与预期不一致。")}</dd>
                <dt>检查结论</dt><dd>{selectedCase.id === "T-258"
                  ? (checkPassed("similarity") ? "相似项判断记录完整，当前改动没有待处理冲突。" : "前往该问答的相似项，完成复用、独立或冲突处理。")
                  : selectedCase.id === "T-232"
                    ? (fixed ? "修正后重新测试已通过。" : "回答动作越过已发布范围，并且政策例外缺少转人工出口。")
                    : (effectiveResult(selectedCase) === "pass" ? "实际结果与预期一致。" : "查看命中的内容版本、工具结果和红线记录。")}</dd>
                <dt>影响</dt><dd>{effectiveResult(selectedCase) === "pass" ? "当前测试通过，不阻止发布。" : selectedCase.redline ? "红线失败，阻断发布。" : "普通失败，需要修正后重跑。"}</dd>
              </dl>
              {!fixed ? <button className="btn primary sm" style={{ marginTop: 12 }} onClick={() => openCaseFix(selectedCase)}><Icons.train s={13} /> 打开对应内容</button> : null}
            </div>
          ) : null}
        </div>
      )}

      {tab === "safety" && (
        <div className="col" style={{ gap: 16 }}>
          <div className="sec-grid-3">
            <window.Stat label="已启用规则" val={REDLINE_RULES.length} unit=" 条" delta="全部进入改动后重新测试" up ico="shield" />
            <window.Stat label="规则覆盖" val={REDLINE_RULES.length} unit={"/ " + REDLINE_RULES.length} delta="覆盖无遗漏" up ico="checkCircle" />
            <window.Stat label="隐藏字段设计用例" val={DND_MATRIX.length} unit={"/ " + DND_MATRIX.length} delta="后续里程碑验收" up ico="eyeOff" />
          </div>
          {redlineFail > 0 && (
            <div className="gate red">
              <div className="gate-ico"><Icons.lock s={17} /></div>
              <div style={{ flex: 1, fontWeight: 500 }}><b>安全规则测试未通过。</b> T-232 仍会承诺绕过身份认证审核，发布保持锁定。</div>
              <button className="btn sm" onClick={() => openTarget("train", "skills")}><Icons.train s={13} /> 前往训练修复</button>
            </div>
          )}
          <div className="card">
            <div className="card-head">
              <Icons.shield s={15} />
              <span className="card-title">安全规则验证</span>
              <span className="card-sub">答案变更后重新验证</span>
              <button className="btn sm ghost" style={{ marginLeft: "auto" }} onClick={() => openTarget("train", "review")}>查看高风险问答</button>
            </div>
            <table className="tbl">
              <thead><tr><th>规则</th><th>严重度</th><th>检查点</th><th>覆盖用例</th><th>最近结果</th></tr></thead>
              <tbody>
                {REDLINE_RULES.map(r => (
                  <tr key={r.id}>
                    <td><div className="row" style={{ gap: 8 }}><span className="mono muted" style={{ fontSize: 11.5 }}>{r.id}</span><div><div style={{ fontWeight: 600 }}>{r.name}</div><div className="muted" style={{ fontSize: 11.5, marginTop: 1 }}>{r.desc}</div></div></div></td>
                    <td><Badge tone={r.sev === "critical" ? "red" : "amber"}>{r.sev === "critical" ? "严重" : "高"}</Badge></td>
                    <td className="muted" style={{ fontSize: 12 }}>{r.scope}</td>
                    <td><b>{ruleTestCounts[r.id] || 2}</b> <span className="muted" style={{ fontSize: 11 }}>个</span></td>
                    <td>{!runBound
                      ? <Badge tone="gray">未运行</Badge>
                      : ruleFailures[r.id]
                        ? <Badge tone="red" dot="var(--red)">{ruleFailures[r.id]} 个失败</Badge>
                        : <Badge tone="green" dot="var(--green)">通过</Badge>}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div className="note"><Icons.eyeOff s={14} style={{ flexShrink: 0 }} /> 在这里验证隐藏字段、来源失效、工具结果和发送前红线。运行命中量见“分析 → 运行健康”。</div>
        </div>
      )}

      {tab === "shadow" && (
        <div>
          {intent.returned === "deploy" && (
            <div className="gate red" style={{ marginBottom: 16 }}>
              <div className="gate-ico"><Icons.lock s={17} /></div>
              <div style={{ flex: 1, fontWeight: 500 }}><b>发布检查已退回。</b> 当前无法解决高于改动前数据。请先在训练中修复，再重跑并重新进入发布检查。</div>
              <button className="btn sm" onClick={() => openTarget("train", "review")}><Icons.train s={13} /> 打开常见问答</button>
            </div>
          )}
          <div className="card" style={{ marginBottom: 16 }}>
            <div className="card-head"><Icons.git s={15} /><span className="card-title">上线前对照测试 · 本次改动</span><span className="card-sub">不影响客户</span></div>
            <div className="card-pad">
              <div className="row" style={{ gap: 24, marginBottom: 16 }}>
                <div><div className="muted" style={{ fontSize: 12 }}>本次内容</div><div style={{ fontWeight: 600, marginTop: 3 }}>{activeChange.contentRefs.join("、")}</div></div>
                <Icons.arrowRight s={18} className="muted" />
                <div><div className="muted" style={{ fontSize: 12 }}>改动前版本</div><div style={{ fontWeight: 600, marginTop: 3 }}>{SHADOW.baseline}</div></div>
              </div>
              <table className="tbl" style={{ border: "1px solid var(--line)", borderRadius: 8, overflow: "hidden" }}>
                <thead><tr><th>指标</th><th>改动前数据</th><th>候选</th><th>目标</th><th>结果</th></tr></thead>
                <tbody>
                  {SHADOW.rows.map((r, i) => {
                    const conflictRow = r.metric === "未处理相似问答冲突";
                    const ok = runBound && (conflictRow ? unresolvedQaConflicts === 0 : r.pass || fixed);
                    const cand = conflictRow
                      ? unresolvedQaConflicts.toString()
                      : (!r.pass && fixed) ? (r.fixedCand || r.cand) : r.cand;
                    return (
                      <tr key={i}>
                        <td style={{ fontWeight: 500 }}>{r.metric}</td>
                        <td className="mono">{r.base}</td>
                        <td className="mono" style={{ fontWeight: 600 }}>{cand}</td>
                        <td className="muted mono">{r.target}</td>
                        <td>{ok ? <Badge tone="green" dot="var(--green)">达标</Badge> : <Badge tone="red" dot="var(--red)">未达标</Badge>}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </div>
          {!shadowReady ? (
            <div className="gate red">
              <div className="gate-ico"><Icons.lock s={17} /></div>
              <div style={{ flex: 1, fontWeight: 500 }}><b>发布已锁定。</b> {pendingQaSimilarity > 0 ? `还有 ${pendingQaSimilarity} 组高相关问答待判断。` : unresolvedQaConflicts > 0 ? `还有 ${unresolvedQaConflicts} 组已确认答案冲突未处理。` : "当前无法解决比改动前数据高 2.7 个百分点，超过 2 个百分点上限。"}</div>
              <button className="btn sm" onClick={runSuite}><Icons.refresh s={13} /> 检查修复并重跑</button>
            </div>
          ) : (
            <div className="gate" style={{ background: "var(--green-bg)", borderColor: "var(--green-bd)", color: "#15803D" }}>
              <div className="gate-ico" style={{ background: "rgba(19,194,135,.15)" }}><Icons.checkCircle s={17} /></div>
              <div style={{ flex: 1, fontWeight: 500 }}>上线检查通过。</div>
              <button className="btn primary sm" onClick={() => window.BeaconNav?.go("deploy", { tab: "releases" })}><Icons.arrowUp s={13} /> 送往发布</button>
            </div>
          )}
        </div>
      )}

      {tab === "gate" && (
        <div className="sec-grid-2">
          <div className="card">
            <div className="card-head"><Icons.shield s={15} /><span className="card-title">上线检查</span></div>
            <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              {goLiveChecks.map((g, i) => (
                <div key={i} className="gate-check">
                  <div className="row" style={{ gap: 9 }}>
                    {g.ok ? <span className="gc-dot ok"><Icons.check s={12} sw={2.6} /></span> : <span className="gc-dot bad"><Icons.x s={12} sw={2.6} /></span>}
                    <div><div style={{ fontWeight: 600, fontSize: 13 }}>{g.k}</div><div className="muted" style={{ fontSize: 11.5 }}>{g.d}</div></div>
                  </div>
                  <Badge tone={g.ok ? "green" : "red"}>{g.v}</Badge>
                </div>
              ))}
            </div>
          </div>
          <div className="card card-pad">
            <div className="card-title" style={{ marginBottom: 12 }}>检查结论</div>
            {goLiveReady ? (
              <div className="gate" style={{ background: "var(--green-bg)", borderColor: "var(--green-bd)", color: "#15803D" }}>
                <div className="gate-ico" style={{ background: "rgba(22,163,74,.15)" }}><Icons.checkCircle s={18} sw={2} /></div>
                <div style={{ flex: 1, fontWeight: 500 }}>检查通过，可进入发布页。</div>
              </div>
            ) : (
              <div className="gate red">
                <div className="gate-ico"><Icons.lock s={18} sw={2} /></div>
                <div style={{ flex: 1, fontWeight: 500 }}>{fail} 个失败用例阻断发布。发布前必须修复并重跑。</div>
              </div>
            )}
            <div className="note" style={{ marginTop: 14 }}><Icons.shield s={14} style={{ flexShrink: 0 }} /> 来源、内容范围、工具结果、红线和覆盖变化都是发布条件。</div>
            {goLiveReady
              ? <button className="btn primary" style={{ marginTop: 16, width: "100%" }} onClick={() => window.BeaconNav?.go("deploy", { tab: "releases" })}><Icons.deploy s={15} /> 打开发布检查</button>
              : <button className="btn" style={{ marginTop: 16, width: "100%" }} onClick={() => setTab("regression")}><Icons.flask s={15} /> 查看被阻断用例</button>}
          </div>
        </div>
      )}
    </div>
  );
}

window.TestView = TestView;
