function normalizeString(value) { return typeof value === "string" ? value.trim() : ""; } function normalizeNumber(value) { return typeof value === "number" && Number.isFinite(value) ? value : 0; } const VERIFICATION_FAILURE_OUTCOMES = new Set([ "issues_present", "fallback_used", "failure", "unknown", "failed", ]); const VERIFICATION_RECOVERED_OUTCOMES = new Set([ "repaired", "success", "passed", "clean", ]); const BLOCKING_VERIFICATION_FAILURES = new Set([ "browserVerification:failure", "guiSmoke:failed", ]); export function splitVerificationOutcomeName(name) { const normalizedName = normalizeString(name); if (!normalizedName) { return { name: "", signal: "", outcome: "" }; } const separatorIndex = normalizedName.indexOf(":"); if (separatorIndex < 0) { return { name: normalizedName, signal: normalizedName, outcome: "", }; } return { name: normalizedName, signal: normalizedName.slice(0, separatorIndex).trim(), outcome: normalizedName.slice(separatorIndex + 1).trim(), }; } export function isVerificationFailureOutcome(outcome) { return VERIFICATION_FAILURE_OUTCOMES.has(normalizeString(outcome)); } export function isVerificationRecoveredOutcome(outcome) { return VERIFICATION_RECOVERED_OUTCOMES.has(normalizeString(outcome)); } export function getVerificationOutcomeRole(signal, outcome) { const normalizedSignal = normalizeString(signal); const normalizedOutcome = normalizeString(outcome); const fingerprint = `${normalizedSignal}:${normalizedOutcome}`; if (BLOCKING_VERIFICATION_FAILURES.has(fingerprint)) { return "blocking_failure"; } if (isVerificationFailureOutcome(normalizedOutcome)) { return "advisory_failure"; } if (isVerificationRecoveredOutcome(normalizedOutcome)) { return "recovered"; } return "other"; } export function getVerificationOutcomeWeight(outcome) { switch (normalizeString(outcome)) { case "failed": return 140; case "failure": return 130; case "unknown": return 115; case "fallback_used": return 110; case "issues_present": return 100; case "repaired": return 70; default: return 0; } } function dedupeNonEmptyStrings(values) { const normalizedValues = Array.isArray(values) ? values : []; return [...new Set(normalizedValues.map((value) => normalizeString(value)).filter(Boolean))]; } export function hasVerificationOutcome(entries, signal, outcome) { const normalizedEntries = Array.isArray(entries) ? entries : []; const normalizedSignal = normalizeString(signal); const normalizedOutcome = normalizeString(outcome); return normalizedEntries.some( (entry) => normalizeString(entry?.signal) === normalizedSignal && normalizeString(entry?.outcome) === normalizedOutcome, ); } export function buildBlockingVerificationFollowUp(entries) { const hasGuiSmokeFailure = hasVerificationOutcome(entries, "guiSmoke", "failed"); const hasBrowserVerificationFailure = hasVerificationOutcome( entries, "browserVerification", "failure", ); const commands = ["npm run harness:eval", "npm run harness:eval:trend"]; const backlogTools = []; const rationale = []; if (hasGuiSmokeFailure) { commands.push("npm run verify:gui-smoke"); rationale.push( "current 样本已出现 guiSmoke:failed,先恢复 GUI 壳 / DevBridge / Workspace 主路径的最小可启动性。", ); backlogTools.push( "优先收敛 GUI 壳 / DevBridge / Workspace 主路径,再复跑 `npm run verify:gui-smoke`。", ); } if (hasBrowserVerificationFailure) { rationale.push( "current 样本已出现 browserVerification:failure,应先回看 browser replay / verification 失败样本,把失败断言回挂到受影响主路径。", ); backlogTools.push( "回看 browser replay / browser verification 失败样本,并把失败断言回挂到受影响主路径。", ); } if (backlogTools.length === 0) { backlogTools.push("按受影响主路径追加 `npm run verify:gui-smoke` 或专项 smoke"); } return { commands: dedupeNonEmptyStrings(commands), backlogTools: dedupeNonEmptyStrings(backlogTools), rationale: dedupeNonEmptyStrings(rationale), }; } export function buildAdvisoryVerificationFollowUp(entries) { const hasArtifactValidatorIssuesPresent = hasVerificationOutcome( entries, "artifactValidator", "issues_present", ); const hasArtifactValidatorFallbackUsed = hasVerificationOutcome( entries, "artifactValidator", "fallback_used", ); const hasBrowserVerificationUnknown = hasVerificationOutcome( entries, "browserVerification", "unknown", ); const rationale = []; const backlogTools = []; if (hasArtifactValidatorIssuesPresent) { rationale.push( "current 样本已出现 artifactValidator:issues_present,应先回看 validator issue 明细,再收敛 artifact 导出字段。", ); backlogTools.push( "回看 artifact validator issue 明细,并收敛 evidence pack / artifacts.json / analysis handoff 的 artifact 字段。", ); } if (hasArtifactValidatorFallbackUsed) { rationale.push( "current 样本已出现 artifactValidator:fallback_used,说明 artifact 主路径仍不稳定,不能继续依赖 fallback 充当事实。", ); backlogTools.push( "补齐 artifact 主路径导出与修复链,减少 fallback_used 持续留在 current 样本。", ); } if (hasBrowserVerificationUnknown) { rationale.push( "current 样本已出现 browserVerification:unknown,需要先把浏览器验证结果收敛成明确 outcome,再继续扩大分析。", ); backlogTools.push( "回看 browser verification 导出链,确保 evidence pack / replay / analysis handoff 写出明确 success 或 failure,而不是 unknown。", ); } if (backlogTools.length === 0) { backlogTools.push( "先对齐 current verification outcome 到 artifact/browser/gui 主路径,再继续补 observability 证据。", ); } return { rationale: dedupeNonEmptyStrings(rationale), backlogTools: dedupeNonEmptyStrings(backlogTools), }; } export function buildRecoveredVerificationFollowUp(entries) { const hasArtifactValidatorRepaired = hasVerificationOutcome( entries, "artifactValidator", "repaired", ); const hasBrowserVerificationSuccess = hasVerificationOutcome( entries, "browserVerification", "success", ); const hasGuiSmokePassed = hasVerificationOutcome(entries, "guiSmoke", "passed"); const commands = ["npm run harness:eval", "npm run harness:eval:trend"]; const rationale = []; const backlogTools = []; if (hasArtifactValidatorRepaired) { rationale.push( "current 样本已出现 artifactValidator:repaired,说明 artifact 修复链已经回到可复用的主路径。", ); backlogTools.push( "在 evidence pack / analysis handoff 里同时保留 artifact issue 与 repaired outcome,避免只剩修复结论而丢失修复上下文。", ); } if (hasBrowserVerificationSuccess) { rationale.push( "current 样本已出现 browserVerification:success,可把浏览器验证成功样本固化成主路径正向基线。", ); backlogTools.push( "把 browser verification 成功样本固定进 current replay 基线,后续 failure 或 unknown 直接对比这条正向路径。", ); } if (hasGuiSmokePassed) { commands.push("npm run verify:gui-smoke"); rationale.push( "current 样本已出现 guiSmoke:passed,可继续把 GUI smoke 通过链路当成桌面主路径的正向守卫。", ); backlogTools.push( "主路径变更时优先复跑 `npm run verify:gui-smoke`,确认 GUI 壳 / DevBridge / Workspace 不从 passed 回退。", ); } return { commands: dedupeNonEmptyStrings(commands), rationale: dedupeNonEmptyStrings(rationale), backlogTools: dedupeNonEmptyStrings(backlogTools), }; } export function formatVerificationOutcomeName(entry) { if (typeof entry === "string") { return normalizeString(entry); } const explicitName = normalizeString(entry?.name); if (explicitName) { return explicitName; } const signal = normalizeString(entry?.signal); const outcome = normalizeString(entry?.outcome); return signal && outcome ? `${signal}:${outcome}` : ""; } export function formatVerificationOutcomeCompactLabel(entry) { if (typeof entry === "string") { const parsed = splitVerificationOutcomeName(entry); if (parsed.signal && parsed.outcome) { return `${parsed.signal} (${parsed.outcome})`; } return normalizeString(entry); } const signal = normalizeString(entry?.signal); const outcome = normalizeString(entry?.outcome); if (signal && outcome) { return `${signal} (${outcome})`; } const parsed = splitVerificationOutcomeName(entry?.name); if (parsed.signal && parsed.outcome) { return `${parsed.signal} (${parsed.outcome})`; } return normalizeString(entry?.name); } export function formatVerificationOutcomeCompactLabels(entries, limit = 0) { const normalizedEntries = Array.isArray(entries) ? entries : []; const truncatedEntries = typeof limit === "number" && limit > 0 ? normalizedEntries.slice(0, limit) : normalizedEntries; return truncatedEntries .map((entry) => formatVerificationOutcomeCompactLabel(entry)) .filter(Boolean); } export function describeVerificationOutcome(entry) { const signal = normalizeString(entry?.signal, "unknown"); const outcome = normalizeString(entry?.outcome, "unknown"); if (signal === "artifactValidator" && outcome === "issues_present") { return "当前 evidence 已记录 artifact 校验问题,优先回看 validator issue 明细。"; } if (signal === "artifactValidator" && outcome === "fallback_used") { return "当前 artifact 导出仍触发 fallback,说明产物结构或修复链未完全稳定。"; } if (signal === "browserVerification" && outcome === "failure") { return "浏览器验证已有明确失败结果,优先回挂到 replay 或 smoke 断言。"; } if (signal === "browserVerification" && outcome === "unknown") { return "浏览器验证结果仍不明确,需要先补 outcome 再继续扩分析。"; } if (signal === "guiSmoke" && outcome === "failed") { return "GUI smoke 已明确失败,应优先收敛到受影响主路径。"; } if (signal === "guiSmoke" && outcome === "passed") { return "GUI smoke 已通过,可继续把注意力放回 gap 与其它失败面。"; } if (signal === "artifactValidator" && outcome === "repaired") { return "artifact validator 已执行修复,可结合 issues/fallback 判断是否还需继续治理。"; } if (signal === "browserVerification" && outcome === "success") { return "浏览器验证已有成功样本,可作为 current 主线路径的正向基线。"; } return "当前 verification outcome 已进入 cleanup 主线,可直接据此定位先修哪层。"; } export function buildVerificationOutcomeEntriesFromDeltas(entries) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries .map((entry) => { const latest = entry != null && typeof entry === "object" ? entry.latest ?? {} : {}; const delta = entry != null && typeof entry === "object" ? entry.delta ?? {} : {}; const baseline = entry != null && typeof entry === "object" ? entry.baseline ?? {} : {}; const parsed = splitVerificationOutcomeName(entry?.name); const latestCase = normalizeNumber(latest.caseCount); const deltaCase = normalizeNumber(delta.caseCount); let state = "stable"; if (deltaCase > 0) { state = "expanding"; } else if (deltaCase < 0) { state = "shrinking"; } else if (latestCase > 0) { state = "present"; } return { name: normalizeString(entry?.name) || "(unknown)", signal: parsed.signal || "(unknown)", outcome: parsed.outcome || "unknown", baseline: { caseCount: normalizeNumber(baseline.caseCount), readyCount: normalizeNumber(baseline.readyCount), invalidCount: normalizeNumber(baseline.invalidCount), pendingRequestCaseCount: normalizeNumber( baseline.pendingRequestCaseCount, ), needsHumanReviewCount: normalizeNumber( baseline.needsHumanReviewCount, ), }, latest: { caseCount: latestCase, readyCount: normalizeNumber(latest.readyCount), invalidCount: normalizeNumber(latest.invalidCount), pendingRequestCaseCount: normalizeNumber( latest.pendingRequestCaseCount, ), needsHumanReviewCount: normalizeNumber(latest.needsHumanReviewCount), }, delta: { caseCount: deltaCase, readyCount: normalizeNumber(delta.readyCount), invalidCount: normalizeNumber(delta.invalidCount), pendingRequestCaseCount: normalizeNumber(delta.pendingRequestCaseCount), needsHumanReviewCount: normalizeNumber(delta.needsHumanReviewCount), }, state, score: latestCase * 10 + Math.abs(deltaCase) * 5, }; }) .filter((entry) => entry.latest.caseCount > 0 || entry.delta.caseCount !== 0) .sort((left, right) => { if (right.latest.caseCount !== left.latest.caseCount) { return right.latest.caseCount - left.latest.caseCount; } if (Math.abs(right.delta.caseCount) !== Math.abs(left.delta.caseCount)) { return Math.abs(right.delta.caseCount) - Math.abs(left.delta.caseCount); } return left.name.localeCompare(right.name); }); } export function buildVerificationOutcomeEntriesFromBreakdowns(entries) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries .map((entry) => { const parsed = splitVerificationOutcomeName(entry?.name); const latestCase = normalizeNumber(entry?.caseCount); return { name: normalizeString(entry?.name) || "(unknown)", signal: parsed.signal || "(unknown)", outcome: parsed.outcome || "unknown", baseline: { caseCount: 0, readyCount: 0, invalidCount: 0, pendingRequestCaseCount: 0, needsHumanReviewCount: 0, }, latest: { caseCount: latestCase, readyCount: normalizeNumber(entry?.readyCount), invalidCount: normalizeNumber(entry?.invalidCount), pendingRequestCaseCount: normalizeNumber(entry?.pendingRequestCaseCount), needsHumanReviewCount: normalizeNumber(entry?.needsHumanReviewCount), }, delta: { caseCount: 0, readyCount: 0, invalidCount: 0, pendingRequestCaseCount: 0, needsHumanReviewCount: 0, }, state: latestCase > 0 ? "present" : "stable", score: latestCase * 10, }; }) .filter((entry) => entry.latest.caseCount > 0) .sort((left, right) => { if (right.latest.caseCount !== left.latest.caseCount) { return right.latest.caseCount - left.latest.caseCount; } return left.name.localeCompare(right.name); }); } export function buildVerificationOutcomeEntriesFromSummary(summary, key) { return buildVerificationOutcomeEntriesFromBreakdowns(summary?.breakdowns?.[key]) .map((entry) => ({ ...entry, latestCaseCount: normalizeNumber(entry?.latest?.caseCount), })) .filter((entry) => formatVerificationOutcomeName(entry) && entry.latestCaseCount > 0); } export function buildVerificationOutcomeEntriesFromTrend(trendReport, key) { return buildVerificationOutcomeEntriesFromDeltas( trendReport?.classificationDeltas?.[key], ) .map((entry) => ({ ...entry, latestCaseCount: normalizeNumber(entry?.latest?.caseCount), deltaCaseCount: normalizeNumber(entry?.delta?.caseCount), })) .filter((entry) => formatVerificationOutcomeName(entry) && entry.latestCaseCount > 0); } export function filterVerificationOutcomeEntriesByRoles(entries, roles) { const normalizedEntries = Array.isArray(entries) ? entries : []; const normalizedRoles = new Set( (Array.isArray(roles) ? roles : [roles]).map((role) => normalizeString(role)).filter(Boolean), ); return normalizedEntries.filter((entry) => normalizedRoles.has(getVerificationOutcomeRole(entry?.signal, entry?.outcome)), ); } export function sumVerificationOutcomeCaseCountsByRoles(entries, roles) { return filterVerificationOutcomeEntriesByRoles(entries, roles).reduce( (total, entry) => total + normalizeNumber(entry?.latestCaseCount ?? entry?.latest?.caseCount), 0, ); } function toVerificationOutcomeNames(entries) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries.map((entry) => formatVerificationOutcomeName(entry)).filter(Boolean); } function pickFirstNonEmptyNames(groups) { for (const group of groups) { if (Array.isArray(group) && group.length > 0) { return group; } } return []; } function getCleanupVerificationFocusEntries(cleanupReport, key) { const entries = cleanupReport?.focus?.[key]; return Array.isArray(entries) ? entries : []; } function withVerificationRole(entries, role) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries.map((entry) => ({ ...entry, role })); } function pickFirstNonEmptyEntries(groups) { for (const group of groups) { if (Array.isArray(group) && group.length > 0) { return group; } } return []; } export function deriveVerificationHistoryRecordFacts({ summary, trendReport, cleanupReport, }) { const trendCurrentEntries = filterVerificationOutcomeEntriesByRoles( buildVerificationOutcomeEntriesFromTrend( trendReport, "currentObservabilityVerificationOutcomes", ), ["blocking_failure", "advisory_failure"], ); const trendFallbackEntries = filterVerificationOutcomeEntriesByRoles( buildVerificationOutcomeEntriesFromTrend( trendReport, "observabilityVerificationOutcomes", ), ["blocking_failure", "advisory_failure"], ); const summaryCurrentEntries = filterVerificationOutcomeEntriesByRoles( buildVerificationOutcomeEntriesFromSummary( summary, "currentObservabilityVerificationOutcomes", ), ["blocking_failure", "advisory_failure"], ); const summaryFallbackEntries = filterVerificationOutcomeEntriesByRoles( buildVerificationOutcomeEntriesFromSummary( summary, "observabilityVerificationOutcomes", ), ["blocking_failure", "advisory_failure"], ); const cleanupCurrentEntries = getCleanupVerificationFocusEntries( cleanupReport, "currentObservabilityVerificationOutcomes", ); const cleanupFallbackEntries = getCleanupVerificationFocusEntries( cleanupReport, "observabilityVerificationOutcomes", ); const verificationFailureOutcomeFocus = pickFirstNonEmptyNames([ toVerificationOutcomeNames(trendCurrentEntries), toVerificationOutcomeNames(trendFallbackEntries), toVerificationOutcomeNames(summaryCurrentEntries), toVerificationOutcomeNames(summaryFallbackEntries), toVerificationOutcomeNames(cleanupCurrentEntries), toVerificationOutcomeNames(cleanupFallbackEntries), ]); const explicitTrendRecoveredEntries = buildVerificationOutcomeEntriesFromTrend( trendReport, "currentRecoveredObservabilityVerificationOutcomes", ); const fallbackTrendRecoveredEntries = filterVerificationOutcomeEntriesByRoles( buildVerificationOutcomeEntriesFromTrend( trendReport, "currentObservabilityVerificationOutcomes", ), "recovered", ); const explicitSummaryRecoveredEntries = buildVerificationOutcomeEntriesFromSummary( summary, "currentRecoveredObservabilityVerificationOutcomes", ); const fallbackSummaryRecoveredEntries = filterVerificationOutcomeEntriesByRoles( buildVerificationOutcomeEntriesFromSummary( summary, "currentObservabilityVerificationOutcomes", ), "recovered", ); const cleanupExplicitRecoveredEntries = getCleanupVerificationFocusEntries( cleanupReport, "currentRecoveredObservabilityVerificationOutcomes", ); const currentRecoveredBaselineFocus = pickFirstNonEmptyNames([ toVerificationOutcomeNames(explicitTrendRecoveredEntries), toVerificationOutcomeNames(fallbackTrendRecoveredEntries), toVerificationOutcomeNames(explicitSummaryRecoveredEntries), toVerificationOutcomeNames(fallbackSummaryRecoveredEntries), toVerificationOutcomeNames(cleanupExplicitRecoveredEntries), toVerificationOutcomeNames( filterVerificationOutcomeEntriesByRoles( cleanupCurrentEntries.length > 0 ? cleanupCurrentEntries : cleanupFallbackEntries, "recovered", ), ), ]); const overallEntries = buildVerificationOutcomeEntriesFromSummary( summary, "observabilityVerificationOutcomes", ); const currentEntries = buildVerificationOutcomeEntriesFromSummary( summary, "currentObservabilityVerificationOutcomes", ); const degradedEntries = buildVerificationOutcomeEntriesFromSummary( summary, "degradedObservabilityVerificationOutcomes", ); const explicitCurrentRecoveredEntries = buildVerificationOutcomeEntriesFromSummary( summary, "currentRecoveredObservabilityVerificationOutcomes", ); const verificationOutcomeCounts = overallEntries.length > 0 || currentEntries.length > 0 || degradedEntries.length > 0 || explicitCurrentRecoveredEntries.length > 0 ? { failureCaseCount: sumVerificationOutcomeCaseCountsByRoles( overallEntries, ["blocking_failure", "advisory_failure"], ), blockingFailureCaseCount: sumVerificationOutcomeCaseCountsByRoles( currentEntries, "blocking_failure", ), advisoryFailureCaseCount: sumVerificationOutcomeCaseCountsByRoles( currentEntries, "advisory_failure", ), recoveredCaseCount: sumVerificationOutcomeCaseCountsByRoles( overallEntries, "recovered", ), currentRecoveredCaseCount: normalizeNumber( trendReport?.latest?.totals?.currentRecoveredVerificationCaseCount, ) || normalizeNumber(summary?.totals?.currentRecoveredVerificationCaseCount) || (explicitCurrentRecoveredEntries.length > 0 ? explicitCurrentRecoveredEntries.reduce( (total, entry) => total + normalizeNumber(entry.latestCaseCount), 0, ) : sumVerificationOutcomeCaseCountsByRoles(currentEntries, "recovered")), degradedBlockingFailureCaseCount: sumVerificationOutcomeCaseCountsByRoles( degradedEntries, "blocking_failure", ), } : (() => { const cleanupSummary = cleanupReport && typeof cleanupReport === "object" && cleanupReport.summary && cleanupReport.summary.verificationOutcomes && typeof cleanupReport.summary.verificationOutcomes === "object" ? cleanupReport.summary.verificationOutcomes : {}; const currentSummary = cleanupSummary && typeof cleanupSummary.current === "object" && !Array.isArray(cleanupSummary.current) ? cleanupSummary.current : {}; const degradedSummary = cleanupSummary && typeof cleanupSummary.degraded === "object" && !Array.isArray(cleanupSummary.degraded) ? cleanupSummary.degraded : {}; return { failureCaseCount: normalizeNumber(cleanupSummary.failureCaseCount), blockingFailureCaseCount: normalizeNumber( currentSummary.blockingFailureCaseCount, ), advisoryFailureCaseCount: normalizeNumber( currentSummary.advisoryFailureCaseCount, ), recoveredCaseCount: normalizeNumber(cleanupSummary.recoveredCaseCount), currentRecoveredCaseCount: normalizeNumber( currentSummary.recoveredCaseCount, ), degradedBlockingFailureCaseCount: normalizeNumber( degradedSummary.blockingFailureCaseCount, ), }; })(); return { verificationFailureOutcomeFocus, currentRecoveredBaselineFocus, verificationOutcomeCounts, }; } export function deriveVerificationDashboardPresentation({ summaryReport, trendReport, cleanupReport, }) { const trendOverallRows = buildVerificationOutcomeEntriesFromTrend( trendReport, "observabilityVerificationOutcomes", ); const trendCurrentRows = buildVerificationOutcomeEntriesFromTrend( trendReport, "currentObservabilityVerificationOutcomes", ); const trendCurrentRecoveredRowsExplicit = buildVerificationOutcomeEntriesFromTrend( trendReport, "currentRecoveredObservabilityVerificationOutcomes", ); const trendDegradedRows = buildVerificationOutcomeEntriesFromTrend( trendReport, "degradedObservabilityVerificationOutcomes", ); const summaryOverallRows = buildVerificationOutcomeEntriesFromSummary( summaryReport, "observabilityVerificationOutcomes", ); const summaryCurrentRows = buildVerificationOutcomeEntriesFromSummary( summaryReport, "currentObservabilityVerificationOutcomes", ); const summaryCurrentRecoveredRowsExplicit = buildVerificationOutcomeEntriesFromSummary( summaryReport, "currentRecoveredObservabilityVerificationOutcomes", ); const summaryDegradedRows = buildVerificationOutcomeEntriesFromSummary( summaryReport, "degradedObservabilityVerificationOutcomes", ); const cleanupCurrentRows = getCleanupVerificationFocusEntries( cleanupReport, "currentObservabilityVerificationOutcomes", ); const cleanupDegradedRows = getCleanupVerificationFocusEntries( cleanupReport, "degradedObservabilityVerificationOutcomes", ); const cleanupFallbackRows = getCleanupVerificationFocusEntries( cleanupReport, "observabilityVerificationOutcomes", ); const cleanupCurrentRecoveredRows = getCleanupVerificationFocusEntries( cleanupReport, "currentRecoveredObservabilityVerificationOutcomes", ); const currentFailureRows = pickFirstNonEmptyEntries([ withVerificationRole( filterVerificationOutcomeEntriesByRoles( trendCurrentRows, ["blocking_failure", "advisory_failure"], ), "current", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles( summaryCurrentRows, ["blocking_failure", "advisory_failure"], ), "current", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles( cleanupCurrentRows, ["blocking_failure", "advisory_failure"], ), "current", ), ]); const degradedFailureRows = pickFirstNonEmptyEntries([ withVerificationRole( filterVerificationOutcomeEntriesByRoles( trendDegradedRows, ["blocking_failure", "advisory_failure"], ), "degraded", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles( summaryDegradedRows, ["blocking_failure", "advisory_failure"], ), "degraded", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles( cleanupDegradedRows, ["blocking_failure", "advisory_failure"], ), "degraded", ), ]); const fallbackFailureRows = pickFirstNonEmptyEntries([ withVerificationRole( filterVerificationOutcomeEntriesByRoles( trendOverallRows, ["blocking_failure", "advisory_failure"], ), "mixed", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles( summaryOverallRows, ["blocking_failure", "advisory_failure"], ), "mixed", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles( cleanupFallbackRows, ["blocking_failure", "advisory_failure"], ), "mixed", ), ]); const currentRecoveredRows = pickFirstNonEmptyEntries([ withVerificationRole(trendCurrentRecoveredRowsExplicit, "current"), withVerificationRole(summaryCurrentRecoveredRowsExplicit, "current"), withVerificationRole( filterVerificationOutcomeEntriesByRoles(trendCurrentRows, "recovered"), "current", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles(summaryCurrentRows, "recovered"), "current", ), withVerificationRole(cleanupCurrentRecoveredRows, "current"), withVerificationRole( filterVerificationOutcomeEntriesByRoles(cleanupCurrentRows, "recovered"), "current", ), withVerificationRole( filterVerificationOutcomeEntriesByRoles(cleanupFallbackRows, "recovered"), "mixed", ), ]); const verificationFocusRows = currentFailureRows.length > 0 || degradedFailureRows.length > 0 ? [...currentFailureRows, ...degradedFailureRows] : fallbackFailureRows; const overallSummaryEntries = pickFirstNonEmptyEntries([ trendOverallRows, summaryOverallRows, [...currentFailureRows, ...degradedFailureRows, ...currentRecoveredRows], ]); const currentSummaryEntries = pickFirstNonEmptyEntries([ trendCurrentRecoveredRowsExplicit.length > 0 ? [ ...filterVerificationOutcomeEntriesByRoles( trendCurrentRows, ["blocking_failure", "advisory_failure"], ), ...trendCurrentRecoveredRowsExplicit, ] : trendCurrentRows, summaryCurrentRecoveredRowsExplicit.length > 0 ? [ ...filterVerificationOutcomeEntriesByRoles( summaryCurrentRows, ["blocking_failure", "advisory_failure"], ), ...summaryCurrentRecoveredRowsExplicit, ] : summaryCurrentRows, cleanupCurrentRecoveredRows.length > 0 ? [ ...filterVerificationOutcomeEntriesByRoles( cleanupCurrentRows, ["blocking_failure", "advisory_failure"], ), ...cleanupCurrentRecoveredRows, ] : cleanupCurrentRows, [...currentFailureRows, ...currentRecoveredRows], ]); const degradedSummaryEntries = pickFirstNonEmptyEntries([ trendDegradedRows, summaryDegradedRows, cleanupDegradedRows, degradedFailureRows, ]); const derivedVerificationSummary = overallSummaryEntries.length > 0 || currentSummaryEntries.length > 0 || degradedSummaryEntries.length > 0 ? { ...buildVerificationOutcomeSummary(overallSummaryEntries), current: buildVerificationOutcomeSummary(currentSummaryEntries), degraded: buildVerificationOutcomeSummary(degradedSummaryEntries), } : null; const fallbackVerificationSummary = cleanupReport && typeof cleanupReport === "object" && cleanupReport.summary && cleanupReport.summary.verificationOutcomes ? cleanupReport.summary.verificationOutcomes : {}; return { verificationSummary: derivedVerificationSummary ?? fallbackVerificationSummary, verificationFocusRows, currentRecoveredRows, currentRecoveredSummaryLabel: currentRecoveredRows .slice(0, 3) .map((entry) => formatVerificationOutcomeCompactLabel(entry)) .filter(Boolean) .join("、"), }; } export function buildVerificationOutcomeSignalMessages({ focusVerificationFailureOutcomes, verificationOutcomeSummary, currentVerificationOutcomeSummary, degradedVerificationOutcomeSummary, currentRecoveredVerificationOutcomes, labelLimit = 3, }) { const failureLabels = formatVerificationOutcomeCompactLabels( focusVerificationFailureOutcomes, labelLimit, ); const recoveredLabels = formatVerificationOutcomeCompactLabels( currentRecoveredVerificationOutcomes, labelLimit, ); return [ failureLabels.length > 0 ? `当前 verification failure outcome 焦点:${failureLabels.join("、")}。` : "当前没有额外的 verification failure outcome 焦点。", normalizeNumber(verificationOutcomeSummary?.failureCaseCount) > 0 ? `当前 verification failure 聚焦 ${normalizeNumber(verificationOutcomeSummary?.failureFocusCount)} 类 outcome,共 ${normalizeNumber(verificationOutcomeSummary?.failureCaseCount)} 个 case。` : "当前没有额外的 verification failure case。", normalizeNumber(currentVerificationOutcomeSummary?.blockingFailureCaseCount) > 0 ? `当前 current 样本里有 ${normalizeNumber(currentVerificationOutcomeSummary?.blockingFailureCaseCount)} 个 blocking verification failure。` : "当前没有额外的 blocking verification failure。", normalizeNumber(currentVerificationOutcomeSummary?.advisoryFailureCaseCount) > 0 ? `当前 current 样本里有 ${normalizeNumber(currentVerificationOutcomeSummary?.advisoryFailureCaseCount)} 个 advisory verification failure。` : "当前没有额外的 advisory verification failure。", normalizeNumber(currentVerificationOutcomeSummary?.recoveredCaseCount) > 0 ? `当前 current recovered verification baseline:${recoveredLabels.join("、") || "暂无"}。` : "当前没有额外的 current recovered verification baseline。", normalizeNumber(degradedVerificationOutcomeSummary?.blockingFailureCaseCount) > 0 ? `当前保留 ${normalizeNumber(degradedVerificationOutcomeSummary?.blockingFailureCaseCount)} 个 degraded blocking verification failure 样本作为诊断基线。` : "当前没有额外的 degraded blocking verification baseline。", normalizeNumber(verificationOutcomeSummary?.recoveredCaseCount) > 0 ? `当前 verification recovered 聚焦 ${normalizeNumber(verificationOutcomeSummary?.recoveredFocusCount)} 类 outcome,共 ${normalizeNumber(verificationOutcomeSummary?.recoveredCaseCount)} 个 case。` : "当前没有额外的 verification recovered case。", ]; } export function buildBlockingVerificationRecommendationRationale({ topCurrentVerificationFailureOutcomes, currentVerificationSummary, degradedVerificationSummary, }) { const currentFailureLabels = formatVerificationOutcomeCompactLabels( topCurrentVerificationFailureOutcomes, 3, ); return [ currentFailureLabels.length > 0 ? `当前 current verification failure outcome 焦点:${currentFailureLabels.join("、")}。` : "当前没有额外的 verification failure outcome 焦点。", normalizeNumber(currentVerificationSummary?.blockingFailureCaseCount) > 0 ? `其中 current blocking verification failure 共 ${normalizeNumber(currentVerificationSummary?.blockingFailureCaseCount)} 个 case:${(Array.isArray(currentVerificationSummary?.topBlockingFailureOutcomes) ? currentVerificationSummary.topBlockingFailureOutcomes : []).join("、") || "暂无"}。` : "当前没有额外的 blocking verification failure。", normalizeNumber(degradedVerificationSummary?.blockingFailureCaseCount) > 0 ? `另有 ${normalizeNumber(degradedVerificationSummary?.blockingFailureCaseCount)} 个 degraded blocking verification failure 样本作为诊断基线,不直接抬高主线优先级。` : "当前没有额外的 degraded blocking verification baseline。", ]; } export function buildAdvisoryVerificationRecommendationRationale({ topCurrentVerificationFailureOutcomes, topDegradedVerificationFailureOutcomes, currentVerificationSummary, }) { const currentFailureLabels = formatVerificationOutcomeCompactLabels( topCurrentVerificationFailureOutcomes, 3, ); const degradedFailureLabels = formatVerificationOutcomeCompactLabels( topDegradedVerificationFailureOutcomes, 3, ); return [ currentFailureLabels.length > 0 ? `当前 current verification failure outcome 焦点:${currentFailureLabels.join("、")}。可用它们直接定位先补 artifact/browser/gui 哪一层。` : "当前没有额外的 verification failure outcome 焦点。", normalizeNumber(currentVerificationSummary?.advisoryFailureCaseCount) > 0 ? `当前 current advisory verification failure 共 ${normalizeNumber(currentVerificationSummary?.advisoryFailureCaseCount)} 个 case:${(Array.isArray(currentVerificationSummary?.topAdvisoryFailureOutcomes) ? currentVerificationSummary.topAdvisoryFailureOutcomes : []).join("、") || "暂无"}。` : "当前没有额外的 advisory verification failure。", degradedFailureLabels.length > 0 ? `当前保留的 degraded verification baseline:${degradedFailureLabels.join("、")}。` : "当前没有额外的 degraded verification baseline。", ]; } export function buildRecoveredVerificationRecommendationRationale({ topCurrentRecoveredVerificationOutcomes, currentVerificationSummary, }) { const recoveredLabels = formatVerificationOutcomeCompactLabels( topCurrentRecoveredVerificationOutcomes, 3, ); return [ recoveredLabels.length > 0 ? `当前 current recovered outcome 焦点:${recoveredLabels.join("、")}。` : `当前 current recovered outcome 共 ${normalizeNumber(currentVerificationSummary?.recoveredCaseCount)} 个 case。`, ]; } export function buildObservabilityRecommendationRationale({ trendSummary, topObservabilitySignals, topCurrentVerificationFailureOutcomes, topDegradedVerificationFailureOutcomes, currentVerificationSummary, }) { const observabilitySignalLabels = Array.isArray(topObservabilitySignals) ? topObservabilitySignals.map((entry) => normalizeString(entry)).filter(Boolean) : []; return [ normalizeNumber(trendSummary?.latestCurrentObservabilityGapCaseCount) > 0 ? `当前仍有 ${normalizeNumber(trendSummary?.latestCurrentObservabilityGapCaseCount)} 个 current case 带着 observability 证据缺口进入 replay/eval。` : "当前 trend 已检测到 observability coverage 漂移,需先修证据而不是空谈根因分析。", normalizeNumber(trendSummary?.latestDegradedObservabilityGapCaseCount) > 0 ? `另有 ${normalizeNumber(trendSummary?.latestDegradedObservabilityGapCaseCount)} 个 degraded gap 样本作为诊断基线保留,它们不应直接被当成主线回归。` : "当前没有额外保留的 degraded observability gap 样本。", `当前缺口焦点:${observabilitySignalLabels.join("、") || "暂无"}。这些缺口会直接降低 analysis handoff、人工审核和 cleanup report 的判断质量。`, ...buildAdvisoryVerificationRecommendationRationale({ topCurrentVerificationFailureOutcomes, topDegradedVerificationFailureOutcomes, currentVerificationSummary, }), ]; } export function buildObservabilityRecommendationBacklog({ topCurrentVerificationFailureOutcomes, advisoryFollowUpBacklogTools, }) { const currentFailureLabels = formatVerificationOutcomeCompactLabels( topCurrentVerificationFailureOutcomes, 3, ); const followUpBacklogTools = Array.isArray(advisoryFollowUpBacklogTools) ? advisoryFollowUpBacklogTools.map((entry) => normalizeString(entry)).filter(Boolean) : []; return dedupeNonEmptyStrings([ "优先补 request telemetry 关联键、artifact validator outcome、browser/gui smoke 结果到 evidence pack / analysis handoff / replay。", currentFailureLabels.length > 0 ? `先对齐 current verification failure outcome:${currentFailureLabels.join("、")}。` : "", ...followUpBacklogTools, ]); } export function buildVerificationFocusEntriesFromDeltas(entries, sampleCount) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries .map((entry) => { const latest = entry != null && typeof entry === "object" ? entry.latest ?? {} : {}; const delta = entry != null && typeof entry === "object" ? entry.delta ?? {} : {}; const baseline = entry != null && typeof entry === "object" ? entry.baseline ?? {} : {}; const parsed = splitVerificationOutcomeName(entry?.name); const positiveDeltaCase = Math.max(0, normalizeNumber(delta.caseCount)); const latestCase = normalizeNumber(latest.caseCount); const weight = getVerificationOutcomeWeight(parsed.outcome); const score = positiveDeltaCase * 140 + latestCase * weight; let state = "stable"; if (sampleCount < 2 && latestCase > 0 && weight > 0) { state = "seed-risk"; } else if (positiveDeltaCase > 0 && weight > 0) { state = "regressing"; } else if (latestCase > 0 && weight > 0) { state = "present"; } return { name: normalizeString(entry?.name) || "(unknown)", signal: parsed.signal || "(unknown)", outcome: parsed.outcome || "unknown", baseline: { caseCount: normalizeNumber(baseline.caseCount), readyCount: normalizeNumber(baseline.readyCount), invalidCount: normalizeNumber(baseline.invalidCount), pendingRequestCaseCount: normalizeNumber( baseline.pendingRequestCaseCount, ), needsHumanReviewCount: normalizeNumber( baseline.needsHumanReviewCount, ), }, latest: { caseCount: latestCase, readyCount: normalizeNumber(latest.readyCount), invalidCount: normalizeNumber(latest.invalidCount), pendingRequestCaseCount: normalizeNumber( latest.pendingRequestCaseCount, ), needsHumanReviewCount: normalizeNumber(latest.needsHumanReviewCount), }, delta: { caseCount: normalizeNumber(delta.caseCount), readyCount: normalizeNumber(delta.readyCount), invalidCount: normalizeNumber(delta.invalidCount), pendingRequestCaseCount: normalizeNumber(delta.pendingRequestCaseCount), needsHumanReviewCount: normalizeNumber(delta.needsHumanReviewCount), }, state, score, }; }) .filter( (entry) => entry.score > 0 || (entry.latest.caseCount > 0 && isVerificationFailureOutcome(entry.outcome)), ) .sort((left, right) => { if (right.score !== left.score) { return right.score - left.score; } return left.name.localeCompare(right.name); }); } export function buildVerificationOutcomeSummary(entries) { const normalizedEntries = Array.isArray(entries) ? entries : []; const blockingFailureEntries = normalizedEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "blocking_failure", ); const advisoryFailureEntries = normalizedEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "advisory_failure", ); const failureEntries = [...blockingFailureEntries, ...advisoryFailureEntries]; const recoveredEntries = normalizedEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "recovered", ); return { focusCount: normalizedEntries.length, failureFocusCount: failureEntries.length, recoveredFocusCount: recoveredEntries.length, blockingFailureFocusCount: blockingFailureEntries.length, advisoryFailureFocusCount: advisoryFailureEntries.length, failureCaseCount: failureEntries.reduce( (total, entry) => total + normalizeNumber(entry?.latest?.caseCount), 0, ), blockingFailureCaseCount: blockingFailureEntries.reduce( (total, entry) => total + normalizeNumber(entry?.latest?.caseCount), 0, ), advisoryFailureCaseCount: advisoryFailureEntries.reduce( (total, entry) => total + normalizeNumber(entry?.latest?.caseCount), 0, ), recoveredCaseCount: recoveredEntries.reduce( (total, entry) => total + normalizeNumber(entry?.latest?.caseCount), 0, ), topFailureOutcomes: failureEntries .slice(0, 3) .map((entry) => `${entry.signal}:${entry.outcome}`), topBlockingFailureOutcomes: blockingFailureEntries .slice(0, 3) .map((entry) => `${entry.signal}:${entry.outcome}`), topAdvisoryFailureOutcomes: advisoryFailureEntries .slice(0, 3) .map((entry) => `${entry.signal}:${entry.outcome}`), topRecoveredOutcomes: recoveredEntries .slice(0, 3) .map((entry) => `${entry.signal}:${entry.outcome}`), }; } export function deriveVerificationOutcomePresentationFromTrend({ trendReport, sampleCount = 0, }) { const rawVerificationFocusEntries = buildVerificationFocusEntriesFromDeltas( trendReport?.classificationDeltas?.observabilityVerificationOutcomes, sampleCount, ); const explicitRecoveredVerificationEntries = buildVerificationOutcomeEntriesFromDeltas( trendReport?.classificationDeltas?.observabilityVerificationOutcomes, ).filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "recovered", ); const focusVerificationFailureOutcomes = rawVerificationFocusEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) !== "recovered", ); const rawCurrentVerificationFocusEntries = buildVerificationFocusEntriesFromDeltas( trendReport?.classificationDeltas?.currentObservabilityVerificationOutcomes, sampleCount, ); const explicitCurrentRecoveredVerificationEntries = buildVerificationOutcomeEntriesFromDeltas( trendReport?.classificationDeltas ?.currentRecoveredObservabilityVerificationOutcomes, ); const focusCurrentVerificationFailureOutcomes = rawCurrentVerificationFocusEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) !== "recovered", ); const focusCurrentRecoveredVerificationOutcomes = explicitCurrentRecoveredVerificationEntries.length > 0 ? explicitCurrentRecoveredVerificationEntries : rawCurrentVerificationFocusEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "recovered", ); const rawDegradedVerificationFocusEntries = buildVerificationFocusEntriesFromDeltas( trendReport?.classificationDeltas?.degradedObservabilityVerificationOutcomes, sampleCount, ); const focusDegradedVerificationFailureOutcomes = rawDegradedVerificationFocusEntries.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) !== "recovered", ); const mergedVerificationFailureOutcomes = focusVerificationFailureOutcomes.length > 0 ? focusVerificationFailureOutcomes : [ ...focusCurrentVerificationFailureOutcomes, ...focusDegradedVerificationFailureOutcomes, ].sort((left, right) => { if (right.score !== left.score) { return right.score - left.score; } return left.name.localeCompare(right.name); }); const verificationFailureSummary = buildVerificationOutcomeSummary( mergedVerificationFailureOutcomes, ); const recoveredVerificationSummary = buildVerificationOutcomeSummary( explicitRecoveredVerificationEntries.length > 0 ? explicitRecoveredVerificationEntries : mergedVerificationFailureOutcomes.filter( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "recovered", ), ); const verificationOutcomeSummary = { ...verificationFailureSummary, recoveredFocusCount: recoveredVerificationSummary.recoveredFocusCount, recoveredCaseCount: recoveredVerificationSummary.recoveredCaseCount, topRecoveredOutcomes: recoveredVerificationSummary.topRecoveredOutcomes, }; const currentVerificationFailureSummary = buildVerificationOutcomeSummary( focusCurrentVerificationFailureOutcomes, ); const currentRecoveredVerificationSummary = buildVerificationOutcomeSummary( focusCurrentRecoveredVerificationOutcomes, ); const currentVerificationOutcomeSummary = { ...currentVerificationFailureSummary, recoveredFocusCount: currentRecoveredVerificationSummary.recoveredFocusCount, recoveredCaseCount: currentRecoveredVerificationSummary.recoveredCaseCount, topRecoveredOutcomes: currentRecoveredVerificationSummary.topRecoveredOutcomes, }; const degradedVerificationOutcomeSummary = buildVerificationOutcomeSummary( focusDegradedVerificationFailureOutcomes, ); return { rawVerificationFocusEntries, explicitRecoveredVerificationEntries, focusVerificationFailureOutcomes, rawCurrentVerificationFocusEntries, explicitCurrentRecoveredVerificationEntries, focusCurrentVerificationFailureOutcomes, focusCurrentRecoveredVerificationOutcomes, rawDegradedVerificationFocusEntries, focusDegradedVerificationFailureOutcomes, mergedVerificationFailureOutcomes, verificationOutcomeSummary: { ...verificationOutcomeSummary, current: currentVerificationOutcomeSummary, degraded: degradedVerificationOutcomeSummary, }, }; }