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 - ? `` - : '

    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)}
    -

    Verdict findings

    -

    Evidence freshness

    ${sourceRows}
    SourcePresenceStateAgeRecordsPath
    -

    Step breakdown

    ${breakdownRows(report.details.by_step)}
    StepRunsFailuresAvg latencyTokensCost
    -

    Provider/model breakdown

    ${breakdownRows(report.details.by_provider)}
    Provider · modelCallsFailuresAvg latencyTokensCost
    -

    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('')}
    +
    +
    ${escapeHtml(report.verdict)}
    +
    Report ID${escapeHtml(report.report_id)}Generated ${escapeHtml(report.generated_at)} · Freshness ${escapeHtml(report.freshness.status)}
    +
    +
    +
    +
    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)}
    +
    ${findings}
    +
    +
    +
    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`)}
    Disclosure notes
      ${warnings}
    +
    +
    +
    Source integrity

    Evidence provenance

    Freshness and presence are evaluated independently for every canonical source.

    +
    ${sourceRows}
    SourceStateAgeRecordsCanonical path
    +
    +
    +
    Runtime

    Execution profile by step

    +
    ${breakdownRows(report.details.by_step)}
    StepRunsFailuresAvg latencyTokensCost
    +
    +
    +
    Provider

    Model usage and provenance

    Only provider-reported token and actual cost values are shown.

    +
    ${breakdownRows(report.details.by_provider)}
    Provider · modelCallsFailuresAvg latencyTokensCost
    +
    +
    `; } 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('_', ' '))}
    +
    +
    Report ID${escapeHtml(report.report_id)}
    +
    Generated${escapeHtml(report.generated_at)}
    +
    Project${escapeHtml(report.project.id)}
    +
    Edition / maturity${escapeHtml(report.project.edition ?? 'unknown')} · ${escapeHtml(report.project.maturity?.status ?? 'not assessed')}
    +
    +
    +
    -
    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)}
    +
    ${spine}
    +
    +
    +
    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, /