/** * /jobs/[id] — Investigation Bureau case file viewer. * * Server-rendered shell with the first snapshot fetched directly from * pg (one round-trip). A client island then polls /api/jobs/[id] every 3s * while the job is non-terminal (queued | running). * * Detectives: * - hypothesis_tournament → Sherlock Holmes * - evidence_chain → Edmond Locard * * Renders: * - Phase tracker (queued → claimed → running → complete | failed) * - Hypothesis cards w/ prior+posterior bars + Tetlock confidence_band badge * - Evidence cards w/ grade A/B/C badge + verbatim_excerpt + bbox crop link */ import { notFound } from "next/navigation"; import Link from "next/link"; import { pgQuery } from "@/lib/retrieval/db"; import { AuthBar } from "@/components/auth-bar"; import { JobStatusPoller } from "@/components/job-status-poller"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; interface InitialJob { job_id: string; kind: string; payload: Record | null; status: string; worker_id: string | null; started_at: string | null; finished_at: string | null; outputs: unknown; error: string | null; created_at: string; } export default async function JobPage({ params, }: { params: Promise<{ id: string }> }) { const { id } = await params; if (!/^[0-9a-f-]{36}$/i.test(id)) notFound(); const rows = await pgQuery( `SELECT job_id, kind, payload, status, worker_id, started_at, finished_at, outputs, error, created_at FROM public.investigation_jobs WHERE job_id = $1`, [id], ).catch(() => [] as InitialJob[]); const job = rows[0]; if (!job) notFound(); const isHolmes = job.kind === "hypothesis_tournament"; const detectiveName = isHolmes ? "Sherlock Holmes" : "Edmond Locard"; const detectiveSlug = isHolmes ? "holmes" : "locard"; const detectiveTone = isHolmes ? "text-[#7fdbff]" : "text-[#06d6a0]"; const detectiveBg = isHolmes ? "from-[rgba(127,219,255,0.08)]" : "from-[rgba(6,214,160,0.08)]"; const question = (job.payload as Record)?.question as string | undefined; const docId = (job.payload as Record)?.doc_id as string | undefined; return (
disclosure.top / investigation / {job.job_id.slice(0, 8)}

{detectiveName}

{isHolmes ? "Hypothesis tournament · rival hypotheses with Bayesian update" : "Evidence chain · verbatim quotes with chain of custody (Locard)"}

{detectiveSlug}
{question && (
Question
{question}
)} {docId && (
Scope: {docId}
)}
); }