import { getCommandStatus, getImportStatus, getTextCountStatus, getTextStatus, } from "./legacy-surface-report-summary.mjs"; import { buildAdvisoryVerificationRecommendationRationale, buildBlockingVerificationRecommendationRationale, buildObservabilityRecommendationBacklog, buildObservabilityRecommendationRationale, buildVerificationOutcomeSignalMessages, buildRecoveredVerificationRecommendationRationale, buildAdvisoryVerificationFollowUp, buildBlockingVerificationFollowUp, buildRecoveredVerificationFollowUp, buildVerificationOutcomeSummary, deriveVerificationOutcomePresentationFromTrend, formatVerificationOutcomeCompactLabel, formatVerificationOutcomeCompactLabels, getVerificationOutcomeRole, } from "./harness-verification-facts.mjs"; const PRIORITY_RANK = { P0: 0, P1: 1, P2: 2, P3: 3, }; const CLASSIFICATION_WEIGHT = { current: 0, compat: 25, deprecated: 35, "dead-candidate": 45, }; const STATUS_WEIGHT = { "违规": 200, "受控": 40, "零引用": 0, "已删除": 0, }; function normalizeNumber(value) { return typeof value === "number" && Number.isFinite(value) ? value : 0; } function normalizeString(value, fallback = "") { return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback; } function isObject(value) { return value != null && typeof value === "object"; } function flattenCommandReferenceGroups(referenceGroups) { if (referenceGroups instanceof Map) { return [...referenceGroups.values()].flat(); } if (isObject(referenceGroups)) { return Object.values(referenceGroups).flatMap((entry) => Array.isArray(entry) ? entry : [], ); } return []; } function toReferenceGroupMap(referenceGroups) { if (referenceGroups instanceof Map) { return referenceGroups; } if (isObject(referenceGroups)) { return new Map( Object.entries(referenceGroups).map(([key, value]) => [ key, Array.isArray(value) ? value : [], ]), ); } return new Map(); } function getTextCountOccurrenceCount(result) { const runtimeMatches = Array.isArray(result?.runtimeMatches) ? result.runtimeMatches : []; return runtimeMatches.reduce( (total, entry) => total + (Array.isArray(entry?.counts) ? entry.counts.reduce( (innerTotal, item) => innerTotal + normalizeNumber(item?.count), 0, ) : 0), 0, ); } function getClassificationWeight(classification) { return CLASSIFICATION_WEIGHT[classification] ?? 10; } function getStatusWeight(status) { return STATUS_WEIGHT[status] ?? 0; } function buildGovernanceSurfaceEntry({ sourceType, result, status, referenceCount, testReferenceCount, occurrenceCount, }) { const classification = normalizeString(result?.classification, "unknown"); const violationCount = Array.isArray(result?.violations) ? result.violations.length : 0; const active = status !== "零引用" && status !== "已删除"; const score = active ? getStatusWeight(status) + getClassificationWeight(classification) + violationCount * 200 + referenceCount * 5 + occurrenceCount : 0; return { id: normalizeString(result?.id, `${sourceType}-surface`), sourceType, classification, description: normalizeString(result?.description, "(无描述)"), status, active, referenceCount, testReferenceCount, occurrenceCount, violationCount, score, }; } function buildGovernanceSurfaceEntries(governanceReport) { const importResults = Array.isArray(governanceReport?.importResults) ? governanceReport.importResults : []; const commandResults = Array.isArray(governanceReport?.commandResults) ? governanceReport.commandResults : []; const frontendTextResults = Array.isArray(governanceReport?.frontendTextResults) ? governanceReport.frontendTextResults : []; const rustTextResults = Array.isArray(governanceReport?.rustTextResults) ? governanceReport.rustTextResults : []; const rustTextCountResults = Array.isArray( governanceReport?.rustTextCountResults, ) ? governanceReport.rustTextCountResults : []; const importEntries = importResults.map((result) => buildGovernanceSurfaceEntry({ sourceType: "import", result, status: getImportStatus(result), referenceCount: Array.isArray(result?.references) ? result.references.length : 0, testReferenceCount: Array.isArray(result?.testReferences) ? result.testReferences.length : 0, occurrenceCount: 0, }), ); const commandEntries = commandResults.map((result) => buildGovernanceSurfaceEntry({ sourceType: "command", result, status: getCommandStatus({ ...result, referencesByCommand: toReferenceGroupMap(result?.referencesByCommand), }), referenceCount: [ ...new Set(flattenCommandReferenceGroups(result?.referencesByCommand)), ].length, testReferenceCount: [ ...new Set(flattenCommandReferenceGroups(result?.testReferencesByCommand)), ].length, occurrenceCount: 0, }), ); const frontendTextEntries = frontendTextResults.map((result) => buildGovernanceSurfaceEntry({ sourceType: "frontend-text", result, status: getTextStatus(result), referenceCount: Array.isArray(result?.references) ? result.references.length : 0, testReferenceCount: Array.isArray(result?.testReferences) ? result.testReferences.length : 0, occurrenceCount: 0, }), ); const rustTextEntries = rustTextResults.map((result) => buildGovernanceSurfaceEntry({ sourceType: "rust-text", result, status: getTextStatus(result), referenceCount: Array.isArray(result?.references) ? result.references.length : 0, testReferenceCount: Array.isArray(result?.testReferences) ? result.testReferences.length : 0, occurrenceCount: 0, }), ); const rustTextCountEntries = rustTextCountResults.map((result) => buildGovernanceSurfaceEntry({ sourceType: "rust-text-count", result, status: getTextCountStatus(result), referenceCount: Array.isArray(result?.runtimeMatches) ? result.runtimeMatches.length : 0, testReferenceCount: Array.isArray(result?.testMatches) ? result.testMatches.length : 0, occurrenceCount: getTextCountOccurrenceCount(result), }), ); return [ ...importEntries, ...commandEntries, ...frontendTextEntries, ...rustTextEntries, ...rustTextCountEntries, ].sort((left, right) => { if (right.score !== left.score) { return right.score - left.score; } if (right.referenceCount !== left.referenceCount) { return right.referenceCount - left.referenceCount; } return left.id.localeCompare(right.id); }); } function buildTrendFocusEntries(entries, sampleCount) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries .map((entry) => { const latest = isObject(entry?.latest) ? entry.latest : {}; const delta = isObject(entry?.delta) ? entry.delta : {}; const baseline = isObject(entry?.baseline) ? entry.baseline : {}; const positiveDeltaInvalid = Math.max(0, normalizeNumber(delta.invalidCount)); const positiveDeltaPending = Math.max( 0, normalizeNumber(delta.pendingRequestCaseCount), ); const positiveDeltaReview = Math.max( 0, normalizeNumber(delta.needsHumanReviewCount), ); const latestInvalid = normalizeNumber(latest.invalidCount); const latestPending = normalizeNumber(latest.pendingRequestCaseCount); const latestReview = normalizeNumber(latest.needsHumanReviewCount); const latestCase = normalizeNumber(latest.caseCount); const latestReady = normalizeNumber(latest.readyCount); const score = positiveDeltaInvalid * 120 + positiveDeltaPending * 80 + positiveDeltaReview * 50 + latestInvalid * 40 + latestPending * 25 + latestReview * 15 + latestCase; let state = "stable"; if (sampleCount < 2 && score > 0) { state = "seed-risk"; } else if ( positiveDeltaInvalid > 0 || positiveDeltaPending > 0 || positiveDeltaReview > 0 ) { state = "regressing"; } else if (latestInvalid > 0 || latestPending > 0 || latestReview > 0) { state = "present"; } return { name: normalizeString(entry?.name, "(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: latestReady, invalidCount: latestInvalid, pendingRequestCaseCount: latestPending, needsHumanReviewCount: latestReview, }, 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) .sort((left, right) => { if (right.score !== left.score) { return right.score - left.score; } return left.name.localeCompare(right.name); }); } function buildGovernanceSummary(governanceReport, surfaces) { const summary = isObject(governanceReport?.summary) ? governanceReport.summary : {}; const activeByClassification = { current: 0, compat: 0, deprecated: 0, "dead-candidate": 0, other: 0, }; for (const surface of surfaces) { if (!surface.active) { continue; } if (surface.classification in activeByClassification) { activeByClassification[surface.classification] += 1; } else { activeByClassification.other += 1; } } return { monitorCount: surfaces.length, activeSurfaceCount: surfaces.filter((surface) => surface.active).length, activeByClassification, violationCount: Array.isArray(summary.violations) ? summary.violations.length : 0, classificationDriftCount: Array.isArray(summary.classificationDriftCandidates) ? summary.classificationDriftCandidates.length : 0, zeroReferenceCandidateCount: Array.isArray(summary.zeroReferenceCandidates) ? summary.zeroReferenceCandidates.length : 0, }; } function buildTrendSummary(trendReport) { const delta = isObject(trendReport?.delta) ? trendReport.delta : {}; const latestTotals = isObject(trendReport?.latest?.totals) ? trendReport.latest.totals : {}; const baselineTotals = isObject(trendReport?.baseline?.totals) ? trendReport.baseline.totals : {}; const latestObservabilityGapCaseCount = normalizeNumber( latestTotals.observabilityGapCaseCount, ); const baselineObservabilityGapCaseCount = normalizeNumber( baselineTotals.observabilityGapCaseCount, ); const latestDegradedObservabilityGapCaseCount = normalizeNumber( latestTotals.degradedObservabilityGapCaseCount, ); const baselineDegradedObservabilityGapCaseCount = normalizeNumber( baselineTotals.degradedObservabilityGapCaseCount, ); const latestCurrentObservabilityGapCaseCount = latestTotals.currentObservabilityGapCaseCount != null ? normalizeNumber(latestTotals.currentObservabilityGapCaseCount) : Math.max( 0, latestObservabilityGapCaseCount - latestDegradedObservabilityGapCaseCount, ); const baselineCurrentObservabilityGapCaseCount = baselineTotals.currentObservabilityGapCaseCount != null ? normalizeNumber(baselineTotals.currentObservabilityGapCaseCount) : Math.max( 0, baselineObservabilityGapCaseCount - baselineDegradedObservabilityGapCaseCount, ); const latestNeedsReviewCount = normalizeNumber( latestTotals.needsHumanReviewCount, ); const latestReviewDecisionRecordedCount = normalizeNumber( latestTotals.reviewDecisionRecordedCount, ); return { sampleCount: normalizeNumber(trendReport?.sampleCount), isSeed: normalizeNumber(trendReport?.sampleCount) < 2, invalidDelta: normalizeNumber(delta.invalidCount), pendingDelta: normalizeNumber(delta.pendingRequestCaseCount), needsReviewDelta: normalizeNumber(delta.needsHumanReviewCount), reviewDecisionRecordedDelta: delta.reviewDecisionRecordedCount != null ? normalizeNumber(delta.reviewDecisionRecordedCount) : latestReviewDecisionRecordedCount - normalizeNumber(baselineTotals.reviewDecisionRecordedCount), latestNeedsReviewCount, latestReviewDecisionRecordedCount, reviewDecisionBacklogCount: Math.max( 0, latestNeedsReviewCount - latestReviewDecisionRecordedCount, ), observabilityGapCaseDelta: normalizeNumber(delta.observabilityGapCaseCount), latestObservabilityGapCaseCount, currentObservabilityGapCaseDelta: delta.currentObservabilityGapCaseCount != null ? normalizeNumber(delta.currentObservabilityGapCaseCount) : latestCurrentObservabilityGapCaseCount - baselineCurrentObservabilityGapCaseCount, latestCurrentObservabilityGapCaseCount, degradedObservabilityGapCaseDelta: delta.degradedObservabilityGapCaseCount != null ? normalizeNumber(delta.degradedObservabilityGapCaseCount) : latestDegradedObservabilityGapCaseCount - baselineDegradedObservabilityGapCaseCount, latestDegradedObservabilityGapCaseCount, readyRateDelta: normalizeNumber(delta.readyRate), signals: Array.isArray(trendReport?.signals) ? trendReport.signals : [], }; } function splitObservabilitySignalName(name) { const normalized = normalizeString(name); if (!normalized.includes(":")) { return { signal: normalized, status: "", }; } const separatorIndex = normalized.indexOf(":"); return { signal: normalized.slice(0, separatorIndex), status: normalizeObservabilityStatus(normalized.slice(separatorIndex + 1)), }; } function normalizeObservabilityStatus(status) { const normalized = normalizeString(status); switch (normalized) { case "unlinked": return "known_gap"; default: return normalized; } } function getObservabilityStatusWeight(status) { switch (status) { case "missing": return 120; case "missing_signal_coverage": return 110; case "known_gap": return 85; case "partial": return 70; default: return 50; } } function buildObservabilityFocusEntries(entries, sampleCount) { const normalizedEntries = Array.isArray(entries) ? entries : []; return normalizedEntries .map((entry) => { const latest = isObject(entry?.latest) ? entry.latest : {}; const delta = isObject(entry?.delta) ? entry.delta : {}; const baseline = isObject(entry?.baseline) ? entry.baseline : {}; const parsed = splitObservabilitySignalName(entry?.name); const signal = parsed.signal || normalizeString(entry?.name, "(unknown)"); const status = parsed.status || "unknown"; const canonicalName = parsed.status ? `${signal}:${parsed.status}` : signal; const positiveDeltaCase = Math.max(0, normalizeNumber(delta.caseCount)); const latestCase = normalizeNumber(latest.caseCount); const score = positiveDeltaCase * 120 + latestCase * getObservabilityStatusWeight(parsed.status); let state = "stable"; if (sampleCount < 2 && latestCase > 0) { state = "seed-risk"; } else if (positiveDeltaCase > 0) { state = "regressing"; } else if (latestCase > 0) { state = "present"; } return { name: canonicalName, signal, status, 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.status && entry.status !== "exported") .filter((entry) => entry.score > 0 || entry.latest.caseCount > 0) .sort((left, right) => { if (right.score !== left.score) { return right.score - left.score; } return left.name.localeCompare(right.name); }); } function buildDocFreshnessSummary(docFreshnessReport) { const summary = isObject(docFreshnessReport?.summary) ? docFreshnessReport.summary : {}; return { monitoredDocumentCount: normalizeNumber(summary.monitoredDocumentCount), existingDocumentCount: normalizeNumber(summary.existingDocumentCount), issueCount: normalizeNumber(summary.issueCount), missingDocumentCount: normalizeNumber(summary.missingDocumentCount), missingRequiredReferenceCount: normalizeNumber( summary.missingRequiredReferenceCount, ), brokenMarkdownLinkCount: normalizeNumber(summary.brokenMarkdownLinkCount), brokenCodePathReferenceCount: normalizeNumber( summary.brokenCodePathReferenceCount, ), deletedSurfaceReferenceCount: normalizeNumber( summary.deletedSurfaceReferenceCount, ), }; } function buildDocFreshnessFocus(docFreshnessReport) { const issues = Array.isArray(docFreshnessReport?.issues) ? docFreshnessReport.issues : []; const issueCounts = new Map(); const documentCounts = new Map(); for (const issue of issues) { const kind = normalizeString(issue?.kind, "unknown"); const documentPath = normalizeString(issue?.documentPath, "(unknown)"); issueCounts.set(kind, normalizeNumber(issueCounts.get(kind)) + 1); documentCounts.set( documentPath, normalizeNumber(documentCounts.get(documentPath)) + 1, ); } return { issueKinds: [...issueCounts.entries()] .map(([kind, count]) => ({ kind, count })) .sort((left, right) => right.count - left.count || left.kind.localeCompare(right.kind)) .slice(0, 5), documents: [...documentCounts.entries()] .map(([documentPath, issueCount]) => ({ documentPath, issueCount })) .sort( (left, right) => right.issueCount - left.issueCount || left.documentPath.localeCompare(right.documentPath), ) .slice(0, 5), }; } function maybePushRecommendation(recommendations, action) { if (recommendations.some((entry) => entry.id === action.id)) { return; } const normalizedAction = { ...action, focusVerificationFailureOutcomes: dedupeNonEmptyStrings( Array.isArray(action?.focusVerificationFailureOutcomes) ? action.focusVerificationFailureOutcomes : [], ), focusVerificationRecoveredOutcomes: dedupeNonEmptyStrings( Array.isArray(action?.focusVerificationRecoveredOutcomes) ? action.focusVerificationRecoveredOutcomes : [], ), }; delete normalizedAction.focusObservabilityVerificationOutcomes; recommendations.push(normalizedAction); } function dedupeNonEmptyStrings(values) { const normalizedValues = Array.isArray(values) ? values : []; return [...new Set(normalizedValues.map((value) => normalizeString(value)).filter(Boolean))]; } function assertStringArrayField(value, label, recommendationId) { if (!Array.isArray(value)) { throw new Error( `cleanup recommendation ${recommendationId} 的 ${label} 必须是字符串数组。`, ); } if ( value.some( (entry) => typeof entry !== "string" || normalizeString(entry).length === 0, ) ) { throw new Error( `cleanup recommendation ${recommendationId} 的 ${label} 只能包含非空字符串。`, ); } } export function assertGeneratedSlopReportContract(report) { const recommendations = Array.isArray(report?.recommendations) ? report.recommendations : []; recommendations.forEach((action, index) => { if (!isObject(action)) { throw new Error(`cleanup recommendation #${index + 1} 必须是对象。`); } const recommendationId = normalizeString(action?.id, `#${index + 1}`); if ( Object.prototype.hasOwnProperty.call( action, "focusObservabilityVerificationOutcomes", ) ) { throw new Error( `cleanup recommendation ${recommendationId} 不允许继续使用 focusObservabilityVerificationOutcomes;请改用 focusVerificationFailureOutcomes / focusVerificationRecoveredOutcomes。`, ); } assertStringArrayField( action?.focusFailureModes, "focusFailureModes", recommendationId, ); assertStringArrayField( action?.focusSuiteTags, "focusSuiteTags", recommendationId, ); assertStringArrayField( action?.focusReviewDecisionStatuses, "focusReviewDecisionStatuses", recommendationId, ); assertStringArrayField( action?.focusReviewRiskLevels, "focusReviewRiskLevels", recommendationId, ); assertStringArrayField( action?.focusVerificationFailureOutcomes, "focusVerificationFailureOutcomes", recommendationId, ); assertStringArrayField( action?.focusVerificationRecoveredOutcomes, "focusVerificationRecoveredOutcomes", recommendationId, ); assertStringArrayField( action?.focusSurfaceIds, "focusSurfaceIds", recommendationId, ); assertStringArrayField(action?.commands, "commands", recommendationId); assertStringArrayField( action?.backlogTools, "backlogTools", recommendationId, ); assertStringArrayField(action?.rationale, "rationale", recommendationId); }); const verificationFailureFocus = Array.isArray( report?.focus?.observabilityVerificationOutcomes, ) ? report.focus.observabilityVerificationOutcomes : []; if ( verificationFailureFocus.some( (entry) => getVerificationOutcomeRole(entry?.signal, entry?.outcome) === "recovered", ) ) { throw new Error( "cleanup report 的 focus.observabilityVerificationOutcomes 只允许 failure outcome,不允许 recovered outcome 混入。", ); } return report; } function buildRecommendations({ trendSummary, verificationOutcomeSummary, focusFailureModes, focusSuiteTags, focusReviewDecisionStatuses, focusReviewRiskLevels, focusObservabilitySignals, focusVerificationFailureOutcomes, focusCurrentObservabilityVerificationOutcomes, focusCurrentRecoveredObservabilityVerificationOutcomes, focusDegradedObservabilityVerificationOutcomes, docFreshnessSummary, docFreshnessFocus, governanceSummary, governanceSurfaces, }) { const recommendations = []; const topFailureModes = focusFailureModes .slice(0, 3) .map((entry) => entry.name); const topSuiteTags = focusSuiteTags.slice(0, 3).map((entry) => entry.name); const topReviewDecisionStatuses = focusReviewDecisionStatuses .slice(0, 3) .map((entry) => entry.name); const topReviewRiskLevels = focusReviewRiskLevels .slice(0, 3) .map((entry) => entry.name); const topObservabilitySignals = focusObservabilitySignals .slice(0, 3) .map((entry) => `${entry.signal} (${entry.status})`); const topVerificationFailureOutcomes = formatVerificationOutcomeCompactLabels( focusVerificationFailureOutcomes, 3, ); const topCurrentVerificationFailureOutcomes = formatVerificationOutcomeCompactLabels( focusCurrentObservabilityVerificationOutcomes, 3, ); const topCurrentRecoveredVerificationOutcomes = formatVerificationOutcomeCompactLabels( focusCurrentRecoveredObservabilityVerificationOutcomes, 3, ); const topDegradedVerificationFailureOutcomes = formatVerificationOutcomeCompactLabels( focusDegradedObservabilityVerificationOutcomes, 3, ); const topRecommendedVerificationFailureOutcomes = topCurrentVerificationFailureOutcomes.length > 0 ? topCurrentVerificationFailureOutcomes : topVerificationFailureOutcomes; const topGovernanceSurfaceIds = governanceSurfaces .filter((entry) => entry.active && entry.classification !== "current") .slice(0, 3) .map((entry) => entry.id); const currentVerificationSummary = verificationOutcomeSummary?.current ?? buildVerificationOutcomeSummary([]); const degradedVerificationSummary = verificationOutcomeSummary?.degraded ?? buildVerificationOutcomeSummary([]); const currentBlockingVerificationFollowUp = buildBlockingVerificationFollowUp( focusCurrentObservabilityVerificationOutcomes, ); const currentAdvisoryVerificationFollowUp = buildAdvisoryVerificationFollowUp( focusCurrentObservabilityVerificationOutcomes, ); const currentRecoveredVerificationFollowUp = buildRecoveredVerificationFollowUp( focusCurrentRecoveredObservabilityVerificationOutcomes, ); if (governanceSummary.violationCount > 0) { maybePushRecommendation(recommendations, { id: "contracts-and-boundary-guards", priority: "P0", title: "先修命令/治理边界违规,再继续扩主线", rationale: [ `当前 governance report 发现 ${governanceSummary.violationCount} 条边界违规。`, "这类问题会让 current / compat / deprecated 边界重新漂移,必须先封老路。", ], commands: ["npm run governance:legacy-report", "npm run test:contracts"], backlogTools: [], focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: topGovernanceSurfaceIds, }); } if (trendSummary.isSeed) { maybePushRecommendation(recommendations, { id: "promote-high-value-replay", priority: "P1", title: "提升高价值 Replay 样本,结束 trend seed 状态", rationale: [ `当前 trend 样本数只有 ${trendSummary.sampleCount},还不能判断长期退化。`, "先把最近一次高价值失败提升为 repo current 样本,再谈趋势治理。", ], commands: [ "npm run harness:eval:promote -- --session-id \"\" --slug \"\"", "npm run harness:eval:trend", ], backlogTools: [], focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: [], }); } const hasTrendPressure = trendSummary.invalidDelta > 0 || trendSummary.pendingDelta > 0 || trendSummary.needsReviewDelta > 0 || currentVerificationSummary.blockingFailureCaseCount > 0 || focusFailureModes.some((entry) => entry.state !== "stable"); if (hasTrendPressure) { maybePushRecommendation(recommendations, { id: "replay-and-smoke-follow-up", priority: currentVerificationSummary.blockingFailureCaseCount > 0 ? "P0" : "P1", title: "把高风险 failure mode 回挂到 replay / smoke 验证", rationale: [ `当前 failure mode 焦点:${topFailureModes.join("、") || "暂无"}。`, "先用 replay / eval 固化失败,再按受影响主路径补最小 smoke,而不是直接凭印象清理。", ...buildBlockingVerificationRecommendationRationale({ topCurrentVerificationFailureOutcomes: focusCurrentObservabilityVerificationOutcomes, currentVerificationSummary, degradedVerificationSummary, }), ...currentBlockingVerificationFollowUp.rationale, ], commands: currentBlockingVerificationFollowUp.commands, backlogTools: currentBlockingVerificationFollowUp.backlogTools, focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: [], }); } const hasReviewDecisionPressure = trendSummary.reviewDecisionBacklogCount > 0 || focusReviewDecisionStatuses.some( (entry) => entry.latest.caseCount > 0 && (entry.name === "pending_review" || entry.name === "needs_more_evidence" || entry.state !== "stable"), ) || focusReviewRiskLevels.some( (entry) => entry.latest.caseCount > 0 && (entry.name === "high" || entry.name === "medium"), ); if (hasReviewDecisionPressure) { maybePushRecommendation(recommendations, { id: "review-decision-follow-up", priority: trendSummary.reviewDecisionBacklogCount > 0 || topReviewRiskLevels.includes("high") ? "P1" : "P2", title: "把人工审核状态与风险等级回挂到回归动作", rationale: [ trendSummary.reviewDecisionBacklogCount > 0 ? `当前仍有 ${trendSummary.reviewDecisionBacklogCount} 个需要人工审核的 case 尚未留下最终 decision。` : `当前人工审核状态焦点:${topReviewDecisionStatuses.join("、") || "暂无"}。`, `当前风险等级焦点:${topReviewRiskLevels.join("、") || "暂无"}。高风险或补证据状态应优先回挂到 replay / contracts / smoke 主链。`, ], commands: [ "npm run harness:eval", "npm run harness:eval:trend", "npm run harness:cleanup-report", ], backlogTools: topReviewDecisionStatuses.includes("needs_more_evidence") || trendSummary.reviewDecisionBacklogCount > 0 ? [ "补 evidence pack / analysis handoff / replay 证据字段,缩短 review-decision 从 pending_review 或 needs_more_evidence 回到可执行回归的路径", ] : [], focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: [], }); } const hasObservabilityPressure = trendSummary.latestCurrentObservabilityGapCaseCount > 0 || trendSummary.currentObservabilityGapCaseDelta > 0 || currentVerificationSummary.advisoryFailureCaseCount > 0; if (hasObservabilityPressure) { maybePushRecommendation(recommendations, { id: "observability-evidence-follow-up", priority: topObservabilitySignals.some( (entry) => entry.includes("observabilitySummary (missing)") || entry.includes("requestTelemetry (known_gap)"), ) || trendSummary.currentObservabilityGapCaseDelta > 0 || currentVerificationSummary.advisoryFailureCaseCount > 0 ? "P1" : "P2", title: "先补 observability 证据覆盖,再扩大外部分析与回归", rationale: [ ...buildObservabilityRecommendationRationale({ trendSummary, topObservabilitySignals, topCurrentVerificationFailureOutcomes: focusCurrentObservabilityVerificationOutcomes, topDegradedVerificationFailureOutcomes: focusDegradedObservabilityVerificationOutcomes, currentVerificationSummary, }), ...currentAdvisoryVerificationFollowUp.rationale, ], commands: [ "npm run harness:eval", "npm run harness:eval:trend", "npm run harness:cleanup-report", ], backlogTools: buildObservabilityRecommendationBacklog({ topCurrentVerificationFailureOutcomes: focusCurrentObservabilityVerificationOutcomes, advisoryFollowUpBacklogTools: currentAdvisoryVerificationFollowUp.backlogTools, }), focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: [], }); } const hasGovernancePressure = governanceSummary.activeByClassification.compat > 0 || governanceSummary.activeByClassification.deprecated > 0 || governanceSummary.activeByClassification["dead-candidate"] > 0 || governanceSummary.classificationDriftCount > 0 || governanceSummary.zeroReferenceCandidateCount > 0; if (hasGovernancePressure) { maybePushRecommendation(recommendations, { id: "governance-cleanup-priority", priority: governanceSummary.activeByClassification["dead-candidate"] > 0 || governanceSummary.activeByClassification.deprecated > 0 ? "P1" : "P2", title: "按治理分类清理 compat / deprecated / dead-candidate 表面", rationale: [ `当前活跃 legacy surface:compat ${governanceSummary.activeByClassification.compat}、deprecated ${governanceSummary.activeByClassification.deprecated}、dead-candidate ${governanceSummary.activeByClassification["dead-candidate"]}。`, "这一步是证据驱动的人类治理,不是 Lime 内部自动清理。", ], commands: ["npm run governance:legacy-report"], backlogTools: [], focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: topGovernanceSurfaceIds, }); } if (currentVerificationSummary.recoveredCaseCount > 0) { maybePushRecommendation(recommendations, { id: "recovered-baseline-follow-up", priority: currentVerificationSummary.blockingFailureCaseCount === 0 && currentVerificationSummary.advisoryFailureCaseCount === 0 ? "P2" : "P3", title: "把 recovered verification outcome 固化成 current 正向基线", rationale: [ ...buildRecoveredVerificationRecommendationRationale({ topCurrentRecoveredVerificationOutcomes: focusCurrentRecoveredObservabilityVerificationOutcomes, currentVerificationSummary, }), ...currentRecoveredVerificationFollowUp.rationale, "恢复成功的 outcome 不应只停留在统计卡里,还应继续回挂到 replay / smoke / evidence 主链,作为后续回退判断的正向对照。", ], commands: currentRecoveredVerificationFollowUp.commands, backlogTools: currentRecoveredVerificationFollowUp.backlogTools, focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationRecoveredOutcomes: topCurrentRecoveredVerificationOutcomes.length > 0 ? topCurrentRecoveredVerificationOutcomes : [], focusSurfaceIds: [], }); } const shouldReviewDocs = docFreshnessSummary.issueCount > 0 || trendSummary.isSeed || governanceSummary.classificationDriftCount > 0 || governanceSummary.activeByClassification.compat > 0 || governanceSummary.activeByClassification.deprecated > 0 || trendSummary.signals.some((signal) => signal.includes("字段漂移")); if (shouldReviewDocs) { const topDocPaths = docFreshnessFocus.documents .slice(0, 3) .map((entry) => entry.documentPath); maybePushRecommendation(recommendations, { id: "doc-freshness-review", priority: docFreshnessSummary.issueCount > 0 ? "P1" : "P2", title: "回看 Harness 文档与事实源是否过期", rationale: [ "当 replay/trend 与治理边界同时在演进时,文档漂移会把分析和修复重新推回聊天窗口。", docFreshnessSummary.issueCount > 0 ? `当前 doc freshness 发现 ${docFreshnessSummary.issueCount} 个问题,应先修回链和失效引用。` : "当前仓库已经有自动化 doc freshness 检查,可先扫描高频 Harness 文档的回链和已删除表面引用。", ], commands: ["npm run harness:doc-freshness"], backlogTools: [], focusFailureModes: topFailureModes, focusSuiteTags: topSuiteTags, focusReviewDecisionStatuses: topReviewDecisionStatuses, focusReviewRiskLevels: topReviewRiskLevels, focusVerificationFailureOutcomes: topRecommendedVerificationFailureOutcomes, focusSurfaceIds: topDocPaths.length > 0 ? topDocPaths : topGovernanceSurfaceIds, }); } return recommendations.sort((left, right) => { const priorityDiff = (PRIORITY_RANK[left.priority] ?? 99) - (PRIORITY_RANK[right.priority] ?? 99); if (priorityDiff !== 0) { return priorityDiff; } return left.id.localeCompare(right.id); }); } export function buildGeneratedSlopReport({ repoRoot, trendReport, docFreshnessReport, governanceReport, sources = {}, }) { const trendSummary = buildTrendSummary(trendReport); const docFreshnessSummary = buildDocFreshnessSummary(docFreshnessReport); const docFreshnessFocus = buildDocFreshnessFocus(docFreshnessReport); const focusFailureModes = buildTrendFocusEntries( trendReport?.classificationDeltas?.failureModes, trendSummary.sampleCount, ); const focusSuiteTags = buildTrendFocusEntries( trendReport?.classificationDeltas?.suiteTags, trendSummary.sampleCount, ); const focusReviewDecisionStatuses = buildTrendFocusEntries( trendReport?.classificationDeltas?.reviewDecisionStatuses, trendSummary.sampleCount, ); const focusReviewRiskLevels = buildTrendFocusEntries( trendReport?.classificationDeltas?.reviewRiskLevels, trendSummary.sampleCount, ); const focusObservabilitySignals = buildObservabilityFocusEntries( trendReport?.classificationDeltas?.observabilitySignals, trendSummary.sampleCount, ); const verificationPresentation = deriveVerificationOutcomePresentationFromTrend({ trendReport, sampleCount: trendSummary.sampleCount, }); const mergedVerificationFailureOutcomes = verificationPresentation.mergedVerificationFailureOutcomes; const focusVerificationFailureOutcomes = mergedVerificationFailureOutcomes; const focusCurrentObservabilityVerificationOutcomes = verificationPresentation.focusCurrentVerificationFailureOutcomes; const focusCurrentRecoveredObservabilityVerificationOutcomes = verificationPresentation.focusCurrentRecoveredVerificationOutcomes; const focusDegradedObservabilityVerificationOutcomes = verificationPresentation.focusDegradedVerificationFailureOutcomes; const combinedVerificationOutcomeSummary = verificationPresentation.verificationOutcomeSummary; const verificationOutcomeSummary = combinedVerificationOutcomeSummary; const currentVerificationOutcomeSummary = combinedVerificationOutcomeSummary.current; const degradedVerificationOutcomeSummary = combinedVerificationOutcomeSummary.degraded; const currentRecoveredVerificationOutcomes = formatVerificationOutcomeCompactLabels( focusCurrentRecoveredObservabilityVerificationOutcomes, 3, ); const governanceSurfaces = buildGovernanceSurfaceEntries(governanceReport); const governanceSummary = buildGovernanceSummary( governanceReport, governanceSurfaces, ); const recommendations = buildRecommendations({ trendSummary, verificationOutcomeSummary: combinedVerificationOutcomeSummary, focusFailureModes, focusSuiteTags, focusReviewDecisionStatuses, focusReviewRiskLevels, focusObservabilitySignals, focusVerificationFailureOutcomes: mergedVerificationFailureOutcomes, focusCurrentObservabilityVerificationOutcomes, focusCurrentRecoveredObservabilityVerificationOutcomes, focusDegradedObservabilityVerificationOutcomes, docFreshnessSummary, docFreshnessFocus, governanceSummary, governanceSurfaces, }); const report = { reportVersion: "v1", generatedAt: new Date().toISOString(), repoRoot: normalizeString(repoRoot), sources: { trend: { kind: normalizeString(sources?.trend?.kind, "generated"), path: normalizeString(sources?.trend?.path), }, docFreshness: { kind: normalizeString(sources?.docFreshness?.kind, "generated"), path: normalizeString(sources?.docFreshness?.path), }, governance: { kind: normalizeString(sources?.governance?.kind, "generated"), path: normalizeString(sources?.governance?.path), }, }, summary: { trend: trendSummary, verificationOutcomes: combinedVerificationOutcomeSummary, docFreshness: docFreshnessSummary, governance: governanceSummary, }, signals: [ ...trendSummary.signals, docFreshnessSummary.issueCount > 0 ? `doc freshness 发现 ${docFreshnessSummary.issueCount} 个问题。` : "当前高频 Harness 文档回链与路径引用保持新鲜。", governanceSummary.violationCount > 0 ? `governance 边界违规 ${governanceSummary.violationCount} 条。` : "当前没有新的 governance 边界违规。", governanceSummary.activeByClassification.compat > 0 ? `compat 活跃 surface ${governanceSummary.activeByClassification.compat} 个。` : "当前没有活跃 compat surface。", governanceSummary.activeByClassification.deprecated > 0 ? `deprecated 活跃 surface ${governanceSummary.activeByClassification.deprecated} 个。` : "当前没有活跃 deprecated surface。", trendSummary.reviewDecisionBacklogCount > 0 ? `仍有 ${trendSummary.reviewDecisionBacklogCount} 个需要人工审核的 case 尚未记录最终 decision。` : "当前没有待补录的人工审核 backlog。", trendSummary.latestCurrentObservabilityGapCaseCount > 0 ? `当前仍有 ${trendSummary.latestCurrentObservabilityGapCaseCount} 个 current case 缺 observability 证据。` : "当前 current 样本没有额外的 observability 证据缺口。", trendSummary.latestDegradedObservabilityGapCaseCount > 0 ? `当前保留 ${trendSummary.latestDegradedObservabilityGapCaseCount} 个 degraded observability gap 样本作为诊断基线。` : "当前没有额外保留的 degraded observability gap 样本。", ...buildVerificationOutcomeSignalMessages({ focusVerificationFailureOutcomes, verificationOutcomeSummary, currentVerificationOutcomeSummary, degradedVerificationOutcomeSummary, currentRecoveredVerificationOutcomes: focusCurrentRecoveredObservabilityVerificationOutcomes, labelLimit: 3, }), ], focus: { failureModes: focusFailureModes.slice(0, 5), suiteTags: focusSuiteTags.slice(0, 5), reviewDecisionStatuses: focusReviewDecisionStatuses.slice(0, 5), reviewRiskLevels: focusReviewRiskLevels.slice(0, 5), observabilitySignals: focusObservabilitySignals.slice(0, 5), observabilityVerificationOutcomes: mergedVerificationFailureOutcomes.slice(0, 5), currentObservabilityVerificationOutcomes: focusCurrentObservabilityVerificationOutcomes.slice(0, 5), currentRecoveredObservabilityVerificationOutcomes: focusCurrentRecoveredObservabilityVerificationOutcomes.slice(0, 5), degradedObservabilityVerificationOutcomes: focusDegradedObservabilityVerificationOutcomes.slice(0, 5), docFreshness: docFreshnessFocus, governanceSurfaces: governanceSurfaces .filter((entry) => entry.active && entry.classification !== "current") .slice(0, 5), }, recommendations, }; return assertGeneratedSlopReportContract(report); } export function renderGeneratedSlopText(report) { const lines = [ "[harness-cleanup] generated slop report", `[harness-cleanup] trend source: ${report.sources.trend.kind}${report.sources.trend.path ? ` (${report.sources.trend.path})` : ""}`, `[harness-cleanup] doc freshness source: ${report.sources.docFreshness.kind}${report.sources.docFreshness.path ? ` (${report.sources.docFreshness.path})` : ""}`, `[harness-cleanup] governance source: ${report.sources.governance.kind}${report.sources.governance.path ? ` (${report.sources.governance.path})` : ""}`, `[harness-cleanup] trend samples: ${report.summary.trend.sampleCount}`, `[harness-cleanup] trend seed: ${report.summary.trend.isSeed ? "yes" : "no"}`, `[harness-cleanup] delta invalid: ${report.summary.trend.invalidDelta}`, `[harness-cleanup] delta pending_request: ${report.summary.trend.pendingDelta}`, `[harness-cleanup] delta review_decision_recorded: ${report.summary.trend.reviewDecisionRecordedDelta}`, `[harness-cleanup] review backlog: ${report.summary.trend.reviewDecisionBacklogCount}`, `[harness-cleanup] observability gap cases: ${report.summary.trend.latestObservabilityGapCaseCount}`, `[harness-cleanup] current observability gap cases: ${report.summary.trend.latestCurrentObservabilityGapCaseCount}`, `[harness-cleanup] degraded observability gap cases: ${report.summary.trend.latestDegradedObservabilityGapCaseCount}`, `[harness-cleanup] verification failure cases: ${report.summary.verificationOutcomes.failureCaseCount}`, `[harness-cleanup] current verification blocking failure cases: ${report.summary.verificationOutcomes.current?.blockingFailureCaseCount ?? 0}`, `[harness-cleanup] current verification advisory failure cases: ${report.summary.verificationOutcomes.current?.advisoryFailureCaseCount ?? 0}`, `[harness-cleanup] degraded verification blocking failure cases: ${report.summary.verificationOutcomes.degraded?.blockingFailureCaseCount ?? 0}`, `[harness-cleanup] verification recovered cases: ${report.summary.verificationOutcomes.recoveredCaseCount}`, `[harness-cleanup] doc freshness issues: ${report.summary.docFreshness.issueCount}`, `[harness-cleanup] active compat/deprecated/dead-candidate: ${report.summary.governance.activeByClassification.compat}/${report.summary.governance.activeByClassification.deprecated}/${report.summary.governance.activeByClassification["dead-candidate"]}`, `[harness-cleanup] governance violations: ${report.summary.governance.violationCount}`, ]; for (const signal of report.signals) { lines.push(`[harness-cleanup] signal: ${signal}`); } if (report.focus.failureModes.length > 0) { lines.push("[harness-cleanup] top failure modes:"); for (const entry of report.focus.failureModes) { lines.push( ` - ${entry.name}: state=${entry.state}, latest_pending=${entry.latest.pendingRequestCaseCount}, latest_invalid=${entry.latest.invalidCount}, score=${entry.score}`, ); } } if (report.focus.governanceSurfaces.length > 0) { lines.push("[harness-cleanup] top governance surfaces:"); for (const entry of report.focus.governanceSurfaces) { lines.push( ` - ${entry.id}: ${entry.classification}/${entry.status}, refs=${entry.referenceCount}, violations=${entry.violationCount}`, ); } } if (report.focus.reviewDecisionStatuses.length > 0) { lines.push("[harness-cleanup] top review decision statuses:"); for (const entry of report.focus.reviewDecisionStatuses) { lines.push( ` - ${entry.name}: state=${entry.state}, latest_case=${entry.latest.caseCount}, delta_case=${entry.delta.caseCount}, score=${entry.score}`, ); } } if (report.focus.reviewRiskLevels.length > 0) { lines.push("[harness-cleanup] top review risk levels:"); for (const entry of report.focus.reviewRiskLevels) { lines.push( ` - ${entry.name}: state=${entry.state}, latest_case=${entry.latest.caseCount}, delta_case=${entry.delta.caseCount}, score=${entry.score}`, ); } } if (report.focus.observabilitySignals.length > 0) { lines.push("[harness-cleanup] top observability gaps:"); for (const entry of report.focus.observabilitySignals) { lines.push( ` - ${entry.signal} (${entry.status}): state=${entry.state}, latest_case=${entry.latest.caseCount}, delta_case=${entry.delta.caseCount}, score=${entry.score}`, ); } } if (report.focus.observabilityVerificationOutcomes.length > 0) { lines.push("[harness-cleanup] top observability verification outcomes:"); for (const entry of report.focus.observabilityVerificationOutcomes) { lines.push( ` - ${formatVerificationOutcomeCompactLabel(entry)}: state=${entry.state}, latest_case=${entry.latest.caseCount}, delta_case=${entry.delta.caseCount}, score=${entry.score}`, ); } } lines.push("[harness-cleanup] observability gap role summary:"); lines.push( ` - current: latest=${report.summary.trend.latestCurrentObservabilityGapCaseCount}, delta=${report.summary.trend.currentObservabilityGapCaseDelta}`, ); lines.push( ` - degraded: latest=${report.summary.trend.latestDegradedObservabilityGapCaseCount}, delta=${report.summary.trend.degradedObservabilityGapCaseDelta}`, ); if (report.focus.docFreshness.issueKinds.length > 0) { lines.push("[harness-cleanup] doc freshness issues:"); for (const entry of report.focus.docFreshness.issueKinds) { lines.push(` - ${entry.kind}: count=${entry.count}`); } } if (report.recommendations.length > 0) { lines.push("[harness-cleanup] recommendations:"); for (const action of report.recommendations) { lines.push(` - [${action.priority}] ${action.title}`); } } return `${lines.join("\n")}\n`; } export function renderGeneratedSlopMarkdown(report) { const lines = [ "# Lime Harness Cleanup / Slop Report", "", `- 生成时间:${report.generatedAt}`, `- trend 来源:${report.sources.trend.kind}${report.sources.trend.path ? `(\`${report.sources.trend.path}\`)` : ""}`, `- doc freshness 来源:${report.sources.docFreshness.kind}${report.sources.docFreshness.path ? `(\`${report.sources.docFreshness.path}\`)` : ""}`, `- governance 来源:${report.sources.governance.kind}${report.sources.governance.path ? `(\`${report.sources.governance.path}\`)` : ""}`, "", "## 摘要", "", `- trend 样本数:${report.summary.trend.sampleCount}`, `- trend 是否仍为 seed:${report.summary.trend.isSeed ? "是" : "否"}`, `- invalid delta:${report.summary.trend.invalidDelta}`, `- pending request delta:${report.summary.trend.pendingDelta}`, `- 已记录人工审核 delta:${report.summary.trend.reviewDecisionRecordedDelta}`, `- 待补录人工审核 backlog:${report.summary.trend.reviewDecisionBacklogCount}`, `- observability gap case:${report.summary.trend.latestObservabilityGapCaseCount}`, `- current observability gap case:${report.summary.trend.latestCurrentObservabilityGapCaseCount}`, `- degraded observability gap case:${report.summary.trend.latestDegradedObservabilityGapCaseCount}`, `- verification failure case:${report.summary.verificationOutcomes.failureCaseCount}`, `- current verification blocking failure case:${report.summary.verificationOutcomes.current?.blockingFailureCaseCount ?? 0}`, `- current verification advisory failure case:${report.summary.verificationOutcomes.current?.advisoryFailureCaseCount ?? 0}`, `- degraded verification blocking failure case:${report.summary.verificationOutcomes.degraded?.blockingFailureCaseCount ?? 0}`, `- verification recovered case:${report.summary.verificationOutcomes.recoveredCaseCount}`, `- doc freshness 问题数:${report.summary.docFreshness.issueCount}`, `- governance 违规数:${report.summary.governance.violationCount}`, `- compat 活跃 surface:${report.summary.governance.activeByClassification.compat}`, `- deprecated 活跃 surface:${report.summary.governance.activeByClassification.deprecated}`, `- dead-candidate 活跃 surface:${report.summary.governance.activeByClassification["dead-candidate"]}`, "", "## 信号", "", ]; for (const signal of report.signals) { lines.push(`- ${signal}`); } lines.push(""); lines.push("## Observability Gap 角色"); lines.push(""); lines.push("| 角色 | latest case | delta case |"); lines.push("| --- | --- | --- |"); lines.push( `| current | ${report.summary.trend.latestCurrentObservabilityGapCaseCount} | ${report.summary.trend.currentObservabilityGapCaseDelta} |`, ); lines.push( `| degraded | ${report.summary.trend.latestDegradedObservabilityGapCaseCount} | ${report.summary.trend.degradedObservabilityGapCaseDelta} |`, ); if (report.focus.failureModes.length > 0) { lines.push(""); lines.push("## Failure Mode 焦点"); lines.push(""); lines.push( "| Failure Mode | 状态 | latest case | latest invalid | latest pending_request | delta invalid | score |", ); lines.push("| --- | --- | --- | --- | --- | --- | --- |"); for (const entry of report.focus.failureModes) { lines.push( `| ${entry.name} | ${entry.state} | ${entry.latest.caseCount} | ${entry.latest.invalidCount} | ${entry.latest.pendingRequestCaseCount} | ${entry.delta.invalidCount} | ${entry.score} |`, ); } } if (report.focus.docFreshness.issueKinds.length > 0) { lines.push(""); lines.push("## Doc Freshness 焦点"); lines.push(""); lines.push("| Issue Kind | Count |"); lines.push("| --- | --- |"); for (const entry of report.focus.docFreshness.issueKinds) { lines.push(`| ${entry.kind} | ${entry.count} |`); } } if (report.focus.governanceSurfaces.length > 0) { lines.push(""); lines.push("## Governance 焦点"); lines.push(""); lines.push( "| Surface | 分类 | 状态 | 引用数 | 违规数 | 来源类型 |", ); lines.push("| --- | --- | --- | --- | --- | --- |"); for (const entry of report.focus.governanceSurfaces) { lines.push( `| ${entry.id} | ${entry.classification} | ${entry.status} | ${entry.referenceCount} | ${entry.violationCount} | ${entry.sourceType} |`, ); } } if (report.focus.reviewDecisionStatuses.length > 0) { lines.push(""); lines.push("## 人工审核状态焦点"); lines.push(""); lines.push( "| 审核状态 | 状态 | latest case | latest invalid | delta case | score |", ); lines.push("| --- | --- | --- | --- | --- | --- |"); for (const entry of report.focus.reviewDecisionStatuses) { lines.push( `| ${entry.name} | ${entry.state} | ${entry.latest.caseCount} | ${entry.latest.invalidCount} | ${entry.delta.caseCount} | ${entry.score} |`, ); } } if (report.focus.reviewRiskLevels.length > 0) { lines.push(""); lines.push("## 风险等级焦点"); lines.push(""); lines.push( "| 风险等级 | 状态 | latest case | latest invalid | delta case | score |", ); lines.push("| --- | --- | --- | --- | --- | --- |"); for (const entry of report.focus.reviewRiskLevels) { lines.push( `| ${entry.name} | ${entry.state} | ${entry.latest.caseCount} | ${entry.latest.invalidCount} | ${entry.delta.caseCount} | ${entry.score} |`, ); } } if (report.focus.observabilitySignals.length > 0) { lines.push(""); lines.push("## Observability 证据缺口"); lines.push(""); lines.push( "| Signal | 状态 | latest case | delta case | score |", ); lines.push("| --- | --- | --- | --- | --- |"); for (const entry of report.focus.observabilitySignals) { lines.push( `| ${entry.signal} | ${entry.status} | ${entry.latest.caseCount} | ${entry.delta.caseCount} | ${entry.score} |`, ); } } if (report.focus.observabilityVerificationOutcomes.length > 0) { lines.push(""); lines.push("## Observability Verification 焦点"); lines.push(""); lines.push( "| Signal | Outcome | latest case | delta case | score |", ); lines.push("| --- | --- | --- | --- | --- |"); for (const entry of report.focus.observabilityVerificationOutcomes) { lines.push( `| ${entry.signal} | ${entry.outcome} | ${entry.latest.caseCount} | ${entry.delta.caseCount} | ${entry.score} |`, ); } } if (report.recommendations.length > 0) { lines.push(""); lines.push("## 推荐动作"); lines.push(""); for (const action of report.recommendations) { lines.push(`### ${action.priority} · ${action.title}`); lines.push(""); for (const rationale of action.rationale) { lines.push(`- ${rationale}`); } if (action.focusFailureModes.length > 0) { lines.push(`- 关注 failure mode:${action.focusFailureModes.join("、")}`); } if (action.focusSuiteTags.length > 0) { lines.push(`- 关注 suite tag:${action.focusSuiteTags.join("、")}`); } if (action.focusReviewDecisionStatuses.length > 0) { lines.push( `- 关注人工审核状态:${action.focusReviewDecisionStatuses.join("、")}`, ); } if (action.focusReviewRiskLevels.length > 0) { lines.push( `- 关注风险等级:${action.focusReviewRiskLevels.join("、")}`, ); } if (action.focusVerificationFailureOutcomes.length > 0) { lines.push( `- 关注 verification failure outcome:${action.focusVerificationFailureOutcomes.join("、")}`, ); } if (action.focusVerificationRecoveredOutcomes.length > 0) { lines.push( `- 关注 verification recovered outcome:${action.focusVerificationRecoveredOutcomes.join("、")}`, ); } if (action.focusSurfaceIds.length > 0) { lines.push(`- 关注 surface:${action.focusSurfaceIds.join("、")}`); } if (action.commands.length > 0) { lines.push("- 可直接执行的命令:"); for (const command of action.commands) { lines.push(` - \`${command}\``); } } if (action.backlogTools.length > 0) { lines.push("- 待补工具 / 条件动作:"); for (const item of action.backlogTools) { lines.push(` - ${item}`); } } lines.push(""); } } return `${lines.join("\n")}\n`; }