feat(#38): IMP-29 frontend zone-level evidence bridge (candidate_evidence reader + types + UI)

This commit is contained in:
2026-05-20 21:53:47 +09:00
parent 265d70ed91
commit b4872ba6ce
3 changed files with 190 additions and 13 deletions

View File

@@ -503,9 +503,20 @@ export async function loadRun(runId: string): Promise<LoadRunResult> {
restructure: 2,
reject: 3,
};
const rawSource = (unit.v4_all_judgments?.length > 0)
? unit.v4_all_judgments
: (unit.v4_candidates ?? []);
// IMP-29 u2 — source priority (deterministic, no LLM):
// 1) unit.candidate_evidence (IMP-05 L2 canonical, 14 fields per entry)
// 2) unit.v4_all_judgments (pre-IMP-05 audit array)
// 3) unit.v4_candidates (legacy minimal)
// fallback_chain alias is intentionally NOT read (Stage 2 guardrail).
const candidateEvidence = Array.isArray(unit.candidate_evidence)
? unit.candidate_evidence
: [];
const rawSource =
candidateEvidence.length > 0
? candidateEvidence
: (unit.v4_all_judgments?.length > 0
? unit.v4_all_judgments
: (unit.v4_candidates ?? []));
const v4Source = [...rawSource].sort((a: any, b: any) => {
const lp = (LABEL_PRIORITY[a.label] ?? 99) - (LABEL_PRIORITY[b.label] ?? 99);
if (lp !== 0) return lp;
@@ -525,12 +536,24 @@ export async function loadRun(runId: string): Promise<LoadRunResult> {
? `/frame-preview/${String(c.frame_number).padStart(2, "0")}`
: undefined,
// backend step09 의 catalog_registered (frame_contracts.yaml 등록 여부).
// v4_all_judgments 에 있음. v4_candidates fallback 시 undefined.
// candidate_evidence 및 v4_all_judgments 에 있음. v4_candidates fallback 시 undefined.
catalogRegistered: c.catalog_registered,
// backend step09 의 min_height_px (frame_contracts.yaml visual_hints.min_height_px).
// logical 1280x720 px 좌표계. contract 미등록 또는 visual_hints 부재 시 undefined.
// v4_all_judgments 에만 있음. v4_candidates fallback 시 undefined (graceful).
// v4_all_judgments 에만 있음. candidate_evidence / v4_candidates fallback 시 undefined (graceful).
minHeightPx: c.min_height_px ?? undefined,
// ─── IMP-05 L2 candidate_evidence fields (IMP-29 u2) ─────────────────
// Populated when source = unit.candidate_evidence; otherwise silently
// undefined for legacy fixtures (pre-IMP-05 fallback path).
rank: c.rank,
frameId: c.frame_id,
v4Label: c.v4_label,
phaseZStatus: c.phase_z_status,
filteredForDirectExecution: c.filtered_for_direct_execution,
routeHint: c.route_hint,
decision: c.decision,
reason: c.reason,
capacityFit: c.capacity_fit,
}));
const displayStrategy = (