mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 03:45:39 +00:00
refactor(evidence): carry producer-owned source records
Carry the final artifact inspection's exact nested source Evidence through AnalysisExecution. Derive links in the shared Evidence builder instead of reparsing the result in CLI and MCP adapters. Retain validation for unknown and historical Evidence inputs. Move the shared source recorder into application ownership and migrate its consumers. Record sources before parents; keep source recording failures from publishing summaries. Decline snapshot entries whose source closure the current entry format cannot represent, while retaining investigation Evidence. Validation: actual ASAR regression failed before the change with missing links and passes afterward; exact nested identity, source recorder refusal, final-close cancellation and cleanup failure, historical authentication, snapshot controls and public CLI/MCP workflows. Fresh runtime/catalog build, full static/docs, discovery and duplication checks pass. Installed native providers and platform-specific skipped cases remain unverified.
This commit is contained in:
1 parent
5ea2c280b8
commit
835904e4ee
30 files changed
+394
-139
No files matched your search
@@ -930,6 +930,63 @@ it("does not replay pre-envelope call graphs under the revised workflow profile"
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("declines source-bearing snapshot entries while replaying omitted and empty source controls", () => {
|
||||
const cache = new AnalysisSnapshotCache();
|
||||
const target = ANALYSIS_SNAPSHOT_TARGET;
|
||||
const profile = ANALYSIS_SNAPSHOT_PROFILE;
|
||||
const source = createEvidence(target, ANALYSIS_SNAPSHOT_PROVIDER, {
|
||||
operation: "source",
|
||||
parameters: {},
|
||||
result: "observed source",
|
||||
});
|
||||
const parameters = { address: "0x1000", document: "fixture" };
|
||||
cache.record({
|
||||
target,
|
||||
profile,
|
||||
operation: "procedure_info",
|
||||
parameters,
|
||||
execution: createAnalysisExecution(
|
||||
"parent observation",
|
||||
ANALYSIS_SNAPSHOT_PROVIDER,
|
||||
{
|
||||
subject: target,
|
||||
analysisProfile: profile,
|
||||
sourceEvidence: [source],
|
||||
},
|
||||
),
|
||||
});
|
||||
expect(
|
||||
cache.lookup(target, profile, "procedure_info", parameters),
|
||||
).toBeUndefined();
|
||||
expect(cache.entries()).toEqual([]);
|
||||
|
||||
for (const sourceEvidence of [undefined, []] as const) {
|
||||
const control = {
|
||||
address: sourceEvidence === undefined ? "0x2000" : "0x3000",
|
||||
document: "fixture",
|
||||
};
|
||||
cache.record({
|
||||
target,
|
||||
profile,
|
||||
operation: "procedure_info",
|
||||
parameters: control,
|
||||
execution: createAnalysisExecution(
|
||||
"source-free observation",
|
||||
ANALYSIS_SNAPSHOT_PROVIDER,
|
||||
{
|
||||
subject: target,
|
||||
analysisProfile: profile,
|
||||
...(sourceEvidence === undefined ? {} : { sourceEvidence }),
|
||||
},
|
||||
),
|
||||
});
|
||||
expect(
|
||||
cache.lookup(target, profile, "procedure_info", control)?.result,
|
||||
).toBe("source-free observation");
|
||||
}
|
||||
expect(cache.entries()).toHaveLength(2);
|
||||
});
|
||||
|
||||
describe("executions that report truncated references", () => {
|
||||
const record = (referencesTruncated: boolean | undefined) => {
|
||||
const cache = new AnalysisSnapshotCache();
|
||||
|
||||
@@ -436,6 +436,9 @@ export class AnalysisSnapshotCache {
|
||||
// The snapshot format does not carry reference truncation; a replay would
|
||||
// present a capped read as complete, so it is not recorded.
|
||||
if (execution.referencesTruncated === true) return;
|
||||
// Provider snapshot entries do not carry execution source records. Replay
|
||||
// must not discard the source closure that supplies the parent's Evidence links.
|
||||
if ((execution.sourceEvidence?.length ?? 0) > 0) return;
|
||||
const queryId = analysisQueryId(
|
||||
snapshotTarget(target),
|
||||
snapshotBinding(profile),
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import { err, ok, type Result } from "../../domain/result.js";
|
||||
import type { JsonValue } from "../../domain/jsonValue.js";
|
||||
import { createEvidence } from "../../domain/evidence.js";
|
||||
import { createAnalysisExecutionEvidence } from "../../domain/analysisObservation.js";
|
||||
import type {
|
||||
AnalysisClient,
|
||||
AnalysisExecution,
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
type SessionProviderRoute,
|
||||
} from "./SessionProviderRouter.js";
|
||||
import { InvestigationRecords } from "../investigation/InvestigationRecords.js";
|
||||
import { recordEvidenceSources } from "../investigation/recordEvidenceSources.js";
|
||||
import { BinarySessionRecords } from "./BinarySessionRecords.js";
|
||||
import { binarySessionStatus } from "./BinarySessionStatus.js";
|
||||
import {
|
||||
@@ -1256,26 +1257,24 @@ export class BinarySession
|
||||
name !== "inspect_keyed_archive" &&
|
||||
name !== "trace_dylib_resolution"
|
||||
) {
|
||||
const evidence = createEvidence(
|
||||
execution.value.subject === undefined
|
||||
? active.target
|
||||
: (execution.value.subject ?? undefined),
|
||||
execution.value.provider,
|
||||
const evidence = createAnalysisExecutionEvidence(
|
||||
name,
|
||||
arguments_,
|
||||
{
|
||||
operation: name,
|
||||
parameters: arguments_,
|
||||
result: execution.value.result,
|
||||
...execution.value,
|
||||
analysisProfile: profile,
|
||||
rawResult: execution.value.rawResult,
|
||||
limitations: execution.value.limitations,
|
||||
...(execution.value.relationshipCoverage === undefined
|
||||
? {}
|
||||
: {
|
||||
relationshipCoverage: execution.value.relationshipCoverage,
|
||||
}),
|
||||
locations: execution.value.locations,
|
||||
subject:
|
||||
execution.value.subject === undefined
|
||||
? active.target
|
||||
: execution.value.subject,
|
||||
},
|
||||
"observed",
|
||||
);
|
||||
const sourcesRecorded = recordEvidenceSources(
|
||||
(source) => this.recordEvidence(source),
|
||||
execution.value.sourceEvidence ?? [],
|
||||
);
|
||||
if (!sourcesRecorded.ok) return sourcesRecorded;
|
||||
const recorded = this.recordEvidence(evidence);
|
||||
if (!recorded.ok) return recorded;
|
||||
const retained = { ...execution.value, evidenceId: evidence.evidence_id };
|
||||
|
||||
Reference in new issue
Block a user