feat(monitor): surface workbench sentinel root causes

This commit is contained in:
Codex
2026-06-27 01:52:50 +00:00
parent 3e4320eb88
commit 631e8ad23e
9 changed files with 382 additions and 17 deletions
+104 -5
View File
@@ -650,6 +650,7 @@ function dashboardFindings(config: WebProbeSentinelServiceConfig, db: Database,
`).all(...where.params, limit) as Record<string, unknown>[];
const items = rows.map((row) => {
const latestRun = latestRunForFinding(db, row);
const latestDetail = latestRun === null ? null : storedFindingDetailForRow(db, row, stringOrNull(latestRun.id));
return {
code: stringOrNull(row.finding_id),
findingId: stringOrNull(row.finding_id),
@@ -661,6 +662,11 @@ function dashboardFindings(config: WebProbeSentinelServiceConfig, db: Database,
latestRunId: latestRun === null ? null : stringOrNull(latestRun.id),
latestReportJsonSha256: latestRun === null ? null : stringOrNull(latestRun.report_json_sha256),
summary: stringOrNull(row.summary),
rootCause: stringOrNull(latestDetail?.rootCause),
rootCauseStatus: stringOrNull(latestDetail?.rootCauseStatus),
rootCauseConfidence: stringOrNull(latestDetail?.rootCauseConfidence),
nextAction: stringOrNull(latestDetail?.nextAction),
evidenceSummary: stringOrNull(latestDetail?.evidenceSummary),
traceability: latestRun === null ? null : runTraceability(config, latestRun),
valuesRedacted: true,
};
@@ -910,8 +916,88 @@ function readRunRow(db: Database, runId: string): Record<string, unknown> | null
}
function findingsForRun(db: Database, runId: string, limit: number): readonly Record<string, unknown>[] {
return db.query("SELECT finding_id, severity, count, summary, report_json_sha256, created_at FROM findings WHERE run_id = ? ORDER BY created_at DESC LIMIT ?")
const rows = db.query("SELECT finding_id, severity, count, summary, report_json_sha256, created_at FROM findings WHERE run_id = ? ORDER BY created_at DESC LIMIT ?")
.all(runId, limit) as Record<string, unknown>[];
return rows.map((row) => enrichFindingRowWithStoredDetail(db, runId, row));
}
function enrichFindingRowWithStoredDetail(db: Database, runId: string, row: Record<string, unknown>): Record<string, unknown> {
const detail = storedFindingDetailForRow(db, row, runId);
return {
...row,
code: stringOrNull(row.finding_id),
findingId: stringOrNull(row.finding_id),
rootCause: stringOrNull(detail?.rootCause),
rootCauseStatus: stringOrNull(detail?.rootCauseStatus),
rootCauseConfidence: stringOrNull(detail?.rootCauseConfidence),
nextAction: stringOrNull(detail?.nextAction),
evidenceSummary: stringOrNull(detail?.evidenceSummary),
valuesRedacted: true,
};
}
function storedFindingDetailForRow(db: Database, row: Record<string, unknown>, runId: string | null): Record<string, unknown> | null {
if (runId === null) return null;
const stored = readMetadata(db, `run.report.${runId}`) ?? {};
const details = arrayRecords(stored.findings);
if (details.length === 0) return null;
const findingId = stringOrNull(row.finding_id) ?? stringOrNull(row.findingId) ?? stringOrNull(row.code);
const severity = stringOrNull(row.severity);
return details.find((item) => {
const itemId = stringOrNull(item.finding_id) ?? stringOrNull(item.findingId) ?? stringOrNull(item.id) ?? stringOrNull(item.code);
if (itemId !== findingId) return false;
const itemSeverity = stringOrNull(item.severity) ?? stringOrNull(item.level);
return severity === null || itemSeverity === null || itemSeverity === severity;
}) ?? null;
}
function compactStoredFinding(value: unknown): Record<string, unknown> {
const item = record(value);
const findingId = stringOrNull(item.id) ?? stringOrNull(item.kind) ?? stringOrNull(item.code) ?? "finding";
const severity = stringOrNull(item.severity) ?? stringOrNull(item.level) ?? "unknown";
const summary = stringOrNull(item.summary) ?? stringOrNull(item.message) ?? findingId;
return {
id: findingId,
finding_id: findingId,
findingId,
code: findingId,
severity,
count: numberOr(item.count, numberOr(item.sampleCount, 1)),
summary: summary.slice(0, 500),
rootCause: stringOrNull(item.rootCause),
rootCauseStatus: stringOrNull(item.rootCauseStatus),
rootCauseConfidence: stringOrNull(item.rootCauseConfidence),
nextAction: stringOrNull(item.nextAction),
evidenceSummary: stringOrNull(item.evidenceSummary) ?? compactFindingEvidenceSummary(item.evidence),
valuesRedacted: true,
};
}
function compactFindingEvidenceSummary(value: unknown): string | null {
if (value === null || value === undefined) return null;
if (typeof value === "string") return value.slice(0, 240);
const item = record(value);
const keys = [
"http404Count",
"responseErrorCount",
"requestFailedCount",
"statuses",
"afterProjectedSeqs",
"sinceSeqs",
"traceIds",
"maxFallbackRatio",
"maxFallbackTitleCount",
"overThresholdSampleCount",
"majorityFallbackSampleCount",
];
const compact: Record<string, unknown> = {};
for (const key of keys) {
const raw = item[key];
if (raw === null || raw === undefined) continue;
compact[key] = Array.isArray(raw) ? raw.slice(0, 6) : raw;
}
const text = Object.keys(compact).length > 0 ? JSON.stringify(compact) : JSON.stringify(item).slice(0, 240);
return text.length > 240 ? `${text.slice(0, 239)}` : text;
}
function globalSeverityCounts(db: Database): Record<string, number> {
@@ -1111,6 +1197,7 @@ function recordRunResult(config: WebProbeSentinelServiceConfig, db: Database, in
reportJsonSha256,
summary: record(input.summary),
views: record(input.views),
findings: findings.map(compactStoredFinding),
publicOrigin: stringOrNull(input.publicOrigin),
screenshot: record(input.screenshot),
artifactCount,
@@ -1131,8 +1218,7 @@ function reportRunView(config: WebProbeSentinelServiceConfig, db: Database, view
const selectedRunId = stringOrNull(row.id);
if (selectedRunId === null) return { ok: false, error: "report-run-id-missing", view, valuesRedacted: true };
const stored = readMetadata(db, `run.report.${selectedRunId}`) ?? {};
const findings = db.query("SELECT finding_id, severity, count, summary, report_json_sha256, created_at FROM findings WHERE run_id = ? ORDER BY created_at DESC LIMIT 50")
.all(selectedRunId) as Record<string, unknown>[];
const findings = findingsForRun(db, selectedRunId, 50);
const views = record(stored.views);
const storedView = record(views[view]);
const renderedText = typeof storedView.renderedText === "string" ? storedView.renderedText : view === "summary" ? renderStoredSummary(row, stored, findings) : view === "findings" ? renderStoredFindings(row, findings) : null;
@@ -1150,6 +1236,19 @@ function reportRunView(config: WebProbeSentinelServiceConfig, db: Database, view
};
}
function formatStoredFindingLine(item: Record<string, unknown>): string {
const rootCause = stringOrNull(item.rootCause);
const status = stringOrNull(item.rootCauseStatus);
const nextAction = stringOrNull(item.nextAction);
const evidence = stringOrNull(item.evidenceSummary);
return [
`${item.severity ?? "-"} ${item.finding_id ?? item.findingId ?? item.code ?? "-"} count=${item.count ?? "-"} ${item.summary ?? ""}`,
rootCause === null ? null : `rootCause=${rootCause}${status === null ? "" : ` status=${status}`}`,
evidence === null ? null : `evidence=${evidence}`,
nextAction === null ? null : `next=${nextAction}`,
].filter((part) => part !== null).join(" | ");
}
function renderStoredSummary(row: Record<string, unknown>, stored: Record<string, unknown>, findings: readonly Record<string, unknown>[]): string {
const summary = record(stored.summary);
return [
@@ -1162,7 +1261,7 @@ function renderStoredSummary(row: Record<string, unknown>, stored: Record<string
`analysisWindow=${JSON.stringify(record(summary.analysisWindow))}`,
"",
"Findings",
findings.length === 0 ? "-" : findings.slice(0, 12).map((item) => `${item.severity ?? "-"} ${item.finding_id ?? "-"} count=${item.count ?? "-"} ${item.summary ?? ""}`).join("\n"),
findings.length === 0 ? "-" : findings.slice(0, 12).map(formatStoredFindingLine).join("\n"),
].join("\n");
}
@@ -1171,7 +1270,7 @@ function renderStoredFindings(row: Record<string, unknown>, findings: readonly R
"Web Probe Sentinel Findings",
"=======================================================",
`run=${stringOrNull(row.id) ?? "-"} report=${stringOrNull(row.report_json_sha256) ?? "-"}`,
findings.length === 0 ? "-" : findings.map((item) => `${item.severity ?? "-"} ${item.finding_id ?? "-"} count=${item.count ?? "-"} ${item.summary ?? ""}`).join("\n"),
findings.length === 0 ? "-" : findings.map(formatStoredFindingLine).join("\n"),
].join("\n");
}