(() => { "use strict"; const params = new URLSearchParams(location.search); const suppliedToken = params.get("token"); if (suppliedToken) sessionStorage.setItem("casan_viewer_token", suppliedToken); const token = suppliedToken || sessionStorage.getItem("casan_viewer_token") || ""; params.delete("token"); history.replaceState({}, "", `${location.pathname}${params.size ? `?${params}` : ""}${location.hash}`); const state = { view: params.get("view") || (params.get("trace") ? "runs" : "overview"), trace: params.get("trace") || "", project: null, registry: null, h6: null, run: null, selectedGate: "H1-context", }; const $ = (selector) => document.querySelector(selector); const esc = (value) => String(value ?? "") .replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">") .replaceAll('"', """).replaceAll("'", "'"); const slug = (value) => String(value || "unknown").toLowerCase().replaceAll("_", "-").replace(/[^a-z0-9-]/g, ""); const text = (value, fallback = "Unavailable") => value === null || value === undefined || value === "" ? fallback : String(value); const number = (value) => value === null || value === undefined || !Number.isFinite(Number(value)) ? "Unavailable" : new Intl.NumberFormat("en-US").format(Number(value)); const time = (value) => value ? String(value).replace("T", " ").replace("Z", " UTC") : "No timestamp"; const money = (value) => value === null || value === undefined ? "Unavailable" : `$${Number(value).toFixed(6)}`; const statusLabel = (value) => String(value || "unknown").replaceAll("_", " "); const pill = (value) => `${esc(String(value || "unknown").replaceAll("_", " "))}`; async function api(path) { const response = await fetch(path, { headers: { "X-CASAN-Viewer-Token": token }, cache: "no-store", }); const payload = await response.json().catch(() => ({})); if (!response.ok) throw new Error(payload.error || `HTTP ${response.status}`); return payload; } function downloadUrl(path, query = {}) { const next = new URLSearchParams({ ...query, token }); return `${path}?${next}`; } function hero({ eyebrow, title, description, verdict, meta = [], actions = "" }) { return `

${esc(eyebrow)}

${esc(title)}

${esc(description)}

${meta.map((item) => `${esc(item)}`).join("")}
${verdict ? pill(verdict) : ""}${actions}
`; } function metric(label, value, detail) { return `
${esc(label)}
${esc(text(value))}
${esc(detail)}
`; } function panel(eyebrow, title, description, body, right = "") { return `

${esc(eyebrow)}

${esc(title)}

${esc(description)}

${right}
${body}
`; } function disclosure(summary, description, body, badge = "") { return `
${esc(summary)}${esc(description)} ${badge}
${body}
`; } function distribution(label, rows) { const maximum = Math.max(...rows.map((row) => Number(row.value) || 0), 1); return ``; } function empty(title, detail) { return `
∅
${esc(title)}

${esc(detail)}

`; } function setView(view, push = true) { state.view = ["overview", "runs", "h6"].includes(view) ? view : "overview"; document.querySelectorAll(".nav-item").forEach((item) => { const active = item.dataset.view === state.view; item.classList.toggle("active", active); if (active) item.setAttribute("aria-current", "page"); else item.removeAttribute("aria-current"); }); document.querySelectorAll(".view").forEach((item) => item.classList.add("hidden")); $(`#${state.view}-view`).classList.remove("hidden"); $("#page-title").textContent = { overview: "Assurance overview", runs: "Run assurance registry", h6: "H6 AgentOps dossier", }[state.view]; if (push) { const next = new URL(location.href); next.searchParams.set("view", state.view); if (state.trace) next.searchParams.set("trace", state.trace); else next.searchParams.delete("trace"); history.pushState({}, "", `${next.pathname}?${next.searchParams}`); } if (state.view === "runs") renderRuns(); if (state.view === "h6") renderH6(); closeNav(); } function renderOverview() { const profile = state.project; const registry = state.registry; const latest = registry.latest || {}; const recent = registry.runs || []; const failures = recent.filter((row) => row.status === "failed").length; const certified = latest.certified === true; const latestTrace = latest.trace_id || recent[0]?.trace_id; const maturity = profile.maturity || {}; const readiness = profile.readiness || {}; const dimensions = readiness.dimensions || {}; const core = dimensions.core || { status: "not_assessed", summary: "Core readiness has not been assessed." }; const domain = dimensions.domain_pipeline || { status: "not_assessed", summary: "Domain Pipeline readiness has not been assessed." }; const telemetry = dimensions.provider_telemetry || { status: "not_assessed", summary: "Provider Telemetry readiness has not been assessed." }; const nextActions = readiness.next_actions || []; const coreReady = ["ready", "ready_with_attention"].includes(core.status); const readinessActionList = `
${nextActions.map((action, index) => `
${String(index + 1).padStart(2, "0")}
${esc(action.code)}

${esc(action.message)}

`).join("")}
`; const readinessCards = `
${metric("Core", statusLabel(core.status), core.summary)} ${metric("Domain Pipeline", statusLabel(domain.status), domain.summary)} ${metric("Provider Telemetry", statusLabel(telemetry.status), telemetry.summary)}
`; const actions = latestTrace ? ` ` : ``; $("#overview-view").innerHTML = hero({ eyebrow: "CASAN Core · Local assurance", title: latestTrace ? "One prompt. One evidence trail." : coreReady ? "Core reporting is ready." : "Finish Core activation.", description: latestTrace ? "A read-only, offline-capable assurance workspace reconstructed from canonical project evidence. No Platform service or HTML generation on the prompt hot path." : coreReady ? "Core visual reporting works without a Domain Pack or application-source changes. Send a governed prompt to create the first run dossier." : "Core visual reporting works without a Domain Pack or application-source changes. Complete the activation action below, then send a governed prompt.", verdict: latestTrace ? (certified ? "certified" : "review required") : core.status, meta: [ `${profile.project_name} · ${profile.edition}`, latestTrace ? `Trace ${latestTrace}` : "No finalized trace yet", `Maturity ${maturity.level == null ? "not assessed" : `L${maturity.level}`} · ${statusLabel(maturity.status)}`, ], actions, }) + readinessCards + (latestTrace && nextActions.length ? panel( "Activation attention", "A selected client route needs action.", "Healthy routes remain operational; complete this step before relying on the affected integration.", readinessActionList, pill(core.status), ) : "") + (latestTrace ? `
${metric("Governed records", number(registry.count), `${recent.length} recent records loaded`)} ${metric("Latest H6 quality", latest.telemetry_quality || "Unavailable", "Missing values are disclosed, never coerced to zero")} ${metric("Observed failures", number(failures), `${recent.length ? Math.round((failures / recent.length) * 100) : 0}% of loaded records`)} ${metric("Evidence gates", latestTrace ? "H1 → H7" : "Waiting", latestTrace ? "Control-by-control reconstruction available" : "Evidence appears after a prompt finalizes")}
` : panel( "First-run onboarding", "No operational KPIs are shown until evidence exists.", "CASAN does not turn missing telemetry into zeroes or claim a run is certified before a governed prompt finishes.", `${nextActions.length ? `
${readinessActionList}
` : ""}
Available now
Local viewer, H1–H7 run dossier, history, H6 AgentOps and on-demand JSON/HTML export.
Optional expansion
Install a Domain Pack only when the team needs project-specific SRS→test acceptance.
` )) + disclosure( "About this local report", "Edition boundaries and implementation notes are hidden until needed.", `
Included in Core
Latest run, history, interactive H1–H7 evidence, H6 AgentOps, and on-demand JSON/HTML export.
Platform boundary
Multi-project fleet views, centralized RBAC, shared approvals, ingestion and organization-wide retention.
` ) + recentRunsPanel(recent.slice(0, 6), "Latest governed evidence"); bindActions(); } function recentRunsPanel(rows, title = "Recent governed runs") { const body = rows.length ? `
${rows.map((row) => ``).join("")}
Observed atLifecycle stepVerdictLatencyTokensEvidence
${esc(time(row.timestamp))}${esc(row.step || row.harness || "Agentic turn")} ${pill(row.status)}${esc(row.latency_ms == null ? "Unavailable" : `${number(row.latency_ms)} ms`)} ${esc(number(row.total_tokens))} ${row.trace_id ? `` : "—"}
` : empty("No governed run yet", "Complete a prompt in a configured client, then refresh this viewer."); return panel("Evidence index", title, "Operational values are shown only when present in canonical telemetry.", body); } function renderRuns() { const rows = state.registry.runs || []; const selected = state.run; const hasRuns = rows.length > 0; const body = hero({ eyebrow: "Run assurance registry", title: hasRuns ? "Every governed run, one evidence trail." : "No governed runs yet.", description: hasRuns ? "Select a lifecycle record to reconstruct H1–H7 decisions, inspect sanitized evidence and export an independent dossier." : "The registry will populate after a configured client finalizes its first governed prompt.", verdict: hasRuns ? (rows.some((row) => row.status === "failed") ? "attention" : "operational") : "waiting", meta: hasRuns ? [`${state.registry.count} records`, `${rows.filter((row) => row.status === "failed").length} failures`, "Local canonical evidence"] : ["No operational counters yet", "Local canonical evidence"], actions: hasRuns ? `` : "", }) + (selected ? renderTrace(selected) : "") + recentRunsPanel(rows); $("#runs-view").innerHTML = body; bindActions(); bindGates(); } function renderTrace(report) { const gates = report.gates || []; let selected = gates.find((gate) => gate.id === state.selectedGate) || gates[0]; if (!selected) return ""; const rail = gates.map((gate, index) => ``).join(""); const events = (selected.events || []).slice(-4).reverse(); const timeline = events.length ? `
${events.map((event) => `
${esc(event.status)}

${esc(event.reason)}

`).join("")}
` : `

No individual event was emitted for this control.

`; const entries = Object.entries(selected.evidence || {}); const manifest = entries.length ? `
${entries.map(([key, value]) => `
${esc(key)}
${esc(typeof value === "string" ? value : JSON.stringify(value))}
`).join("")}
` : empty("No safe evidence fields", "This control has not emitted a sanitized evidence manifest."); const actions = `JSON evidence Export dossier`; return `
${panel( "Run assurance", "Governed execution dossier", "A control-by-control reconstruction backed by sanitized lifecycle evidence.", `

Trace provenance

${esc(report.trace_id)}

${report.summary.gates_observed}/7 controls observed${report.project.edition} edition
${pill(report.verdict)}
${rail}

Selected control

${esc(selected.title)}

${esc(selected.description)}

Latest decision · ${esc(time(selected.updated_at))}

${esc(selected.reason)}

${disclosure("Event history", `${events.length} recent lifecycle events · hidden by default`, timeline)}
${disclosure("Safe evidence manifest", "Sanitized fields persisted by the harness · hidden by default", manifest, pill(`${entries.length} fields`))}
`, actions, )}
`; } function renderH6() { const data = state.h6; if (!data) return; const hasRuns = Number(data.summary?.runs) > 0; const query = data.scope || {}; const queryObject = Object.fromEntries(Object.entries(query).filter(([, value]) => value)); const actions = `JSON evidence Export dossier`; if (!hasRuns) { const provider = state.project?.readiness?.dimensions?.provider_telemetry || {}; $("#h6-view").innerHTML = hero({ eyebrow: "H6 · AgentOps assurance", title: "H6 begins with the first governed run.", description: "No runtime record exists yet, so CASAN hides failure, latency, token and cost counters instead of presenting fabricated zeroes.", verdict: "waiting", meta: [data.report_id, `Generated ${time(data.generated_at)}`, "No operational evidence yet"], actions: "", }) + panel( "H6 onboarding", "Provider telemetry is optional.", provider.summary || "Provider token and cost telemetry has not been observed; this does not block Core.", `
Core remains ready
Send a prompt through a configured client. CASAN will persist runtime evidence automatically.
No automatic export
Open H6 or export a dossier only when a review artifact is needed.
`, ); return; } const findings = data.findings.length ? `
${data.findings.map((item, index) => `
${String(index + 1).padStart(2, "0")}
${esc(item.code)}

${esc(item.message)}

`).join("")}
` : `
No threshold breach was detected in the selected evidence boundary.
`; const sources = data.evidence_sources.map((source) => { const status = !source.present ? "missing" : source.stale ? "stale" : "fresh"; return `

${esc(source.source)}

${source.records} records · ${source.age_s == null ? "no timestamp" : `${number(source.age_s)}s old`}
${pill(status)}
${esc(source.path)}
`; }).join(""); const breakdown = (rows, subject) => `
${rows.length ? rows.map((row) => ``).join("") : ``}
${esc(subject)}RunsFailuresAvg latencyTokensCost
${esc(row.key)}${row.runs}${row.failures}${number(row.latency_avg_ms)} ms${number(row.tokens)}${money(row.cost_usd)}
${empty("No matching records", `No ${subject.toLowerCase()} evidence is available.`)}
`; const outcomes = distribution("Governed run outcome distribution", data.details.by_status.map((row) => ({ label: String(row.status).replaceAll("_", " "), value: row.count, detail: `${data.summary.runs ? Math.round((row.count / data.summary.runs) * 100) : 0}% of selected runs`, tone: row.status === "failed" ? "danger" : row.status === "degraded" ? "warning" : "success", }))); $("#h6-view").innerHTML = hero({ eyebrow: "H6 · AgentOps assurance", title: "Operational evidence, ready for a decision.", description: "Runtime health, reliability, cost provenance and telemetry integrity—designed to answer what happened, why it matters and where the evidence lives.", verdict: data.verdict, meta: [data.report_id, `Generated ${time(data.generated_at)}`, `Freshness ${data.freshness.status}`], actions, }) + disclosure("Filter the evidence boundary", "Project, date and trace filters stay out of the executive view until needed.", h6Filters(data)) + `
${metric("Governed runs", number(data.summary.runs), `${data.summary.success} successful · ${data.summary.degraded} degraded`)} ${metric("Failure rate", `${data.summary.failure_rate_pct}%`, `${data.summary.failed} failed · ${data.summary.alerts} alerts`)} ${metric("P95 latency", `${number(data.summary.latency_ms.p95)} ms`, `P50 ${number(data.summary.latency_ms.p50)} ms`)} ${metric("Telemetry integrity", data.data_quality.status.replaceAll("_", " "), `${data.summary.coverage.token_pct}% token · ${data.summary.coverage.cost_pct}% cost`)}
` + `
${panel("Decision brief", "What requires attention", "Threshold findings are review signals, not maturity claims.", findings, pill(data.verdict))} ${panel("Outcome mix", "Run distribution", "Canonical runtime status values, normalized against the largest observed group.", outcomes, `${number(data.summary.runs)} total`)}
` + panel("Evidence quality", "Coverage and disclosure", "Unavailable telemetry remains null. Coverage gaps stay visible.", `
${coverage("Token attribution", data.summary.coverage.token_pct, `${data.summary.coverage.token_records}/${data.summary.coverage.runtime_records} records`)} ${coverage("Cost attribution", data.summary.coverage.cost_pct, `${data.summary.coverage.cost_records}/${data.summary.coverage.runtime_records} records`)}
Disclosure notes${data.data_quality.warnings.length ? `` : `

All required sources are present with no estimation warning.

`}
`, pill(data.data_quality.status)) + disclosure( "Technical evidence and breakdowns", "Provider counters, canonical paths and raw tables are preserved for audit without crowding the decision view.", `
${metric("Provider tokens", data.summary.coverage.token_records > 0 ? number(data.summary.tokens.provider_total ?? data.summary.tokens.total) : "Unavailable", `${data.summary.coverage.token_pct}% record coverage`)} ${metric("Actual cost", money(data.summary.cost_usd.provider_actual), `${data.summary.coverage.cost_pct}% record coverage`)} ${metric("Provider calls", number(data.summary.provider_calls), "Provider-attributed requests")} ${metric("Retries", number(data.summary.retries), "Observed reroute attempts")}

Source integrity

Evidence provenance

${sources}
${panel("Runtime", "Execution profile by step", "Latency, failure and attribution by governed lifecycle step.", breakdown(data.details.by_step, "Step"))} ${panel("Provider", "Model usage and provenance", "Only provider-reported token and actual cost values are shown.", breakdown(data.details.by_provider, "Provider · model"))}
`, pill(data.freshness.status), ); bindH6Filters(); } function coverage(label, value, detail) { const width = Math.round(Math.max(0, Math.min(100, Number(value) || 0)) / 5) * 5; return `
${esc(label)}${esc(value)}%
${esc(detail)}
`; } function h6Filters(data) { const scope = data.scope || {}; const options = data.available_filters || { projects: [], runs: [] }; const date = (value) => value ? value.slice(0, 10) : ""; return `
`; } async function loadTrace(traceId) { if (!traceId) return; state.trace = traceId; state.selectedGate = "H1-context"; $("#loading").classList.remove("hidden"); try { state.run = await api(`/api/v1/reports/run/${encodeURIComponent(traceId)}`); setView("runs"); const dossier = $("#run-dossier"); if (dossier) { requestAnimationFrame(() => { dossier.focus({ preventScroll: true }); dossier.scrollIntoView({ behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth", block: "start", }); }); } } catch (error) { showError(`Run report could not be reconstructed: ${error.message}`); } finally { $("#loading").classList.add("hidden"); } } async function loadH6(query = {}) { const next = new URLSearchParams(Object.fromEntries(Object.entries(query).filter(([, value]) => value))); $("#loading").classList.remove("hidden"); try { state.h6 = await api(`/api/v1/reports/h6${next.size ? `?${next}` : ""}`); renderH6(); } catch (error) { showError(`H6 report could not be generated: ${error.message}`); } finally { $("#loading").classList.add("hidden"); } } function bindActions() { document.querySelectorAll("[data-view-target]").forEach((button) => button.addEventListener("click", () => setView(button.dataset.viewTarget))); document.querySelectorAll("[data-open-trace]").forEach((button) => button.addEventListener("click", () => loadTrace(button.dataset.openTrace))); document.querySelectorAll("[data-open-h6]").forEach((button) => button.addEventListener("click", async () => { await loadH6({ run: button.dataset.openH6 }); setView("h6"); })); } function bindGates() { document.querySelectorAll("[data-gate]").forEach((button) => button.addEventListener("click", () => { state.selectedGate = button.dataset.gate; renderRuns(); })); } function bindH6Filters() { $("#h6-filters")?.addEventListener("submit", async (event) => { event.preventDefault(); const values = Object.fromEntries(new FormData(event.currentTarget)); await loadH6(values); }); $("#clear-h6")?.addEventListener("click", () => loadH6()); } function showError(message) { $("#error").textContent = message; $("#error").classList.remove("hidden"); } function closeNav() { $(".sidebar").classList.remove("open"); $("#nav-scrim").classList.add("hidden"); $("#menu-button").setAttribute("aria-expanded", "false"); } async function loadAll() { $("#error").classList.add("hidden"); $("#loading").classList.remove("hidden"); try { [state.project, state.registry, state.h6] = await Promise.all([ api("/api/v1/project"), api("/api/v1/runs?limit=100"), api("/api/v1/reports/h6?limit=50"), ]); $("#freshness-pill").textContent = `${state.h6.freshness.status} evidence`; $("#freshness-pill").className = `pill ${slug(state.h6.freshness.status)}`; renderOverview(); renderH6(); if (state.trace) { await loadTrace(state.trace); } else { setView(state.view, false); } } catch (error) { showError(`Local evidence could not be loaded: ${error.message}`); } finally { $("#loading").classList.add("hidden"); } } document.querySelectorAll(".nav-item").forEach((button) => button.addEventListener("click", () => setView(button.dataset.view))); $("#refresh-button").addEventListener("click", loadAll); $("#menu-button").addEventListener("click", () => { const open = !$(".sidebar").classList.contains("open"); $(".sidebar").classList.toggle("open", open); $("#nav-scrim").classList.toggle("hidden", !open); $("#menu-button").setAttribute("aria-expanded", String(open)); }); $("#nav-scrim").addEventListener("click", closeNav); document.addEventListener("keydown", (event) => { if (event.key === "Escape") closeNav(); }); window.addEventListener("popstate", () => setView(new URLSearchParams(location.search).get("view") || "overview", false)); loadAll(); })();