diff --git a/src/domain/analysisView/analysisView.ts b/src/domain/analysisView/analysisView.ts index cfd24de9c0..07a97cb3fa 100644 --- a/src/domain/analysisView/analysisView.ts +++ b/src/domain/analysisView/analysisView.ts @@ -1,3 +1,4 @@ +import { analysisViewCoverageSchema } from "./analysisViewCoverage.js"; import { javaScriptRouteInventorySourceSchema, javaScriptRouteInventorySchema, @@ -480,14 +481,6 @@ export const inspectAnalysisViewInputSchema = z.strictObject({ view: analysisViewRequestSchema, }); -const coverageSchema = z.strictObject({ - status: z.enum(["complete-within-view", "page", "empty"]), - examined: z.int().nonnegative(), - total: z.int().nonnegative(), - next_offset: z.int().nonnegative().nullable(), - exhausted: z.boolean(), -}); - const artifactSchema = z.strictObject({ path: z .string() @@ -566,7 +559,7 @@ const viewResultBase = { parent_digest: digestSchema, view_digest: digestSchema, artifact: artifactSchema, - coverage: coverageSchema, + coverage: analysisViewCoverageSchema, limitations: z.array(z.string()), unknowns: z.array(z.string()), } as const; @@ -1432,7 +1425,6 @@ export type InspectAnalysisViewInput = z.output< typeof inspectAnalysisViewInputSchema >; export type AnalysisViewResult = z.output; -export type AnalysisViewCoverage = z.output; /** Parent record already resolved from inline Evidence or a session reference. */ export interface AnalysisViewParent { diff --git a/src/domain/analysisView/analysisViewCoverage.ts b/src/domain/analysisView/analysisViewCoverage.ts index c012568460..392c711095 100644 --- a/src/domain/analysisView/analysisViewCoverage.ts +++ b/src/domain/analysisView/analysisViewCoverage.ts @@ -1,5 +1,15 @@ import { uniqueSorted } from "../canonicalOrdering.js"; -import type { AnalysisViewCoverage } from "./analysisView.js"; +import { z } from "zod"; + +export const analysisViewCoverageSchema = z.strictObject({ + status: z.enum(["complete-within-view", "page", "empty"]), + examined: z.int().nonnegative(), + total: z.int().nonnegative(), + next_offset: z.int().nonnegative().nullable(), + exhausted: z.boolean(), +}); + +export type AnalysisViewCoverage = z.output; /** Coverage for a summary, facet, or single selected object. */ export const completeWithinViewCoverage = ( diff --git a/src/domain/analysisView/analysisViewText.ts b/src/domain/analysisView/analysisViewText.ts index 6c2fa8bfb9..3caff87ee4 100644 --- a/src/domain/analysisView/analysisViewText.ts +++ b/src/domain/analysisView/analysisViewText.ts @@ -1,8 +1,17 @@ import { analysisViewInputError } from "./analysisViewErrors.js"; import type { AnalysisError } from "../analysisErrorBase.js"; import { err, ok, type Result } from "../result.js"; -import type { AnalysisViewCoverage } from "./analysisView.js"; -import { pageViewCoverage } from "./analysisViewCoverage.js"; +import { z } from "zod"; +import { + pageViewCoverage, + type AnalysisViewCoverage, +} from "./analysisViewCoverage.js"; + +/** Exact text pages use UTF-16 code-unit offsets without splitting surrogate pairs. */ +export const analysisTextPageItemSchema = z.strictObject({ + text: z.string(), + unit: z.literal("utf16-code-units"), +}); const viewError = (message: string): AnalysisError => analysisViewInputError([ @@ -17,7 +26,7 @@ export const analysisTextPage = ( label = "Pseudocode", ): Result< { - readonly item: { readonly text: string; readonly unit: "utf16-code-units" }; + readonly item: Readonly>; readonly coverage: AnalysisViewCoverage; }, AnalysisError diff --git a/src/domain/analysisView/androidPackageView.ts b/src/domain/analysisView/androidPackageView.ts index 4a0c9b7da1..82bac05d34 100644 --- a/src/domain/analysisView/androidPackageView.ts +++ b/src/domain/analysisView/androidPackageView.ts @@ -10,7 +10,10 @@ import type { UnsignedAnalysisView, } from "./analysisView.js"; import { completeWithinViewCoverage } from "./analysisViewCoverage.js"; -import { analysisTextPage } from "./analysisViewText.js"; +import { + analysisTextPage, + analysisTextPageItemSchema, +} from "./analysisViewText.js"; const packageSchema = androidResultSchemas.inspect_android_package; @@ -30,9 +33,7 @@ export const androidViewRequestSchema = z.strictObject({ limit: z.int().positive(), }); -export const androidManifestViewItemSchema = z.strictObject({ - text: z.string(), - unit: z.literal("utf16-code-units"), +export const androidManifestViewItemSchema = analysisTextPageItemSchema.extend({ source_status: packageSchema.shape.manifest.shape.status, reported_total_bytes: packageSchema.shape.manifest.shape.reported_total_bytes, }); diff --git a/src/domain/analysisView/browserScenarioView.ts b/src/domain/analysisView/browserScenarioView.ts index 4b66c6bf82..a64363a275 100644 --- a/src/domain/analysisView/browserScenarioView.ts +++ b/src/domain/analysisView/browserScenarioView.ts @@ -11,10 +11,10 @@ import { analysisViewInputError } from "./analysisViewErrors.js"; import { completeWithinViewCoverage, pageViewCoverage, + type AnalysisViewCoverage, } from "./analysisViewCoverage.js"; import { createAnalysisViewResultReader } from "./analysisViewParent.js"; import type { - AnalysisViewCoverage, AnalysisViewParent, AnalysisViewRequest, UnsignedAnalysisView, diff --git a/src/domain/analysisView/evmInterfaceView.ts b/src/domain/analysisView/evmInterfaceView.ts index d8f89e9469..f16352307c 100644 --- a/src/domain/analysisView/evmInterfaceView.ts +++ b/src/domain/analysisView/evmInterfaceView.ts @@ -14,7 +14,10 @@ import { completeWithinViewCoverage, pageViewCoverage, } from "./analysisViewCoverage.js"; -import { analysisTextPage } from "./analysisViewText.js"; +import { + analysisTextPage, + analysisTextPageItemSchema, +} from "./analysisViewText.js"; /** Retained inferred candidates or exact text; offsets for text count UTF-16 code units. */ export const evmViewRequestSchema = z.strictObject({ @@ -26,7 +29,7 @@ export const evmViewRequestSchema = z.strictObject({ export const evmViewItemSchema = z.union([ evmInterfaceSchema.shape.functions, - z.strictObject({ text: z.string(), unit: z.literal("utf16-code-units") }), + analysisTextPageItemSchema, ]); /** Complete inferred interface facts without the unrequested hex or duplicated stdout. */ diff --git a/src/domain/analysisView/wasmArtifactView.ts b/src/domain/analysisView/wasmArtifactView.ts index ef62fac0a4..be1c0c6e8f 100644 --- a/src/domain/analysisView/wasmArtifactView.ts +++ b/src/domain/analysisView/wasmArtifactView.ts @@ -17,7 +17,10 @@ import { completeWithinViewCoverage, pageViewCoverage, } from "./analysisViewCoverage.js"; -import { analysisTextPage } from "./analysisViewText.js"; +import { + analysisTextPage, + analysisTextPageItemSchema, +} from "./analysisViewText.js"; /** Source forms and text from completed WASM Evidence; this never executes a VM. */ export const wasmViewRequestSchema = z.strictObject({ @@ -43,7 +46,7 @@ export const wasmViewItemSchema = z.union([ wasmArtifactSchema.shape.candidates, wasmArtifactSchema.shape.glue, wasmArtifactSchema.shape.tool_profile, - z.strictObject({ text: z.string(), unit: z.literal("utf16-code-units") }), + analysisTextPageItemSchema, ]); /** Counts are observations of the completed producer, independent of runtime semantics. */