diff --git a/packages/casan-control-panel/backend/src/reports/h6-report.html.ts b/packages/casan-control-panel/backend/src/reports/h6-report.html.ts
index c8b42ef..206ed4b 100644
--- a/packages/casan-control-panel/backend/src/reports/h6-report.html.ts
+++ b/packages/casan-control-panel/backend/src/reports/h6-report.html.ts
@@ -11,51 +11,113 @@ const number = (value: number): string => new Intl.NumberFormat('en-US').format(
const money = (value: number): string => `$${value.toFixed(6)}`;
function breakdownRows(rows: H6Breakdown[]): string {
- if (rows.length === 0) return '
| No records in the selected scope. |
';
+ if (rows.length === 0) return '| No records in the selected evidence boundary. |
';
return rows.map((row) => `
- | ${escapeHtml(row.key)} | ${number(row.runs)} | ${number(row.failures)} |
- ${number(row.latency_avg_ms)} ms | ${row.tokens === null ? 'Unavailable' : number(row.tokens)} | ${row.cost_usd === null ? 'Unavailable' : money(row.cost_usd)} |
+ ${escapeHtml(row.key)} |
+ ${number(row.runs)} |
+ ${number(row.failures)} |
+ ${number(row.latency_avg_ms)} ms |
+ ${row.tokens === null ? 'Unavailable' : number(row.tokens)} |
+ ${row.cost_usd === null ? 'Unavailable' : money(row.cost_usd)} |
`).join('');
}
+function coverage(label: string, value: number, detail: string): string {
+ const bounded = Math.min(Math.max(value, 0), 100);
+ const tone = bounded >= 95 ? 'good' : bounded > 0 ? 'warn' : 'empty';
+ return `
+
${escapeHtml(label)}${bounded}%
+
+
${escapeHtml(detail)}
+
`;
+}
+
export function renderH6ReportHtml(report: H6Report): string {
const verdictClass = report.verdict === 'pass' ? 'pass' : report.verdict === 'fail' ? 'fail' : report.verdict === 'attention' ? 'attention' : 'neutral';
const scope = [
- report.scope.project ? `Project: ${report.scope.project}` : 'All projects',
- report.scope.run ? `Run: ${report.scope.run}` : 'All runs',
- report.scope.from ? `From: ${report.scope.from}` : null,
- report.scope.to ? `To: ${report.scope.to}` : null,
+ report.scope.project ? `Project · ${report.scope.project}` : 'All projects',
+ report.scope.run ? `Run · ${report.scope.run}` : 'All runs',
+ report.scope.from ? `From · ${report.scope.from}` : null,
+ report.scope.to ? `To · ${report.scope.to}` : null,
].filter((value): value is string => Boolean(value));
const findings = report.findings.length
- ? report.findings.map((finding) => `${escapeHtml(finding.code)}${escapeHtml(finding.message)}`).join('')
- : 'NO_FINDINGSNo threshold breach was detected in this scope.';
- const sourceRows = report.evidence_sources.map((source) => `
- | ${escapeHtml(source.source)} | ${source.present ? 'present' : 'missing'} | ${source.stale ? 'stale' : 'fresh'} |
- ${source.age_s === null ? '—' : `${number(source.age_s)} s`} | ${number(source.records)} | ${escapeHtml(source.path)} |
-
`).join('');
+ ? report.findings.map((finding, index) => `
+ ${String(index + 1).padStart(2, '0')}
+ ${escapeHtml(finding.code)}${finding.metric ? `${escapeHtml(finding.metric)}: ${escapeHtml(finding.value)}${finding.threshold !== undefined ? ` / ${escapeHtml(finding.threshold)}` : ''}` : ''}
${escapeHtml(finding.message)}
+ `).join('')
+ : '✓
NO_THRESHOLD_BREACH
No threshold breach was detected in this evidence boundary.
';
+ const sourceRows = report.evidence_sources.map((source) => {
+ const status = !source.present ? 'missing' : source.stale ? 'stale' : 'fresh';
+ return `
+ | ${escapeHtml(source.source)} |
+ ${status} |
+ ${source.age_s === null ? 'Unavailable' : `${number(source.age_s)} s`} |
+ ${number(source.records)} |
+ ${escapeHtml(source.path)} |
+
`;
+ }).join('');
const warnings = report.data_quality.warnings.length
- ? `${report.data_quality.warnings.map((warning) => `- ${escapeHtml(warning)}
`).join('')}
`
- : 'No data-quality warning.
';
+ ? report.data_quality.warnings.map((warning) => `${escapeHtml(warning)}`).join('')
+ : 'All required sources are present and no estimation warning was detected.';
return `
${escapeHtml(report.title)} · ${escapeHtml(report.report_id)}
-CASAN assurance dossier · contract v${report.schema_version}
${escapeHtml(report.title)}
${scope.map((item) => `${escapeHtml(item)}`).join('')}
${escapeHtml(report.verdict)}
Generated ${escapeHtml(report.generated_at)} · ${escapeHtml(report.report_id)} · Freshness ${escapeHtml(report.freshness.status)}
-Governed runs${number(report.summary.runs)}
Failure rate${report.summary.failure_rate_pct}%
P95 latency${number(report.summary.latency_ms.p95)} ms
Provider tokens${report.summary.coverage.token_records > 0 ? number(report.summary.tokens.provider_total ?? report.summary.tokens.total ?? 0) : 'Unavailable'}
Actual provider cost${report.summary.cost_usd.provider_actual !== null ? money(report.summary.cost_usd.provider_actual) : 'Unavailable'}
Token coverage${report.summary.coverage.token_pct}%
Cost coverage${report.summary.coverage.cost_pct}%
Retries${number(report.summary.retries)}
-
-Evidence freshness
| Source | Presence | State | Age | Records | Path |
${sourceRows}
-Step breakdown
| Step | Runs | Failures | Avg latency | Tokens | Cost |
${breakdownRows(report.details.by_step)}
-Provider/model breakdown
| Provider · model | Calls | Failures | Avg latency | Tokens | Cost |
${breakdownRows(report.details.by_provider)}
-Data quality · ${escapeHtml(report.data_quality.status)}
${warnings}
-
+
+ CASAN · H6 AgentOps assurance
+ Operational evidence, ready for a decision.
+ ${escapeHtml(report.title)} · Runtime health, reliability, provider usage, cost provenance and telemetry integrity.
+ ${scope.map((item) => `${escapeHtml(item)}`).join('')}
+
+
+
+ Governed runs${number(report.summary.runs)}${number(report.summary.success)} successful · ${number(report.summary.degraded)} degraded
+ Failure rate${report.summary.failure_rate_pct}%${number(report.summary.failed)} failed · ${number(report.summary.alerts)} alerts
+ P95 latency${number(report.summary.latency_ms.p95)} msP50 ${number(report.summary.latency_ms.p50)} ms
+ Data quality${escapeHtml(report.data_quality.status.replaceAll('_', ' '))}Coverage disclosed below
+ Provider tokens${report.summary.coverage.token_records > 0 ? number(report.summary.tokens.provider_total ?? report.summary.tokens.total ?? 0) : 'Unavailable'}${report.summary.coverage.token_pct}% record coverage
+ Actual provider cost${report.summary.cost_usd.provider_actual !== null ? money(report.summary.cost_usd.provider_actual) : 'Unavailable'}${number(report.summary.provider_calls)} provider calls
+ Cost attribution${report.summary.coverage.cost_pct}%${report.summary.coverage.cost_records}/${report.summary.coverage.runtime_records} runtime records
+ Retries${number(report.summary.retries)}Observed reroute attempts
+
+
+ Decision brief
What requires attention
Threshold findings are operational review signals, not maturity claims.
${escapeHtml(report.verdict)}
+
+
+
+ Evidence quality
Coverage and disclosure
Unavailable telemetry remains null and is never rendered as zero.
${escapeHtml(report.data_quality.status)}
+ ${coverage('Token attribution', report.summary.coverage.token_pct, `${report.summary.coverage.token_records}/${report.summary.coverage.runtime_records} runtime records`)}${coverage('Cost attribution', report.summary.coverage.cost_pct, `${report.summary.coverage.cost_records}/${report.summary.coverage.runtime_records} runtime records`)}
+
+
+ Source integrity
Evidence provenance
Freshness and presence are evaluated independently for every canonical source.
+ | Source | State | Age | Records | Canonical path |
${sourceRows}
+
+
+ Runtime
Execution profile by step
+ | Step | Runs | Failures | Avg latency | Tokens | Cost |
${breakdownRows(report.details.by_step)}
+
+
+ Provider
Model usage and provenance
Only provider-reported token and actual cost values are shown.
+ | Provider · model | Calls | Failures | Avg latency | Tokens | Cost |
${breakdownRows(report.details.by_provider)}
+
+
`;
}
diff --git a/packages/casan-control-panel/backend/src/reports/run-report.html.ts b/packages/casan-control-panel/backend/src/reports/run-report.html.ts
index 83a1b70..4a137c4 100644
--- a/packages/casan-control-panel/backend/src/reports/run-report.html.ts
+++ b/packages/casan-control-panel/backend/src/reports/run-report.html.ts
@@ -1,4 +1,4 @@
-import type { RunAssuranceReport } from './run-report.js';
+import type { RunAssuranceReport, RunGateSnapshot } from './run-report.js';
const escapeHtml = (value: unknown): string => String(value ?? '')
.replaceAll('&', '&')
@@ -14,44 +14,91 @@ const badgeClass = (status: string): string => {
return 'fail';
};
+const evidenceFields = (gate: RunGateSnapshot): string => {
+ const entries = Object.entries(gate.evidence);
+ if (entries.length === 0) return 'No safe evidence fields were emitted.
';
+ return `${entries.map(([key, value]) => `
+ - ${escapeHtml(key)}
- ${escapeHtml(
+ typeof value === 'string' ? value : JSON.stringify(value),
+ )}
`).join('')}
`;
+};
+
export function renderRunAssuranceHtml(report: RunAssuranceReport): string {
- const gates = report.gates.map((gate) => `
-
- ${escapeHtml(gate.title)}${escapeHtml(gate.status)}
- ${escapeHtml(gate.reason)}
- ${escapeHtml(gate.updated_at ?? 'No timestamp')}
- Evidence fields
${escapeHtml(JSON.stringify(gate.evidence, null, 2))}
- `).join('');
const tokenValue = report.summary.token_usage_available ? 'Available' : 'Unavailable';
const costValue = report.summary.cost_available ? 'Available' : 'Unavailable';
+ const evidenceState = report.source.trace_found && report.source.graph_found ? 'Verified' : 'Partial';
+ const gates = report.gates.map((gate, index) => `
+
+ H${index + 1}
+
+
${escapeHtml(gate.title.split(' · ')[1] ?? gate.title)}
${escapeHtml(gate.status)}
+
${escapeHtml(gate.description)}
+
Latest decision${escapeHtml(gate.reason || 'No decision reason recorded.')}${escapeHtml(gate.updated_at ?? 'No timestamp')}
+
Evidence fields
+ ${evidenceFields(gate)}
+
+ `).join('');
+ const spine = report.gates.map((gate, index) => `
+
+ ${gate.status === 'pass' ? '✓' : gate.status === 'warning' ? '!' : gate.status === 'queued' ? '○' : '×'}
+ H${index + 1}
+ ${escapeHtml(gate.title.split(' · ')[1] ?? gate.title)}
+
`).join('');
+
return `
-CASAN assurance receipt · ${escapeHtml(report.trace_id)}
+CASAN assurance dossier · ${escapeHtml(report.trace_id)}
-CASAN · evidence-backed assurance
${escapeHtml(report.verdict.replace('_', ' ').toUpperCase())}
${escapeHtml(report.trace_id)}
+
+ CASAN · independent assurance dossier
+ ${escapeHtml(report.verdict.replace('_', ' ').toUpperCase())} governed run
+ ${escapeHtml(report.trace_id)}
+
+
${escapeHtml(report.verdict.replace('_', ' '))}
+
+
+
- Harness gates${report.summary.gates_observed}/7
- H6 quality${escapeHtml(report.summary.telemetry_quality)}
- Token usage${tokenValue}
- Cost${costValue}
- Duration${report.summary.duration_ms === null ? 'Unavailable' : `${report.summary.duration_ms} ms`}
- Tool calls${report.summary.tool_calls}
- Failures${report.summary.failures}
- Evidence source${report.source.trace_found && report.source.graph_found ? 'Verified' : 'Partial'}
+ Harness controls${report.summary.gates_observed}/7H1–H7 observed
+ Evidence source${evidenceState}Trace + graph reconstruction
+ H6 quality${escapeHtml(report.summary.telemetry_quality)}Telemetry disclosure status
+ Duration${report.summary.duration_ms === null ? 'Unavailable' : `${report.summary.duration_ms} ms`}End-to-end governed run
+ Tool calls${report.summary.tool_calls}Observed side-effect attempts
+ Failures${report.summary.failures}Recorded execution failures
+ Token usage${tokenValue}Never inferred as zero
+ Actual cost${costValue}Provider attribution only
-Live assurance rail · H1 → H7
${gates}
-Certification
Strength: ${escapeHtml(report.certification.strength ?? 'unknown')}
${escapeHtml(report.certification.reasons.join(' · ') || 'No certification reason recorded.')}
-
+
+ Control sequence
Live assurance rail · H1 → H7
The evidence spine shows the terminal state of every governed control.
${escapeHtml(report.verdict)}
+
+
+
+ Control dossiers
Decision and evidence detail
Every field below is sanitized before persistence. Raw prompts and tool output are excluded.
+ ${gates}
+
+
+ Certification
Assurance conclusion
+ ${escapeHtml(report.certification.strength ?? 'unknown')}
${escapeHtml(report.certification.reasons.join(' · ') || 'No certification reason recorded.')}
+
+
`;
}
diff --git a/packages/casan-control-panel/backend/test/reports.test.ts b/packages/casan-control-panel/backend/test/reports.test.ts
index daafc67..d5834e6 100644
--- a/packages/casan-control-panel/backend/test/reports.test.ts
+++ b/packages/casan-control-panel/backend/test/reports.test.ts
@@ -144,6 +144,9 @@ test('HTML export is standalone, escaped and contains no hard-coded maturity sco
assert.doesNotMatch(html, /