Natal answers were opening on parameter tables, and rectification turns were one-sentence legal copy. Centralize user-facing strings, keep representative-minute and question-slot red lines, and stop duplicating the opening collect prompt as a second assistant message. Co-authored-by: Cursor <cursoragent@cursor.com>
108 lines
3.3 KiB
TypeScript
108 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
displayTechniqueAuditLabel,
|
|
displayTechniqueAuditNote,
|
|
techniqueAuditStatusLabel,
|
|
} from "@/lib/consultation-technique-audit";
|
|
import type { TechniqueAuditRow } from "@/lib/consultation-agent-events";
|
|
import type { ConfirmationGate } from "@/lib/rectification-agentic/v9/confirmation-gate";
|
|
import { engineMeaningToDisplayCopy } from "@/lib/rectification-agentic/user-copy";
|
|
|
|
export function TechniqueAuditDisclosure({
|
|
rows,
|
|
}: {
|
|
readonly rows: readonly TechniqueAuditRow[];
|
|
}) {
|
|
if (rows.length === 0) return null;
|
|
return (
|
|
<details className="technique-audit">
|
|
<summary>
|
|
本轮技法
|
|
<small>{rows.length} 项</small>
|
|
</summary>
|
|
<div className="technique-audit-panel">
|
|
<table>
|
|
<caption className="sr-only">本轮技法审计</caption>
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">技法</th>
|
|
<th scope="col">状态</th>
|
|
<th scope="col">说明</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{rows.map((row, index) => (
|
|
<tr key={`${row.technique}-${index}`}>
|
|
<th scope="row">{displayTechniqueAuditLabel(row.technique)}</th>
|
|
<td data-status={row.status}>{techniqueAuditStatusLabel(row.status)}</td>
|
|
<td>{displayTechniqueAuditNote(row.note)}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</details>
|
|
);
|
|
}
|
|
|
|
const GATE_LABELS: Readonly<Record<ConfirmationGate["blockers"][number]["id"], string>> = {
|
|
vedastro_minute_sensitive: "官方分钟层",
|
|
adjacent_minutes_indistinguishable: "相邻分钟",
|
|
public_aa_holdout: "公开密封集",
|
|
};
|
|
|
|
function gateStatusLabel(status: string): string {
|
|
if (status === "passed") return "已通过";
|
|
if (status === "not_evaluated") return "尚未跑通";
|
|
if (status === "not_ready") return "未达标";
|
|
if (status === "failed") return "未通过";
|
|
return "未通过";
|
|
}
|
|
|
|
function gateStatusToken(status: string): "executed" | "blocked" {
|
|
return status === "passed" ? "executed" : "blocked";
|
|
}
|
|
|
|
export function ConfirmationGateDisclosure({
|
|
gate,
|
|
}: {
|
|
readonly gate: ConfirmationGate;
|
|
}) {
|
|
return (
|
|
<details className="technique-audit">
|
|
<summary>
|
|
唯一分钟确认门
|
|
<small>
|
|
{gate.confirmation_allowed
|
|
? "已允许"
|
|
: gate.unique_minute_path === "closed_at_representative"
|
|
? "以代表性时间收口"
|
|
: "未允许"}
|
|
</small>
|
|
</summary>
|
|
<div className="technique-audit-panel">
|
|
<table>
|
|
<caption className="sr-only">唯一分钟确认门</caption>
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">条件</th>
|
|
<th scope="col">状态</th>
|
|
<th scope="col">说明</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{gate.blockers.map((blocker) => (
|
|
<tr key={blocker.id}>
|
|
<th scope="row">{GATE_LABELS[blocker.id]}</th>
|
|
<td data-status={gateStatusToken(blocker.status)}>{gateStatusLabel(blocker.status)}</td>
|
|
<td>{engineMeaningToDisplayCopy(blocker.user_meaning)}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</details>
|
|
);
|
|
}
|