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.
This commit is contained in:
morluto committed 2026-10-27 03:02:09 +08:00
1 parent bab49aaf7c
commit 7a237aa721
3 files changed
+27 -61

No files matched your search

@@ -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();
+10 -30
View File
@@ -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<typeof inventoryRecordSchema>;
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<object>();
const checkedStrings = new WeakSet<object>();
type InventoryRecord = z.infer<typeof inventoryRecordSchema>;
/** Cache only a successful, representation-preserving validation of owned immutable facts. */
const readRows = (
parent: AnalysisViewParent,
strings: boolean,
): Result<readonly InventoryRecord[], AnalysisError> => {
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,
+2 -31
View File
@@ -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<object, RustBinary>();
const parseReport = (
parent: AnalysisViewParent,
): Result<RustBinary, AnalysisError> => {
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,