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) => ({
@@ -452,6 +452,40 @@ test("assembled document passes the canonical server parse with a D1 of 12 house
);
});
test("technique audit reflects final evidence status and narrative usage", () => {
const workflow = pythonStyleChartPayload() as Record<string, unknown>;
const machinePacket = workflow.machine_evidence_packet as Record<string, unknown>;
const sections = machinePacket.sections as Record<string, Record<string, unknown>>;
sections.external_oracle_status.status = "official_blocked";
const packet = buildPacket({ workflow });
assert.deepEqual(packet.blockedTechniques, []);
const output = agentOutput();
const blockedRef = packet.evidenceRefs.find((ref) => ref.technique === "D2");
assert.ok(blockedRef);
output.thematicNarrative[0].evidenceRefs.push(blockedRef.id);
const document = assembleReportDocument({
reportId: "22222222-2222-4222-8222-222222222222",
generatedAt: "2026-08-06T00:00:00.000Z",
packet,
agentOutput: output,
});
const auditById = new Map(document.evidenceAppendix.techniqueAudit.map((row) => [row.id, row]));
const referencedIds = new Set(document.thematicNarrative.flatMap((section) => section.evidenceRefs));
assert.ok([...referencedIds].every((id) => auditById.get(id)?.used === true));
assert.equal(document.evidenceAppendix.techniqueAudit.find((row) => row.techniqueName === "D1")?.status, "verified");
assert.equal(document.evidenceAppendix.techniqueAudit.find((row) => row.techniqueName === "D2")?.status, "blocked");
assert.match(
document.evidenceAppendix.techniqueAudit.find((row) => row.techniqueName === "D2")?.notes ?? "",
/未返回本次计算数据/,
);
const external = document.evidenceAppendix.techniqueAudit.find(
(row) => row.techniqueName === "external_oracle_status",
);
assert.equal(external?.status, "blocked");
assert.match(external?.notes ?? "", /官方外部引擎本次未验证或不可用/);
});
test("D9/D10 charts are omitted when no real divisional houses exist", () => {
const workflow = pythonStyleChartPayload() as Record<string, unknown>;
const chart = workflow.chart as Record<string, unknown>;