feat(AI): 增加严格估时策略
This commit is contained in:
25
apps/web/lib/ai-estimation-policy.test.ts
Normal file
25
apps/web/lib/ai-estimation-policy.test.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
|
||||||
|
import {
|
||||||
|
clampDevEstimateHours,
|
||||||
|
clampTestCaseEstimateHours,
|
||||||
|
getDefaultTestCaseEstimateHours,
|
||||||
|
} from './ai-estimation-policy';
|
||||||
|
|
||||||
|
test('clamps simple frontend interaction to AI-assisted range', () => {
|
||||||
|
assert.equal(clampDevEstimateHours('frontend_interaction', 5), 1);
|
||||||
|
assert.equal(clampDevEstimateHours('frontend_interaction', 0.1), 0.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps backend API within strict range', () => {
|
||||||
|
assert.equal(clampDevEstimateHours('backend_api', 0.25), 0.75);
|
||||||
|
assert.equal(clampDevEstimateHours('backend_api', 2), 1.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defaults and clamps test case estimates', () => {
|
||||||
|
assert.equal(getDefaultTestCaseEstimateHours('test_functional'), 0.5);
|
||||||
|
assert.equal(clampTestCaseEstimateHours('test_functional', 2), 0.5);
|
||||||
|
assert.equal(clampTestCaseEstimateHours('test_api', 0.25), 0.5);
|
||||||
|
assert.equal(clampTestCaseEstimateHours('test_exception', 2), 1);
|
||||||
|
});
|
||||||
43
apps/web/lib/ai-estimation-policy.ts
Normal file
43
apps/web/lib/ai-estimation-policy.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type { AgentTaskCategoryCode } from '@ftb/shared';
|
||||||
|
|
||||||
|
type EstimateRange = { min: number; max: number; fallback: number };
|
||||||
|
|
||||||
|
const DEV_ESTIMATE_RANGES: Record<string, EstimateRange> = {
|
||||||
|
frontend_development: { min: 0.5, max: 1.5, fallback: 1 },
|
||||||
|
frontend_interaction: { min: 0.5, max: 1, fallback: 0.5 },
|
||||||
|
backend_development: { min: 1, max: 3, fallback: 2 },
|
||||||
|
backend_api: { min: 0.75, max: 1.5, fallback: 1 },
|
||||||
|
database_schema: { min: 0.5, max: 0.5, fallback: 0.5 },
|
||||||
|
api_integration: { min: 0.75, max: 1.5, fallback: 1 },
|
||||||
|
data_processing: { min: 1, max: 2, fallback: 1.5 },
|
||||||
|
implementation_support: { min: 0.5, max: 1.5, fallback: 1 },
|
||||||
|
documentation: { min: 0.25, max: 0.5, fallback: 0.5 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEST_ESTIMATE_RANGES: Record<string, EstimateRange> = {
|
||||||
|
test_functional: { min: 0.25, max: 0.5, fallback: 0.5 },
|
||||||
|
test_api: { min: 0.5, max: 1, fallback: 0.5 },
|
||||||
|
test_exception: { min: 0.5, max: 1, fallback: 0.5 },
|
||||||
|
test_compatibility: { min: 0.5, max: 1, fallback: 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
function roundQuarterHour(hours: number): number {
|
||||||
|
return Math.round(hours * 4) / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampToRange(raw: number | undefined, range: EstimateRange): number {
|
||||||
|
const base = typeof raw === 'number' && Number.isFinite(raw) && raw > 0 ? raw : range.fallback;
|
||||||
|
return roundQuarterHour(Math.min(range.max, Math.max(range.min, base)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clampDevEstimateHours(code: AgentTaskCategoryCode | string | undefined, raw: number | undefined): number {
|
||||||
|
return clampToRange(raw, DEV_ESTIMATE_RANGES[code ?? ''] ?? { min: 0.5, max: 2, fallback: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDefaultTestCaseEstimateHours(code: AgentTaskCategoryCode | string | undefined): number {
|
||||||
|
return (TEST_ESTIMATE_RANGES[code ?? ''] ?? TEST_ESTIMATE_RANGES.test_functional).fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clampTestCaseEstimateHours(code: AgentTaskCategoryCode | string | undefined, raw: number | undefined): number {
|
||||||
|
return clampToRange(raw, TEST_ESTIMATE_RANGES[code ?? ''] ?? TEST_ESTIMATE_RANGES.test_functional);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user