refactor(coverage): 覆盖度改按类型统计 + 新增 list_untested_assets 工具

- 去掉 backlog(避免把未测清单塞进提示词引导 plan),改由 plan 自行判断。
- Coverage 去 Backlog、加 by_type [{type,total,tested}];TaskCoverage 改 GROUP BY type,
  累加得总分母/总已测。
- 新增 db.ListUntestedAssets(范围内未测资产,可按类型过滤 + 分页)与 list_untested_assets
  工具(type + page/page_size,默认页大小 10),绑 planner、随 BuiltinToolSeeds 播种。
- graph_overview 的 coverage 现为 {denominator,tested,pct,by_type,note};note 提示按需调
  list_untested_assets 自行判断,不再推送 backlog。
- /api/tasks/{id}/coverage 去掉 backlog 参数;前端覆盖度卡改为按类型「已测/总数」徽章。

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Autumn-27andClaude Opus 5 committed 2026-08-08 11:50:51 -04:00
1 parent aeadd0d48b
commit 4c4f65f40a
6 files changed
+144 -52

No files matched your search

@@ -57,7 +57,7 @@ export function OverviewTab({ taskId }: { taskId: string }) {
denominator: number;
tested: number;
pct: number | null;
backlog_sample: { id: number; type: string; label: string }[];
by_type: { type: string; total: number; tested: number }[];
} | null>(null);
React.useEffect(() => {
@@ -126,16 +126,16 @@ export function OverviewTab({ taskId }: { taskId: string }) {
</span>
</div>
{coverage.pct != null && <Progress value={Math.round(coverage.pct * 100)} />}
{coverage.backlog_sample.length > 0 && (
<div className="text-xs">
<div className="text-muted-foreground mb-1">未测(优先补测):</div>
<div className="flex flex-wrap gap-1">
{coverage.backlog_sample.slice(0, 12).map((a) => (
<span key={a.id} className="bg-muted rounded px-1.5 py-0.5 font-mono">
{a.label || a.type}
{coverage.by_type.length > 0 && (
<div className="flex flex-wrap gap-1.5 text-xs">
{coverage.by_type.map((b) => (
<span key={b.type} className="bg-muted rounded px-1.5 py-0.5">
<span className="text-muted-foreground">{b.type}</span>{" "}
<span className="tabular-nums font-medium">
{b.tested}/{b.total}
</span>
))}
</div>
</span>
))}
</div>
)}
</CardContent>
+2 -2
View File
@@ -115,14 +115,14 @@ export const api = {
setActive: (id: string) => post<{ active: string }>("/active", { id }),
// ---- stats ----
stats: (task?: string) => get<Stats>(`/stats${tq(task)}`),
// 资产测试覆盖度(粗估,供参考):范围内资产里被 fact 碰过的占比 + 未测 backlog 取样。
// 资产测试覆盖度(粗估,供参考):范围内资产被 fact 碰过的占比 + 按类型的 总数/已测。
taskCoverage: (id: string) =>
get<{
scope_rows: number;
denominator: number;
tested: number;
pct: number | null;
backlog_sample: { id: number; type: string; label: string }[];
by_type: { type: string; total: number; tested: number }[];
}>(`/tasks/${id}/coverage`),
// ---- assets ----