fix: align report technique audit evidence
Staging Backend Quality Gate / validate (push) Successful in 10m37s
Staging Backend Quality Gate / publish (push) Has been cancelled

This commit is contained in:
Jesse_Chen
2026-08-10 17:18:52 +08:00
parent 455917a870
commit 07ea504e91
2 changed files with 68 additions and 25 deletions
+34 -25
View File
@@ -426,7 +426,7 @@ function sectionEvidenceStatus(
name: string,
sourcePath: string,
): "verified" | "partial" | "blocked" {
if (status === "missing" || status === "blocked") return "blocked";
if (status === "missing" || status === "blocked" || status === "official_blocked") return "blocked";
if (status === "verified") return "verified";
if (status === "partial") return "partial";
// used / available / received_unverified / unknown / undefined
@@ -527,7 +527,6 @@ export function buildReportEvidencePacket(input: BuildEvidencePacketInput): Repo
const techniqueAudit: { technique: string; status: string; note: string }[] = [];
const seenTechniques = new Set<string>();
const sections = readSections(machinePacket);
const sectionsByName = new Map(sections.map((section) => [section.name, section]));
// Layer names alone are route availability, not verified facts: they map to
// partial at best.
for (const technique of [...availableLayers, ...missingLayers, ...hardBlockers]) {
@@ -548,22 +547,30 @@ export function buildReportEvidencePacket(input: BuildEvidencePacketInput): Repo
: "",
});
}
// Machine-packet sections (object map in the real engine, array accepted).
// The section name is the technique key; status comes from section.status
// via the deterministic sectionEvidenceStatus rule.
// Machine-packet facts override route-layer availability for the same technique.
const sectionReason: Readonly<Record<string, string>> = {
missing: "未返回本次计算数据",
official_blocked: "官方外部引擎本次未验证或不可用",
received_unverified: "已收到外部响应,但未完成官方验证",
local_fallback: "本次仅有本地回退结果,未取得官方验证",
blocked: "本次执行被阻塞",
};
for (const section of sections) {
if (seenTechniques.has(section.name)) continue;
seenTechniques.add(section.name);
techniqueAudit.push({
const row = {
technique: section.name,
status: section.status,
note: section.sourcePath ? `source: ${section.sourcePath}` : "",
});
status: sectionEvidenceStatus(section.status, section.name, section.sourcePath),
note: [sectionReason[section.status], section.sourcePath ? `source: ${section.sourcePath}` : ""]
.filter(Boolean)
.join(""),
};
const existingIndex = techniqueAudit.findIndex((item) => item.technique === section.name);
if (existingIndex >= 0) techniqueAudit[existingIndex] = row;
else techniqueAudit.push(row);
}
const blockedTechniques = hardBlockers.length > 0
? hardBlockers
: techniqueAudit.filter((row) => row.status === "blocked").map((row) => row.technique);
: sections.filter((section) => section.status === "blocked").map((section) => section.name);
const conflicts: { techniques: string[]; summary: string }[] = [];
const rawConflicts = Array.isArray(machinePacket.conflicts)
@@ -580,14 +587,10 @@ export function buildReportEvidencePacket(input: BuildEvidencePacketInput): Repo
const evidenceRefs: { id: string; technique: string; status: EvidenceRefStatus }[] = [];
techniqueAudit.forEach((row, index) => {
const section = sectionsByName.get(row.technique);
const status = section
? sectionEvidenceStatus(section.status, section.name, section.sourcePath)
: canonicalTechniqueStatus(row.status);
evidenceRefs.push({
id: `ev-audit-${index + 1}`,
technique: row.technique,
status,
status: canonicalTechniqueStatus(row.status),
});
});
conflicts.forEach((conflict, index) => {
@@ -713,15 +716,21 @@ export function assembleReportDocument(
throw new ReportEvidenceInsufficientError("ascendant_missing");
}
const usedEvidenceRefs = new Set(
input.agentOutput.thematicNarrative.flatMap((section) => section.evidenceRefs),
);
const techniqueAudit: EvidenceAppendix["techniqueAudit"] = packet.techniqueAudit.map(
(row, index) => ({
id: `ev-audit-${index + 1}`,
techniqueId: techniqueSlug(row.technique, `tech-${index + 1}`),
techniqueName: row.technique,
status: canonicalTechniqueStatus(row.status),
used: canonicalTechniqueStatus(row.status) === "verified",
...(row.note ? { notes: row.note.slice(0, 500) } : {}),
}),
(row, index) => {
const id = `ev-audit-${index + 1}`;
return {
id,
techniqueId: techniqueSlug(row.technique, `tech-${index + 1}`),
techniqueName: row.technique,
status: canonicalTechniqueStatus(row.status),
used: usedEvidenceRefs.has(id),
...(row.note ? { notes: row.note.slice(0, 500) } : {}),
};
},
);
const conflicts: EvidenceAppendix["conflicts"] = packet.conflicts.map((conflict, index) => ({