fix(reconstruction): include constituent unknowns in overall function claims

Have the function observation owner select aggregate dimensions before residual-unknown lookup. Retain independent dimension scope, unknown citations and recommended probes through the public MCP verifier.

Validation is pending the centrally coordinated lane; single-file formatting and lint completed.
This commit is contained in:
morluto
2026-10-24 02:29:23 +08:00
parent f5b11131b3
commit 7b77db7eff
4 changed files with 121 additions and 12 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ it("keeps explicit dependencies while excluding unrelated scoped unknowns", () =
]),
comparisonId,
[ev("b")],
"calls",
["calls"],
);
expect(selected.map(({ unknown_id }) => unknown_id)).toEqual([
calls.unknown_id,
+3 -5
View File
@@ -28,17 +28,15 @@ export const reconstructionClaimUnknowns = (
heads: ReadonlyMap<string, ResidualUnknown>,
comparisonId: string,
sourceIds: readonly string[],
dimension?: string,
dimensions?: readonly string[],
): ResidualUnknown[] => {
const appliesToClaim = (item: ResidualUnknown): boolean => {
const scope = item.comparison_conclusion_scope;
return (
scope === undefined ||
(scope.comparison_evidence_id === comparisonId &&
(dimension === undefined ||
scope.dimensions.some(
(scopedDimension) => scopedDimension === dimension,
)))
(dimensions === undefined ||
scope.dimensions.some((dimension) => dimensions.includes(dimension))))
);
};
const evidenceIds = new Set([comparisonId, ...sourceIds]);
+9 -6
View File
@@ -153,15 +153,13 @@ const evaluateClaim = (
...authorityLimitations(claim, sources, sides),
...callCoverage.blockers,
];
const relatedUnknowns = reconstructionClaimUnknowns(
const relevantUnknowns = reconstructionClaimUnknowns(
heads,
comparison.evidence_id,
allSourceIds,
claim.dimension,
observation.selectedDimensions ?? [claim.dimension],
);
const relevantUnknowns = relatedUnknowns;
const status = classify(observed, blockers, relevantUnknowns);
const displayedUnknowns = relevantUnknowns;
return reconstructionClaimResultSchema.parse({
claim_id: claim.claim_id,
kind: claim.kind,
@@ -172,13 +170,13 @@ const evaluateClaim = (
left_evidence_ids: sides.left,
right_evidence_ids: sides.right,
evidence_links: uniqueSorted([comparison.evidence_id, ...allSourceIds]),
unknown_ids: displayedUnknowns.map(({ unknown_id: id }) => id),
unknown_ids: relevantUnknowns.map(({ unknown_id: id }) => id),
limitations: uniqueSorted([
...comparison.limitations,
...observation.limitations,
...blockers,
...callCoverage.diagnostics,
...displayedUnknowns.map(
...relevantUnknowns.map(
({ question }) => `Residual unknown: ${question}`,
),
]),
@@ -279,6 +277,7 @@ const comparisonObservation = (
readonly status: ObservedStatus;
readonly limitations: readonly string[];
readonly hasIndependentFunctionChange?: boolean;
readonly selectedDimensions?: readonly string[];
} => {
if (claim.kind === "behavioral") {
const parsed = readComparisonResult(evidence, "compare_process_captures");
@@ -306,6 +305,10 @@ const comparisonObservation = (
if (claim.dimension === "overall")
return {
status: result.status,
selectedDimensions: [
"overall",
...result.dimensions.map(({ dimension }) => dimension),
],
limitations: result.dimensions.flatMap(
({ limitations }) => limitations,
),
@@ -592,3 +592,111 @@ const close = async (
) => {
await Promise.allSettled([client.close(), server.close(), session.close()]);
};
it("keeps an aggregate function reconstruction unknown while a constituent dimension is unresolved", async () => {
const { session, server, client } = await connected();
try {
const left = FUNCTION_COMPARISON_EXAMPLE.left;
const right = createEvidence(
{
path: "/tmp/rebuilt-function",
sha256: "2".repeat(64),
format: "mach-o",
},
left.provider,
{
operation: left.operation,
parameters: left.parameters,
result: left.normalized_result,
confidence: left.confidence,
authority: left.authority,
relationshipCoverage: { status: "complete" },
},
);
const compared = await client.callTool({
name: "compare_functions",
arguments: { left, right },
});
expect(compared.isError).not.toBe(true);
const comparison = inlineEvidence(compared.structuredContent);
const specification = {
name: "Function reconstruction",
claims: ["overall", "pseudocode", "assembly"].map((dimension) => ({
kind: "structural-function",
claim_id: dimension,
title: dimension,
dimension,
comparison_evidence_id: comparison.evidence_id,
})),
};
const baseline = await client.callTool({
name: "verify_reconstruction",
arguments: { specification },
});
expect(
inlineEvidence(baseline.structuredContent).normalized_result,
).toMatchObject({ status: "pass" });
const recorded = await client.callTool({
name: "record_unknown",
arguments: {
question: "Does the pseudocode preserve the unresolved edge case?",
severity: "high",
domain: "function-comparison",
supporting_evidence_ids: [comparison.evidence_id],
contradicting_evidence_ids: [],
required_authority: null,
required_confidence: "derived",
required_environment: null,
recommended_probes: [
{
operation: "analyze_function",
rationale: "Resolve the pseudocode edge case.",
},
],
relationships: [],
comparison_conclusion_scope: {
comparison_evidence_id: comparison.evidence_id,
dimensions: ["pseudocode"],
},
},
});
expect(recorded.isError).not.toBe(true);
const result = await client.callTool({
name: "verify_reconstruction",
arguments: { specification },
});
const payload = inlineEvidence(result.structuredContent).normalized_result;
expect(payload).toMatchObject({
status: "unknown",
claims: {
items: [
{ claim_id: "assembly", status: "pass", unknown_ids: [] },
{
claim_id: "overall",
status: "unknown",
unknown_ids: [expect.stringMatching(/^unk_/u)],
},
{
claim_id: "pseudocode",
status: "unknown",
unknown_ids: [expect.stringMatching(/^unk_/u)],
},
],
},
recommended_probes: [
expect.objectContaining({ claim_ids: ["overall", "pseudocode"] }),
],
});
const overallOnly = await client.callTool({
name: "verify_reconstruction",
arguments: {
specification: { ...specification, claims: [specification.claims[0]] },
},
});
expect(
inlineEvidence(overallOnly.structuredContent).normalized_result,
).toMatchObject({ status: "unknown", summary: { unknown: 1 } });
} finally {
await close(session, server, client);
}
});