From 7a237aa72144a7ee2198c7a0193b767d2285b989 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Tue, 27 Oct 2026 03:02:09 +0800 Subject: [PATCH] refactor(views): share immutable result readers Use the common analysis-view reader for Rust and native inventory validation, preserving historical defaults and original Evidence while retaining schema-specific validation. Validated 123 focused view and service tests and check:fast. --- .../analysisView/nativeInventoryView.test.ts | 15 +++++++ .../analysisView/nativeInventoryView.ts | 40 +++++-------------- src/domain/analysisView/rustBinaryView.ts | 33 +-------------- 3 files changed, 27 insertions(+), 61 deletions(-) diff --git a/src/domain/analysisView/nativeInventoryView.test.ts b/src/domain/analysisView/nativeInventoryView.test.ts index 80dafb012b..ed946415ca 100644 --- a/src/domain/analysisView/nativeInventoryView.test.ts +++ b/src/domain/analysisView/nativeInventoryView.test.ts @@ -96,6 +96,21 @@ it("reuses only authenticated immutable validation while rebinding provenance to }); }); +it("retains caller metadata in Evidence while reusing owner-normalized inventory rows", () => { + const original = [{ ...rows()[0]!, caller_metadata: { label: "keep me" } }]; + const source = parent(freezeJsonSnapshot(original)); + const parse = vi.spyOn(nativeInventoryRowsSchemas.names, "safeParse"); + for (let attempt = 0; attempt < 2; attempt++) { + const page = project(source, { kind: "native-inventory", limit: 1 }); + expect(page).toMatchObject({ + rows: [{ source_index: 0, record: rows()[0] }], + }); + } + expect(parse).toHaveBeenCalledOnce(); + expect(source.normalizedResult).toEqual(original); + expect(original[0]?.caller_metadata).toEqual({ label: "keep me" }); +}); + it("revalidates mutable and shallow-frozen arrays despite a forged sealing flag", () => { for (const shallowFreeze of [false, true]) { const values: unknown[] = rows(); diff --git a/src/domain/analysisView/nativeInventoryView.ts b/src/domain/analysisView/nativeInventoryView.ts index c10c86e300..f63a5958d0 100644 --- a/src/domain/analysisView/nativeInventoryView.ts +++ b/src/domain/analysisView/nativeInventoryView.ts @@ -1,6 +1,5 @@ import { z } from "zod"; import { analysisStringSchema } from "../hopperValues.js"; -import { canBorrowParsedJsonSnapshot } from "../immutableJson.js"; import { jsonValueSchema } from "../jsonValue.js"; import { addressedValueSchema, @@ -15,7 +14,7 @@ import type { UnsignedAnalysisView, } from "./analysisView.js"; import { analysisViewInputError } from "./analysisViewErrors.js"; -import { parseAnalysisViewResult } from "./analysisViewParent.js"; +import { createAnalysisViewResultReader } from "./analysisViewParent.js"; import { boundedViewMessages, completeWithinViewCoverage, @@ -31,6 +30,7 @@ const inventoryRecordSchema = addressedValueSchema.extend({ addressedValueSchema.shape.string, ]), }); +type InventoryRecord = z.infer; const fieldSchema = inventoryRecordSchema.keyof(); export const nativeInventoryViewRequestSchema = z.strictObject({ @@ -58,32 +58,12 @@ export const nativeInventorySummarySchema = z.strictObject({ selectable_fields: z.array(fieldSchema), }); -const checkedNames = new WeakSet(); -const checkedStrings = new WeakSet(); -type InventoryRecord = z.infer; - -/** Cache only a successful, representation-preserving validation of owned immutable facts. */ -const readRows = ( - parent: AnalysisViewParent, - strings: boolean, -): Result => { - const checked = strings ? checkedStrings : checkedNames; - const source = parent.normalizedResult; - if (Array.isArray(source) && checked.has(source)) return ok(source); - const parsed = strings - ? parseAnalysisViewResult(nativeInventoryRowsSchemas.strings, parent) - : parseAnalysisViewResult(nativeInventoryRowsSchemas.names, parent); - if (!parsed.ok) return parsed; - if ( - Array.isArray(source) && - parent.sealedResult === true && - canBorrowParsedJsonSnapshot(source, parsed.value) - ) { - checked.add(source); - return ok(source as readonly InventoryRecord[]); - } - return parsed; -}; +const readNames = createAnalysisViewResultReader( + nativeInventoryRowsSchemas.names, +); +const readStrings = createAnalysisViewResultReader( + nativeInventoryRowsSchemas.strings, +); /** Project already completed provider observations without another provider read or sort. */ export const projectNativeInventoryView = ( @@ -107,9 +87,9 @@ export const projectNativeInventoryView = ( const strings = parent.operation === "list_strings" || parent.operation === "search_strings"; - const parsed = readRows(parent, strings); + const parsed = strings ? readStrings(parent) : readNames(parent); if (!parsed.ok) return parsed; - const rows = parsed.value; + const rows: readonly InventoryRecord[] = parsed.value; const shared = { parent_evidence_id: parent.evidenceId, parent_operation: parent.operation, diff --git a/src/domain/analysisView/rustBinaryView.ts b/src/domain/analysisView/rustBinaryView.ts index c2ada29cad..cb3c9dfb71 100644 --- a/src/domain/analysisView/rustBinaryView.ts +++ b/src/domain/analysisView/rustBinaryView.ts @@ -8,11 +8,6 @@ import { rustcCommitSchema, type RustBinary, } from "../rust/rustBinary.js"; -import { - canBorrowParsedJsonSnapshot, - freezeOwnedJsonTreeSnapshot, - isImmutableJsonSnapshot, -} from "../immutableJson.js"; import { err, ok, type Result } from "../result.js"; import type { AnalysisViewParent, @@ -25,7 +20,7 @@ import { pageViewCoverage, } from "./analysisViewCoverage.js"; import { analysisViewInputError } from "./analysisViewErrors.js"; -import { parseAnalysisViewResult } from "./analysisViewParent.js"; +import { createAnalysisViewResultReader } from "./analysisViewParent.js"; import { selectViewRows } from "./selectViewRows.js"; const count = z.number().int().nonnegative(); @@ -63,31 +58,7 @@ export const rustBinaryViewContextSchema = z.strictObject({ }), }); -// Exact immutable Evidence identity, not a path or a live-file result cache. -// Mutable/merely frozen imports are validated normally; no failures are cached. -const checkedReports = new WeakMap(); -const parseReport = ( - parent: AnalysisViewParent, -): Result => { - const key = parent.normalizedResult; - const reusable = - parent.sealedResult === true && - typeof key === "object" && - key !== null && - isImmutableJsonSnapshot(key); - const known = reusable ? checkedReports.get(key) : undefined; - if (known !== undefined) return ok(known); - const parsed = parseAnalysisViewResult(rustBinarySchema, parent); - if (!parsed.ok) return parsed; - if (reusable) { - const report = canBorrowParsedJsonSnapshot(key, parsed.value) - ? key - : freezeOwnedJsonTreeSnapshot(parsed.value); - checkedReports.set(key, report); - return ok(report); - } - return parsed; -}; +const parseReport = createAnalysisViewResultReader(rustBinarySchema); const summarize = ( report: RustBinary,