mirror of
https://github.com/morluto/rea.git
synced 2026-10-28 02:15:44 +00:00
feat(javascript): return a retained summary view on request (#1568)
analyze_javascript_application returns the complete application graph inline, which repeats tens of kilobytes even for a few source lines and exceeds the default 10 MiB MCP frame for a 300-function source file. The new optional detail input keeps complete delivery by default. With detail "summary" the server records the complete analysis Evidence in the session and returns its inspect_analysis_view summary, whose parent_evidence_id lets callers page modules, select items, or pass the retained reference to application workflows. A server without Evidence retention refuses summary detail with capability_unavailable rather than returning a summary whose analysis cannot be reached. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
649661dc8b
commit
c19e15a2b3
9 files changed
+279
-7
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { expect, it } from "vitest";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE } from "../../contracts/javascript/javascriptRuntimeReconciliationExample.js";
|
||||
import { createEvidence, parseEvidence } from "../../domain/evidence.js";
|
||||
@@ -9,7 +9,13 @@ import {
|
||||
analysisViewJavaScriptEvidence,
|
||||
analysisViewLayoutEvidence,
|
||||
} from "../../../tests/fixtures/analysisView.js";
|
||||
import { inspectAnalysisView } from "./AnalysisViewService.js";
|
||||
import {
|
||||
inspectAnalysisView,
|
||||
summarizeRetainedAnalysis,
|
||||
} from "./AnalysisViewService.js";
|
||||
import type { Evidence } from "../../domain/evidence.js";
|
||||
import { EvidenceIntegrityError } from "../../domain/evidenceErrors.js";
|
||||
import { err, ok } from "../../domain/result.js";
|
||||
|
||||
it.each(["/fixtures/unknown.exe", ""])(
|
||||
"preserves recorded empty native identity fields: path=%j",
|
||||
@@ -266,3 +272,47 @@ it("rejects contradictory subject and analysis artifact digests", () => {
|
||||
error: { _tag: "EvidenceIntegrityError" },
|
||||
});
|
||||
});
|
||||
|
||||
describe("summarizeRetainedAnalysis", () => {
|
||||
const parent = analysisViewJavaScriptEvidence(
|
||||
analysisViewJavaScriptAnalysisWithSource(),
|
||||
);
|
||||
|
||||
it("retains the complete Evidence before projecting its summary", () => {
|
||||
const retained = new Map<string, Evidence>();
|
||||
const summary = summarizeRetainedAnalysis(parent, {
|
||||
recordEvidence: (evidence) => {
|
||||
retained.set(evidence.evidence_id, evidence);
|
||||
return ok("added");
|
||||
},
|
||||
evidenceById: (evidenceId) => retained.get(evidenceId),
|
||||
});
|
||||
if (!summary.ok) throw summary.error;
|
||||
expect(retained.get(parent.evidence_id)).toBe(parent);
|
||||
expect(summary.value.evidence_links).toEqual([parent.evidence_id]);
|
||||
expect(summary.value.normalized_result).toMatchObject({
|
||||
kind: "summary",
|
||||
parent_evidence_id: parent.evidence_id,
|
||||
parent_operation: "analyze_javascript_application",
|
||||
});
|
||||
});
|
||||
|
||||
it("refuses a summary whose complete Evidence cannot be retained", () => {
|
||||
const unavailable = summarizeRetainedAnalysis(parent, {
|
||||
recordEvidence: undefined,
|
||||
evidenceById: undefined,
|
||||
});
|
||||
expect(unavailable.ok).toBe(false);
|
||||
if (unavailable.ok) return;
|
||||
expect(unavailable.error._tag).toBe("AnalysisCapabilityUnavailableError");
|
||||
expect(unavailable.error.userMessage).toContain("detail complete");
|
||||
|
||||
const conflict = new EvidenceIntegrityError("ledger conflict");
|
||||
expect(
|
||||
summarizeRetainedAnalysis(parent, {
|
||||
recordEvidence: () => err(conflict),
|
||||
evidenceById: () => parent,
|
||||
}),
|
||||
).toEqual(err(conflict));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user