feat(phase-30): add coverage snapshots, temporal comparison and auto re-testing (T-230 to T-232)

This commit is contained in:
2026-02-10 08:34:29 +01:00
parent 2ac8e7f4a5
commit 4d124b42dd
20 changed files with 1517 additions and 4 deletions

View File

@@ -0,0 +1,93 @@
import client from "./client";
// ── Types ───────────────────────────────────────────────────────────
export interface SnapshotSummary {
id: string;
name: string | null;
organization_score: number;
total_techniques: number;
validated_count: number;
partial_count: number;
not_covered_count: number;
in_progress_count: number;
not_evaluated_count: number;
created_by: string | null;
created_at: string | null;
}
export interface TechniqueState {
mitre_id: string;
technique_id: string;
status: string;
score: number | null;
}
export interface SnapshotDetail extends SnapshotSummary {
technique_states: TechniqueState[];
}
export interface SnapshotComparisonDelta {
mitre_id: string;
old_status: string;
new_status: string;
old_score: number;
new_score: number;
}
export interface SnapshotComparison {
snapshot_a: SnapshotSummary;
snapshot_b: SnapshotSummary;
score_delta: number;
improved: SnapshotComparisonDelta[];
worsened: SnapshotComparisonDelta[];
unchanged_count: number;
summary: {
improved_count: number;
worsened_count: number;
new_count: number;
};
}
// ── API Functions ───────────────────────────────────────────────────
/** List snapshots (paginated, newest first). */
export async function listSnapshots(params?: {
offset?: number;
limit?: number;
}): Promise<{ total: number; items: SnapshotSummary[] }> {
const { data } = await client.get("/snapshots", { params });
return data;
}
/** Create a manual snapshot. */
export async function createSnapshot(name?: string): Promise<SnapshotSummary> {
const { data } = await client.post<SnapshotSummary>("/snapshots", {
name: name || null,
});
return data;
}
/** Get snapshot detail with per-technique states. */
export async function getSnapshot(snapshotId: string): Promise<SnapshotDetail> {
const { data } = await client.get<SnapshotDetail>(
`/snapshots/${snapshotId}`,
);
return data;
}
/** Compare two snapshots. */
export async function compareSnapshots(
aId: string,
bId: string,
): Promise<SnapshotComparison> {
const { data } = await client.get<SnapshotComparison>("/snapshots/compare", {
params: { a: aId, b: bId },
});
return data;
}
/** Delete a snapshot (admin only). */
export async function deleteSnapshot(snapshotId: string): Promise<void> {
await client.delete(`/snapshots/${snapshotId}`);
}