fix(小宝预警): 接入静默风险证据
This commit is contained in:
@@ -128,3 +128,55 @@ test('calcXiaobaoVersionRisk preserves daily evidence on the returned risk objec
|
|||||||
|
|
||||||
assert.equal(risk.dailyEvidence, dailyEvidence);
|
assert.equal(risk.dailyEvidence, dailyEvidence);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('calcXiaobaoVersionRisk uses silent risks from daily evidence', () => {
|
||||||
|
const silentRisk = {
|
||||||
|
key: 'no_progress_today',
|
||||||
|
title: '今日无进展',
|
||||||
|
detail: '进行中的任务今天没有动态。',
|
||||||
|
itemId: 'dev-1',
|
||||||
|
itemType: 'dev_task' as const,
|
||||||
|
};
|
||||||
|
const dailyEvidence: VersionDailyEvidence = {
|
||||||
|
todayDeliveries: [],
|
||||||
|
todayProgress: [],
|
||||||
|
todayRisks: [],
|
||||||
|
progressNotes: [],
|
||||||
|
needsProgressItems: [],
|
||||||
|
recentActivityCount: 0,
|
||||||
|
silentRisks: [silentRisk],
|
||||||
|
};
|
||||||
|
|
||||||
|
const risk = calcXiaobaoVersionRisk({
|
||||||
|
version: version(),
|
||||||
|
devTasks: [],
|
||||||
|
testCases: [],
|
||||||
|
bugs: [],
|
||||||
|
dailyEvidence,
|
||||||
|
now: new Date('2026-07-02T01:00:00.000Z'),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(risk.silentRisks, [silentRisk]);
|
||||||
|
assert.equal(risk.signals.silentRiskCount, 1);
|
||||||
|
assert.ok(risk.riskScore > 0);
|
||||||
|
assert.ok(risk.reasons.some((reason: { key: string }) => reason.key === 'silent_risk'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calcXiaobaoVersionRisk preserves null expected release date as a compatible output value', () => {
|
||||||
|
const versionWithNullRelease = {
|
||||||
|
id: 'ver-null-release',
|
||||||
|
name: 'V1.1',
|
||||||
|
expectedReleaseDate: null,
|
||||||
|
members: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const risk = calcXiaobaoVersionRisk({
|
||||||
|
version: versionWithNullRelease,
|
||||||
|
devTasks: [],
|
||||||
|
testCases: [],
|
||||||
|
bugs: [],
|
||||||
|
now: new Date('2026-07-02T01:00:00.000Z'),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(risk.expectedReleaseDate, null);
|
||||||
|
});
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface XiaobaoVersionRef {
|
|||||||
status?: string;
|
status?: string;
|
||||||
productName?: string;
|
productName?: string;
|
||||||
projectName?: string;
|
projectName?: string;
|
||||||
expectedReleaseDate?: string;
|
expectedReleaseDate?: string | null;
|
||||||
members?: Array<{ id?: string; name: string; role?: string }>;
|
members?: Array<{ id?: string; name: string; role?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ export interface XiaobaoVersionRisk {
|
|||||||
versionId: string;
|
versionId: string;
|
||||||
riskScore: number;
|
riskScore: number;
|
||||||
riskLevel: XiaobaoRiskLevel;
|
riskLevel: XiaobaoRiskLevel;
|
||||||
|
expectedReleaseDate: string | null;
|
||||||
confidence: number;
|
confidence: number;
|
||||||
confidenceLevel: XiaobaoConfidenceLevel;
|
confidenceLevel: XiaobaoConfidenceLevel;
|
||||||
forecastReleaseDate?: string;
|
forecastReleaseDate?: string;
|
||||||
@@ -86,7 +87,7 @@ export function calcXiaobaoVersionRisk(input: CalcXiaobaoVersionRiskInput): Xiao
|
|||||||
const devTasks = input.devTasks ?? [];
|
const devTasks = input.devTasks ?? [];
|
||||||
const testCases = input.testCases ?? [];
|
const testCases = input.testCases ?? [];
|
||||||
const bugs = input.bugs ?? [];
|
const bugs = input.bugs ?? [];
|
||||||
const silentRisks = input.silentRisks ?? [];
|
const silentRisks = input.dailyEvidence?.silentRisks ?? [];
|
||||||
|
|
||||||
const remainingDevHours = devTasks.reduce((sum, task) => {
|
const remainingDevHours = devTasks.reduce((sum, task) => {
|
||||||
const estimate = getEstimateHours(task);
|
const estimate = getEstimateHours(task);
|
||||||
@@ -164,6 +165,15 @@ export function calcXiaobaoVersionRisk(input: CalcXiaobaoVersionRiskInput): Xiao
|
|||||||
count: failedTestCount,
|
count: failedTestCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (silentRisks.length > 0) {
|
||||||
|
reasons.push({
|
||||||
|
key: 'silent_risk',
|
||||||
|
title: '静默风险',
|
||||||
|
detail: `发现 ${silentRisks.length} 个今日缺少进展或证据的风险项。`,
|
||||||
|
severity: 'warning',
|
||||||
|
count: silentRisks.length,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const signals: XiaobaoRiskSignals = {
|
const signals: XiaobaoRiskSignals = {
|
||||||
unfinishedCount,
|
unfinishedCount,
|
||||||
@@ -193,6 +203,7 @@ export function calcXiaobaoVersionRisk(input: CalcXiaobaoVersionRiskInput): Xiao
|
|||||||
versionId: input.version.id,
|
versionId: input.version.id,
|
||||||
riskScore,
|
riskScore,
|
||||||
riskLevel,
|
riskLevel,
|
||||||
|
expectedReleaseDate: input.version.expectedReleaseDate ?? null,
|
||||||
confidence,
|
confidence,
|
||||||
confidenceLevel: getConfidenceLevel(confidence),
|
confidenceLevel: getConfidenceLevel(confidence),
|
||||||
forecastReleaseDate,
|
forecastReleaseDate,
|
||||||
@@ -297,7 +308,7 @@ function getConfidenceLevel(confidence: number): XiaobaoConfidenceLevel {
|
|||||||
return 'low';
|
return 'low';
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDate(iso?: string): Date | undefined {
|
function parseDate(iso?: string | null): Date | undefined {
|
||||||
if (!iso) return undefined;
|
if (!iso) return undefined;
|
||||||
const date = new Date(iso);
|
const date = new Date(iso);
|
||||||
return Number.isNaN(date.getTime()) ? undefined : date;
|
return Number.isNaN(date.getTime()) ? undefined : date;
|
||||||
|
|||||||
Reference in New Issue
Block a user