feat(小宝预警): 增加日报证据与风险趋势

This commit is contained in:
Script Generator
2026-06-29 18:05:58 +08:00
parent 585316d1cf
commit b48a7e2049
5 changed files with 636 additions and 23 deletions

View File

@@ -4,6 +4,7 @@ import { STATUS_PROGRESS, getEstimateHours } from './dev-task';
import type { TestCase } from './test-case';
import { getTestCaseEstimateHours } from './test-case';
import type { VersionDailyEvidence } from './xiaobao-risk-evidence';
import { summarizeRiskTrendWithCurrent, type XiaobaoRiskSnapshot } from './xiaobao-risk-trend';
import { WORK_HOURS, addWorkHours } from './work-hours';
export type XiaobaoRiskLevel = 'on_track' | 'attention' | 'at_risk' | 'likely_delayed' | 'blocked';
@@ -72,7 +73,7 @@ export interface CalcXiaobaoVersionRiskInput {
testCases?: TestCase[];
bugs?: Bug[];
now?: Date;
snapshots?: Array<{ riskScore: number; createdAt?: string; date?: string }>;
snapshots?: XiaobaoRiskSnapshot[];
silentRisks?: SilentRisk[];
dailyEvidence?: VersionDailyEvidence;
recentActivityCount?: number;
@@ -197,7 +198,19 @@ export function calcXiaobaoVersionRisk(input: CalcXiaobaoVersionRiskInput): Xiao
const hasBlockingRisk = criticalBugCount > 0 || blockedCount > 0;
const riskLevel = getRiskLevel(riskScore, delayDays, hasBlockingRisk);
const confidence = calcConfidence(input, devTasks, testCases, bugs);
const trend = calcTrend(riskScore, input.snapshots ?? []);
const trend = summarizeRiskTrendWithCurrent(input.snapshots ?? [], {
versionId: input.version.id,
date: now.toISOString().slice(0, 10),
riskScore,
riskLevel,
forecastReleaseDate,
openBugCount: signals.criticalBugCount,
failedTestCount: signals.failedTestCount,
blockedCount: signals.blockedCount,
silentRiskCount: signals.silentRiskCount,
confidence,
createdAt: now.toISOString(),
});
return {
versionId: input.version.id,
@@ -280,27 +293,6 @@ function hasEstimate(item: DevTask | TestCase | Bug): boolean {
|| (typeof item.aiEstimateHours === 'number' && item.aiEstimateHours > 0);
}
function calcTrend(
currentScore: number,
snapshots: Array<{ riskScore: number; createdAt?: string; date?: string }>,
): XiaobaoVersionRisk['trend'] {
if (snapshots.length === 0) {
return { direction: 'unknown', delta: 0, summary: '暂无历史快照。' };
}
const latest = [...snapshots].sort((a, b) => {
const aTime = parseDate(a.createdAt ?? a.date)?.getTime() ?? 0;
const bTime = parseDate(b.createdAt ?? b.date)?.getTime() ?? 0;
return bTime - aTime;
})[0];
const delta = clampScore(currentScore) - clampScore(latest.riskScore);
const direction = Math.abs(delta) < 5 ? 'flat' : delta > 0 ? 'up' : 'down';
const summary = direction === 'flat'
? '风险基本持平。'
: direction === 'up'
? `风险上升 ${delta} 分。`
: `风险下降 ${Math.abs(delta)} 分。`;
return { direction, delta, summary };
}
function getConfidenceLevel(confidence: number): XiaobaoConfidenceLevel {
if (confidence >= 75) return 'high';