fix: split web sentinel ambiguous check codes

This commit is contained in:
Codex
2026-07-06 16:17:07 +00:00
parent 79a35183aa
commit cc694e9d20
7 changed files with 453 additions and 19 deletions
+144 -1
View File
@@ -1760,7 +1760,7 @@ function visibleFindingsForRun(
const artifactFindings = arrayRecords(artifactSummary.findings)
.slice(0, limit)
.map((item) => enrichFindingWithCheck(config, compactStoredFinding(item)));
return mergeVisibleFindings(config, storedFindings, artifactFindings, limit);
return reclassifyVisibleFindings(config, row, mergeVisibleFindings(config, storedFindings, artifactFindings, limit), limit);
}
function mergeVisibleFindings(config: WebProbeSentinelServiceConfig, primary: readonly Record<string, unknown>[], artifact: readonly Record<string, unknown>[], limit: number): readonly Record<string, unknown>[] {
@@ -1793,6 +1793,126 @@ function canonicalFindingIdentity(config: WebProbeSentinelServiceConfig, item: R
return stringOrNull(entry?.code) ?? stringOrNull(entry?.id) ?? findingId;
}
function reclassifyVisibleFindings(config: WebProbeSentinelServiceConfig, row: Record<string, unknown>, findings: readonly Record<string, unknown>[], limit: number): readonly Record<string, unknown>[] {
const hasObserverCommandFailure = findings.some((item) => findingIdentityCandidates(item).includes("observer-command-failed"));
const failure = stringOrNull(record(row.summary).failure) ?? stringOrNull(row.failure) ?? stringOrNull(record(row.businessStatus).failure);
return findings
.map((item) => enrichFindingWithCheck(config, reclassifyVisibleFinding(item, failure, hasObserverCommandFailure)))
.slice(0, limit);
}
function findingIdentityCandidates(item: Record<string, unknown>): readonly string[] {
const check = record(item.check);
const candidates = [
stringOrNull(item.finding_id),
stringOrNull(item.findingId),
stringOrNull(item.id),
stringOrNull(item.kind),
stringOrNull(item.code),
stringOrNull(item.checkId),
stringOrNull(item.checkCode),
stringOrNull(check.id),
stringOrNull(check.code),
];
return [...new Set(candidates.filter((value): value is string => value !== null))];
}
function reclassifyVisibleFinding(item: Record<string, unknown>, failure: string | null, hasObserverCommandFailure: boolean): Record<string, unknown> {
const ids = findingIdentityCandidates(item);
if (ids.includes("quick-verify-command-sequence-failed")) {
return retagVisibleFinding(item, "account-session-command-failed-before-observation", {
summary: "account/session setup command failed before any business turn could be observed.",
rootCause: `account-session-command-stage-failed:${failure ?? "unknown"}`,
rootCauseStatus: "confirmed",
rootCauseConfidence: "high",
evidenceSummary: `stage=account-session-command failure=${failure ?? "-"}`,
nextAction: "Inspect the first failed account/session/workbench command and rerun quick verify after that command succeeds.",
});
}
if (ids.includes("observer-command-failed") && !hasCommandFailureEvidence(item)) {
return retagVisibleFinding(item, "observer-command-failure-evidence-missing", {
summary: "report says observer control commands failed, but the first failed command evidence is missing.",
rootCause: "observer-command-failure-evidence-missing",
rootCauseStatus: "evidence-gap",
rootCauseConfidence: "high",
evidenceSummary: "firstCommandFailure missing from indexed and artifact findings",
nextAction: "Fix analyzer/report commandFailures compact output before using this finding as a page root cause.",
});
}
if (ids.includes("quick-verify-observer-stop-failed")) {
const evidence = `${stringOrNull(item.evidenceSummary) ?? ""} ${stringOrNull(item.summary) ?? ""}`;
if (/aliveAfter\s*=\s*true/u.test(evidence)) {
return retagVisibleFinding(item, "observer-force-stop-left-process-alive", {
summary: "observer force stop completed but process liveness evidence still reports aliveAfter=true.",
rootCause: "observer-process-still-alive-after-force-stop",
rootCauseStatus: "confirmed",
rootCauseConfidence: "high",
});
}
if (/aliveAfter\s*=\s*false/u.test(evidence)) {
return retagVisibleFinding(item, "observer-graceful-stop-timeout-force-stop-succeeded", {
severity: "warning",
level: "warning",
summary: "observer graceful stop did not drain before timeout, but force stop confirmed aliveAfter=false.",
rootCause: "observer-graceful-stop-timeout-force-stop-succeeded",
rootCauseStatus: "confirmed",
rootCauseConfidence: "high",
});
}
return retagVisibleFinding(item, "observer-cleanup-evidence-missing", {
summary: "observer cleanup stop-state evidence is missing or incomplete; this is an evidence gap, not confirmed process leakage.",
rootCause: "observer-cleanup-evidence-missing",
rootCauseStatus: "evidence-gap",
rootCauseConfidence: "medium",
evidenceSummary: stringOrNull(item.evidenceSummary) ?? "cleanup evidence missing",
});
}
if (ids.includes("no-samples")) {
if (hasObserverCommandFailure) {
return retagVisibleFinding(item, "no-samples-after-observer-command-failed", {
summary: "observer produced zero samples after a blocking control command failed; the command failure is the deterministic precondition.",
rootCause: "observer-command-failed-before-sampling",
rootCauseStatus: "confirmed",
rootCauseConfidence: "high",
});
}
return retagVisibleFinding(item, "no-samples-artifact-evidence-missing", {
summary: "observer produced zero samples and analyzer has no failed command precondition; sampling/source evidence is missing.",
rootCause: "sample-artifact-evidence-missing",
rootCauseStatus: "evidence-gap",
rootCauseConfidence: "medium",
});
}
return item;
}
function hasCommandFailureEvidence(item: Record<string, unknown>): boolean {
const first = record(item.firstCommandFailure ?? firstArrayRecord(item.commands));
return stringOrNull(first.type) !== null
|| stringOrNull(first.phase) !== null
|| stringOrNull(first.status) !== null
|| stringOrNull(first.stdoutPreview) !== null
|| stringOrNull(first.stderrPreview) !== null
|| numberOrNull(first.exitCode) !== null;
}
function retagVisibleFinding(item: Record<string, unknown>, id: string, extra: Record<string, unknown>): Record<string, unknown> {
return {
...item,
...extra,
id,
kind: id,
code: id,
finding_id: id,
findingId: id,
check: null,
checkId: null,
checkCode: null,
checkTitleZh: null,
valuesRedacted: true,
};
}
function findingIdentity(item: Record<string, unknown>): string | null {
return stringOrNull(item.finding_id)
?? stringOrNull(item.findingId)
@@ -1871,6 +1991,7 @@ function enrichFindingRowWithStoredDetail(config: WebProbeSentinelServiceConfig,
rootCauseConfidence: stringOrNull(detail?.rootCauseConfidence),
nextAction: stringOrNull(detail?.nextAction),
evidenceSummary: stringOrNull(detail?.evidenceSummary),
firstCommandFailure: compactCommandFailureEvidence(detail?.firstCommandFailure ?? firstArrayRecord(detail?.commands)),
rootCauseSignals: record(detail?.rootCauseSignals),
timingSourceOfTruth: stringOrNull(detail?.timingSourceOfTruth),
timingStatus: stringOrNull(detail?.timingStatus),
@@ -1918,6 +2039,7 @@ function compactStoredFinding(value: unknown): Record<string, unknown> {
rootCauseConfidence: stringOrNull(item.rootCauseConfidence),
nextAction: stringOrNull(item.nextAction),
evidenceSummary: stringOrNull(item.evidenceSummary) ?? compactFindingEvidenceSummary(item.evidence),
firstCommandFailure: compactCommandFailureEvidence(item.firstCommandFailure ?? firstArrayRecord(item.commands)),
rootCauseSignals: compactFindingRootCauseSignals(item.rootCauseSignals),
timingSourceOfTruth: stringOrNull(item.timingSourceOfTruth) ?? stringOrNull(item.expectedElapsedSource) ?? stringOrNull(item.evidenceKind),
timingStatus: stringOrNull(item.timingStatus),
@@ -1926,6 +2048,27 @@ function compactStoredFinding(value: unknown): Record<string, unknown> {
};
}
function compactCommandFailureEvidence(value: unknown): Record<string, unknown> | null {
const item = record(value);
if (Object.keys(item).length === 0) return null;
return {
commandId: stringOrNull(item.commandId),
type: stringOrNull(item.type),
phase: stringOrNull(item.phase),
status: stringOrNull(item.status),
exitCode: numberOrNull(item.exitCode),
timedOut: item.timedOut === true ? true : item.timedOut === false ? false : null,
stdoutPreview: stringOrNull(item.stdoutPreview)?.slice(0, 240) ?? null,
stderrPreview: stringOrNull(item.stderrPreview)?.slice(0, 240) ?? null,
artifactRef: stringOrNull(item.artifactRef),
valuesRedacted: true,
};
}
function firstArrayRecord(value: unknown): Record<string, unknown> | null {
return Array.isArray(value) && value.length > 0 ? record(value[0]) : null;
}
function compactFindingRootCauseSignals(value: unknown): Record<string, unknown> | null {
const item = record(value);
const keys = [