fix: enforce grounded AI legal review gate
Build and Test Quality Gate / Contract Web typecheck and build (pull_request) Successful in 5m40s
Build and Test Quality Gate / Isolated Alibaba and Tencent KMS gateway (pull_request) Failing after 1m39s
Build and Test Quality Gate / Python tests and Contract API migration (pull_request) Failing after 17m10s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 6m29s

This commit is contained in:
2026-08-26 18:24:32 +08:00
parent ebb5d410ad
commit ddd60875a3
15 changed files with 831 additions and 43 deletions
@@ -63,7 +63,7 @@ export default function ModelJobOperationsPage() {
<Metric icon={Activity} label="窗口任务" value={String(snapshot.metrics.total)} />
<Metric icon={Clock3} label="总耗时 P95" value={formatDuration(snapshot.metrics.total_latency_p95_ms)} />
<Metric icon={CheckCircle2} label="自动门禁通过率" value={formatRate(snapshot.quality_pass_rate)} />
<Metric icon={ShieldAlert} label="开放告警" value={String(snapshot.alerts.length)} />
<Metric icon={ShieldAlert} label="复核批准率" value={formatRate(snapshot.review_approval_rate)} />
</div>
<div className="grid-two">
@@ -79,7 +79,7 @@ export default function ModelJobOperationsPage() {
<div className="guided-draft-progress" aria-label={`已完成 ${snapshot.completed_sample_count} / ${snapshot.target_sample_count}`}>
<span style={{ width: `${Math.min(100, snapshot.completed_sample_count / Math.max(1, snapshot.target_sample_count) * 100)}%` }} />
</div>
<p className="item-meta">通过 {snapshot.quality_passed} · 待人工 {snapshot.quality_needs_review} · 阻断 {snapshot.quality_failed}</p>
<p className="item-meta">自动通过 {snapshot.quality_passed} · 待治理复核 {snapshot.quality_needs_review} · 自动阻断 {snapshot.quality_failed}</p>
</div>
</section>
@@ -90,11 +90,13 @@ export default function ModelJobOperationsPage() {
<tbody>
<tr><th>排队 / 运行 / 已取消</th><td>{snapshot.metrics.queued} / {snapshot.metrics.running} / {snapshot.metrics.cancelled}</td></tr>
<tr><th>成功 / fallback / 失败</th><td>{snapshot.metrics.succeeded} / {snapshot.metrics.fallback} / {snapshot.metrics.failed}</td></tr>
<tr><th>人工复核</th><td>{snapshot.metrics.awaiting_human}</td></tr>
<tr><th>待治理复核</th><td>{snapshot.metrics.awaiting_human}</td></tr>
<tr><th>执行 P50 / P95</th><td>{formatDuration(snapshot.metrics.execution_latency_p50_ms)} / {formatDuration(snapshot.metrics.execution_latency_p95_ms)}</td></tr>
<tr><th>fallback / 失败率</th><td>{formatRate(snapshot.metrics.fallback_rate)} / {formatRate(snapshot.metrics.failure_rate)}</td></tr>
<tr><th>重试率</th><td>{formatRate(snapshot.metrics.retry_rate)}</td></tr>
<tr><th>抽检要求 / 已完成</th><td>{snapshot.review_required} / {snapshot.review_completed}</td></tr>
<tr><th>复核要求 / 已完成</th><td>{snapshot.review_required} / {snapshot.review_completed}</td></tr>
<tr><th>接受 / 修订 / 拒绝</th><td>{snapshot.review_accepted} / {snapshot.review_corrected} / <strong>{snapshot.review_rejected}</strong></td></tr>
<tr><th>法律复核门禁</th><td><span className={snapshot.review_gate_passed ? "tag tag-success" : "tag tag-danger"}>{snapshot.review_gate_passed ? "通过" : "未通过"}</span></td></tr>
</tbody>
</table>
</div>
@@ -119,8 +121,8 @@ export default function ModelJobOperationsPage() {
<div className="panel-header"><h2 className="panel-title">分层质量结果</h2><span className="tag">{snapshot.quality_segments.length} 个分层</span></div>
<div className="panel-body table-wrap">
{snapshot.quality_segments.length === 0 ? <div className="empty-state empty-state-compact">当前窗口尚无带分层标签的样本。</div> : (
<table className="data-table"><thead><tr><th>维度</th><th>分层</th><th>样本</th><th>通过率</th><th>抽检</th></tr></thead><tbody>
{snapshot.quality_segments.map((segment) => <tr key={`${segment.dimension}-${segment.value}`}><td>{dimensionLabel(segment.dimension)}</td><td>{segment.value}</td><td>{segment.sample_count}</td><td>{formatRate(segment.quality_pass_rate)}</td><td>{segment.review_completed}/{segment.review_required}</td></tr>)}
<table className="data-table"><thead><tr><th>维度</th><th>分层</th><th>样本</th><th>自动通过率</th><th>复核</th><th>接受/修订/拒绝</th></tr></thead><tbody>
{snapshot.quality_segments.map((segment) => <tr key={`${segment.dimension}-${segment.value}`}><td>{dimensionLabel(segment.dimension)}</td><td>{segment.value}</td><td>{segment.sample_count}</td><td>{formatRate(segment.quality_pass_rate)}</td><td>{segment.review_completed}/{segment.review_required}</td><td>{segment.review_accepted}/{segment.review_corrected}/{segment.review_rejected}</td></tr>)}
</tbody></table>
)}
</div>
@@ -149,9 +151,9 @@ export default function ModelJobOperationsPage() {
</section>
<section className="panel">
<div className="panel-header"><div><h2 className="panel-title">人工抽检与接管队列</h2><p className="item-meta">记录事实一致性、引用可核验性和高风险遗漏,形成规则迭代数据。</p></div><span className={reviewQueue.length ? "tag tag-warning" : "tag tag-success"}>{reviewQueue.length} 条</span></div>
<div className="panel-header"><div><h2 className="panel-title">治理复核与接管队列</h2><p className="item-meta">AI 受托复核优先,疑难、冲突和低置信度任务再转人工;所有结论均记录复核主体与证据。</p></div><span className={reviewQueue.length ? "tag tag-warning" : "tag tag-success"}>{reviewQueue.length} 条</span></div>
<div className="panel-body">
{reviewQueue.length === 0 ? <div className="empty-state empty-state-compact">当前没有待人工抽检任务。</div> : (
{reviewQueue.length === 0 ? <div className="empty-state empty-state-compact">当前没有待治理复核任务。</div> : (
<div className="task-list">
{reviewQueue.map((job) => <QualityReviewCard job={job} key={job.id} onReviewed={loadSnapshot} />)}
</div>
@@ -205,7 +207,7 @@ function QualityReviewCard({ job, onReviewed }: { job: ModelInferenceJob; onRevi
<ReviewSelect label="处置结论" value={payload.disposition} options={dispositionOptions} onChange={(value) => setPayload((current) => ({ ...current, disposition: value }))} />
</div>
<label className="field" style={{ marginTop: 12 }}><span>复核说明</span><textarea value={payload.feedback_text ?? ""} onChange={(event) => setPayload((current) => ({ ...current, feedback_text: event.target.value }))} placeholder="记录事实、引用核验结果和修订建议。" rows={3} /></label>
<label style={{ alignItems: "center", display: "flex", gap: 8, marginTop: 12 }}><input checked={confirmed} onChange={(event) => setConfirmed(event.target.checked)} style={{ width: "auto" }} type="checkbox" /><span>我已核对模型输出、可用法源和本案事实,并确认以上结论。</span></label>
<label style={{ alignItems: "center", display: "flex", gap: 8, marginTop: 12 }}><input checked={confirmed} onChange={(event) => setConfirmed(event.target.checked)} style={{ width: "auto" }} type="checkbox" /><span>复核主体已核对模型输出、可用法源和任务事实,并确认以上结论;AI 复核不得冒充人类法务。</span></label>
{error && <div className="notice notice-error"><AlertTriangle size={16} />{error}</div>}
<button className="button button-primary" disabled={submitting || !confirmed} onClick={() => void submit()} type="button"><CheckCircle2 size={16} />{submitting ? "提交中…" : "提交抽检结论"}</button>
</div>
@@ -264,6 +264,11 @@ export type ModelJobOperationsSnapshot = {
quality_pass_rate: number;
review_required: number;
review_completed: number;
review_accepted: number;
review_corrected: number;
review_rejected: number;
review_approval_rate: number;
review_gate_passed: boolean;
evaluation_run_id?: string | null;
admission: {
running: number;
@@ -284,6 +289,10 @@ export type ModelJobOperationsSnapshot = {
quality_failed: number;
review_required: number;
review_completed: number;
review_accepted: number;
review_corrected: number;
review_rejected: number;
review_approval_rate: number;
quality_pass_rate: number;
}>;
};
@@ -9143,7 +9143,7 @@ components:
threshold: { type: number }
ModelJobOperationsSnapshot:
type: object
required: [metrics, alerts, completed_sample_count, target_sample_count, remaining_sample_count, baseline_ready, quality_passed, quality_needs_review, quality_failed, quality_pass_rate, review_required, review_completed, admission, quality_segments]
required: [metrics, alerts, completed_sample_count, target_sample_count, remaining_sample_count, baseline_ready, quality_passed, quality_needs_review, quality_failed, quality_pass_rate, review_required, review_completed, review_accepted, review_corrected, review_rejected, review_approval_rate, review_gate_passed, admission, quality_segments]
properties:
metrics:
$ref: "#/components/schemas/ModelInferenceJobMetrics"
@@ -9161,6 +9161,11 @@ components:
quality_pass_rate: { type: number }
review_required: { type: integer }
review_completed: { type: integer }
review_accepted: { type: integer }
review_corrected: { type: integer }
review_rejected: { type: integer }
review_approval_rate: { type: number }
review_gate_passed: { type: boolean }
evaluation_run_id: { type: string, nullable: true }
admission: { $ref: "#/components/schemas/ModelJobAdmissionSnapshot" }
quality_segments:
@@ -9180,7 +9185,7 @@ components:
accepting_submissions: { type: boolean }
ModelJobQualitySegment:
type: object
required: [dimension, value, sample_count, quality_passed, quality_needs_review, quality_failed, review_required, review_completed, quality_pass_rate]
required: [dimension, value, sample_count, quality_passed, quality_needs_review, quality_failed, review_required, review_completed, review_accepted, review_corrected, review_rejected, review_approval_rate, quality_pass_rate]
properties:
dimension: { type: string, enum: [contract_type, risk_level, industry] }
value: { type: string }
@@ -9190,6 +9195,10 @@ components:
quality_failed: { type: integer }
review_required: { type: integer }
review_completed: { type: integer }
review_accepted: { type: integer }
review_corrected: { type: integer }
review_rejected: { type: integer }
review_approval_rate: { type: number }
quality_pass_rate: { type: number }
ModelJobQualityReviewRequest:
type: object