diff --git a/docs/adr/0003-managed-code-evidence-and-provider-boundary.md b/docs/adr/0003-managed-code-evidence-and-provider-boundary.md index 13c0e6c0ef..aad482df55 100644 --- a/docs/adr/0003-managed-code-evidence-and-provider-boundary.md +++ b/docs/adr/0003-managed-code-evidence-and-provider-boundary.md @@ -218,7 +218,7 @@ declaring type + normalized CLI signature build-local metadata token RVA/file extent when present raw CIL byte length + SHA-256 when the body is admitted -member-result schema version + decoded-instruction-tuple SHA-256 when CIL is valid +decoded-instruction-tuple SHA-256 when CIL is valid separate max-stack, locals-token, and exception-region observations ``` @@ -232,9 +232,8 @@ The caller-visible field remains named `normalized_il_sha256`, but its shipped v1 meaning is deliberately narrower than a canonical semantic CIL identity. For a completely decoded method, REA serializes the instruction-order array of `[opcode, operand_kind, operand]` tuples with JavaScript `JSON.stringify`, -encodes that text as UTF-8, and reports its lowercase SHA-256. The member -result's `schema_version: 1` scopes this convention; there is no independent -normalized-CIL algorithm-version field in v1. +encodes that text as UTF-8, and reports its lowercase SHA-256. The tuple +projection is defined here; the member result carries no schema-version field. Operands retain the current decoder projection: metadata and user-string operands are build-local lowercase hexadecimal tokens, scalar branch operands @@ -258,8 +257,8 @@ normalized-CIL schema. Metadata tokens are reported because they are precise coordinates inside one module. Cross-version identity never consists of a token alone. A structural -match cites both build commitments, both local tokens, the v1 tuple inputs, the -member-result schema version, and all competing candidates. V1 cannot cite a +match cites both build commitments, both local tokens, the v1 tuple inputs, and +all competing candidates. V1 cannot cite a separate matching-algorithm version because none is exposed. ### 5. Separate five evidence layers diff --git a/docs/managed-code-analysis.md b/docs/managed-code-analysis.md index d504a66674..88b0b5ea5c 100644 --- a/docs/managed-code-analysis.md +++ b/docs/managed-code-analysis.md @@ -121,8 +121,8 @@ boundaries: The normalized field is available only when the entire CIL stream decodes with status `present`. A partial, malformed, absent, or over-limit body reports -`null`. The containing member result's `schema_version: 1` scopes the tuple -format; v1 does not expose a separate algorithm-version field. +`null`. The tuple format is defined here and does not add a schema-version field +to the member result. Tuple operands use these exact projections: @@ -220,7 +220,7 @@ Cross-version matching is two-stage: 1. Exact identity requires compatible artifact/module commitments and exact raw CIL identity; v1 does not expose a standalone complete-method-body digest. -2. Structural identity compares schema-versioned signatures, the limited v1 +2. Structural identity compares normalized signatures, the limited v1 decoded-CIL tuple fingerprint, constants, and bounded shape context. It reports all candidates at the winning score and remains ambiguous when the evidence does not distinguish them. The v1 digest does not itself remap @@ -327,7 +327,6 @@ absolute or relative to the manifest file. A compact manifest contains: ```json { - "schema_version": 1, "label": "operator-local osu!stable semantic slice", "target": { "path": "./osu!.exe", diff --git a/docs/reconstruction-obligation-ledgers.md b/docs/reconstruction-obligation-ledgers.md index 886527416c..ffb0b9999c 100644 --- a/docs/reconstruction-obligation-ledgers.md +++ b/docs/reconstruction-obligation-ledgers.md @@ -39,9 +39,7 @@ rea build-reconstruction-obligation-ledger \ "manifest": { "bindings": [], "contradictions": [] - }, - "limits": { "max_obligations": 100 }, - "page": { "offset": 0, "limit": 50 } + } }' \ --json ``` @@ -322,8 +320,6 @@ close a `packaged-process` obligation. A static-only source cannot close a runtime or process claim. Marking a claim `blocked` or `out-of-scope` records the disposition but does not silently count it as verified. -Pagination changes only `page` and the returned `obligations` slice. Every page -retains the same `ledger_id`, `closure_digest`, full-ledger summaries, reports, -ownership graph, dependency graph, Evidence links, and limitations. Consumers -should follow `next_offset` until it is `null`, and should reject pages whose -identity or closure digest changes mid-read. +The tool returns every obligation inline. Its `ledger_id` and `closure_digest` +identify the complete result, including summaries, reports, ownership and +dependency graphs, Evidence links, and limitations. diff --git a/docs/verification/managed-conformance-ledger.json b/docs/verification/managed-conformance-ledger.json index e324782268..fb714a0f8c 100644 --- a/docs/verification/managed-conformance-ledger.json +++ b/docs/verification/managed-conformance-ledger.json @@ -1,103 +1,102 @@ { - "schema_version": 1, - "ledger_id": "ecl_2d5c1c83c1fd56615a663bcb3a432b7023afa316133b744c64dcaa659cab53c0", + "ledger_id": "ecl_578e5853b332ae050e69dc1a2c72fc98be527371311d6a98a9ae3bf28a24fa6c", "records": [ { "claim_id": "managed.application-graph-projection", "status": "pass", "evidence_ids": [ - "ev_0c73f33f51048a7c7cc5d908cb951512ee9f3d9dcf4124f0f0eb2c4a88ceb7cc" + "ev_a09c9014515baea9a709c1d5c0ae32d343a1f1b6e4da498ce5afe14eaab0ddbb" ] }, { "claim_id": "managed.decompiler-reconstruction-import", "status": "pass", "evidence_ids": [ - "ev_0504a7fc4cc8f77ca07a3aa59d62830b5769c7b41e7518677771fe7aa54c7b5d" + "ev_14052dcba244a91019c042feae78440d800570dde163c991931d9c09b7e6bbdd" ] }, { "claim_id": "managed.dotnet-framework-x86-pinvoke", "status": "pass", "evidence_ids": [ - "ev_9b63cdeef9d48e567dc8f4de9fe6b424e94929ac1f17aafd0ef1807775f72d96" + "ev_c11aa40e3fbc2de8bb11d6b5783ee3a74d4d79fe16ea7f6ddd85d4b253c6d769" ] }, { "claim_id": "managed.ilspy-reconstruction-oracle", "status": "unsupported", "evidence_ids": [ - "ev_4e3fbc7203c29aab5d9119332a09c14e285e85007b3d7fc7433880b39a507435" + "ev_76ca183c167d63e6c58b65e2f9b3bef3e569669dc66abb0b8b850948878a70e3" ] }, { "claim_id": "managed.malformed-metadata", "status": "pass", "evidence_ids": [ - "ev_dbd885adc65f9cc8abacb04642db609d2180b0af71adc0b0732719f06a057063" + "ev_99e1185da1fcbf1330b4b86beca27e0abeef10f95870b1982da39827278e16e8" ] }, { "claim_id": "managed.managed-native-verification", "status": "pass", "evidence_ids": [ - "ev_e7841bf63d7b83804987d21f4f432752870ff7338862360bbcf54653eb782731" + "ev_9d1c5bc641c0da1551c8fbae4507d7719847cfb40edf73c13e2bdf5fb670ec9e" ] }, { "claim_id": "managed.modern-dotnet-anycpu", "status": "pass", "evidence_ids": [ - "ev_9593b026617002c64d0618ec079d42dbc0ddeef7cd53f2f8b2c8fca9ffebb2a9" + "ev_7f959cb9642a2c52da0cce0d3c9c888b889240ee7697c5fdb5390d7578634782" ] }, { "claim_id": "managed.mvid-and-token-drift", "status": "pass", "evidence_ids": [ - "ev_ba32694a35810acd211745efdf41c88887f4931efb6027e876eea3e8e506aee0" + "ev_dd6c3e3fbe115f1b9b38ee06f720d5efb7dd6ef693a1b9555e9ff73babdaea9f" ] }, { "claim_id": "managed.not-managed", "status": "pass", "evidence_ids": [ - "ev_ac700cf6c8efdda7f689b29a9c3d5a679ecb24893f93bb1c76e50e23b2b9dcbb" + "ev_ca183a8f4159136df29d9d5e44a88239c996d6e758b71ad023289871875a9367" ] }, { "claim_id": "managed.operator-local-manifest", "status": "unsupported", "evidence_ids": [ - "ev_f96f07bc28f2e6da5a71597f9a38f5eaa7cde0217f0df10d6ef6d655937fc1a2" + "ev_4173365e113f71b28fd1f3f1c583557a487e36ec6a6d0e63b1249eb7a4334b8c" ] }, { "claim_id": "managed.operator-manifest-self-test", "status": "pass", "evidence_ids": [ - "ev_ed0f3ff1749f0927d493609423a366ec6a432f016c767aeeedd9b4a520672eaf" + "ev_063c68b649379811e56c7788ab6b01891f1dd78abfe3008c6bf06a1c0727a095" ] }, { "claim_id": "managed.runtime-correlation-admission-plan", "status": "pass", "evidence_ids": [ - "ev_24a622e16a885e2d21025f51c3f4b5900719c21d9f0d04ba1d55f6093a702c20" + "ev_530ff114b2f05f85b6baeaa56df60a60a927f1de3b07bbbe86aa462faad71772" ] }, { "claim_id": "managed.unicode-obfuscated-identifiers", "status": "pass", "evidence_ids": [ - "ev_2e9bc5213917635c3eb3d094449adf088c450c07d078dcb26312182c04966bc9" + "ev_17f9013d5ce058be847c1f3efec19688c268fa2feecf974bbc18428cd87144e5" ] }, { "claim_id": "managed.x64-ready-to-run-native-body", "status": "pass", "evidence_ids": [ - "ev_bbf3dd8daec6d46d16ac7befc3875572e7103b27b815f81903e3dca61880c70b" + "ev_60dc353ad66b83ee50163ab55fb0f4c7caefd06e08ccc2e0ebb5d2a7a23cb55b" ] } ], diff --git a/docs/verification/managed-conformance-manifest.json b/docs/verification/managed-conformance-manifest.json index d3fd13858e..b273841438 100644 --- a/docs/verification/managed-conformance-manifest.json +++ b/docs/verification/managed-conformance-manifest.json @@ -1,6 +1,5 @@ { - "schema_version": 1, - "manifest_id": "ecm_3a42d32a96315338e06700b64afc0367603e2c5050b1ec0bf1ce012e227b4df3", + "manifest_id": "ecm_0f98c38501954b90ff9f949f1ee9a0b550061347cf92780cfb1b14ccef5131f7", "verifier": { "id": "rea-managed-conformance", "version": "1" @@ -14,7 +13,7 @@ "skill_digests": [ { "skill_id": "reverse-engineer-anything", - "sha256": "89b09782340415790ecf161a5bc33f60e1a23cd66e0f4c29dd26e959b2baa0a9" + "sha256": "b78dbf9a5f0db15415f03dccab71bfb2d133900ab061e37825f55f3b7f0f80bc" } ], "claims": [ @@ -30,8 +29,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.decompiler-reconstruction-import", @@ -45,8 +43,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.dotnet-framework-x86-pinvoke", @@ -60,8 +57,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.ilspy-reconstruction-oracle", @@ -73,8 +69,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.malformed-metadata", @@ -88,8 +83,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.managed-native-verification", @@ -104,8 +98,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.modern-dotnet-anycpu", @@ -119,8 +112,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.mvid-and-token-drift", @@ -135,8 +127,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.not-managed", @@ -150,8 +141,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.operator-local-manifest", @@ -163,8 +153,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.operator-manifest-self-test", @@ -178,8 +167,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.runtime-correlation-admission-plan", @@ -193,8 +181,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.unicode-obfuscated-identifiers", @@ -208,8 +195,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } }, { "claim_id": "managed.x64-ready-to-run-native-body", @@ -223,8 +209,7 @@ "provider": { "id": "rea-managed-conformance", "version": "1" - }, - "result_schema_version": 1 + } } ] } diff --git a/docs/windows-ghidra-p0.md b/docs/windows-ghidra-p0.md index b93537e684..0c80ee2093 100644 --- a/docs/windows-ghidra-p0.md +++ b/docs/windows-ghidra-p0.md @@ -95,8 +95,8 @@ and no verified no-follow equivalent for every path component. Linux continues to use a mode-restricted Unix socket. Windows uses a Java listener bound to `127.0.0.1` on an ephemeral port. The bridge atomically -publishes a bounded endpoint record containing only schema version, literal -loopback host, and port. The random 256-bit request token remains only in the +publishes a bounded endpoint record containing only the literal loopback host +and port. The random 256-bit request token remains only in the ephemeral session descriptor and every request is authenticated. `analyzeHeadless.bat` is invoked through an absolute `cmd.exe` with a fixed diff --git a/scripts/hopper-demo-x11.py b/scripts/hopper-demo-x11.py index 74ce9e57e0..8aa5b03ac7 100644 --- a/scripts/hopper-demo-x11.py +++ b/scripts/hopper-demo-x11.py @@ -291,7 +291,6 @@ def diagnostic( (0, False, "") if capture is None else capture.snapshot() ) return { - "schema_version": 1, "component": "hopper_private_display", "operation": operation, "status": status, diff --git a/scripts/lib/browser-scenario-verifier.mjs b/scripts/lib/browser-scenario-verifier.mjs index 0896572428..e09adf514a 100644 --- a/scripts/lib/browser-scenario-verifier.mjs +++ b/scripts/lib/browser-scenario-verifier.mjs @@ -42,7 +42,6 @@ const duplicateOriginStorage = (origin) => ({ /** Build the source-owned full-capture browser scenario. */ export function browserScenario(browser, origin) { return browserScenarioSchema.parse({ - schema_version: 1, browser, start_url: { url: `${origin}/app`, query: [] }, allowed_origins: [origin], diff --git a/scripts/lib/managed-completion-report.mjs b/scripts/lib/managed-completion-report.mjs index b5e9aad04d..3ad9e66fe0 100644 --- a/scripts/lib/managed-completion-report.mjs +++ b/scripts/lib/managed-completion-report.mjs @@ -22,7 +22,6 @@ const completionClaim = ({ parameters: { scenario_id: scenarioId, scenario_version: 1, - result_schema_version: 1, artifact_sha256s: artifactSha256s, }, result: { status }, @@ -37,7 +36,6 @@ const completionClaim = ({ id: COMPLETION_PROVIDER.id, version: COMPLETION_PROVIDER.version, }, - result_schema_version: 1, status, evidence_ids: [evidence.evidence_id], }; @@ -151,7 +149,6 @@ const optionalClaims = ({ operatorManifest, ilspyOracle }) => [ /** Project completed managed assertions into the standard verifier report. */ export const createManagedCompletionReport = (input, verifierRun) => ({ - schema_version: 1, verifier: { id: COMPLETION_PROVIDER.id, version: COMPLETION_PROVIDER.version, diff --git a/scripts/lib/managed-conformance-manifest-parser.mjs b/scripts/lib/managed-conformance-manifest-parser.mjs index c007568587..0461eea9a9 100644 --- a/scripts/lib/managed-conformance-manifest-parser.mjs +++ b/scripts/lib/managed-conformance-manifest-parser.mjs @@ -1,14 +1,9 @@ export function parseManagedAppManifest(rawManifest) { const manifest = object(rawManifest, "manifest"); - ensure( - manifest.schema_version === 1, - "manifest.schema_version must be exactly 1", - ); const target = object(manifest.target, "manifest.target"); const methods = array(manifest.methods, "manifest.methods"); ensure(manifest.methods.length > 0, "manifest.methods must not be empty"); return { - schema_version: 1, label: optionalString(manifest.label, "manifest.label"), target: { path: string(target.path, "manifest.target.path"), diff --git a/scripts/lib/managed-conformance-oracles.mjs b/scripts/lib/managed-conformance-oracles.mjs index ba73622fc3..7181ccbe1e 100644 --- a/scripts/lib/managed-conformance-oracles.mjs +++ b/scripts/lib/managed-conformance-oracles.mjs @@ -43,7 +43,6 @@ async function runManagedAppManifestSelfTest(context) { assert.ok(method); const summary = await context.verifyManagedAppManifest( { - schema_version: 1, label: "source-owned manifest verifier self-test", target: { path: sample.path, diff --git a/scripts/lib/verifier-run.d.mts b/scripts/lib/verifier-run.d.mts index d385d45824..1e9d41324f 100644 --- a/scripts/lib/verifier-run.d.mts +++ b/scripts/lib/verifier-run.d.mts @@ -1,5 +1,4 @@ export interface VerifierRunStart { - readonly schema_version: 1; readonly run_id: string; readonly verifier_pid: number; readonly parent_pid: number; @@ -14,7 +13,6 @@ export interface VerifierRunDescendant { export type VerifierProcessLineage = | { readonly status: "verified"; - readonly schema_version: 1; readonly observed_at: string; readonly launcher_pid: number; readonly launcher_parent_pid: number; diff --git a/scripts/lib/verifier-run.mjs b/scripts/lib/verifier-run.mjs index 54175c1c80..c3e0d2c28a 100644 --- a/scripts/lib/verifier-run.mjs +++ b/scripts/lib/verifier-run.mjs @@ -11,7 +11,6 @@ export const createVerifierRun = () => { return activeVerifierRun; } activeVerifierRun = Object.freeze({ - schema_version: 1, run_id: randomUUID(), verifier_pid: process.pid, parent_pid: process.ppid, @@ -85,7 +84,6 @@ const observeVerifierLineage = async (run, observedAt) => { } return { status: "verified", - schema_version: 1, observed_at: observedAt, launcher_pid: run.verifier_pid, launcher_parent_pid: run.parent_pid, diff --git a/scripts/verify-package-discovery.mjs b/scripts/verify-package-discovery.mjs index 91f7abb250..f404b7915c 100644 --- a/scripts/verify-package-discovery.mjs +++ b/scripts/verify-package-discovery.mjs @@ -5,7 +5,6 @@ const REQUIRED_HELP_COMMANDS = [ "upgrade", "inventory-artifact", "extract-artifact", - "investigate-versions", "import-reference-source", "list-browser-targets", "inspect-web-page", diff --git a/scripts/verify-real-electron.mjs b/scripts/verify-real-electron.mjs index e61e486e5d..be29475ed6 100644 --- a/scripts/verify-real-electron.mjs +++ b/scripts/verify-real-electron.mjs @@ -20,7 +20,6 @@ const applicationRoot = const applicationPath = process.env.REA_ELECTRON_APPLICATION_PATH ?? join(applicationRoot, "main.js"); const input = electronActiveObservationInputSchema.parse({ - schema_version: 1, executable_path: executable, application_path: applicationPath, application_root: applicationRoot, diff --git a/scripts/verify-real-javascript-runtime-observation.mjs b/scripts/verify-real-javascript-runtime-observation.mjs index 4d01f02ccb..8332fddac0 100644 --- a/scripts/verify-real-javascript-runtime-observation.mjs +++ b/scripts/verify-real-javascript-runtime-observation.mjs @@ -71,7 +71,6 @@ try { throw new Error("Real Node Inspector capture was incomplete"); process.stdout.write( `${JSON.stringify({ - schema_version: 1, status: "pass", provider: observed.provider.id, target_id: target.target_id, diff --git a/scripts/verify-reconstruction-readiness.mjs b/scripts/verify-reconstruction-readiness.mjs index 41a30df9ec..775d328a6c 100644 --- a/scripts/verify-reconstruction-readiness.mjs +++ b/scripts/verify-reconstruction-readiness.mjs @@ -157,7 +157,6 @@ try { process.stdout.write( `${JSON.stringify({ - schema_version: 1, status: cliReport.status, report_id: cliReport.report_id, report_digest: cliReport.report_digest, diff --git a/skills/reverse-engineer-anything/SKILL.md b/skills/reverse-engineer-anything/SKILL.md index 855c05ea7f..826c6f89f8 100644 --- a/skills/reverse-engineer-anything/SKILL.md +++ b/skills/reverse-engineer-anything/SKILL.md @@ -4,7 +4,7 @@ description: Reverse engineer native, managed, Electron/JavaScript, packaged, an metadata: version: "23" tool_count: 115 - catalog_digest: "94f7cd1ac629a6bbffa77ba3b3d3f2e208e15df821bc0b14db4f81692d6f8eaa" + catalog_digest: "85d3e5545b3e01eb22b67a1794fdcb737654a1abbea803e1f2445815ee4f17ff" --- # REA diff --git a/src/application/AnalysisProviderRegistry.test.ts b/src/application/AnalysisProviderRegistry.test.ts index cde5d7c15b..333a57b8c3 100644 --- a/src/application/AnalysisProviderRegistry.test.ts +++ b/src/application/AnalysisProviderRegistry.test.ts @@ -396,8 +396,6 @@ const capability = (provider: ProviderIdentity): CapabilityDescriptor => ({ operation: "address_name", available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: true, @@ -407,7 +405,6 @@ const capability = (provider: ProviderIdentity): CapabilityDescriptor => ({ changesPermissions: false, requiresRoot: false, }, - limits: { maxResults: null, maxPayloadBytes: 1_000, timeoutMs: 1_000 }, limitations: [], }); diff --git a/src/application/ApplicationWorkflowEvidenceResolver.ts b/src/application/ApplicationWorkflowEvidenceResolver.ts index 9050fb003b..ecab092a3f 100644 --- a/src/application/ApplicationWorkflowEvidenceResolver.ts +++ b/src/application/ApplicationWorkflowEvidenceResolver.ts @@ -161,7 +161,6 @@ export const resolveCompareApplicationVersionsRequestValidated = ( ...input.right_native_observations, ...rightNative.value, ], - limits: input.limits, ...(input.unknown_registry_approved === undefined ? {} : { unknown_registry_approved: input.unknown_registry_approved }), @@ -241,7 +240,6 @@ export const resolveCompareJavaScriptExportShapesRequestValidated = ( left_export_name: input.left_export_name, right_module_path: input.right_module_path, right_export_name: input.right_export_name, - limits: input.limits, ...(input.unknown_registry_approved === undefined ? {} : { unknown_registry_approved: input.unknown_registry_approved }), diff --git a/src/application/EvidenceBundleCommands.ts b/src/application/EvidenceBundleCommands.ts index 547abcb83e..d780e51354 100644 --- a/src/application/EvidenceBundleCommands.ts +++ b/src/application/EvidenceBundleCommands.ts @@ -53,8 +53,6 @@ export const exportEvidenceBundleCommand = async ( export const compareEvidenceBundlesCommand = async (input: { readonly leftPath: string; readonly rightPath: string; - readonly offset: number; - readonly limit: number; readonly policy: EvidenceFilePolicy; }): Promise> => { const [left, right] = await Promise.all([ @@ -64,11 +62,7 @@ export const compareEvidenceBundlesCommand = async (input: { if (!left.ok) return left; if (!right.ok) return right; try { - return ok( - jsonValueSchema.parse( - compareBundles(left.value, right.value, [], input.offset, input.limit), - ), - ); + return ok(jsonValueSchema.parse(compareBundles(left.value, right.value))); } catch (cause: unknown) { return err( new EvidenceIntegrityError("Evidence bundle comparison failed", { diff --git a/src/application/JavaScriptApplicationWorkflowService.ts b/src/application/JavaScriptApplicationWorkflowService.ts index 4a98acd794..aa31d7d810 100644 --- a/src/application/JavaScriptApplicationWorkflowService.ts +++ b/src/application/JavaScriptApplicationWorkflowService.ts @@ -119,9 +119,9 @@ export const compareApplicationVersionsEvidenceValidated = ( rootArtifactSha256: right.rootArtifactSha256, graph: right.graph, }, + limits: input.limits, leftNativeEvidence: leftNative, rightNativeEvidence: rightNative, - limits: input.limits, }); return ok( createApplicationVersionComparisonEvidence( @@ -214,7 +214,6 @@ export const compareJavaScriptExportShapesEvidenceValidated = ( modulePath: input.right_module_path, exportName: input.right_export_name, }, - limits: input.limits, }); return ok( createJavaScriptExportShapeComparisonEvidence( @@ -225,7 +224,6 @@ export const compareJavaScriptExportShapesEvidenceValidated = ( left_export_name: input.left_export_name, right_module_path: input.right_module_path, right_export_name: input.right_export_name, - limits: input.limits, }, result, ), diff --git a/src/application/JavaScriptReplayPlanning.ts b/src/application/JavaScriptReplayPlanning.ts index 336e3851f0..1752d10836 100644 --- a/src/application/JavaScriptReplayPlanning.ts +++ b/src/application/JavaScriptReplayPlanning.ts @@ -125,7 +125,6 @@ export const prepareReplayPlan = async ( : prepareSide(input.right, input.limits.module_bytes, host), ]); const withoutDigest = { - schema_version: 1 as const, policy_version: REPLAY_POLICY_VERSION, policy_sha256: digestJson(REPLAY_POLICY_DOCUMENT), network: "none" as const, diff --git a/src/application/JavaScriptReplayService.ts b/src/application/JavaScriptReplayService.ts index 5c7644250c..57e8af830f 100644 --- a/src/application/JavaScriptReplayService.ts +++ b/src/application/JavaScriptReplayService.ts @@ -310,7 +310,6 @@ const applyReproducerExport = async ( return executed; const manifest = { - schema_version: 1, plan: prepared.publicPlan, result: executed, sources: exportContext.includeSources diff --git a/src/application/JavaScriptSemanticGraphBuilder.test.ts b/src/application/JavaScriptSemanticGraphBuilder.test.ts index 64ac9456db..d32920dfb2 100644 --- a/src/application/JavaScriptSemanticGraphBuilder.test.ts +++ b/src/application/JavaScriptSemanticGraphBuilder.test.ts @@ -54,7 +54,7 @@ it("projects closure and direct interprocedural flow without execution", () => { ); }); -it("keeps dynamic calls explicit and returns bounded deterministic pages", () => { +it("keeps dynamic calls explicit and returns complete deterministic results", () => { const graph = graphFor(` const handlers = { ready() { return 1; } }; const key = process.argv[2]; @@ -73,21 +73,11 @@ it("keeps dynamic calls explicit and returns bounded deterministic pages", () => seed: { kind: "semantic-node", node_id: seedNodeId }, direction: "forward-influence", include_ambiguous_dynamic_edges: true, - limits: { - max_seed_matches: 25, - max_nodes: 2_000, - max_edges: 4_000, - max_depth: 12, - max_functions: 500, - max_modules: 500, - page_size: 1, - }, }); const repeated = queryJavaScriptSemanticGraph(graph, { seed: { kind: "semantic-node", node_id: seedNodeId }, direction: "forward-influence", include_ambiguous_dynamic_edges: true, - limits: first.applied_limits, }); expect(repeated).toEqual(first); }); diff --git a/src/application/JavaScriptSemanticTraceService.ts b/src/application/JavaScriptSemanticTraceService.ts index d776b22aea..baa5f54ac0 100644 --- a/src/application/JavaScriptSemanticTraceService.ts +++ b/src/application/JavaScriptSemanticTraceService.ts @@ -8,7 +8,6 @@ import { import type { Evidence } from "../domain/evidence.js"; import { jsonValueSchema } from "../domain/jsonValue.js"; import { queryJavaScriptSemanticGraph } from "../domain/javascriptSemanticQuery.js"; -import { JavaScriptSemanticQueryCursorError } from "../domain/javascriptSemanticQueryIdentity.js"; import { javaScriptSemanticTraceResultSchema, traceJavaScriptSemanticsInputSchema, @@ -55,16 +54,6 @@ export const traceJavaScriptSemanticsEvidenceValidated = ( ), ); } catch (cause: unknown) { - if (cause instanceof JavaScriptSemanticQueryCursorError) - return err( - new AnalysisInputError(OPERATION, undefined, [ - { - path: ["query", "cursor"], - reason: "invalid_value", - expected: "a cursor returned by the same graph, query, and limits", - }, - ]), - ); return err( new AnalysisProtocolError("JavaScript semantic trace failed", { cause }), ); diff --git a/src/application/NodeRuntimeCharacterizationService.ts b/src/application/NodeRuntimeCharacterizationService.ts index 34a738c627..96fa7bbb86 100644 --- a/src/application/NodeRuntimeCharacterizationService.ts +++ b/src/application/NodeRuntimeCharacterizationService.ts @@ -284,7 +284,6 @@ const createCharacterizationPlan = ( replayPlan: ReplayPlan, ): RuntimeCharacterizationPlan => createRuntimeCharacterizationPlan({ - schema_version: 1, preparation_sha256: digestPreparation( instrumentation.manifest.instrumented_sha256, replayPlan.plan_digest, diff --git a/src/application/ReconstructionObligationLedger.authority.test.ts b/src/application/ReconstructionObligationLedger.authority.test.ts index 216884e2fd..740481f401 100644 --- a/src/application/ReconstructionObligationLedger.authority.test.ts +++ b/src/application/ReconstructionObligationLedger.authority.test.ts @@ -11,9 +11,9 @@ import { createEvidenceBundle } from "../domain/evidenceBundle.js"; import { jsonValueSchema } from "../domain/jsonValue.js"; import { processCaptureSchema } from "../domain/processCapture.js"; import { - reconstructionObligationLedgerPageSchema, + reconstructionObligationLedgerSchema, type ReconstructionObligationLedgerInput, - type ReconstructionObligationLedgerPage, + type ReconstructionObligationLedger, type ReviewedReconstructionObligation, } from "../domain/reconstructionObligationLedgerSchemas.js"; @@ -81,26 +81,25 @@ const request = ( evidence_bundle: createEvidenceBundle(records), reviewed_obligations: [], manifest: { bindings: [], contradictions: [] }, - page: { offset: 0, limit: 50 }, ...overrides, }); const build = ( input: ReconstructionObligationLedgerInput, -): ReconstructionObligationLedgerPage => { +): ReconstructionObligationLedger => { const parsed = resolveReconstructionObligationLedgerRequest(input); if (!parsed.ok) throw parsed.error; const result = buildReconstructionObligationLedgerEvidenceValidated( parsed.value, ); if (!result.ok) throw result.error; - return reconstructionObligationLedgerPageSchema.parse( + return reconstructionObligationLedgerSchema.parse( result.value.normalized_result, ); }; const originalCases = ( - obligation: ReconstructionObligationLedgerPage["obligations"][number], + obligation: ReconstructionObligationLedger["obligations"][number], evidenceId: string, ) => obligation.required_case_kinds.map((caseKind) => ({ diff --git a/src/application/ReconstructionObligationLedger.closure.test.ts b/src/application/ReconstructionObligationLedger.closure.test.ts index da3b51fe91..ce1e07b3c6 100644 --- a/src/application/ReconstructionObligationLedger.closure.test.ts +++ b/src/application/ReconstructionObligationLedger.closure.test.ts @@ -11,10 +11,10 @@ import { createEvidenceBundle } from "../domain/evidenceBundle.js"; import { jsonValueSchema } from "../domain/jsonValue.js"; import { processCaptureSchema } from "../domain/processCapture.js"; import { - reconstructionObligationLedgerPageSchema, + reconstructionObligationLedgerSchema, serializeReconstructionObligationLedger, type ReconstructionObligationLedgerInput, - type ReconstructionObligationLedgerPage, + type ReconstructionObligationLedger, type ReviewedReconstructionObligation, } from "../domain/reconstructionObligationLedgerSchemas.js"; @@ -82,36 +82,25 @@ const request = ( evidence_bundle: createEvidenceBundle(records), reviewed_obligations: [], manifest: { bindings: [], contradictions: [] }, - page: { offset: 0, limit: 50 }, ...overrides, }); const build = ( input: ReconstructionObligationLedgerInput, -): ReconstructionObligationLedgerPage => { +): ReconstructionObligationLedger => { const parsed = resolveReconstructionObligationLedgerRequest(input); if (!parsed.ok) throw parsed.error; const result = buildReconstructionObligationLedgerEvidenceValidated( parsed.value, ); if (!result.ok) throw result.error; - return reconstructionObligationLedgerPageSchema.parse( + return reconstructionObligationLedgerSchema.parse( result.value.normalized_result, ); }; -const completeLedger = ( - page: ReconstructionObligationLedgerPage, - obligations: ReconstructionObligationLedgerPage["obligations"], -) => { - const { page: pagination, ...ledger } = page; - if (pagination.total !== obligations.length) - throw new TypeError("Incomplete obligation page set"); - return { ...ledger, obligations }; -}; - const originalCases = ( - obligation: ReconstructionObligationLedgerPage["obligations"][number], + obligation: ReconstructionObligationLedger["obligations"][number], evidenceId: string, ) => obligation.required_case_kinds.map((caseKind) => ({ @@ -150,45 +139,26 @@ const reviewedObligation = ( }); describe("reconstruction obligation ledger", () => { - it("emits deterministic closure identity and paging", () => { + it("emits the complete deterministic ledger and closure identity", () => { const evidence = proofEvidence("review"); const reviewed = [ reviewedObligation("obl.review.one", evidence.evidence_id), reviewedObligation("obl.review.two", evidence.evidence_id), ]; const first = build( - request([evidence], { - reviewed_obligations: reviewed, - page: { offset: 0, limit: 1 }, - }), + request([evidence], { reviewed_obligations: reviewed }), ); const second = build( - request([evidence], { - reviewed_obligations: reviewed, - page: { offset: 1, limit: 1 }, - }), + request([evidence], { reviewed_obligations: reviewed }), ); - - expect(first.page).toEqual({ - offset: 0, - limit: 1, - total: 2, - returned: 1, - next_offset: 1, - }); - expect(second.page.next_offset).toBeNull(); + expect(first.obligations).toHaveLength(2); + expect(first).toEqual(second); expect(second.ledger_id).toBe(first.ledger_id); expect(second.closure_digest).toBe(first.closure_digest); expect(first.obligations[0]?.source_state).toBe("reviewed"); expect(first.status).toBe("open"); - expect( - serializeReconstructionObligationLedger( - completeLedger(first, [...first.obligations, ...second.obligations]), - ), - ).toBe( - serializeReconstructionObligationLedger( - completeLedger(second, [...first.obligations, ...second.obligations]), - ), + expect(serializeReconstructionObligationLedger(first)).toBe( + serializeReconstructionObligationLedger(second), ); }); diff --git a/src/application/ReconstructionObligationLedgerService.ts b/src/application/ReconstructionObligationLedgerService.ts index 15fae4fdca..dee8efe79f 100644 --- a/src/application/ReconstructionObligationLedgerService.ts +++ b/src/application/ReconstructionObligationLedgerService.ts @@ -9,9 +9,9 @@ import { createEvidence, type Evidence } from "../domain/evidence.js"; import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js"; import { reconstructionObligationLedgerInputSchema, - reconstructionObligationLedgerPageSchema, + reconstructionObligationLedgerSchema, type ReconstructionObligationLedgerInput, - type ReconstructionObligationLedgerPage, + type ReconstructionObligationLedger, } from "../domain/reconstructionObligationLedgerSchemas.js"; import { err, ok, type Result } from "../domain/result.js"; import { JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER } from "./InvestigationProviders.js"; @@ -30,7 +30,7 @@ export const resolveReconstructionObligationLedgerRequest = ( : err(new AnalysisInputError(OPERATION, { cause: parsed.error })); }; -/** Build one deterministic ledger page and wrap it in portable Evidence. */ +/** Build the complete deterministic ledger and wrap it in portable Evidence. */ export const buildReconstructionObligationLedgerEvidenceValidated = ( input: ReconstructionObligationLedgerInput, ): Result => { @@ -45,8 +45,7 @@ export const buildReconstructionObligationLedgerEvidenceValidated = ( manifest: input.manifest, generationLimitations: generated.limitations, }); - const page = pageLedger(ledger, input.page.offset, input.page.limit); - return ok(createLedgerEvidence(input, page)); + return ok(createLedgerEvidence(input, ledger)); } catch (cause: unknown) { if (cause instanceof z.ZodError) return err(new AnalysisInputError(OPERATION, { cause })); @@ -59,47 +58,24 @@ export const buildReconstructionObligationLedgerEvidenceValidated = ( } }; -const pageLedger = ( - ledger: ReturnType, - offset: number, - limit: number, -): ReconstructionObligationLedgerPage => { - const obligations = ledger.obligations.slice(offset, offset + limit); - const nextOffset = - offset + obligations.length < ledger.obligations.length - ? offset + obligations.length - : null; - const { obligations: _allObligations, ...summary } = ledger; - return reconstructionObligationLedgerPageSchema.parse({ - ...summary, - page: { - offset, - limit, - total: ledger.obligations.length, - returned: obligations.length, - next_offset: nextOffset, - }, - obligations, - }); -}; - const createLedgerEvidence = ( input: ReconstructionObligationLedgerInput, - page: ReconstructionObligationLedgerPage, -): Evidence => - createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, { + ledger: ReconstructionObligationLedger, +): Evidence => { + const completeLedger = reconstructionObligationLedgerSchema.parse(ledger); + return createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, { predicateType: "rea.reconstruction-obligation-ledger/v1", operation: OPERATION, parameters: jsonObjectSchema.parse({ - ledger_id: page.ledger_id, - closure_digest: page.closure_digest, - page: input.page, + ledger_id: completeLedger.ledger_id, + closure_digest: completeLedger.closure_digest, }), - result: jsonValueSchema.parse(page), + result: jsonValueSchema.parse(completeLedger), rawResult: null, confidence: "inferred", authority: "analyst-inference", environment: null, - limitations: page.limitations, - evidenceLinks: page.evidence_links, + limitations: completeLedger.limitations, + evidenceLinks: completeLedger.evidence_links, }); +}; diff --git a/src/config/parseConfig.ts b/src/config/parseConfig.ts index 815ce907ed..b437353032 100644 --- a/src/config/parseConfig.ts +++ b/src/config/parseConfig.ts @@ -125,8 +125,8 @@ const buildPermissionCeilings = ( const ceilings: PermissionCeiling[] = [ permissionScope("evidence_read", arrays.evidenceRoots), permissionScope("evidence_write", arrays.evidenceRoots), - permissionScope("investigation_workspace_read", arrays.evidenceRoots), - permissionScope("investigation_workspace_write", arrays.evidenceRoots), + permissionScope("reconstruction_coverage_read", arrays.evidenceRoots), + permissionScope("reconstruction_coverage_write", arrays.evidenceRoots), permissionScope("snapshot_read", arrays.analysisSnapshotRoots), permissionScope("snapshot_write", arrays.analysisSnapshotRoots), permissionScope("artifact_extract", ["/"]), diff --git a/src/contracts/applicationToolContracts.ts b/src/contracts/applicationToolContracts.ts index c7c1f6c973..c905ca361e 100644 --- a/src/contracts/applicationToolContracts.ts +++ b/src/contracts/applicationToolContracts.ts @@ -28,7 +28,7 @@ import { import { reconstructionClosureResultSchema } from "../domain/reconstructionCoverage.js"; import { reconstructionObligationLedgerInputSchema, - reconstructionObligationLedgerPageSchema, + reconstructionObligationLedgerSchema, } from "../domain/reconstructionObligationLedgerSchemas.js"; import { reconstructionReadinessInputSchema, @@ -60,7 +60,7 @@ const exportShapeComparisonOutputSchema = evidenceResultOf( javaScriptExportShapeComparisonResultSchema, ); const reconstructionObligationLedgerOutputSchema = evidenceResultOf( - reconstructionObligationLedgerPageSchema, + reconstructionObligationLedgerSchema, ); const reconstructionReadinessOutputSchema = evidenceResultOf( reconstructionReadinessReportSchema, @@ -301,13 +301,13 @@ export const APPLICATION_TOOL_CONTRACTS = [ name: "build_reconstruction_obligation_ledger", ...toolContractMetadata("build_reconstruction_obligation_ledger"), description: - "Generate one deterministic page of a ReconstructionObligationLedger from an authenticated Evidence bundle, reviewed obligations, and an explicit reconstruction manifest. Static candidates remain candidates; duplicate ownership, missing original or reconstruction cases, missing parser/type, weak verifier authority, unenumerated claims, contradictions, dependencies, and residual unknowns fail closed. Every page carries the same full-ledger closure digest and typed per-obligation diagnostics.", + "Generate the complete deterministic ReconstructionObligationLedger from an authenticated Evidence bundle, reviewed obligations, and an explicit reconstruction manifest. Static candidates remain candidates; duplicate ownership, missing original or reconstruction cases, missing parser/type, weak verifier authority, unenumerated claims, contradictions, dependencies, and residual unknowns fail closed. The inline result carries the full-ledger closure digest and typed per-obligation diagnostics.", kind: "application", inputSchema: reconstructionObligationLedgerInputSchema, outputSchema: reconstructionObligationLedgerOutputSchema, examples: [ { - title: "Generate the first obligation-ledger page", + title: "Generate the complete obligation ledger", input: { evidence_bundle: { artifacts: [], @@ -323,7 +323,6 @@ export const APPLICATION_TOOL_CONTRACTS = [ bindings: [], contradictions: [], }, - page: { offset: 0, limit: 50 }, }, }, ], diff --git a/src/contracts/applicationWorkflowInputContracts.ts b/src/contracts/applicationWorkflowInputContracts.ts index 52fbb49ba4..e15a5a22b8 100644 --- a/src/contracts/applicationWorkflowInputContracts.ts +++ b/src/contracts/applicationWorkflowInputContracts.ts @@ -108,7 +108,6 @@ const compareJavaScriptExportShapesFacts = { compareJavaScriptExportShapesInputSchema.shape.right_module_path, right_export_name: compareJavaScriptExportShapesInputSchema.shape.right_export_name, - limits: compareJavaScriptExportShapesInputSchema.shape.limits, unknown_registry_approved: compareJavaScriptExportShapesInputSchema.shape.unknown_registry_approved, } as const; diff --git a/src/contracts/toolContractExamples.ts b/src/contracts/toolContractExamples.ts index b9c618e6e0..b0df117b6b 100644 --- a/src/contracts/toolContractExamples.ts +++ b/src/contracts/toolContractExamples.ts @@ -54,8 +54,8 @@ export const TOOL_EXAMPLE_OVERRIDES: Readonly< right_evidence_id: `ev_${"1".repeat(64)}`, }, compare_artifacts: { - left_evidence_ids: [ARTIFACT_COMPARISON_EXAMPLE.left.evidence_id], - right_evidence_ids: [ARTIFACT_COMPARISON_EXAMPLE.right.evidence_id], + left_evidence_id: ARTIFACT_COMPARISON_EXAMPLE.left.evidence_id, + right_evidence_id: ARTIFACT_COMPARISON_EXAMPLE.right.evidence_id, }, compare_functions: { left_evidence_id: FUNCTION_COMPARISON_EXAMPLE.left.evidence_id, diff --git a/src/contracts/toolOutputSchemaPrimitives.ts b/src/contracts/toolOutputSchemaPrimitives.ts index 09284a6a60..cd8ccc0535 100644 --- a/src/contracts/toolOutputSchemaPrimitives.ts +++ b/src/contracts/toolOutputSchemaPrimitives.ts @@ -70,8 +70,6 @@ export const targetKindSchema = z.enum([ const providerCapabilityFacts = { operation: z.string(), - pagination: z.enum(["none", "offset", "cursor"]), - exhaustive: z.boolean(), effects: z.object({ mutates_artifact: z.boolean(), launches_process: z.boolean(), @@ -81,11 +79,6 @@ const providerCapabilityFacts = { changes_permissions: z.boolean(), requires_root: z.boolean(), }), - limits: z.object({ - max_results: z.number().int().min(0).nullable(), - max_payload_bytes: z.number().int().min(0).nullable(), - timeout_ms: z.number().int().min(0).nullable(), - }), limitations: z.array(z.string()), }; @@ -418,26 +411,6 @@ const availableMemoryPermissions = z.object({ source: z.literal("ghidra-memory-block"), }); -export const bounded = (item: z.ZodType) => { - const facts = { - items: z.array(item), - total: z.number().int().min(0).nullable(), - returned: z.number().int().min(0), - } as const; - return z.discriminatedUnion("truncated", [ - z.object({ - ...facts, - truncated: z.literal(false), - next_offset: z.null(), - }), - z.object({ - ...facts, - truncated: z.literal(true), - next_offset: z.number().int().min(0).nullable(), - }), - ]); -}; - export const addressedValue = z.object({ address: z.string(), value: z.string(), diff --git a/src/contracts/toolSchemaMetadata.ts b/src/contracts/toolSchemaMetadata.ts index 864532f447..13274e8509 100644 --- a/src/contracts/toolSchemaMetadata.ts +++ b/src/contracts/toolSchemaMetadata.ts @@ -29,11 +29,9 @@ const PROPERTY_DESCRIPTIONS: Readonly> = { question: "Concrete unresolved question to retain for later investigation.", result: "Primary structured result returned by this operation.", left: "Left-hand input used for comparison or differential execution.", - limit: "Maximum number of results to return in this page.", limits: "Bounded resource-consumption and result-size limits for this operation.", mode: "Operation mode that selects the requested behavior.", - offset: "Zero-based index of the first result to return.", overwrite: "Whether an existing destination may be replaced.", path: "Local filesystem path used by this operation.", provider_id: @@ -119,10 +117,6 @@ const fallbackPropertyDescription = (property: string): string => { const words = property.replaceAll("_", " "); if (property.endsWith("_approved")) return `Explicit operator approval for ${words.slice(0, -9)}.`; - if (property.endsWith("_offset")) - return `Zero-based index of the first ${words.slice(0, -7)} to return.`; - if (property.endsWith("_limit")) - return `Maximum number of ${words.slice(0, -6)} entries to return.`; if (property.startsWith("max_")) return `Maximum permitted ${words.slice(4)} for this operation.`; if (property.startsWith("include_")) diff --git a/src/domain/analysisErrorPresentation.ts b/src/domain/analysisErrorPresentation.ts index 713276fb36..954e3972be 100644 --- a/src/domain/analysisErrorPresentation.ts +++ b/src/domain/analysisErrorPresentation.ts @@ -11,7 +11,7 @@ import { HopperProcessError, HopperStartError, HopperTimeoutError, - InvestigationWorkspaceError, + WorkspaceStorageError, NoBinaryOpenError, PermissionRequiredError, ProviderSelectionError, @@ -81,8 +81,8 @@ export const analysisErrorCategory = ( return artifactErrorCategory(error.reason); if (error instanceof EvidenceFileError && error.reason === "disabled") return "unavailable"; - if (error instanceof InvestigationWorkspaceError) - return investigationWorkspaceCategory(error.reason); + if (error instanceof WorkspaceStorageError) + return workspaceStorageCategory(error.reason); return STATIC_ERROR_CATEGORIES[error._tag] ?? "execution_failure"; }; @@ -101,8 +101,8 @@ const browserErrorCategory = ( return "execution_failure"; }; -const investigationWorkspaceCategory = ( - reason: InvestigationWorkspaceError["reason"], +const workspaceStorageCategory = ( + reason: WorkspaceStorageError["reason"], ): AnalysisErrorProjection["category"] => { if ( reason === "disabled" || @@ -162,8 +162,8 @@ export const analysisErrorUserMessage = (error: AnalysisError): string => { return "Evidence is too large for this session. Reduce the evidence set and try again."; if (error instanceof EvidenceFileError) return evidenceFileMessage(error.reason); - if (error instanceof InvestigationWorkspaceError) - return investigationWorkspaceMessage(error.reason); + if (error instanceof WorkspaceStorageError) + return workspaceStorageMessage(error.reason); if (error instanceof UnknownRegistryError && error.reason === "not-found") return "The requested residual unknown does not exist in this session. Check the unknown_id and try again."; if (error instanceof UnknownRegistryError) @@ -274,8 +274,8 @@ const evidenceFileMessage = (reason: EvidenceFileError["reason"]): string => { return "Evidence file could not be accessed. Check file permissions and try again."; }; -const investigationWorkspaceMessage = ( - reason: InvestigationWorkspaceError["reason"], +const workspaceStorageMessage = ( + reason: WorkspaceStorageError["reason"], ): string => { if (reason === "disabled") return "Investigation workspace access is disabled. Configure a workspace directory and try again."; @@ -309,7 +309,7 @@ const KNOWN_ERROR_TAGS = { EvidenceIntegrityError: true, EvidenceLimitError: true, EvidenceFileError: true, - InvestigationWorkspaceError: true, + WorkspaceStorageError: true, UnknownRegistryError: true, HopperTimeoutError: true, HopperCancelledError: true, diff --git a/src/domain/analysisErrorProjection.test.ts b/src/domain/analysisErrorProjection.test.ts index e3d2ba7496..f0d6b0a471 100644 --- a/src/domain/analysisErrorProjection.test.ts +++ b/src/domain/analysisErrorProjection.test.ts @@ -246,32 +246,6 @@ describe("analysis error projection: caller contract", () => { }); }); - it("retains schema-authored input guidance", () => { - expect( - projectAnalysisError( - new AnalysisInputError("find_changed_behavior", undefined, [ - { - path: [], - reason: "invalid_value", - message: - "Supply either existing comparisons or one investigation_run", - }, - ]), - ), - ).toMatchObject({ - details: { - issues: [ - { - path: [], - reason: "invalid_value", - message: - "Supply either existing comparisons or one investigation_run", - }, - ], - }, - }); - }); - it("distinguishes disabled integrity continuation from format support", () => { expect( projectAnalysisError( diff --git a/src/domain/analysisErrorProjection.ts b/src/domain/analysisErrorProjection.ts index 4214c2d8b9..307ddc64e0 100644 --- a/src/domain/analysisErrorProjection.ts +++ b/src/domain/analysisErrorProjection.ts @@ -18,7 +18,7 @@ import { HopperProcessError, HopperRemoteError, HopperTimeoutError, - InvestigationWorkspaceError, + WorkspaceStorageError, PermissionRequiredError, ProviderAdapterError, ProviderSelectionError, @@ -73,8 +73,8 @@ const errorCode = (error: AnalysisError): AnalysisErrorProjection["code"] => { if (error instanceof ArtifactOperationError) return artifactOperationCode(error); if (error instanceof EvidenceFileError) return evidenceFileCode(error.reason); - if (error instanceof InvestigationWorkspaceError) - return investigationWorkspaceCode(error.reason); + if (error instanceof WorkspaceStorageError) + return workspaceStorageCode(error.reason); if (error instanceof UnknownRegistryError) return unknownRegistryCode(error.reason); if (error._tag === "ProcessCaptureError") return processCaptureCode(error); @@ -115,8 +115,8 @@ const evidenceFileCode = ( return "execution_failure"; }; -const investigationWorkspaceCode = ( - reason: InvestigationWorkspaceError["reason"], +const workspaceStorageCode = ( + reason: WorkspaceStorageError["reason"], ): AnalysisErrorProjection["code"] => { if (reason === "revision-conflict" || reason === "name-conflict") return "revision_conflict"; @@ -152,7 +152,7 @@ type SpecializedErrorTag = | "ArtifactOperationError" | "BrowserObservationError" | "EvidenceFileError" - | "InvestigationWorkspaceError" + | "WorkspaceStorageError" | "PermissionRequiredError" | "ProcessCaptureError" | "ProviderSelectionError" @@ -192,7 +192,7 @@ const staticErrorCode = ( case "ArtifactOperationError": case "BrowserObservationError": case "EvidenceFileError": - case "InvestigationWorkspaceError": + case "WorkspaceStorageError": case "PermissionRequiredError": case "ProcessCaptureError": case "ProviderSelectionError": @@ -268,7 +268,7 @@ const artifactStateErrorDetails = ( }; if (error instanceof EvidenceLimitError) return { limit: error.limit, maximum: error.maximum, truncated: true }; - if (error instanceof InvestigationWorkspaceError) + if (error instanceof WorkspaceStorageError) return { operation: error.operation, reason: error.reason }; if (error instanceof UnknownRegistryError) return { reason: error.reason }; if (error instanceof EvidenceFileError) diff --git a/src/domain/analysisSnapshot.test.ts b/src/domain/analysisSnapshot.test.ts index a07ffdd07c..7806ea3fda 100644 --- a/src/domain/analysisSnapshot.test.ts +++ b/src/domain/analysisSnapshot.test.ts @@ -65,9 +65,7 @@ describe("analysis snapshot contract", () => { ).toBeUndefined(); }); - it("rejects snapshot v1 with explicit recapture guidance", () => { - expect(() => parseAnalysisSnapshot({ snapshot_version: 1 })).toThrow( - /v1.*recapture.*v2/iu, - ); + it("rejects an input without the current snapshot shape", () => { + expect(() => parseAnalysisSnapshot({ snapshot_version: 1 })).toThrow(); }); }); diff --git a/src/domain/analysisSnapshot.ts b/src/domain/analysisSnapshot.ts index 526e5f3641..906121a24d 100644 --- a/src/domain/analysisSnapshot.ts +++ b/src/domain/analysisSnapshot.ts @@ -270,9 +270,8 @@ export const createAnalysisSnapshotEntry = (input: { }; }; -/** Parse v2 and reject legacy snapshots, altered query IDs, or non-canonical order. */ +/** Parse a provider/profile-exact snapshot and verify its entries and evidence. */ export const parseAnalysisSnapshot = (input: unknown): AnalysisSnapshot => { - rejectLegacySnapshot(input); const parsed = analysisSnapshotSchema.parse(input); parseEvidenceBundle(parsed.evidence_bundle); if ( @@ -314,15 +313,3 @@ export const parseAnalysisSnapshot = (input: unknown): AnalysisSnapshot => { /** Serialize a validated snapshot with byte-stable canonical entry ordering. */ export const serializeAnalysisSnapshot = (snapshot: AnalysisSnapshot): string => `${canonicalJson(parseAnalysisSnapshot(snapshot))}\n`; - -const rejectLegacySnapshot = (input: unknown): void => { - if ( - typeof input === "object" && - input !== null && - "snapshot_version" in input && - input.snapshot_version === 1 - ) - throw new TypeError( - "Analysis snapshot v1 is incompatible with profile-exact replay; recapture it as snapshot v2. Its Evidence bundle may be imported separately.", - ); -}; diff --git a/src/domain/bundleComparison.test.ts b/src/domain/bundleComparison.test.ts index bbf96dcf26..a76e5e81de 100644 --- a/src/domain/bundleComparison.test.ts +++ b/src/domain/bundleComparison.test.ts @@ -29,7 +29,7 @@ describe("bundle comparison", () => { const second = evidence("second"); const left = createEvidenceBundle([first, second]); const right = createEvidenceBundle([second, first]); - const result = compareBundles(left, right, [], 0, 100); + const result = compareBundles(left, right); expect(bundleComparisonResultSchema.parse(result)).toMatchObject({ status: "unchanged", summary: { @@ -38,12 +38,12 @@ describe("bundle comparison", () => { records_removed: 0, unresolved: 0, }, - changes: { total: 0, next_offset: null }, + changes: [], }); expect(result.left_bundle_sha256).toBe(result.right_bundle_sha256); }); - it("classifies explicit pairs and pages stable membership changes", () => { + it("classifies explicit pairs and returns every membership change inline", () => { const oldRecord = evidence("old"); const newRecord = evidence("new"); const removed = evidence("removed"); @@ -56,8 +56,8 @@ describe("bundle comparison", () => { right_evidence_id: newRecord.evidence_id, }, ]; - const first = compareBundles(left, right, pairs, 0, 1); - const repeated = compareBundles(left, right, pairs, 0, 1); + const first = compareBundles(left, right, pairs); + const repeated = compareBundles(left, right, pairs); expect(first).toEqual(repeated); expect(first).toMatchObject({ status: "changed", @@ -66,61 +66,57 @@ describe("bundle comparison", () => { records_removed: 1, records_changed: 1, }, - changes: { total: 3, next_offset: 1 }, + changes: expect.arrayContaining([ + expect.objectContaining({ classification: "changed" }), + ]), }); - expect( - compareBundles(left, right, pairs, 1, 500).changes.items, - ).toHaveLength(2); + expect(first.changes).toHaveLength(3); expect(first.limitations).toContain( "One-sided membership proves only bundle inclusion or omission, not behavioral absence.", ); }); + it("returns more than 500 changes without a display-page ceiling", () => { + const records = Array.from({ length: 501 }, (_, index) => + evidence(`record-${String(index)}`), + ); + const result = compareBundles( + createEvidenceBundle([]), + createEvidenceBundle(records), + ); + expect(result.changes).toHaveLength(501); + expect(bundleComparisonResultSchema.parse(result).changes).toHaveLength( + 501, + ); + }); + it("rejects missing and non-bijective explicit pairs", () => { const leftRecord = evidence("left"); const rightRecord = evidence("right"); const left = createEvidenceBundle([leftRecord]); const right = createEvidenceBundle([rightRecord]); expect(() => - compareBundles( - left, - right, - [ - { - left_evidence_id: evidence("missing").evidence_id, - right_evidence_id: rightRecord.evidence_id, - }, - ], - 0, - 100, - ), + compareBundles(left, right, [ + { + left_evidence_id: evidence("missing").evidence_id, + right_evidence_id: rightRecord.evidence_id, + }, + ]), ).toThrow(/missing left evidence/u); expect(() => - compareBundles( - left, - right, - [ - { - left_evidence_id: leftRecord.evidence_id, - right_evidence_id: rightRecord.evidence_id, - }, - { - left_evidence_id: leftRecord.evidence_id, - right_evidence_id: rightRecord.evidence_id, - }, - ], - 0, - 100, - ), + compareBundles(left, right, [ + { + left_evidence_id: leftRecord.evidence_id, + right_evidence_id: rightRecord.evidence_id, + }, + { + left_evidence_id: leftRecord.evidence_id, + right_evidence_id: rightRecord.evidence_id, + }, + ]), ).toThrow(/one-to-one/u); expect(() => - compareBundles( - { ...left, records: [leftRecord, leftRecord] }, - right, - [], - 0, - 100, - ), + compareBundles({ ...left, records: [leftRecord, leftRecord] }, right), ).toThrow(/duplicate record IDs/u); }); }); @@ -170,31 +166,27 @@ describe("bundle comparison history", () => { [mutationOne, mutationTwo], [initial, advanced], ); - expect( - compareBundles(initialBundle, advancedBundle, [], 0, 100), - ).toMatchObject({ + expect(compareBundles(initialBundle, advancedBundle)).toMatchObject({ status: "changed", summary: { unknowns_advanced: 1, unresolved: 0 }, - changes: { - items: [ - expect.objectContaining({ - entity: "evidence", - classification: "added", - }), - expect.objectContaining({ - entity: "residual_unknown", - classification: "history_advanced", - }), - ], - }, + changes: [ + expect.objectContaining({ + entity: "evidence", + classification: "added", + }), + expect.objectContaining({ + entity: "residual_unknown", + classification: "history_advanced", + }), + ], }); const absent = createEvidenceBundle([]); - const missing = compareBundles(initialBundle, absent, [], 0, 100); + const missing = compareBundles(initialBundle, absent); expect(missing).toMatchObject({ status: "unknown", summary: { unknowns_removed: 1, unresolved: 1 }, }); - expect(missing.changes.items).toContainEqual( + expect(missing.changes).toContainEqual( expect.objectContaining({ classification: "removed", conclusion_kind: "unresolved_branch", diff --git a/src/domain/bundleComparison.ts b/src/domain/bundleComparison.ts index b074275991..f9c5ec2aeb 100644 --- a/src/domain/bundleComparison.ts +++ b/src/domain/bundleComparison.ts @@ -20,7 +20,7 @@ const classificationSchema = z.enum([ "history_diverged", ]); -/** Strict bounded input for canonical Evidence bundle comparison. */ +/** Strict input for canonical Evidence bundle comparison. */ export const bundleComparisonInputSchema = z.strictObject({ left_bundle_path: z.string().min(1).max(4_096), right_bundle_path: z.string().min(1).max(4_096), @@ -31,10 +31,7 @@ export const bundleComparisonInputSchema = z.strictObject({ right_evidence_id: evidenceIdSchema, }), ) - .max(500) .default([]), - offset: z.number().int().min(0).default(0), - limit: z.number().int().min(1).max(500).default(100), }); const bundleChangeSchema = z.object({ @@ -70,13 +67,7 @@ export const bundleComparisonResultSchema = z.object({ unknowns_diverged: z.number().int().min(0), unresolved: z.number().int().min(0), }), - changes: z.object({ - items: z.array(bundleChangeSchema).max(500), - offset: z.number().int().min(0), - limit: z.number().int().min(1).max(500), - total: z.number().int().min(0), - next_offset: z.number().int().min(0).nullable(), - }), + changes: z.array(bundleChangeSchema), limitations: z.array(z.string()), }); @@ -92,13 +83,9 @@ const MAX_ENTITIES = 100_000; /** Compare canonical bundle membership and only explicitly paired observations. */ export const compareBundles = ( - ...[leftInput, rightInput, recordPairs, offset, limit]: readonly [ - unknown, - unknown, - readonly RecordPair[], - number, - number, - ] + leftInput: unknown, + rightInput: unknown, + recordPairs: readonly RecordPair[] = [], ): BundleComparisonResult => { const left = parseEvidenceBundle(leftInput); const right = parseEvidenceBundle(rightInput); @@ -110,7 +97,6 @@ export const compareBundles = ( const changes = [...recordResult.changes, ...unknownResult.changes].sort( compareChanges, ); - const page = changes.slice(offset, offset + limit); const unresolved = changes.filter( ({ conclusion_kind: kind }) => kind !== "observed_change", ).length; @@ -128,14 +114,7 @@ export const compareBundles = ( ...unknownResult.summary, unresolved, }, - changes: { - items: page, - offset, - limit, - total: changes.length, - next_offset: - offset + page.length < changes.length ? offset + page.length : null, - }, + changes, limitations: changes.some(({ limitations }) => limitations.length > 0) ? [ "One-sided membership proves only bundle inclusion or omission, not behavioral absence.", diff --git a/src/domain/changedBehavior.test.ts b/src/domain/changedBehavior.test.ts index b2354c6da1..ac626c3e86 100644 --- a/src/domain/changedBehavior.test.ts +++ b/src/domain/changedBehavior.test.ts @@ -85,11 +85,6 @@ const processResult = ( }); const artifactResult = ( - pagination: { - readonly offset?: number; - readonly next_offset?: number | null; - readonly total?: number; - } = {}, nestedLinks: string[] = [left.evidence_id, right.evidence_id], ): JsonValue => ({ status: "changed", @@ -102,24 +97,18 @@ const artifactResult = ( changed: 1, unknown: 0, }, - changes: { - items: [ - { - classification: "changed", - logical_path: "main.js", - dimensions: ["content"], - left_occurrence_id: `occ_${"5".repeat(64)}`, - right_occurrence_id: `occ_${"6".repeat(64)}`, - left_artifact_id: `art_${"7".repeat(64)}`, - right_artifact_id: `art_${"8".repeat(64)}`, - evidence_links: nestedLinks, - }, - ], - offset: pagination.offset ?? 0, - limit: 100, - total: pagination.total ?? 1, - next_offset: pagination.next_offset ?? null, - }, + changes: [ + { + classification: "changed", + logical_path: "main.js", + dimensions: ["content"], + left_occurrence_id: `occ_${"5".repeat(64)}`, + right_occurrence_id: `occ_${"6".repeat(64)}`, + left_artifact_id: `art_${"7".repeat(64)}`, + right_artifact_id: `art_${"8".repeat(64)}`, + evidence_links: nestedLinks, + }, + ], limitations: [], }); @@ -134,11 +123,9 @@ const expectInvalidSummary = (result: ChangedBehaviorResult): void => { describe("changed behavior", () => { it("accepts process comparison Evidence", () => { - const result = findChangedBehavior( - [comparison("compare_process_captures", processResult())], - 0, - 100, - ); + const result = findChangedBehavior([ + comparison("compare_process_captures", processResult()), + ]); expect(result.behavior_status).toBe("observed_unchanged"); }); @@ -152,7 +139,7 @@ describe("changed behavior", () => { }), ); - expect(findChangedBehavior([evidence], 0, 100)).toMatchObject({ + expect(findChangedBehavior([evidence])).toMatchObject({ behavior_status: "observed_changed", summary: { observed_changes: 2 }, findings: { @@ -172,11 +159,11 @@ describe("changed behavior", () => { "compare_process_captures", processResult({ status: "changed", terminal: "changed" }), ); - const result = findChangedBehavior([evidence], 0, 100); + const result = findChangedBehavior([evidence]); expect(changedBehaviorResultSchema.parse(result)).toMatchObject({ behavior_status: "observed_changed", summary: { observed_changes: 1, static_candidates: 0 }, - findings: { total: 1, next_offset: null }, + findings: { items: expect.any(Array) }, }); expectInvalidSummary(result); expect(result.findings.items[0]).toMatchObject({ @@ -193,7 +180,7 @@ describe("changed behavior", () => { it("keeps static differences as candidates, never runtime observations", () => { const evidence = comparison("compare_artifacts", artifactResult()); - const result = findChangedBehavior([evidence], 0, 100); + const result = findChangedBehavior([evidence]); expect(result).toMatchObject({ behavior_status: "unknown", summary: { observed_changes: 0, static_candidates: 1 }, @@ -217,40 +204,26 @@ describe("changed behavior", () => { "compare_process_captures", processResult({ status: "unknown", exit: "unknown" }), ); - const result = findChangedBehavior([changed, unknown], 0, 1); + const result = findChangedBehavior([changed, unknown]); expect(result).toMatchObject({ behavior_status: "unknown", - findings: { total: 2, limit: 1, next_offset: 1 }, + findings: { items: expect.any(Array) }, }); - expect(findChangedBehavior([changed, unknown], 0, 1)).toEqual(result); + expect(findChangedBehavior([changed, unknown])).toEqual(result); }); - it("keeps incomplete artifact comparison pagination explicit", () => { - const paged = comparison( - "compare_artifacts", - artifactResult({ next_offset: 1, total: 2 }), - ); - const result = findChangedBehavior([paged], 0, 100); - expect(result).toMatchObject({ - behavior_status: "unknown", - summary: { static_candidates: 1, unresolved: 1 }, - findings: { total: 2 }, - }); - expect(result.limitations).toContain( - "Artifact comparison reports 1 of 2 changes.", - ); - const laterPage = comparison( - "compare_artifacts", - artifactResult({ offset: 1, next_offset: null, total: 2 }), - ); - expect(() => findChangedBehavior([laterPage], 0, 100)).toThrow( - /pagination from offset zero/u, + it("uses complete inline artifact deltas as static candidates", () => { + const complete = comparison("compare_artifacts", artifactResult()); + expect(findChangedBehavior([complete]).findings.items).toEqual( + expect.arrayContaining([ + expect.objectContaining({ dimension: "artifact:main.js" }), + ]), ); }); it("rejects bundles, duplicate comparisons, and malformed exact results", () => { const valid = comparison("compare_process_captures", processResult()); - expect(() => findChangedBehavior([valid, valid], 0, 100)).toThrow( + expect(() => findChangedBehavior([valid, valid])).toThrow( /duplicate comparison Evidence/u, ); const bundle = createEvidence( @@ -266,25 +239,25 @@ describe("changed behavior", () => { evidenceLinks: [left.evidence_id, right.evidence_id], }, ); - expect(() => findChangedBehavior([bundle], 0, 100)).toThrow( + expect(() => findChangedBehavior([bundle])).toThrow( /requires process, artifact, or function/u, ); const malformed = comparison("compare_process_captures", { status: "unchanged", }); - expect(() => findChangedBehavior([malformed], 0, 100)).toThrow(); + expect(() => findChangedBehavior([malformed])).toThrow(); const contradictory = comparison( "compare_process_captures", processResult({ status: "unchanged", terminal: "changed" }), ); - expect(() => findChangedBehavior([contradictory], 0, 100)).toThrow( + expect(() => findChangedBehavior([contradictory])).toThrow( /contradicts its dimensions/u, ); const danglingNested = comparison( "compare_artifacts", - artifactResult({}, [`ev_${"f".repeat(64)}`, right.evidence_id]), + artifactResult([`ev_${"f".repeat(64)}`, right.evidence_id]), ); - expect(() => findChangedBehavior([danglingNested], 0, 100)).toThrow( + expect(() => findChangedBehavior([danglingNested])).toThrow( /outside its top-level closure/u, ); }); diff --git a/src/domain/changedBehavior.ts b/src/domain/changedBehavior.ts index e92dd349f7..79a9e9eb19 100644 --- a/src/domain/changedBehavior.ts +++ b/src/domain/changedBehavior.ts @@ -9,33 +9,14 @@ import { PROCESS_COMPARISON_DIMENSIONS, processCaptureComparisonSchema, } from "./processCapture.js"; -import { - crossVersionInvestigationInputSchema, - investigationRunSummarySchema, -} from "./investigationWorkspace.js"; const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u); /** Strict bounded input for aggregating existing comparison Evidence. */ -export const changedBehaviorInputSchema = z - .object({ - comparisons: z.array(evidenceSchema).max(100).default([]), - investigation_run: crossVersionInvestigationInputSchema.optional(), - offset: z.number().int().min(0).default(0), - limit: z.number().int().min(1).max(100).default(100), - unknown_registry_approved: z.literal(true).optional(), - }) - .superRefine((input, context) => { - if ( - input.comparisons.length > 0 === - (input.investigation_run !== undefined) - ) - context.addIssue({ - code: "custom", - message: - "Supply either existing comparisons or one investigation_run, but not both", - }); - }); +export const changedBehaviorInputSchema = z.object({ + comparisons: z.array(evidenceSchema).max(100).default([]), + unknown_registry_approved: z.literal(true).optional(), +}); const findingSchema = z.object({ scope: z.enum(["runtime", "protocol", "resource", "static_candidate"]), @@ -68,47 +49,22 @@ export const changedBehaviorResultSchema = z unresolved: z.number().int().min(0), }), findings: z.object({ - items: z.array(findingSchema).max(100), - offset: z.number().int().min(0), - limit: z.number().int().min(1).max(100), - total: z.number().int().min(0), - next_offset: z.number().int().min(0).nullable(), + items: z.array(findingSchema), }), evidence_links: z.array(evidenceIdSchema).min(3).max(20_100), limitations: z.array(z.string()), - investigation_run: investigationRunSummarySchema.optional(), }) .superRefine((result, context) => { const summaryTotal = Object.values(result.summary).reduce( (total, count) => total + count, 0, ); - const expectedNextOffset = - result.findings.offset + result.findings.items.length < - result.findings.total - ? result.findings.offset + result.findings.items.length - : null; - if (summaryTotal !== result.findings.total) + if (summaryTotal !== result.findings.items.length) context.addIssue({ code: "custom", message: "Finding classification counts must equal the finding total", path: ["summary"], }); - if (result.findings.next_offset !== expectedNextOffset) - context.addIssue({ - code: "custom", - message: "Finding cursor must identify the next retained offset", - path: ["findings", "next_offset"], - }); - if ( - result.findings.offset < result.findings.total && - result.findings.items.length === 0 - ) - context.addIssue({ - code: "custom", - message: "A nonterminal finding page must retain at least one item", - path: ["findings", "items"], - }); if ( (result.behavior_status === "observed_changed" && result.summary.observed_changes === 0) || @@ -155,13 +111,9 @@ const acceptsPredicate = ( /** Find observed runtime changes and separately report static change candidates. */ export const findChangedBehavior = ( comparisonsInput: unknown, - offset: number, - limit: number, ): ChangedBehaviorResult => { const parsedInput = changedBehaviorInputSchema.parse({ comparisons: comparisonsInput, - offset, - limit, }); const comparisons = parsedInput.comparisons; const evidence = comparisons.map(parseComparisonEvidence); @@ -176,10 +128,6 @@ export const findChangedBehavior = ( ); if (links.length > 20_100) throw new TypeError("Changed-behavior Evidence closure exceeds limit"); - const page = findings.slice( - parsedInput.offset, - parsedInput.offset + parsedInput.limit, - ); return changedBehaviorResultSchema.parse({ behavior_status: behaviorStatus(runtimeStatuses), summary: { @@ -189,14 +137,7 @@ export const findChangedBehavior = ( unresolved: count(findings, "unresolved_branch"), }, findings: { - items: page, - offset: parsedInput.offset, - limit: parsedInput.limit, - total: findings.length, - next_offset: - parsedInput.offset + page.length < findings.length - ? parsedInput.offset + page.length - : null, + items: findings, }, evidence_links: links, limitations: uniqueSorted([ @@ -211,7 +152,6 @@ export const findChangedBehavior = ( ...(runtimeStatuses.length === 0 ? ["No process comparison Evidence was supplied."] : []), - ...evidence.flatMap(artifactPaginationLimitations), ]), }); }; @@ -278,13 +218,9 @@ const parseResult = (evidence: Evidence): void => { const result = artifactComparisonResultSchema.parse( evidence.normalized_result, ); - if (result.changes.offset !== 0) - throw new TypeError( - "Changed-behavior analysis requires artifact comparison pagination from offset zero", - ); assertNestedLinks( evidence, - result.changes.items.flatMap(({ evidence_links: links }) => links), + result.changes.flatMap(({ evidence_links: links }) => links), ); }; @@ -366,7 +302,7 @@ const artifactFindings = (evidence: Evidence): Finding[] => { const result = artifactComparisonResultSchema.parse( evidence.normalized_result, ); - const changes = result.changes.items.map((change) => + const changes = result.changes.map((change) => makeFinding({ evidence, dimension: `artifact:${change.logical_path}`, @@ -382,9 +318,7 @@ const artifactFindings = (evidence: Evidence): Finding[] => { links: change.evidence_links, }), ); - return (result.status === "unknown" || - result.status === "truncated" || - result.changes.next_offset !== null) && + return (result.status === "unknown" || result.status === "truncated") && !changes.some( ({ classification }) => classification === "unresolved_branch", ) @@ -402,18 +336,6 @@ const artifactFindings = (evidence: Evidence): Finding[] => { : changes; }; -const artifactPaginationLimitations = (evidence: Evidence): string[] => { - if (evidence.operation !== "compare_artifacts") return []; - const result = artifactComparisonResultSchema.parse( - evidence.normalized_result, - ); - return result.changes.next_offset === null - ? [] - : [ - `Artifact comparison reports ${String(result.changes.items.length)} of ${String(result.changes.total)} changes.`, - ]; -}; - const makeFinding = (input: { readonly evidence: Evidence; readonly dimension: string; diff --git a/src/domain/completionLedgerGeneration.test.ts b/src/domain/completionLedgerGeneration.test.ts index c9514fbf2b..9eaf4e431e 100644 --- a/src/domain/completionLedgerGeneration.test.ts +++ b/src/domain/completionLedgerGeneration.test.ts @@ -12,16 +12,13 @@ const digest = (digit: string): string => digit.repeat(64); const evidenceId = (digit: string): string => `ev_${digest(digit)}`; const report = (): CompletionVerifierReport => ({ - schema_version: 1, verifier: { id: "managed-conformance", version: "1" }, verifier_run: { - schema_version: 1, run_id: "11111111-1111-4111-8111-111111111111", verifier_pid: 100, parent_pid: 1, process_lineage: { status: "verified", - schema_version: 1, observed_at: "2026-07-22T10:00:00.000Z", launcher_pid: 100, launcher_parent_pid: 1, @@ -41,7 +38,6 @@ const report = (): CompletionVerifierReport => ({ scenario: { id: "inspect-managed", version: 1 }, artifact_sha256s: [digest("1")], provider: { id: "managed-static", version: "2" }, - result_schema_version: 1, status: "pass", evidence_ids: [evidenceId("1")], }, @@ -50,7 +46,6 @@ const report = (): CompletionVerifierReport => ({ scenario: { id: "external-oracle", version: 1 }, artifact_sha256s: [], provider: { id: "managed-static", version: "2" }, - result_schema_version: 1, status: "unsupported", evidence_ids: [evidenceId("2")], }, @@ -86,7 +81,6 @@ describe("completion ledger generation", () => { artifact_sha256s: [digest("1")], scenario: { id: "inspect-managed", version: 1 }, provider: { id: "managed-static", version: "2" }, - result_schema_version: 1, }); expect(generated.manifest.claims[0]).not.toHaveProperty("status"); expect(generated.manifest.claims[0]).not.toHaveProperty("evidence_ids"); @@ -142,7 +136,6 @@ describe("completion verifier report validation", () => { ...input.verifier_run, process_lineage: { status: "verified", - schema_version: 1, observed_at: "2026-07-22T10:00:00.000Z", launcher_pid: 100, launcher_parent_pid: 1, @@ -177,12 +170,6 @@ describe("completion ledger commitment drift", () => { firstClaim(input).provider.version = "3"; }, ], - [ - "result schema", - (input: CompletionVerifierReport) => { - firstClaim(input).result_schema_version = 2; - }, - ], [ "environment", (input: CompletionVerifierReport) => { diff --git a/src/domain/completionLedgerGeneration.ts b/src/domain/completionLedgerGeneration.ts index ac87a36f2e..46ca369403 100644 --- a/src/domain/completionLedgerGeneration.ts +++ b/src/domain/completionLedgerGeneration.ts @@ -31,14 +31,12 @@ const skillDigestSchema = z.strictObject({ }); const verifierRunSchema = z .strictObject({ - schema_version: z.literal(1), run_id: z.string().uuid(), verifier_pid: z.number().int().positive(), parent_pid: z.number().int().nonnegative(), process_lineage: z.discriminatedUnion("status", [ z.strictObject({ status: z.literal("verified"), - schema_version: z.literal(1), observed_at: z.iso.datetime(), launcher_pid: z.number().int().positive(), launcher_parent_pid: z.number().int().nonnegative(), @@ -80,13 +78,11 @@ const reportClaimSchema = z.strictObject({ scenario: scenarioSchema, artifact_sha256s: z.array(digestSchema).max(100), provider: identitySchema, - result_schema_version: z.number().int().positive(), status: evidenceCompletionRecordSchema.shape.status, evidence_ids: evidenceCompletionRecordSchema.shape.evidence_ids, }); const completionVerifierReportObjectSchema = z.strictObject({ - schema_version: z.literal(1), verifier: identitySchema, verifier_run: verifierRunSchema, environment: environmentSchema, @@ -114,7 +110,6 @@ const manifestClaimSchema = reportClaimSchema.omit({ evidence_ids: true, }); const completionManifestObjectSchema = z.strictObject({ - schema_version: z.literal(1), manifest_id: z.string().regex(/^ecm_[a-f0-9]{64}$/u), verifier: identitySchema, environment: environmentSchema, @@ -222,7 +217,6 @@ export const createCompletionLedgerArtifacts = ( if (!isSortedUnique(skills.map(({ skill_id }) => skill_id))) throw new TypeError("Completion skill IDs must be unique"); const projection = { - schema_version: 1 as const, verifier: report.verifier, environment: report.environment, skill_digests: skills, diff --git a/src/domain/conformancePackage.ts b/src/domain/conformancePackage.ts index 95a2810c1c..13daa240d7 100644 --- a/src/domain/conformancePackage.ts +++ b/src/domain/conformancePackage.ts @@ -7,9 +7,6 @@ import { evidenceEnvelopeSchema } from "./evidence.js"; import { evidenceBundleSchema } from "./evidenceBundle.js"; import { err, ok, type Result } from "./result.js"; -/** Schema version for the conformance package format. */ -export const CONFORMANCE_PACKAGE_VERSION = 1; - const conformancePackageIdSchema = z.string().regex(/^cp_[a-f0-9]{64}$/u); const scenarioIdSchema = z.string().regex(/^[A-Za-z][A-Za-z0-9._-]{0,99}$/u); @@ -87,7 +84,6 @@ const verifierContractSchema = z.strictObject({ }); const conformancePackageContentsSchema = z.strictObject({ - schema_version: z.literal(CONFORMANCE_PACKAGE_VERSION), name: z.string().min(1), description: z.string().min(1), created_at: z.string().datetime(), @@ -311,7 +307,6 @@ const parseScenarioSection = ( const packageContents = ( pkg: ConformancePackageRecord, ): ConformancePackageContents => ({ - schema_version: pkg.schema_version, name: pkg.name, description: pkg.description, created_at: pkg.created_at, diff --git a/src/domain/evidenceCompletionLedger.ts b/src/domain/evidenceCompletionLedger.ts index 5a98fdf4d0..6afc008479 100644 --- a/src/domain/evidenceCompletionLedger.ts +++ b/src/domain/evidenceCompletionLedger.ts @@ -33,7 +33,6 @@ const completionSummarySchema = z.strictObject({ }); const completionLedgerObjectSchema = z.strictObject({ - schema_version: z.literal(1), ledger_id: z.string().regex(/^ecl_[a-f0-9]{64}$/u), records: z.array(evidenceCompletionRecordSchema).min(1).max(10_000), summary: completionSummarySchema, @@ -95,7 +94,7 @@ const computeLedgerId = ( records: readonly EvidenceCompletionRecord[], ): string => `ecl_${createHash("sha256") - .update(canonicalJson({ schema_version: 1, records })) + .update(canonicalJson({ records })) .digest("hex")}`; const ledgerIssues = ( @@ -156,7 +155,6 @@ export const createEvidenceCompletionLedger = ( if (!isSortedUnique(record.evidence_ids)) throw new TypeError("Completion Evidence IDs must be unique per claim"); return evidenceCompletionLedgerSchema.parse({ - schema_version: 1, ledger_id: computeLedgerId(records), records, summary: summarize(records), diff --git a/src/domain/hopperStartupFailure.ts b/src/domain/hopperStartupFailure.ts index 0f2734814e..1c740cba6c 100644 --- a/src/domain/hopperStartupFailure.ts +++ b/src/domain/hopperStartupFailure.ts @@ -64,7 +64,6 @@ const failures = [ export type HopperStartupFailureCode = (typeof failures)[number][1]; interface HopperStartupDiagnosticContext { - readonly schema_version: 1; readonly component: "hopper_private_display"; readonly operation: "probe" | "launch"; readonly reason: string; diff --git a/src/domain/hopperValues.fixture.ts b/src/domain/hopperValues.fixture.ts index d62e67c18d..405c8b729c 100644 --- a/src/domain/hopperValues.fixture.ts +++ b/src/domain/hopperValues.fixture.ts @@ -1,5 +1,3 @@ -import type { JsonValue } from "./jsonValue.js"; - export const ghidraFunctionClassification = () => ({ external: false, thunk: false, @@ -40,14 +38,6 @@ export const ghidraReferenceEdge = () => ({ kind: ghidraReferenceKind(), }); -export const ghidraBounded = (items: readonly JsonValue[]) => ({ - items: [...items], - total: items.length, - returned: items.length, - truncated: false, - next_offset: null, -}); - export const ghidraNativeApiBoundary = (mappingsTruncated = false) => ({ available: true as const, provenance: "ghidra-high-function", @@ -173,3 +163,4 @@ export const ghidraFunctionDossier = ( ], }; }; +import type { JsonValue } from "./jsonValue.js"; diff --git a/src/domain/javascriptExportInstrumentation.ts b/src/domain/javascriptExportInstrumentation.ts index bfaeb2187d..565a098c06 100644 --- a/src/domain/javascriptExportInstrumentation.ts +++ b/src/domain/javascriptExportInstrumentation.ts @@ -16,7 +16,6 @@ export const javascriptExportInstrumentationInputSchema = z.strictObject({ }); export const javascriptExportTransformationManifestSchema = z.strictObject({ - schema_version: z.literal(1), kind: z.literal("commonjs-factory-export-v1"), artifact_path: z.string().min(1).max(4_096), original_sha256: digestSchema, @@ -77,7 +76,6 @@ export const instrumentJavaScriptExport = ( const bindingStart = prefix.byteLength + source.byteLength; const suffixStart = bindingStart + binding.byteLength; const manifest = javascriptExportTransformationManifestSchema.parse({ - schema_version: 1, kind: "commonjs-factory-export-v1", artifact_path: input.artifact_path, original_sha256: input.artifact_sha256, diff --git a/src/domain/javascriptExportShapeComparison.ts b/src/domain/javascriptExportShapeComparison.ts index f9289f0336..be64195c45 100644 --- a/src/domain/javascriptExportShapeComparison.ts +++ b/src/domain/javascriptExportShapeComparison.ts @@ -2,7 +2,6 @@ import { compareCodePoints } from "./javascriptApplicationGraph.js"; import { digestExportShapeValue } from "./javascriptExportShapeComparisonIdentity.js"; import { javaScriptExportShapeComparisonResultSchema, - type CompareJavaScriptExportShapesInput, type JavaScriptExportShapeComparisonChange, type JavaScriptExportShapeComparisonResult, } from "./javascriptExportShapeComparisonSchemas.js"; @@ -25,29 +24,16 @@ import { export interface JavaScriptExportShapeComparisonProjectionInput { readonly left: JavaScriptExportShapeSideInput; readonly right: JavaScriptExportShapeSideInput; - readonly limits: CompareJavaScriptExportShapesInput["limits"]; } /** Compare exact selected export return shapes without executing JavaScript. */ export const compareJavaScriptExportShapes = ( input: JavaScriptExportShapeComparisonProjectionInput, ): JavaScriptExportShapeComparisonResult => { - const left = selectJavaScriptExport( - input.left, - input.limits.max_candidate_exports, - ); - const right = selectJavaScriptExport( - input.right, - input.limits.max_candidate_exports, - ); - const leftRetained = retainJavaScriptExportShapes( - left, - input.limits.max_return_variants, - ); - const rightRetained = retainJavaScriptExportShapes( - right, - input.limits.max_return_variants, - ); + const left = selectJavaScriptExport(input.left); + const right = selectJavaScriptExport(input.right); + const leftRetained = retainJavaScriptExportShapes(left); + const rightRetained = retainJavaScriptExportShapes(right); const pairing = pairJavaScriptExportShapeVariants( leftRetained.shapes, rightRetained.shapes, @@ -64,8 +50,8 @@ export const compareJavaScriptExportShapes = ( rightShapes: rightRetained.shapes, evidenceLinks, }).sort(compareJavaScriptExportShapeChanges); - const changes = allChanges.slice(0, input.limits.max_changes); - const omittedChanges = allChanges.length - changes.length; + const changes = allChanges; + const omittedChanges = 0; const coverage = comparisonCoverage({ input, left, diff --git a/src/domain/javascriptExportShapeComparisonSchemas.ts b/src/domain/javascriptExportShapeComparisonSchemas.ts index 312c604f36..56b47b2f52 100644 --- a/src/domain/javascriptExportShapeComparisonSchemas.ts +++ b/src/domain/javascriptExportShapeComparisonSchemas.ts @@ -54,13 +54,7 @@ const sourceRangeSchema = z }); }); -const comparisonLimitsSchema = z.strictObject({ - max_candidate_exports: z.number().int().min(1).max(1_000).default(100), - max_return_variants: z.number().int().min(1).max(1_000).default(128), - max_changes: z.number().int().min(1).max(10_000).default(1_000), -}); - -/** Two authenticated application graphs, exact export selectors, and bounds. */ +/** Two authenticated application graphs and exact export selectors. */ export const compareJavaScriptExportShapesInputSchema = z .strictObject({ left: evidenceSchema, @@ -69,11 +63,6 @@ export const compareJavaScriptExportShapesInputSchema = z left_export_name: selectorTextSchema, right_module_path: selectorTextSchema, right_export_name: selectorTextSchema, - limits: comparisonLimitsSchema.default({ - max_candidate_exports: 100, - max_return_variants: 128, - max_changes: 1_000, - }), unknown_registry_approved: z.literal(true).optional(), }) .superRefine((input, context) => { @@ -304,9 +293,6 @@ export const javaScriptExportShapeComparisonResultSchema = z.strictObject({ }), }); -export type CompareJavaScriptExportShapesInput = z.output< - typeof compareJavaScriptExportShapesInputSchema ->; export type ProjectedExportReturnShapes = z.output< typeof projectedExportReturnShapesSchema >; diff --git a/src/domain/javascriptExportShapeSelection.ts b/src/domain/javascriptExportShapeSelection.ts index d7538234f7..4a89db62b8 100644 --- a/src/domain/javascriptExportShapeSelection.ts +++ b/src/domain/javascriptExportShapeSelection.ts @@ -53,7 +53,7 @@ export type SelectedJavaScriptExport = readonly limitations: readonly string[]; }; -/** Caller-retained return shapes and their exact caller-limit omission count. */ +/** Complete return-shape inventory retained from an authenticated projection. */ export interface RetainedJavaScriptExportShapes { readonly shapes: readonly Shape[]; readonly omitted: number; @@ -62,7 +62,6 @@ export interface RetainedJavaScriptExportShapes { /** Select one exact trusted export and its exact static return-shape observation. */ export const selectJavaScriptExport = ( side: JavaScriptExportShapeSideInput, - maxCandidates: number, ): SelectedJavaScriptExport => { const candidates = exportCandidates(side.graph); const exact = candidates.filter( @@ -79,8 +78,7 @@ export const selectJavaScriptExport = ( : matchingOneSelector.length > 0 ? matchingOneSelector : candidates; - const retainedCandidates = diagnosticPool.slice(0, maxCandidates); - const base = selectorBase(side, diagnosticPool, retainedCandidates); + const base = selectorBase(side, diagnosticPool); if (exact.length === 0) return unresolvedSelection( base, @@ -128,33 +126,30 @@ export const selectJavaScriptExport = ( }; }; -/** Apply the caller's explicit return-variant limit. */ +/** Retain every projected return variant. */ export const retainJavaScriptExportShapes = ( selection: SelectedJavaScriptExport, - maximum: number, ): RetainedJavaScriptExportShapes => { const shapes = selection.projection?.static_return_shapes ?? []; - const retained = shapes.slice(0, maximum); - return { shapes: retained, omitted: shapes.length - retained.length }; + return { shapes, omitted: 0 }; }; const selectorBase = ( side: JavaScriptExportShapeSideInput, candidates: readonly ExportCandidate[], - retained: readonly ExportCandidate[], ): SelectorBase => ({ evidence_id: side.evidenceId, graph_id: side.graph.graph_id, requested_module_path: side.modulePath, requested_export_name: side.exportName, - candidates: retained.map((candidate) => ({ + candidates: candidates.map((candidate) => ({ node_id: candidate.node.node_id, module_path: candidate.modulePath, export_name: candidate.exportName, matches_requested_module: candidate.modulePath === side.modulePath, matches_requested_export: candidate.exportName === side.exportName, })), - omitted_candidates: candidates.length - retained.length, + omitted_candidates: 0, }); const unresolvedSelection = ( diff --git a/src/domain/javascriptReplay.ts b/src/domain/javascriptReplay.ts index 68819ec918..b03c3367be 100644 --- a/src/domain/javascriptReplay.ts +++ b/src/domain/javascriptReplay.ts @@ -214,7 +214,6 @@ const runtimeFileIdentitySchema = z const replayPlanSchema = z .object({ - schema_version: z.literal(1), plan_digest: digestSchema, policy_version: z.literal("linux-bwrap-systemd-v1"), policy_sha256: digestSchema, diff --git a/src/domain/javascriptSemanticGraphTraversal.test.ts b/src/domain/javascriptSemanticGraphTraversal.test.ts index 602735b57b..08d223c1ad 100644 --- a/src/domain/javascriptSemanticGraphTraversal.test.ts +++ b/src/domain/javascriptSemanticGraphTraversal.test.ts @@ -15,7 +15,6 @@ import { type JavaScriptSemanticGraphNode, } from "./javascriptSemanticGraph.js"; import { queryJavaScriptSemanticGraph } from "./javascriptSemanticQuery.js"; -import { javaScriptSemanticQueryInputSchema } from "./javascriptSemanticQuerySchemas.js"; const SHA = "a".repeat(64); const JAG_ID = `jag_${"b".repeat(64)}`; @@ -244,70 +243,35 @@ const graphWithCandidateEdge = (): JavaScriptSemanticGraph => { }); }; -const graphWithDuplicateLiteral = (): JavaScriptSemanticGraph => { - const graph = fixtureGraph(); - const duplicate = node("literal", "literal-copy", { value: "TOKEN" }); - const { graph_id: _graphId, ...input } = graph; - return createJavaScriptSemanticGraph({ - ...input, - nodes: [...graph.nodes, duplicate], - }); -}; - -it("bounds relevant unknown frontiers independently from relation pages", () => { +it("returns every relevant unknown inline", () => { const graph = fixtureGraph(true); const callable = graph.nodes.find(({ kind }) => kind === "function"); if (callable === undefined) throw new Error("Expected callable node"); const result = queryJavaScriptSemanticGraph(graph, { seed: { kind: "semantic-node", node_id: callable.node_id }, direction: "forward-influence", - limits: { max_unknowns: 0 }, }); expect(result).toMatchObject({ - status: "truncated", - unknowns: [], - summary: { relevant_unknowns: 1, retained_unknowns: 0 }, - coverage: { status: "truncated" }, + summary: { relevant_unknowns: 1, retained_unknowns: 1 }, }); + expect(result.unknowns).toHaveLength(1); }); -it("traces deterministic forward influence and pages without changing identity", () => { +it("returns the complete deterministic forward influence result inline", () => { const graph = fixtureGraph(); const input = { seed: { kind: "literal" as const, value: "TOKEN" }, direction: "forward-influence" as const, expected: { role: "sink" as const, classes: ["request" as const] }, - limits: { - max_seed_matches: 25, - max_nodes: 20, - max_edges: 20, - max_depth: 12, - max_functions: 10, - max_modules: 10, - page_size: 2, - }, }; const first = queryJavaScriptSemanticGraph(graph, input); expect(first).toMatchObject({ status: "found", summary: { traversed_nodes: 4, traversed_relations: 3 }, - page: { offset: 0, size: 2 }, + relations: expect.any(Array), }); expect(first.expected_match_node_ids).toHaveLength(1); - expect(first.page.next_cursor).not.toBeNull(); - const second = queryJavaScriptSemanticGraph(graph, { - ...input, - cursor: first.page.next_cursor, - }); - expect(second.query_id).toBe(first.query_id); - expect(second.page).toMatchObject({ - offset: 2, - size: 1, - next_cursor: null, - }); - expect(second.relations[0]?.relation_id).not.toBe( - first.relations[0]?.relation_id, - ); + expect(first.relations).toHaveLength(3); }); it("keeps relevant dynamic frontiers unknown", () => { @@ -343,103 +307,3 @@ it("excludes candidate edges unless the caller explicitly opts in", () => { { relation: "supplies-request-field", resolution: "candidate" }, ]); }); - -it("bounds seed ambiguity before traversal", () => { - const result = queryJavaScriptSemanticGraph(graphWithDuplicateLiteral(), { - seed: { kind: "literal", value: "TOKEN" }, - direction: "forward-influence", - limits: { - max_seed_matches: 1, - max_nodes: 20, - max_edges: 20, - max_depth: 12, - max_functions: 10, - max_modules: 10, - page_size: 10, - }, - }); - expect(result.summary).toMatchObject({ - total_seed_matches: 2, - retained_seed_matches: 1, - }); - expect(result.status).toBe("truncated"); - expect(result.coverage.frontier).toContainEqual( - expect.objectContaining({ reason: "max-seed-matches", depth: 0 }), - ); -}); - -it("reports exact caller limits and a deterministic truncation frontier", () => { - const result = queryJavaScriptSemanticGraph(fixtureGraph(), { - seed: { kind: "literal", value: "TOKEN" }, - direction: "forward-influence", - limits: { - max_seed_matches: 1, - max_nodes: 2, - max_edges: 10, - max_depth: 12, - max_functions: 10, - max_modules: 10, - page_size: 10, - }, - }); - expect(result.status).toBe("truncated"); - expect(result.coverage.frontier).toMatchObject([{ reason: "max-nodes" }]); - expect(result.applied_limits.max_nodes).toBe(2); - expect(result.accepted_limit_ranges.max_nodes).toEqual({ - minimum: 1, - maximum: 50_000, - }); -}); - -it.each([ - { - limit: { max_edges: 1 }, - reason: "max-edges", - }, - { - limit: { max_depth: 0 }, - reason: "max-depth", - }, -])("reports the $reason frontier", ({ limit, reason }) => { - const result = queryJavaScriptSemanticGraph(fixtureGraph(), { - seed: { kind: "literal", value: "TOKEN" }, - direction: "forward-influence", - limits: { - max_seed_matches: 10, - max_nodes: 20, - max_edges: limit.max_edges ?? 20, - max_depth: limit.max_depth ?? 12, - max_functions: 10, - max_modules: 10, - page_size: 10, - }, - }); - expect(result.status).toBe("truncated"); - expect(result.coverage.frontier).toContainEqual( - expect.objectContaining({ reason }), - ); -}); - -it("rejects out-of-range limits and cursors from another query", () => { - expect(() => - javaScriptSemanticQueryInputSchema.parse({ - seed: { kind: "literal", value: "TOKEN" }, - direction: "forward-influence", - limits: { max_nodes: 50_001 }, - }), - ).toThrow(); - const graph = fixtureGraph(); - const first = queryJavaScriptSemanticGraph(graph, { - seed: { kind: "literal", value: "TOKEN" }, - direction: "forward-influence", - limits: { page_size: 1 }, - }); - expect(() => - queryJavaScriptSemanticGraph(graph, { - seed: { kind: "endpoint", value: "https://example.invalid/v1" }, - direction: "backward-provenance", - limits: { page_size: 1 }, - cursor: first.page.next_cursor, - }), - ).toThrow(/cursor does not match/u); -}); diff --git a/src/domain/javascriptSemanticQuery.ts b/src/domain/javascriptSemanticQuery.ts index 4841225a69..0d2a54e65f 100644 --- a/src/domain/javascriptSemanticQuery.ts +++ b/src/domain/javascriptSemanticQuery.ts @@ -18,13 +18,20 @@ import { } from "./javascriptSemanticQueryAssessment.js"; import { canonicalJavaScriptSemanticQueryJson as canonicalJson, - createJavaScriptSemanticQueryCursor as createCursor, - JavaScriptSemanticQueryCursorError, javaScriptSemanticQueryIdentifier as queryIdentifier, - parseJavaScriptSemanticQueryCursor as parseCursor, resolveJavaScriptSemanticQuerySeeds as resolveSeeds, } from "./javascriptSemanticQueryIdentity.js"; +const TRAVERSAL_LIMITS = { + max_seed_matches: 1_000, + max_nodes: 50_000, + max_edges: 100_000, + max_depth: 64, + max_functions: 10_000, + max_modules: 10_000, + max_unknowns: 10_000, +} as const; + interface TraversalEntry { readonly relation: JavaScriptSemanticGraphRelation; readonly nextNodeId: string; @@ -45,21 +52,9 @@ interface SeedAdmission { readonly frontier: QueryFrontier[]; } -interface QueryPage { +interface QueryResult { readonly retainedNodes: JavaScriptSemanticGraphNode[]; readonly retainedRelations: JavaScriptSemanticGraphRelation[]; - readonly pageRelations: JavaScriptSemanticGraphRelation[]; - readonly pageNodes: JavaScriptSemanticGraphNode[]; - readonly nextCursor: string | null; -} - -interface QueryPageInput { - readonly graph: JavaScriptSemanticGraph; - readonly traversal: Traversal; - readonly query: JavaScriptSemanticQueryInput; - readonly queryId: string; - readonly offset: number; - readonly retainedSeeds: readonly string[]; } /** Run one deterministic bounded traversal over a verified semantic graph. */ @@ -69,7 +64,6 @@ export const queryJavaScriptSemanticGraph = ( ): JavaScriptSemanticQueryResult => { const input = javaScriptSemanticQueryInputSchema.parse(rawInput); const queryId = queryIdentifier(graph, input); - const offset = parseCursor(input.cursor, queryId); const seeds = resolveSeeds(graph, input); const admission = admitSeeds(graph, seeds, input); const retainedSeeds = admission.nodeIds; @@ -79,14 +73,7 @@ export const queryJavaScriptSemanticGraph = ( ...traversal.frontier, ...admission.frontier, ]); - const page = createQueryPage({ - graph, - traversal, - query: input, - queryId, - offset, - retainedSeeds, - }); + const result = createQueryResult(graph, traversal); const allRelevantUnknowns = relevantUnknownFrontiers( graph, traversal.nodeIds, @@ -94,7 +81,7 @@ export const queryJavaScriptSemanticGraph = ( ); const relevantUnknowns = allRelevantUnknowns.slice( 0, - input.limits.max_unknowns, + TRAVERSAL_LIMITS.max_unknowns, ); const candidateRelations = relevantCandidateRelationCount( graph, @@ -102,8 +89,8 @@ export const queryJavaScriptSemanticGraph = ( input, ); const expectedMatches = expectedMatchesFor( - page.retainedNodes, - page.retainedRelations, + result.retainedNodes, + result.retainedRelations, input, ); const assessment = assessJavaScriptSemanticQuery({ @@ -124,8 +111,8 @@ export const queryJavaScriptSemanticGraph = ( direction: input.direction, status: assessment.status, seed_node_ids: retainedSeeds, - nodes: page.pageNodes, - relations: page.pageRelations, + nodes: result.retainedNodes, + relations: result.retainedRelations, unknowns: relevantUnknowns, expected_match_node_ids: expectedMatches.map(({ node_id }) => node_id), summary: { @@ -139,60 +126,21 @@ export const queryJavaScriptSemanticGraph = ( retained_unknowns: relevantUnknowns.length, }, coverage: assessment.coverage, - page: { - offset, - size: page.pageRelations.length, - next_cursor: page.nextCursor, - }, - applied_limits: input.limits, - accepted_limit_ranges: assessment.acceptedLimitRanges, limitations: assessment.limitations, }); }; -const createQueryPage = ({ - graph, - traversal, - query, - queryId, - offset, - retainedSeeds, -}: QueryPageInput): QueryPage => { +const createQueryResult = ( + graph: JavaScriptSemanticGraph, + traversal: Traversal, +): QueryResult => { const retainedNodes = graph.nodes.filter(({ node_id }) => traversal.nodeIds.has(node_id), ); const retainedRelations = graph.relations.filter(({ relation_id }) => traversal.relationIds.has(relation_id), ); - if (offset > retainedRelations.length) - throw new JavaScriptSemanticQueryCursorError( - "Semantic query cursor is beyond the retained result", - ); - const pageRelations = retainedRelations.slice( - offset, - offset + query.limits.page_size, - ); - const pageNodeIds = new Set([ - ...retainedSeeds, - ...pageRelations.flatMap(({ source_node_id, target_node_id }) => [ - source_node_id, - target_node_id, - ]), - ]); - const pageNodes = graph.nodes.filter(({ node_id }) => - pageNodeIds.has(node_id), - ); - const nextOffset = offset + pageRelations.length; - return { - retainedNodes, - retainedRelations, - pageRelations, - pageNodes, - nextCursor: - nextOffset < retainedRelations.length - ? createCursor(queryId, nextOffset) - : null, - }; + return { retainedNodes, retainedRelations }; }; const admitSeeds = ( @@ -244,20 +192,19 @@ const seedBlockedReason = ( node: JavaScriptSemanticGraphNode, bounds: SeedBounds, ): QueryFrontier["reason"] | null => { - if (bounds.retained.length >= bounds.input.limits.max_seed_matches) + if (bounds.retained.length >= TRAVERSAL_LIMITS.max_seed_matches) return "max-seed-matches"; - if (bounds.retained.length >= bounds.input.limits.max_nodes) - return "max-nodes"; + if (bounds.retained.length >= TRAVERSAL_LIMITS.max_nodes) return "max-nodes"; const functionId = functionOwner(node); if ( functionId !== null && !bounds.functions.has(functionId) && - bounds.functions.size >= bounds.input.limits.max_functions + bounds.functions.size >= TRAVERSAL_LIMITS.max_functions ) return "max-functions"; if ( !bounds.modules.has(node.identity.module_path) && - bounds.modules.size >= bounds.input.limits.max_modules + bounds.modules.size >= TRAVERSAL_LIMITS.max_modules ) return "max-modules"; return null; @@ -407,26 +354,26 @@ const blockedReason = ( depth: number, bounds: TraversalBounds, ): QueryFrontier["reason"] | null => { - if (depth >= bounds.input.limits.max_depth) return "max-depth"; + if (depth >= TRAVERSAL_LIMITS.max_depth) return "max-depth"; if ( !bounds.relationIds.has(entry.relation.relation_id) && - bounds.relationIds.size >= bounds.input.limits.max_edges + bounds.relationIds.size >= TRAVERSAL_LIMITS.max_edges ) return "max-edges"; if (bounds.nodeIds.has(entry.nextNodeId)) return null; - if (bounds.nodeIds.size >= bounds.input.limits.max_nodes) return "max-nodes"; + if (bounds.nodeIds.size >= TRAVERSAL_LIMITS.max_nodes) return "max-nodes"; const node = bounds.nodes.get(entry.nextNodeId); if (node === undefined) return null; const functionId = functionOwner(node); if ( functionId !== null && !bounds.functionIds.has(functionId) && - bounds.functionIds.size >= bounds.input.limits.max_functions + bounds.functionIds.size >= TRAVERSAL_LIMITS.max_functions ) return "max-functions"; if ( !bounds.modules.has(node.identity.module_path) && - bounds.modules.size >= bounds.input.limits.max_modules + bounds.modules.size >= TRAVERSAL_LIMITS.max_modules ) return "max-modules"; return null; diff --git a/src/domain/javascriptSemanticQueryAssessment.ts b/src/domain/javascriptSemanticQueryAssessment.ts index 44953094ae..bc7082476d 100644 --- a/src/domain/javascriptSemanticQueryAssessment.ts +++ b/src/domain/javascriptSemanticQueryAssessment.ts @@ -34,7 +34,6 @@ export interface JavaScriptSemanticQueryAssessment { readonly status: JavaScriptSemanticQueryResult["status"]; readonly coverage: JavaScriptSemanticQueryResult["coverage"]; readonly limitations: string[]; - readonly acceptedLimitRanges: JavaScriptSemanticQueryResult["accepted_limit_ranges"]; } /** Classify a bounded semantic traversal without promoting unknowns to absence. */ @@ -44,16 +43,6 @@ export const assessJavaScriptSemanticQuery = ( status: queryStatus(input), coverage: queryCoverage(input), limitations: queryLimitations(input), - acceptedLimitRanges: { - max_seed_matches: { minimum: 1, maximum: 1_000 }, - max_nodes: { minimum: 1, maximum: 50_000 }, - max_edges: { minimum: 1, maximum: 100_000 }, - max_depth: { minimum: 0, maximum: 64 }, - max_functions: { minimum: 1, maximum: 10_000 }, - max_modules: { minimum: 1, maximum: 10_000 }, - max_unknowns: { minimum: 0, maximum: 10_000 }, - page_size: { minimum: 1, maximum: 1_000 }, - }, }); const queryCoverage = ( @@ -98,12 +87,12 @@ const queryLimitations = ( ...(input.totalSeeds === input.retainedSeeds ? [] : [ - "Seed matches exceeded caller bounds; omitted starts remain unexplored.", + "Seed matches exceeded the internal traversal safety ceiling; omitted starts remain unexplored.", ]), ...(input.frontier.length === 0 ? [] : [ - "Traversal stopped at explicit caller limits; frontier facts remain unknown.", + "Traversal stopped at an internal resource ceiling; frontier facts remain unknown.", ]), ...(input.unknowns.length === 0 ? [] @@ -112,7 +101,7 @@ const queryLimitations = ( ]), ...(input.unknownsTruncated ? [ - "Relevant unknown frontiers exceeded the caller limit; omitted unknowns remain unresolved.", + "Relevant unknown frontiers exceeded the internal result safety ceiling; omitted unknowns remain unresolved.", ] : []), ...(input.candidateRelations === 0 diff --git a/src/domain/javascriptSemanticQueryIdentity.ts b/src/domain/javascriptSemanticQueryIdentity.ts index b83d6c6ef0..3b7633de95 100644 --- a/src/domain/javascriptSemanticQueryIdentity.ts +++ b/src/domain/javascriptSemanticQueryIdentity.ts @@ -9,9 +9,6 @@ import type { } from "./javascriptSemanticGraph.js"; import type { JavaScriptSemanticQueryInput } from "./javascriptSemanticQuerySchemas.js"; -/** Caller cursor that cannot identify a page of the current semantic query. */ -export class JavaScriptSemanticQueryCursorError extends TypeError {} - /** Canonical JSON used by semantic query commitments and ordering. */ export const canonicalJavaScriptSemanticQueryJson = ( value: unknown, @@ -32,12 +29,12 @@ const digest = (value: unknown): string => const uniqueSorted = (values: readonly string[]): string[] => [...new Set(values)].sort(compareCodePoints); -/** Derive the stable identity for one graph-bound query without its cursor. */ +/** Derive the stable identity for one graph-bound query. */ export const javaScriptSemanticQueryIdentifier = ( graph: JavaScriptSemanticGraph, input: JavaScriptSemanticQueryInput, ): string => { - const { cursor: _cursor, ...semantic } = input; + const semantic = input; return `jsrq_${digest({ source_graph_id: graph.graph_id, ...semantic, @@ -55,37 +52,6 @@ export const javaScriptSemanticQueryIdentifier = ( })}`; }; -/** Commit one deterministic relation-page offset to a query identity. */ -export const createJavaScriptSemanticQueryCursor = ( - queryId: string, - offset: number, -): string => `jsrqc_${String(offset)}_${digest({ query_id: queryId, offset })}`; - -/** Parse a query-bound cursor and reject stale, malformed, or foreign values. */ -export const parseJavaScriptSemanticQueryCursor = ( - cursor: string | null, - queryId: string, -): number => { - if (cursor === null) return 0; - const match = /^jsrqc_([0-9]+)_([a-f0-9]{64})$/u.exec(cursor); - const offsetText = match?.[1]; - const commitment = match?.[2]; - if (offsetText === undefined || commitment === undefined) - throw new JavaScriptSemanticQueryCursorError( - "Semantic query cursor is malformed", - ); - const offset = Number(offsetText); - if ( - !Number.isSafeInteger(offset) || - offset < 0 || - commitment !== digest({ query_id: queryId, offset }) - ) - throw new JavaScriptSemanticQueryCursorError( - "Semantic query cursor does not match this query", - ); - return offset; -}; - /** Resolve deterministic seed candidates without applying traversal limits. */ export const resolveJavaScriptSemanticQuerySeeds = ( graph: JavaScriptSemanticGraph, diff --git a/src/domain/javascriptSemanticQuerySchemas.ts b/src/domain/javascriptSemanticQuerySchemas.ts index e7f3f90dee..1797938ebb 100644 --- a/src/domain/javascriptSemanticQuerySchemas.ts +++ b/src/domain/javascriptSemanticQuerySchemas.ts @@ -57,18 +57,6 @@ export const javaScriptSemanticQuerySeedSchema = z.discriminatedUnion("kind", [ }), ]); -/** Strict caller limits for deterministic bounded traversal. */ -export const javaScriptSemanticQueryLimitsSchema = z.strictObject({ - max_seed_matches: z.number().int().min(1).max(1_000).default(25), - max_nodes: z.number().int().min(1).max(50_000).default(2_000), - max_edges: z.number().int().min(1).max(100_000).default(4_000), - max_depth: z.number().int().min(0).max(64).default(12), - max_functions: z.number().int().min(1).max(10_000).default(500), - max_modules: z.number().int().min(1).max(10_000).default(500), - max_unknowns: z.number().int().min(0).max(10_000).default(1_000), - page_size: z.number().int().min(1).max(1_000).default(200), -}); - const sourceMapAuthoritySchema = z.strictObject({ authority: z.literal("none"), }); @@ -96,21 +84,6 @@ export const javaScriptSemanticQueryInputSchema = z.strictObject({ .nullable() .default(null), source_map_authority: sourceMapAuthoritySchema.default({ authority: "none" }), - limits: javaScriptSemanticQueryLimitsSchema.default({ - max_seed_matches: 25, - max_nodes: 2_000, - max_edges: 4_000, - max_depth: 12, - max_functions: 500, - max_modules: 500, - max_unknowns: 1_000, - page_size: 200, - }), - cursor: z - .string() - .regex(/^jsrqc_[0-9]+_[a-f0-9]{64}$/u) - .nullable() - .default(null), }); const queryFrontierSchema = z.strictObject({ @@ -126,7 +99,7 @@ const queryFrontierSchema = z.strictObject({ ]), }); -/** Deterministic, pageable semantic trace result. */ +/** Deterministic semantic trace result. */ export const javaScriptSemanticQueryResultSchema = z.strictObject({ query_id: z.string().regex(/^jsrq_[a-f0-9]{64}$/u), source_graph_id: z.string().regex(/^jsrg_[a-f0-9]{64}$/u), @@ -159,49 +132,6 @@ export const javaScriptSemanticQueryResultSchema = z.strictObject({ status: z.enum(["complete", "partial", "truncated", "unavailable"]), frontier: z.array(queryFrontierSchema).max(100_000), }), - page: z.strictObject({ - offset: z.number().int().min(0), - size: z.number().int().min(0).max(1_000), - next_cursor: z - .string() - .regex(/^jsrqc_[0-9]+_[a-f0-9]{64}$/u) - .nullable(), - }), - applied_limits: javaScriptSemanticQueryLimitsSchema, - accepted_limit_ranges: z.strictObject({ - max_seed_matches: z.strictObject({ - minimum: z.literal(1), - maximum: z.literal(1_000), - }), - max_nodes: z.strictObject({ - minimum: z.literal(1), - maximum: z.literal(50_000), - }), - max_edges: z.strictObject({ - minimum: z.literal(1), - maximum: z.literal(100_000), - }), - max_depth: z.strictObject({ - minimum: z.literal(0), - maximum: z.literal(64), - }), - max_functions: z.strictObject({ - minimum: z.literal(1), - maximum: z.literal(10_000), - }), - max_modules: z.strictObject({ - minimum: z.literal(1), - maximum: z.literal(10_000), - }), - max_unknowns: z.strictObject({ - minimum: z.literal(0), - maximum: z.literal(10_000), - }), - page_size: z.strictObject({ - minimum: z.literal(1), - maximum: z.literal(1_000), - }), - }), limitations: z.array(z.string().min(1).max(4_096)).max(1_000), }); diff --git a/src/domain/reconstructionObligationLedgerSchemas.ts b/src/domain/reconstructionObligationLedgerSchemas.ts index b81c3361fb..21bd56c977 100644 --- a/src/domain/reconstructionObligationLedgerSchemas.ts +++ b/src/domain/reconstructionObligationLedgerSchemas.ts @@ -283,22 +283,6 @@ export const reconstructionObligationLedgerInputSchema = z.strictObject({ evidence_bundle: evidenceBundleSchema, reviewed_obligations: z.array(reviewedReconstructionObligationSchema), manifest: reconstructionObligationManifestSchema, - page: z.strictObject({ - offset: z.number().int().min(0).max(10_000), - limit: z.number().int().min(1).max(100), - }), -}); - -export const reconstructionObligationLedgerPageSchema = z.strictObject({ - ...reconstructionObligationLedgerSchema.omit({ obligations: true }).shape, - page: z.strictObject({ - offset: z.number().int().min(0), - limit: z.number().int().min(1).max(100), - total: z.number().int().min(0), - returned: z.number().int().min(0), - next_offset: z.number().int().min(0).nullable(), - }), - obligations: z.array(reconstructionObligationSchema).max(100), }); export type ReconstructionObligation = z.infer< @@ -310,9 +294,6 @@ export type ReconstructionObligationLedger = z.infer< export type ReconstructionObligationLedgerInput = z.infer< typeof reconstructionObligationLedgerInputSchema >; -export type ReconstructionObligationLedgerPage = z.infer< - typeof reconstructionObligationLedgerPageSchema ->; export type ReviewedReconstructionObligation = z.infer< typeof reviewedReconstructionObligationSchema >; diff --git a/src/domain/reconstructionUnknowns.ts b/src/domain/reconstructionUnknowns.ts index 5ade6219be..99215f18c3 100644 --- a/src/domain/reconstructionUnknowns.ts +++ b/src/domain/reconstructionUnknowns.ts @@ -66,14 +66,11 @@ export const reconstructionClaimUnknowns = ( ); }; -/** Aggregate and bound deterministic probes for unresolved claims. */ +/** Aggregate deterministic probes for unresolved claims. */ export const reconstructionProbes = ( results: readonly ReconstructionClaimResult[], heads: ReadonlyMap, -): { - readonly items: ReconstructionVerificationResult["recommended_probes"]; - readonly truncated: boolean; -} => { +): ReconstructionVerificationResult["recommended_probes"] => { const output = new Map< string, { @@ -111,7 +108,7 @@ export const reconstructionProbes = ( "en", ), ); - return { items: sorted.slice(0, 2_000), truncated: sorted.length > 2_000 }; + return sorted; }; const defaultProbe = ( diff --git a/src/domain/reconstructionVerification.test.ts b/src/domain/reconstructionVerification.test.ts index 06afae7af9..5b650a41f6 100644 --- a/src/domain/reconstructionVerification.test.ts +++ b/src/domain/reconstructionVerification.test.ts @@ -118,19 +118,35 @@ const behavioralSpec = (comparison: Evidence) => ({ ], }); -const artifactResult = (partial = false): JsonValue => ({ - status: "unchanged", +const artifactResult = ( + partial = false, + evidenceLinks: readonly string[] = [], +): JsonValue => ({ + status: partial ? "truncated" : "unchanged", left_manifest_id: `agm_${"3".repeat(64)}`, right_manifest_id: `agm_${"4".repeat(64)}`, - summary: { unchanged: 1, added: 0, removed: 0, changed: 0, unknown: 0 }, - changes: { - items: [], - offset: 0, - limit: 100, - total: partial ? 1 : 0, - next_offset: partial ? 1 : null, + summary: { + unchanged: partial ? 0 : 1, + added: 0, + removed: 0, + changed: 0, + unknown: partial ? 1 : 0, }, - limitations: [], + changes: partial + ? [ + { + classification: "unknown", + logical_path: "unavailable", + dimensions: ["availability"], + left_occurrence_id: null, + right_occurrence_id: null, + left_artifact_id: null, + right_artifact_id: null, + evidence_links: [...evidenceLinks], + }, + ] + : [], + limitations: partial ? ["Inventory evidence is incomplete."] : [], }); const artifactComparison = ( @@ -152,7 +168,7 @@ const artifactComparison = ( left_evidence_ids: [left.evidence_id], right_evidence_ids: [right.evidence_id], }, - result: artifactResult(partial), + result: artifactResult(partial, [left.evidence_id, right.evidence_id]), confidence: "derived", authority: "analyst-inference", evidenceLinks: [left.evidence_id, right.evidence_id], @@ -207,8 +223,6 @@ describe("reconstruction verification", () => { ], }, createEvidenceBundle([comparison, right, left]), - 0, - 100, ), ).toMatchObject({ summary: { total: 2, passed: 1, failed: 1, unknown: 0 }, @@ -222,13 +236,11 @@ describe("reconstruction verification", () => { const result = verifyReconstruction( behavioralSpec(comparison), createEvidenceBundle([comparison, right, left]), - 0, - 100, ); expect(reconstructionVerificationResultSchema.parse(result)).toMatchObject({ status: "pass", summary: { total: 1, passed: 1, failed: 0, unknown: 0 }, - claims: { total: 1, next_offset: null }, + claims: { items: expect.any(Array) }, }); expect( reconstructionVerificationResultSchema.safeParse({ @@ -258,8 +270,6 @@ describe("reconstruction verification", () => { const result = verifyReconstruction( behavioralSpec(comparison), createEvidenceBundle([left, right, comparison]), - 0, - 100, ); expect(result).toMatchObject({ status: "fail", @@ -276,8 +286,6 @@ describe("reconstruction verification", () => { verifyReconstruction( behavioralSpec(runtime), createEvidenceBundle([weakLeft, replayRight, runtime]), - 0, - 100, ).status, ).toBe("unknown"); @@ -298,8 +306,6 @@ describe("reconstruction verification", () => { ], }, createEvidenceBundle([left, comparison, right]), - 0, - 100, ); expect(result.status).toBe("unknown"); expect(result.recommended_probes[0]?.operation).toBe("inventory_artifact"); @@ -318,13 +324,11 @@ describe("reconstruction verification integrity", () => { verifyReconstruction( behavioralSpec(comparison), createEvidenceBundle([left, right, extra, comparison]), - 0, - 100, ), ).toThrow(/closure disagrees/u); }); - it("pages claims deterministically and gives specification a stable digest", () => { + it("returns every claim deterministically and gives specification a stable digest", () => { const left = source("1", "controlled-replay"); const right = source("2", "controlled-replay"); const comparison = processComparison(left, right, processResult()); @@ -342,8 +346,6 @@ describe("reconstruction verification integrity", () => { const first = verifyReconstruction( { name: "Compatibility", claims }, bundle, - 0, - 1, ); const repeated = verifyReconstruction( { @@ -351,15 +353,15 @@ describe("reconstruction verification integrity", () => { claims: [...claims].reverse(), }, bundle, - 0, - 1, ); expect(first).toEqual(repeated); - expect(first.claims.items[0]?.claim_id).toBe("terminal-output"); - expect(first.claims.next_offset).toBe(1); + expect(first.claims.items.map(({ claim_id }) => claim_id)).toEqual([ + "terminal-output", + "z-exit", + ]); }); - it("keeps all active unknowns gating while bounding their projection", () => { + it("returns all active unknowns while keeping them gating", () => { const left = source("1", "controlled-replay"); const right = source("2", "controlled-replay"); const comparison = processComparison(left, right, processResult()); @@ -400,13 +402,8 @@ describe("reconstruction verification integrity", () => { const result = verifyReconstruction( behavioralSpec(comparison), createEvidenceBundle([left, right, comparison, ...mutations], unknowns), - 0, - 100, ); expect(result.status).toBe("unknown"); - expect(result.claims.items[0]?.unknown_ids).toHaveLength(100); - expect(result.claims.items[0]?.limitations).toContain( - "1 additional active residual unknowns affect this claim but are omitted by the 100-item display limit.", - ); + expect(result.claims.items[0]?.unknown_ids).toHaveLength(101); }); }); diff --git a/src/domain/reconstructionVerification.ts b/src/domain/reconstructionVerification.ts index 663d299289..59e287ea7e 100644 --- a/src/domain/reconstructionVerification.ts +++ b/src/domain/reconstructionVerification.ts @@ -73,8 +73,6 @@ const acceptsPredicate = ( export const verifyReconstruction = ( specificationInput: unknown, bundleInput: unknown, - offset: number, - limit: number, ): ReconstructionVerificationResult => { const specification = reconstructionSpecificationSchema.parse(specificationInput); @@ -91,7 +89,6 @@ export const verifyReconstruction = ( const results = specification.claims .map((claim) => evaluateClaim(claim, records, heads)) .sort((left, right) => left.claim_id.localeCompare(right.claim_id, "en")); - const page = results.slice(offset, offset + limit); const failed = count(results, "fail"); const unresolved = count(results, "unknown"); const probes = reconstructionProbes(results, heads); @@ -117,20 +114,12 @@ export const verifyReconstruction = ( structural: results.filter(({ kind }) => kind !== "behavioral").length, }, claims: { - items: page, - offset, - limit, - total: results.length, - next_offset: - offset + page.length < results.length ? offset + page.length : null, + items: results, }, - recommended_probes: probes.items, + recommended_probes: probes, evidence_links: evidenceLinks, limitations: [ "Pass means every declared claim passed; it does not establish global implementation equivalence.", - ...(probes.truncated - ? ["Recommended probes were truncated at the 2,000-item limit."] - : []), ], }; return reconstructionVerificationResultSchema.parse(output); @@ -172,8 +161,7 @@ const evaluateClaim = ( allSourceIds, ); const status = classify(observed, limitations, relevantUnknowns); - const displayedUnknowns = relevantUnknowns.slice(0, 100); - const hiddenUnknownCount = relevantUnknowns.length - displayedUnknowns.length; + const displayedUnknowns = relevantUnknowns; return reconstructionClaimResultSchema.parse({ claim_id: claim.claim_id, kind: claim.kind, @@ -191,11 +179,6 @@ const evaluateClaim = ( ...displayedUnknowns.map( ({ question }) => `Residual unknown: ${question}`, ), - ...(hiddenUnknownCount > 0 - ? [ - `${hiddenUnknownCount} additional active residual unknowns affect this claim but are omitted by the 100-item display limit.`, - ] - : []), ]), }); }; @@ -307,13 +290,7 @@ const observedStatus = (claim: Claim, evidence: Evidence): ObservedStatus => { evidence.normalized_result, ); if ( - result.changes.offset !== 0 || - result.changes.next_offset !== null || - result.changes.items.length !== result.changes.total - ) - return "unknown"; - if ( - result.changes.items.some((item) => + result.changes.some((item) => item.evidence_links.some((id) => !evidence.evidence_links.includes(id)), ) ) diff --git a/src/domain/reconstructionVerificationSchemas.ts b/src/domain/reconstructionVerificationSchemas.ts index a7e8e39a37..eae5360fdb 100644 --- a/src/domain/reconstructionVerificationSchemas.ts +++ b/src/domain/reconstructionVerificationSchemas.ts @@ -57,7 +57,7 @@ const reconstructionClaimSchema = z.discriminatedUnion("kind", [ export const reconstructionSpecificationSchema = z .object({ name: z.string().trim().min(1).max(200), - claims: z.array(reconstructionClaimSchema).min(1).max(100), + claims: z.array(reconstructionClaimSchema).min(1), }) .superRefine((value, context) => { const ids = value.claims.map(({ claim_id: id }) => id); @@ -85,8 +85,6 @@ export const reconstructionVerificationInputSchema = z.strictObject({ boundary_id: z.string().min(1).max(200), }) .optional(), - offset: z.number().int().min(0).default(0), - limit: z.number().int().min(1).max(100).default(100), unknown_registry_approved: z.literal(true).optional(), }); @@ -105,20 +103,20 @@ export const reconstructionClaimResultSchema = z.object({ "contradiction", ]), comparison_evidence_id: evidenceIdSchema, - left_evidence_ids: z.array(evidenceIdSchema).min(1).max(100), - right_evidence_ids: z.array(evidenceIdSchema).min(1).max(100), + left_evidence_ids: z.array(evidenceIdSchema).min(1), + right_evidence_ids: z.array(evidenceIdSchema).min(1), evidence_links: z.array(evidenceIdSchema).min(3).max(201), - unknown_ids: z.array(unknownIdSchema).max(100), + unknown_ids: z.array(unknownIdSchema), limitations: z.array(z.string()), }); -/** Evidence-cited result over every declared claim, independently paged. */ +/** Evidence-cited result over every declared claim. */ export const reconstructionVerificationResultSchema = z .object({ status: verificationStatusSchema, specification_sha256: digestSchema, summary: z.object({ - total: z.number().int().min(1).max(100), + total: z.number().int().min(1), passed: z.number().int().min(0), failed: z.number().int().min(0), unknown: z.number().int().min(0), @@ -126,22 +124,16 @@ export const reconstructionVerificationResultSchema = z structural: z.number().int().min(0), }), claims: z.object({ - items: z.array(reconstructionClaimResultSchema).max(100), - offset: z.number().int().min(0), - limit: z.number().int().min(1).max(100), - total: z.number().int().min(1).max(100), - next_offset: z.number().int().min(0).nullable(), + items: z.array(reconstructionClaimResultSchema), }), - recommended_probes: z - .array( - z.object({ - operation: z.string().min(1).max(200), - rationale: z.string().min(1).max(1_000), - claim_ids: z.array(claimIdSchema).min(1).max(100), - unknown_ids: z.array(unknownIdSchema).max(100), - }), - ) - .max(2_000), + recommended_probes: z.array( + z.object({ + operation: z.string().min(1).max(200), + rationale: z.string().min(1).max(1_000), + claim_ids: z.array(claimIdSchema).min(1), + unknown_ids: z.array(unknownIdSchema), + }), + ), evidence_links: z.array(evidenceIdSchema).min(3).max(20_100), limitations: z.array(z.string()), }) @@ -161,9 +153,9 @@ export const reconstructionVerificationResultSchema = z ["summary", "total"], ], [ - result.claims.total !== summary.total, - "Paged claim total must equal the summary total", - ["claims", "total"], + result.claims.items.length !== summary.total, + "Retained claims must equal the summary total", + ["claims", "items"], ], [ result.status !== expectedStatus, diff --git a/src/domain/runtimeCharacterization.test.ts b/src/domain/runtimeCharacterization.test.ts index 0d93c65182..33d1eebed4 100644 --- a/src/domain/runtimeCharacterization.test.ts +++ b/src/domain/runtimeCharacterization.test.ts @@ -10,7 +10,6 @@ const digest = (character: string): string => character.repeat(64); describe("provider-neutral runtime characterization plan", () => { it("commits preparation separately from execution approval", () => { const plan = createRuntimeCharacterizationPlan({ - schema_version: 1, preparation_sha256: digest("5"), artifact: { path: "/approved/app.js", diff --git a/src/domain/runtimeCharacterization.ts b/src/domain/runtimeCharacterization.ts index 2434555d81..1c4679e1e9 100644 --- a/src/domain/runtimeCharacterization.ts +++ b/src/domain/runtimeCharacterization.ts @@ -33,7 +33,6 @@ const callableIdentitySchema = z.strictObject({ }); export const runtimeCharacterizationPlanSchema = z.strictObject({ - schema_version: z.literal(1), plan_sha256: digestSchema, preparation_sha256: digestSchema, artifact: artifactIdentitySchema, diff --git a/src/domain/staticRuntimeCorrelation.test.ts b/src/domain/staticRuntimeCorrelation.test.ts index 5df9f95d80..e7273fd28d 100644 --- a/src/domain/staticRuntimeCorrelation.test.ts +++ b/src/domain/staticRuntimeCorrelation.test.ts @@ -132,7 +132,6 @@ describe("static/runtime correlation", () => { status: "correlated", summary: { hypotheses: 1, contradictions: 0, unresolved: 0 }, correlations: { - total: 1, items: [ { observed_pattern: "cochanged", @@ -187,7 +186,7 @@ describe("static/runtime correlation", () => { }); }); - it("is order-stable, paginated, and rejects duplicates and absent selectors", () => { + it("returns all correlations order-stably and rejects duplicates and absent selectors", () => { const runtime = processComparison("changed"); const base = mapping(runtime, "cochanged"); const second = { @@ -201,17 +200,13 @@ describe("static/runtime correlation", () => { const forward = correlateStaticAndRuntime({ ...base, mappings: [base.mappings[0], second], - offset: 0, - limit: 1, }); const reversed = correlateStaticAndRuntime({ ...base, mappings: [second, base.mappings[0]], - offset: 0, - limit: 1, }); expect(reversed).toEqual(forward); - expect(forward.correlations).toMatchObject({ total: 2, next_offset: 1 }); + expect(forward.correlations.items).toHaveLength(2); expect(() => correlateStaticAndRuntime({ ...base, diff --git a/src/domain/staticRuntimeCorrelation.ts b/src/domain/staticRuntimeCorrelation.ts index dd2edd72cd..5eee93ef9c 100644 --- a/src/domain/staticRuntimeCorrelation.ts +++ b/src/domain/staticRuntimeCorrelation.ts @@ -88,8 +88,6 @@ export const staticRuntimeCorrelationInputSchema = z static_comparisons: z.array(evidenceSchema).min(1).max(100), runtime_comparisons: z.array(evidenceSchema).min(1).max(100), mappings: z.array(mappingSchema).min(1).max(500), - offset: z.number().int().min(0).default(0), - limit: z.number().int().min(1).max(100).default(100), unknown_registry_approved: z.literal(true).optional(), }) .strict(); @@ -122,7 +120,7 @@ const correlationItemSchema = z.object({ limitations: z.array(z.string()), }); -/** Deterministic, paginated static/runtime correlation payload. */ +/** Deterministic static/runtime correlation payload. */ export const staticRuntimeCorrelationResultSchema = z.object({ status: z.enum(["correlated", "contradicted", "unknown", "truncated"]), summary: z.object({ @@ -131,11 +129,7 @@ export const staticRuntimeCorrelationResultSchema = z.object({ unresolved: z.number().int().min(0), }), correlations: z.object({ - items: z.array(correlationItemSchema).max(100), - offset: z.number().int().min(0), - limit: z.number().int().min(1).max(100), - total: z.number().int().min(0), - next_offset: z.number().int().min(0).nullable(), + items: z.array(correlationItemSchema), }), evidence_links: z.array(evidenceIdSchema).min(2).max(20_100), limitations: z.array(z.string()), @@ -191,7 +185,6 @@ export const correlateStaticAndRuntime = ( throw new TypeError( "Static/runtime correlation rejects duplicate mappings", ); - const page = correlations.slice(parsed.offset, parsed.offset + parsed.limit); const links = uniqueSorted( correlations.flatMap(({ evidence_links: evidenceLinks }) => evidenceLinks), ); @@ -220,14 +213,7 @@ export const correlateStaticAndRuntime = ( unresolved: unresolved.length, }, correlations: { - items: page, - offset: parsed.offset, - limit: parsed.limit, - total: correlations.length, - next_offset: - parsed.offset + page.length < correlations.length - ? parsed.offset + page.length - : null, + items: correlations, }, evidence_links: links, limitations: [ @@ -324,15 +310,7 @@ const selectStatic = ( const result = artifactComparisonResultSchema.parse( evidence.normalized_result, ); - if ( - result.changes.offset !== 0 || - result.changes.next_offset !== null || - result.changes.items.length !== result.changes.total - ) - throw new TypeError( - "Static/runtime correlation requires complete artifact comparison pagination", - ); - const matches = result.changes.items.filter( + const matches = result.changes.filter( ({ logical_path: path }) => path === selector.logical_path, ); const match = matches.at(0); @@ -366,10 +344,9 @@ const parseStatic = (input: unknown): Evidence => { const result = artifactComparisonResultSchema.parse( evidence.normalized_result, ); - assertCompleteArtifactResult(result); assertNestedLinks( evidence, - result.changes.items.flatMap(({ evidence_links: links }) => links), + result.changes.flatMap(({ evidence_links: links }) => links), ); } else { const result = functionComparisonResultSchema.parse( @@ -470,19 +447,6 @@ const sameSet = (left: readonly string[], right: readonly string[]): boolean => new Set(left).size === left.length && left.every((item) => right.includes(item)); -const assertCompleteArtifactResult = ( - result: z.infer, -): void => { - if ( - result.changes.offset !== 0 || - result.changes.next_offset !== null || - result.changes.items.length !== result.changes.total - ) - throw new TypeError( - "Static/runtime correlation requires complete artifact comparison pagination", - ); -}; - const observedPattern = ( staticStatus: ComparisonStatus, runtimeStatus: ComparisonStatus, diff --git a/src/dotnet/ManagedNativeBoundaryHelpers.ts b/src/dotnet/ManagedNativeBoundaryHelpers.ts index 57f796c717..b5a7140025 100644 --- a/src/dotnet/ManagedNativeBoundaryHelpers.ts +++ b/src/dotnet/ManagedNativeBoundaryHelpers.ts @@ -369,7 +369,6 @@ export const buildNativeBoundaryInspection = ({ issues, }: BoundaryInspectionContext): ManagedNativeBoundaryInspection => managedNativeBoundaryInspectionSchema.parse({ - schema_version: 1, artifact: { path: target.path, sha256: target.sha256, diff --git a/src/dotnet/ManagedPe.fixture.ts b/src/dotnet/ManagedPe.fixture.ts index 90c7c24c95..a5aa295df4 100644 --- a/src/dotnet/ManagedPe.fixture.ts +++ b/src/dotnet/ManagedPe.fixture.ts @@ -89,12 +89,6 @@ export const MANAGED_MEMBER_FIXTURE_LIMITS = { maxMethodInstructions: 1_000, }; -/** Member bounds for fixture tests that inspect a real local path. */ -export const MANAGED_MEMBER_PATH_FIXTURE_LIMITS = { - ...MANAGED_MEMBER_FIXTURE_LIMITS, - maxFileBytes: 1024 * 1024, -}; - /** Generous native-boundary bounds for the source-owned PE fixture. */ export const MANAGED_NATIVE_BOUNDARY_FIXTURE_LIMITS = { maxMetadataBytes: 1024 * 1024, diff --git a/src/dotnet/ManagedStaticProvider.ts b/src/dotnet/ManagedStaticProvider.ts index 6dcc671b21..aa404200bc 100644 --- a/src/dotnet/ManagedStaticProvider.ts +++ b/src/dotnet/ManagedStaticProvider.ts @@ -50,8 +50,6 @@ export class ManagedStaticProvider implements AnalysisProvider { operation: contract.name, available: true as const, reason: null, - pagination: "none" as const, - exhaustive: true, effects: Object.freeze({ mutatesArtifact: false, launchesProcess: false, @@ -61,11 +59,6 @@ export class ManagedStaticProvider implements AnalysisProvider { changesPermissions: false, requiresRoot: false, }), - limits: Object.freeze({ - maxResults: null, - maxPayloadBytes: 4 * 1024 * 1024, - timeoutMs: null, - }), limitations: limitationsFor(contract.name), }), ), diff --git a/src/ghidra/GhidraLauncher.ts b/src/ghidra/GhidraLauncher.ts index 2f239138a6..45aaaff5b8 100644 --- a/src/ghidra/GhidraLauncher.ts +++ b/src/ghidra/GhidraLauncher.ts @@ -95,7 +95,6 @@ export class GhidraHeadlessLauncher implements GhidraLauncher { await writeFileAtomic( paths.descriptorPath, `${JSON.stringify({ - schema_version: 2, transport: session.transport, endpoint_path: session.endpointPath, token: session.token, @@ -137,7 +136,6 @@ export class GhidraHeadlessLauncher implements GhidraLauncher { await writeFileAtomic( paths.ownershipPath, `${JSON.stringify({ - schema_version: 1, run_id: session.runId, pid: started.ownership.leaderPid, process_group_id: started.ownership.processGroupId, diff --git a/src/ghidra/GhidraProvider.behavior.test.ts b/src/ghidra/GhidraProvider.behavior.test.ts index 9bc797e678..730a2d4eaf 100644 --- a/src/ghidra/GhidraProvider.behavior.test.ts +++ b/src/ghidra/GhidraProvider.behavior.test.ts @@ -65,26 +65,14 @@ describe("Ghidra provider", () => { expect.arrayContaining([ expect.objectContaining({ operation: "list_procedures", - pagination: "none", effects: expect.objectContaining({ mutatesArtifact: false, mayShowUi: false, mayWriteFilesystem: true, }), - limits: { - maxResults: null, - maxPayloadBytes: 1024 * 1024, - timeoutMs: 10_000, - }, }), expect.objectContaining({ operation: "analyze_function", - pagination: "none", - limits: { - maxResults: null, - maxPayloadBytes: 1024 * 1024, - timeoutMs: 35_000, - }, limitations: expect.arrayContaining([ expect.stringContaining( "unresolved targetless flows remain unknown", diff --git a/src/ghidra/GhidraProvider.test.ts b/src/ghidra/GhidraProvider.test.ts index d61332537c..7cf4e440a6 100644 --- a/src/ghidra/GhidraProvider.test.ts +++ b/src/ghidra/GhidraProvider.test.ts @@ -39,7 +39,6 @@ describe("Ghidra provider capabilities", () => { Reflect.set(capabilities, 0, { ...first, available: false }); Reflect.set(first, "available", false); Reflect.set(first.effects, "mutatesArtifact", true); - Reflect.set(first.limits, "maxResults", 0); Reflect.set(first.limitations, 0, "forged limitation"); expect(provider.capabilities()).toEqual(published); diff --git a/src/ghidra/GhidraProviderCapabilities.ts b/src/ghidra/GhidraProviderCapabilities.ts index 1cf13acd51..2c2276b54b 100644 --- a/src/ghidra/GhidraProviderCapabilities.ts +++ b/src/ghidra/GhidraProviderCapabilities.ts @@ -4,11 +4,6 @@ import type { } from "../application/AnalysisProvider.js"; import { WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON } from "../process/WindowsAuthority.js"; import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js"; -import { - GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, - GHIDRA_MAX_LINE_BYTES, - GHIDRA_REQUEST_TIMEOUT_MS, -} from "./GhidraDefaults.js"; import { GHIDRA_FUNCTION_OPERATIONS } from "./GhidraFunctionValues.js"; import { GHIDRA_INVENTORY_OPERATIONS } from "./GhidraInventoryValues.js"; @@ -39,12 +34,6 @@ export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze( ), ); -const PAGINATED_OPERATIONS: ReadonlySet = new Set([]); -const DECOMPILE_OPERATIONS: ReadonlySet = new Set([ - "procedure_pseudo_code", - "analyze_function", -]); - /** Health limitations shared by every Ghidra-backed capability. */ export const healthLimitations = Object.freeze([ "The session serves operations only after default Ghidra auto-analysis completes; an analysis timeout fails the open instead of exposing partial results.", @@ -157,10 +146,6 @@ export const CAPABILITIES: readonly CapabilityDescriptor[] = Object.freeze( operation, available: true, reason: null, - pagination: PAGINATED_OPERATIONS.has(contract.name) - ? ("offset" as const) - : ("none" as const), - exhaustive: !PAGINATED_OPERATIONS.has(contract.name), effects: Object.freeze({ mutatesArtifact: false, launchesProcess: true, @@ -170,13 +155,6 @@ export const CAPABILITIES: readonly CapabilityDescriptor[] = Object.freeze( changesPermissions: false, requiresRoot: false, }), - limits: Object.freeze({ - maxResults: PAGINATED_OPERATIONS.has(contract.name) ? 500 : null, - maxPayloadBytes: GHIDRA_MAX_LINE_BYTES, - timeoutMs: DECOMPILE_OPERATIONS.has(contract.name) - ? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS - : GHIDRA_REQUEST_TIMEOUT_MS, - }), limitations: Object.freeze(limitationsFor(contract.name)), }); }), diff --git a/src/ghidra/GhidraTransport.ts b/src/ghidra/GhidraTransport.ts index 65ef1641af..f4528b9f32 100644 --- a/src/ghidra/GhidraTransport.ts +++ b/src/ghidra/GhidraTransport.ts @@ -79,8 +79,7 @@ const parseTcpEndpoint = ( typeof value !== "object" || value === null || Array.isArray(value) || - !hasExactKeys(value, ["host", "port", "schema_version"]) || - value.schema_version !== 1 || + !hasExactKeys(value, ["host", "port"]) || value.host !== "127.0.0.1" || !Number.isSafeInteger(value.port) || typeof value.port !== "number" || diff --git a/src/hopper/BridgeLauncher.ts b/src/hopper/BridgeLauncher.ts index 6acec4a8ab..4597e587b0 100644 --- a/src/hopper/BridgeLauncher.ts +++ b/src/hopper/BridgeLauncher.ts @@ -193,7 +193,6 @@ export class HopperApplicationLauncher implements BridgeLauncher { lease?.release(), ); const ownership = { - schema_version: 1, run_id: session.runId, pid: started.ownership.leaderPid, process_group_id: started.ownership.leaderPid, diff --git a/src/hopper/HopperProvider.test.ts b/src/hopper/HopperProvider.test.ts index 880f9d08db..f0adfe9bb6 100644 --- a/src/hopper/HopperProvider.test.ts +++ b/src/hopper/HopperProvider.test.ts @@ -25,7 +25,7 @@ describe("Hopper provider capabilities", () => { } expect( capabilities.find(({ operation }) => operation === "list_procedures"), - ).toMatchObject({ pagination: "none" }); + ).toMatchObject({ available: true }); expect( capabilities.find(({ operation }) => operation === "set_comment"), ).toMatchObject({ @@ -36,7 +36,6 @@ describe("Hopper provider capabilities", () => { Reflect.set(capabilities, 0, { ...first, available: false }); Reflect.set(first, "available", false); Reflect.set(first.effects, "mutatesArtifact", true); - Reflect.set(first.limits, "maxResults", 0); Reflect.set(first.limitations, 0, "forged limitation"); expect(provider.capabilities()).toEqual(published); diff --git a/src/hopper/HopperProvider.ts b/src/hopper/HopperProvider.ts index 5ab23855e7..0833af9c29 100644 --- a/src/hopper/HopperProvider.ts +++ b/src/hopper/HopperProvider.ts @@ -60,12 +60,6 @@ const CAPABILITIES: readonly CapabilityDescriptor[] = Object.freeze( operation, available: true, reason: null, - pagination: - isRecord(contract.inputSchema.properties) && - "offset" in contract.inputSchema.properties - ? "offset" - : "none", - exhaustive: false, effects: Object.freeze({ mutatesArtifact: MUTATING_OPERATIONS.has(contract.name), launchesProcess: true, @@ -75,11 +69,6 @@ const CAPABILITIES: readonly CapabilityDescriptor[] = Object.freeze( changesPermissions: false, requiresRoot: false, }), - limits: Object.freeze({ - maxResults: null, - maxPayloadBytes: contract.name === "read_bytes" ? 4_096 : null, - timeoutMs: null, - }), limitations: Object.freeze([ "Results depend on Hopper's completed static analysis.", ]), @@ -87,10 +76,6 @@ const CAPABILITIES: readonly CapabilityDescriptor[] = Object.freeze( }), ); -function isRecord(value: unknown): value is Readonly> { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - /** Concrete analysis provider backed by REA's private Hopper bridge. */ export class HopperProvider implements AnalysisProviderCandidate { constructor( diff --git a/src/hopper/HopperProviderDiscovery.test.ts b/src/hopper/HopperProviderDiscovery.test.ts index e3177464a1..bf43604511 100644 --- a/src/hopper/HopperProviderDiscovery.test.ts +++ b/src/hopper/HopperProviderDiscovery.test.ts @@ -45,24 +45,18 @@ describe("Hopper provider discovery", () => { }); }); - it("advertises the exact bounded byte-read limit", () => { + it("advertises byte reads as an available operation", () => { const capabilities = provider(process.execPath).capabilities(); expect( capabilities.find(({ operation }) => operation === "read_bytes"), ).toMatchObject({ available: true, - pagination: "none", - limits: { - maxResults: null, - maxPayloadBytes: 4_096, - timeoutMs: null, - }, }); expect( capabilities.find( ({ operation }) => operation === "address_to_file_offset", ), - ).toMatchObject({ available: true, pagination: "none" }); + ).toMatchObject({ available: true }); }); }); diff --git a/src/hopper/LinuxPrivateDisplayDiagnostic.ts b/src/hopper/LinuxPrivateDisplayDiagnostic.ts index 0506c1d470..acba15dee5 100644 --- a/src/hopper/LinuxPrivateDisplayDiagnostic.ts +++ b/src/hopper/LinuxPrivateDisplayDiagnostic.ts @@ -8,7 +8,6 @@ import { export const LINUX_PRIVATE_DISPLAY_DIAGNOSTIC_PREFIX = "REA_X11_DIAGNOSTIC_V1="; const diagnosticContextSchema = z.object({ - schema_version: z.literal(1), component: z.literal("hopper_private_display"), operation: z.enum(["probe", "launch"]), reason: z diff --git a/src/hopper/LinuxPrivateDisplayProbe.ts b/src/hopper/LinuxPrivateDisplayProbe.ts index eeb0a60320..81d0f42fa5 100644 --- a/src/hopper/LinuxPrivateDisplayProbe.ts +++ b/src/hopper/LinuxPrivateDisplayProbe.ts @@ -267,7 +267,6 @@ const syntheticDiagnostic = ( reason: string, failureCode: HopperStartupFailureCode = "private_display_unavailable", ): HopperStartupFailureDiagnostic => ({ - schema_version: 1, component: "hopper_private_display", operation: "probe", status: "error", diff --git a/src/native/NativeMacOSProvider.ts b/src/native/NativeMacOSProvider.ts index 600f83f95f..153f233133 100644 --- a/src/native/NativeMacOSProvider.ts +++ b/src/native/NativeMacOSProvider.ts @@ -82,8 +82,6 @@ export class NativeMacOSProvider implements AnalysisProvider { provider: IDENTITY, operation: contract.name, ...availability, - pagination: "none" as const, - exhaustive: contract.name !== "inspect_macho", effects: Object.freeze({ mutatesArtifact: false, launchesProcess: true, @@ -93,11 +91,6 @@ export class NativeMacOSProvider implements AnalysisProvider { changesPermissions: false, requiresRoot: false, }), - limits: Object.freeze({ - maxResults: contract.name === "demangle_swift" ? 500 : null, - maxPayloadBytes: OUTPUT_LIMIT, - timeoutMs: TIMEOUT_MS, - }), limitations: Object.freeze([ "Availability and textual formats depend on the installed macOS/Xcode toolchain.", ]), diff --git a/src/replay/JavaScriptReplayWorker.ts b/src/replay/JavaScriptReplayWorker.ts index bd48658690..e74bba8c8c 100644 --- a/src/replay/JavaScriptReplayWorker.ts +++ b/src/replay/JavaScriptReplayWorker.ts @@ -126,7 +126,6 @@ const main = async (): Promise => { } process.stdout.write( JSON.stringify({ - schema_version: 1, left, ...(request.right === undefined ? {} : { right }), }), diff --git a/src/replay/ReplayWorkerProtocol.test.ts b/src/replay/ReplayWorkerProtocol.test.ts index a3877eeb3e..52c18d6c55 100644 --- a/src/replay/ReplayWorkerProtocol.test.ts +++ b/src/replay/ReplayWorkerProtocol.test.ts @@ -16,15 +16,11 @@ const outcome = { describe("replay worker protocol", () => { it("accepts only the exact committed case sequence", () => { expect( - parseReplayWorkerResponse( - { schema_version: 1, left: [outcome] }, - cases, - "single", - ), + parseReplayWorkerResponse({ left: [outcome] }, cases, "single"), ).toMatchObject({ left: [outcome] }); expect(() => parseReplayWorkerResponse( - { schema_version: 1, left: [{ ...outcome, case_id: "forged" }] }, + { left: [{ ...outcome, case_id: "forged" }] }, cases, "single", ), @@ -32,7 +28,6 @@ describe("replay worker protocol", () => { expect(() => parseReplayWorkerResponse( { - schema_version: 1, left: [{ ...outcome, input_sha256: "2".repeat(64) }], }, cases, @@ -43,16 +38,11 @@ describe("replay worker protocol", () => { it("requires the exact differential shape and strict outcomes", () => { expect(() => - parseReplayWorkerResponse( - { schema_version: 1, left: [outcome] }, - cases, - "differential", - ), + parseReplayWorkerResponse({ left: [outcome] }, cases, "differential"), ).toThrow(); expect(() => parseReplayWorkerResponse( { - schema_version: 1, left: [{ ...outcome, unexpected: true }], }, cases, @@ -62,7 +52,6 @@ describe("replay worker protocol", () => { expect(() => parseReplayWorkerResponse( { - schema_version: 1, left: [{ ...outcome, outcome: "exception", value: undefined }], }, cases, diff --git a/src/replay/ReplayWorkerProtocol.ts b/src/replay/ReplayWorkerProtocol.ts index ded2b8453e..a65f24213d 100644 --- a/src/replay/ReplayWorkerProtocol.ts +++ b/src/replay/ReplayWorkerProtocol.ts @@ -30,14 +30,12 @@ const workerOutcomeSchema = z.discriminatedUnion("outcome", [ const singleWorkerResponseSchema = z .object({ - schema_version: z.literal(1), left: z.array(workerOutcomeSchema), }) .strict(); const differentialWorkerResponseSchema = z .object({ - schema_version: z.literal(1), left: z.array(workerOutcomeSchema), right: z.array(workerOutcomeSchema), }) diff --git a/src/server/promptCompletion.ts b/src/server/promptCompletion.ts index 07563b44c2..e831a35e11 100644 --- a/src/server/promptCompletion.ts +++ b/src/server/promptCompletion.ts @@ -151,7 +151,7 @@ const evidenceValues = ( ); if (!inventory.success) return []; if (kind === "manifest") return [inventory.data.manifest.manifest_id]; - return inventory.data.occurrences.items.map(({ occurrence_id: id }) => id); + return inventory.data.occurrences.map(({ occurrence_id: id }) => id); }; const isProcessCaptureEvidence = (evidence: LedgerEvidence): boolean => { diff --git a/src/server/registerApplicationTools/coverage.ts b/src/server/registerApplicationTools/coverage.ts index 8764f89e4f..a49a2211e8 100644 --- a/src/server/registerApplicationTools/coverage.ts +++ b/src/server/registerApplicationTools/coverage.ts @@ -58,8 +58,8 @@ const registerCommitTool = ( options.permissionAuthority, { path: input.workspace_path, - readCapability: "investigation_workspace_read", - writeCapability: "investigation_workspace_write", + readCapability: "reconstruction_coverage_read", + writeCapability: "reconstruction_coverage_write", operation: commitContract.name, }, ); @@ -104,7 +104,7 @@ const registerQueryTool = ( const authorized = await authorizeRootPermission( options.permissionAuthority, { - capability: "investigation_workspace_read", + capability: "reconstruction_coverage_read", roots: [input.workspace_path], access: "read", operation: queryContract.name, diff --git a/src/server/registerArtifactComparisonTool.ts b/src/server/registerArtifactComparisonTool.ts index c01e5373ef..16c79fdbc5 100644 --- a/src/server/registerArtifactComparisonTool.ts +++ b/src/server/registerArtifactComparisonTool.ts @@ -29,31 +29,29 @@ export const registerArtifactComparisonTool = ( }; const left = resolveSessionEvidenceIds( session, - input.left_evidence_ids, + [input.left_evidence_id], expected, ); if (!left.ok) return toCallToolResult(left, contract); const right = resolveSessionEvidenceIds( session, - input.right_evidence_ids, + [input.right_evidence_id], expected, ); if (!right.ok) return toCallToolResult(right, contract); const computed = await runDerivedOperation(context, contract.name, () => - compareArtifacts(left.value, right.value, input.offset, input.limit), + compareArtifacts(left.value, right.value), ); if (!computed.ok) return toCallToolResult(computed, contract); const comparison = computed.value; - const leftEvidenceIds = input.left_evidence_ids; - const rightEvidenceIds = input.right_evidence_ids; + const leftEvidenceIds = [input.left_evidence_id]; + const rightEvidenceIds = [input.right_evidence_id]; const evidence = createEvidence(undefined, ARTIFACT_COMPARISON_PROVIDER, { predicateType: "rea.artifact-comparison/v1", operation: contract.name, parameters: { left_evidence_ids: leftEvidenceIds, right_evidence_ids: rightEvidenceIds, - offset: input.offset, - limit: input.limit, }, result: jsonValueSchema.parse(comparison), confidence: "derived", @@ -75,8 +73,8 @@ export const registerArtifactComparisonTool = ( const artifactUnknownInput = ( input: { - readonly left_evidence_ids: readonly string[]; - readonly right_evidence_ids: readonly string[]; + readonly left_evidence_id: string; + readonly right_evidence_id: string; readonly unknown_registry_approved?: true | undefined; }, status: ReturnType["status"], @@ -89,8 +87,8 @@ const artifactUnknownInput = ( severity: status === "unknown" || status === "truncated" ? "high" : "medium", domain: "artifact-comparison", - supporting_evidence_ids: [...input.left_evidence_ids], - contradicting_evidence_ids: [...input.right_evidence_ids], + supporting_evidence_ids: [input.left_evidence_id], + contradicting_evidence_ids: [input.right_evidence_id], required_authority: "shipped-artifact", required_confidence: "observed", required_environment: null, diff --git a/src/server/registerBundleComparisonTool.ts b/src/server/registerBundleComparisonTool.ts index bfed60a932..fd9ae02ba4 100644 --- a/src/server/registerBundleComparisonTool.ts +++ b/src/server/registerBundleComparisonTool.ts @@ -31,13 +31,7 @@ export const registerBundleComparisonTool = ( if (!left.ok) return toCallToolResult(left, contract); if (!right.ok) return toCallToolResult(right, contract); const computed = await runDerivedOperation(context, contract.name, () => - compareBundles( - left.value, - right.value, - input.record_pairs, - input.offset, - input.limit, - ), + compareBundles(left.value, right.value, input.record_pairs), ); if (!computed.ok) return toCallToolResult(computed, contract); const comparison = computed.value; @@ -48,8 +42,6 @@ export const registerBundleComparisonTool = ( left_bundle_sha256: comparison.left_bundle_sha256, right_bundle_sha256: comparison.right_bundle_sha256, record_pairs: input.record_pairs, - offset: input.offset, - limit: input.limit, }, result: jsonValueSchema.parse(comparison), confidence: "derived", diff --git a/src/server/registerEvidenceTools.ts b/src/server/registerEvidenceTools.ts index a808442f4e..b7eb49a5a0 100644 --- a/src/server/registerEvidenceTools.ts +++ b/src/server/registerEvidenceTools.ts @@ -17,6 +17,7 @@ import { mcpProgressReporter } from "./mcpProgress.js"; import { logToolExecution } from "./toolLogging.js"; import { toolRegistrationOptions } from "./toolRegistrationOptions.js"; import { toCallToolResult } from "./toolResult.js"; +import { createArtifactExtractionDestination } from "../application/ArtifactExtractionDestination.js"; interface EvidenceToolRegistration { readonly logger: Logger; @@ -49,8 +50,15 @@ export const registerEvidenceTools = ( message: "started", }); const parameters = jsonObjectSchema.parse(input); + const executionParameters = + contract.name === "extract_artifact" + ? { + ...parameters, + output_root: createArtifactExtractionDestination(), + } + : parameters; if (options.permissionAuthority !== undefined) { - const request = permissionRequest(contract.name, parameters); + const request = permissionRequest(contract.name, executionParameters); if (request !== undefined) { const authorized = await options.permissionAuthority.authorize( request, @@ -67,7 +75,7 @@ export const registerEvidenceTools = ( options.logger, contract.name, () => - analysis.execute(contract.name, parameters, { + analysis.execute(contract.name, executionParameters, { signal: context.mcpReq.signal, progress, }), diff --git a/src/serverIdentity.ts b/src/serverIdentity.ts index b36aeee5c7..55a4f1a3b4 100644 --- a/src/serverIdentity.ts +++ b/src/serverIdentity.ts @@ -97,25 +97,3 @@ export const createServerIdentity = (input: { }, } as const; }; - -/** Compact identity projection for CLI summaries; MCP retains full identity. */ -export const createServerIdentitySummary = ( - input: Parameters[0], -) => { - const identity = createServerIdentity(input); - return { - package: { - name: identity.package.name, - version: identity.package.version, - }, - server: { - name: identity.server.name, - version: identity.server.version, - }, - catalog: { - counts: identity.catalog.counts, - digests: identity.catalog.digests, - }, - alignment: identity.alignment, - } as const; -}; diff --git a/tests/acceptance/applications/applicationEvidenceMcp.test.ts b/tests/acceptance/applications/applicationEvidenceMcp.test.ts index 5a554ab143..cb62bc43b9 100644 --- a/tests/acceptance/applications/applicationEvidenceMcp.test.ts +++ b/tests/acceptance/applications/applicationEvidenceMcp.test.ts @@ -78,7 +78,6 @@ async function runInlineEvidenceScenarios( expect(compared.isError).not.toBe(true); expect(compared.structuredContent).toMatchObject({ result: { - schema_version: 1, summary: { unknown: expect.any(Number) }, coverage: { status: expect.any(String) }, }, @@ -94,7 +93,6 @@ async function runInlineEvidenceScenarios( expect(sourceCompared.isError).not.toBe(true); expect(sourceCompared.structuredContent).toMatchObject({ result: { - schema_version: 1, reference: { root_sha256: SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE.reference.root_sha256, }, diff --git a/tests/acceptance/applications/applicationExportShapeMcp.test.ts b/tests/acceptance/applications/applicationExportShapeMcp.test.ts index 90f3f15049..99e76a45c4 100644 --- a/tests/acceptance/applications/applicationExportShapeMcp.test.ts +++ b/tests/acceptance/applications/applicationExportShapeMcp.test.ts @@ -116,7 +116,6 @@ describe("application workflow MCP parity", () => { expect(semantic.isError).not.toBe(true); expect(semantic.structuredContent).toMatchObject({ result: { - schema_version: 1, source_evidence_id: left.value.evidence_id, source_graph_id: analyzed.semantic_graph.graph_id, summary: { retained_seed_matches: 1 }, diff --git a/tests/acceptance/applications/applicationReplayMcp.test.ts b/tests/acceptance/applications/applicationReplayMcp.test.ts index 06abef8a08..555a2b65e5 100644 --- a/tests/acceptance/applications/applicationReplayMcp.test.ts +++ b/tests/acceptance/applications/applicationReplayMcp.test.ts @@ -93,7 +93,6 @@ function createReplayScenario(root: string) { }, javascriptReplayRunner: { execute: async (prepared) => ({ - schema_version: 1, plan_digest: prepared.publicPlan.plan_digest, outcomes: [ { diff --git a/tests/acceptance/applications/applicationWorkflowCli.test.ts b/tests/acceptance/applications/applicationWorkflowCli.test.ts index 8726d01dfc..aa683fc028 100644 --- a/tests/acceptance/applications/applicationWorkflowCli.test.ts +++ b/tests/acceptance/applications/applicationWorkflowCli.test.ts @@ -60,7 +60,6 @@ describe("application workflow CLI parity", () => { expect(compared).toMatchObject({ operation: "compare_application_versions", normalized_result: { - schema_version: 1, summary: { unknown: expect.any(Number) }, }, }); @@ -74,7 +73,7 @@ describe("application workflow CLI parity", () => { ]); expect(sourceCompared).toMatchObject({ operation: "compare_source_to_bundle", - normalized_result: { schema_version: 1 }, + normalized_result: { reference: expect.any(Object) }, }); }, 20_000); @@ -177,7 +176,7 @@ describe("application workflow CLI Evidence resolution", () => { ); expect(compared).toMatchObject({ operation: "compare_application_versions", - normalized_result: { schema_version: 1 }, + normalized_result: { summary: expect.any(Object) }, }); const missingRecord = await runCli( @@ -322,7 +321,6 @@ describe("application workflow CLI validation and replay", () => { "--json", ]); expect(inline).toMatchObject({ - schema_version: 1, final_state: "complete", decisions: [{ outcome: "matched" }], transition_journal: [ diff --git a/tests/boundary/cli/cliOutput.test.ts b/tests/boundary/cli/cliOutput.test.ts index aaf3a5fbec..0e4781d113 100644 --- a/tests/boundary/cli/cliOutput.test.ts +++ b/tests/boundary/cli/cliOutput.test.ts @@ -13,7 +13,6 @@ import { } from "../../../src/cliOutput.js"; const CLI_INTEGRATION_TIMEOUT_MS = 60_000; -const CLI_VARIANT_TIMEOUT_MS = 120_000; describe("CLI output argument and sanitization boundary", () => { it("rejects token windows that would corrupt structured output", () => { @@ -175,59 +174,4 @@ describe("compiled CLI output boundary", () => { }, CLI_INTEGRATION_TIMEOUT_MS, ); - - workspaceCliTest( - "keeps operation failure status independent of output controls", - async ({ cli }) => { - const variants = [ - ["--format", "toon"], - ["--format", "json"], - ["--format", "yaml"], - ["--format", "md"], - ["--format", "jsonl"], - ["--filter-output", "category", "--json"], - ["--token-limit", "5", "--json"], - ["--token-count", "--json"], - ]; - - for (const flags of variants) { - const result = await cli.run({ - arguments: [ - ...flags, - "investigate-versions", - "/tmp/left", - "/tmp/right", - "/tmp/workspace.json", - ], - }); - expect(result).toMatchObject({ - exitCode: 1, - stdout: expect.any(String), - }); - } - }, - CLI_VARIANT_TIMEOUT_MS, - ); - - workspaceCliTest( - "keeps failure logs out of structured stdout", - async ({ cli }) => { - const result = await cli.run({ - arguments: [ - "--json", - "investigate-versions", - "/tmp/left", - "/tmp/right", - "/tmp/workspace.json", - ], - environment: { REA_LOG_LEVEL: "error" }, - }); - expect(result).toMatchObject({ - exitCode: 1, - stderr: expect.stringContaining('"status":"error"'), - }); - expect(result.json).toMatchObject({ error: "ApprovalRequired" }); - }, - CLI_INTEGRATION_TIMEOUT_MS, - ); }); diff --git a/tests/boundary/cli/reconstructionObligationLedgerCli.test.ts b/tests/boundary/cli/reconstructionObligationLedgerCli.test.ts index 0687d0435a..0ad8173664 100644 --- a/tests/boundary/cli/reconstructionObligationLedgerCli.test.ts +++ b/tests/boundary/cli/reconstructionObligationLedgerCli.test.ts @@ -16,7 +16,6 @@ describe("reconstruction obligation ledger CLI parity", () => { bindings: [], contradictions: [], }, - page: { offset: 0, limit: 50 }, }; const { stdout } = await execute( process.execPath, diff --git a/tests/boundary/filesystem/evidenceBundleFiles.test.ts b/tests/boundary/filesystem/evidenceBundleFiles.test.ts index 1270c031aa..414dcb606b 100644 --- a/tests/boundary/filesystem/evidenceBundleFiles.test.ts +++ b/tests/boundary/filesystem/evidenceBundleFiles.test.ts @@ -95,8 +95,6 @@ describe("evidence bundle filesystem adapter", () => { await compareEvidenceBundlesCommand({ leftPath: path, rightPath: path, - offset: 0, - limit: 100, policy: policy(directory), }), ).toMatchObject({ diff --git a/tests/boundary/filesystem/javascriptExportShapeComparison.test.ts b/tests/boundary/filesystem/javascriptExportShapeComparison.test.ts index 0453ff81b4..635f63d13b 100644 --- a/tests/boundary/filesystem/javascriptExportShapeComparison.test.ts +++ b/tests/boundary/filesystem/javascriptExportShapeComparison.test.ts @@ -121,7 +121,7 @@ describe("JavaScript export return-shape comparison", () => { }); describe("JavaScript export return-shape selection", () => { - it("reports selector candidates and enforces candidate, variant, and change limits", async () => { + it("returns complete candidate, variant, and change inventories", async () => { const candidates = await analyzeSources({ left: ` export const first = () => ({ type: "first" }); @@ -132,38 +132,30 @@ describe("JavaScript export return-shape selection", () => { }); const missing = compare(candidates[0], candidates[1], { leftExportName: "missing", - limits: { max_candidate_exports: 1 }, }); expect(missing.left).toMatchObject({ status: "missing", - omitted_candidates: 2, - candidates: [expect.objectContaining({ module_path: "parser.mjs" })], + omitted_candidates: 0, + candidates: expect.arrayContaining([ + expect.objectContaining({ export_name: "first" }), + expect.objectContaining({ export_name: "second" }), + expect.objectContaining({ export_name: "third" }), + ]), }); - expect(missing.coverage.status).toBe("truncated"); const parsers = await sourceOwnedParsers(); - const variantLimited = compare(parsers[0], parsers[1], { - limits: { max_return_variants: 1 }, - }); - expect(variantLimited.coverage).toMatchObject({ - status: "truncated", - omitted_left_variants: 2, - omitted_right_variants: 2, - }); + const variants = compare(parsers[0], parsers[1]); + expect(variants.coverage.omitted_left_variants).toBe(0); + expect(variants.coverage.omitted_right_variants).toBe(0); const changes = await analyzeSources({ left: `export default () => ({ type: "item" });`, right: `export default () => ({ type: "item", depth: 1, level: 2 });`, }); - const changeLimited = compare(changes[0], changes[1], { - limits: { max_changes: 1 }, - }); - expect(changeLimited.summary.added).toBe(2); - expect(changeLimited.changes).toHaveLength(1); - expect(changeLimited.coverage).toMatchObject({ - status: "truncated", - omitted_changes: 1, - }); + const complete = compare(changes[0], changes[1]); + expect(complete.summary.added).toBe(2); + expect(complete.changes).toHaveLength(2); + expect(complete.coverage.omitted_changes).toBe(0); }); it("refuses an exact selector that resolves to multiple graph nodes", async () => { @@ -241,11 +233,6 @@ const compare = ( options: { readonly leftExportName?: string; readonly rightExportName?: string; - readonly limits?: Partial<{ - readonly max_candidate_exports: number; - readonly max_return_variants: number; - readonly max_changes: number; - }>; } = {}, ) => compareJavaScriptExportShapes({ @@ -261,11 +248,6 @@ const compare = ( modulePath: "parser.mjs", exportName: options.rightExportName ?? "default", }, - limits: { - max_candidate_exports: options.limits?.max_candidate_exports ?? 100, - max_return_variants: options.limits?.max_return_variants ?? 128, - max_changes: options.limits?.max_changes ?? 1_000, - }, }); const analyzeGraph = async (root: string) => { diff --git a/tests/boundary/filesystem/reconstructionCoverage.test.ts b/tests/boundary/filesystem/reconstructionCoverage.test.ts index bc5ed9e953..ad164e2c2b 100644 --- a/tests/boundary/filesystem/reconstructionCoverage.test.ts +++ b/tests/boundary/filesystem/reconstructionCoverage.test.ts @@ -49,7 +49,7 @@ describe("reconstruction coverage persistence", () => { ).toMatchObject({ ok: false, error: { - _tag: "InvestigationWorkspaceError", + _tag: "WorkspaceStorageError", reason: "revision-conflict", }, }); diff --git a/tests/boundary/mcp/mainReload.test.ts b/tests/boundary/mcp/mainReload.test.ts index fa6cf96a22..dfd462c1d5 100644 --- a/tests/boundary/mcp/mainReload.test.ts +++ b/tests/boundary/mcp/mainReload.test.ts @@ -286,7 +286,6 @@ const projectStore = ( projectRoot: string, grants: readonly ReturnType[], ): ProjectPermissionStore => ({ - schema_version: 1, project_id: `project_${createHash("sha256").update(projectRoot).digest("hex")}`, project_root: projectRoot, grants: [...grants], diff --git a/tests/boundary/mcp/permissionMcp.test.ts b/tests/boundary/mcp/permissionMcp.test.ts index b84bc47acb..6e1526ceea 100644 --- a/tests/boundary/mcp/permissionMcp.test.ts +++ b/tests/boundary/mcp/permissionMcp.test.ts @@ -1,6 +1,4 @@ import { Client, InMemoryTransport } from "@modelcontextprotocol/client"; -import { realpath } from "node:fs/promises"; -import { join } from "node:path"; import { describe, expect, it } from "vitest"; import type { AnalysisOperationPort } from "../../../src/application/AnalysisProvider.js"; @@ -10,7 +8,6 @@ import { createServer } from "../../../src/server/createServer.js"; describe("MCP permission preflight", () => { it("denies extraction before dispatch and returns exact typed remediation", async () => { - const outputRoot = join(await realpath("/tmp"), "rea-permission-denied"); let dispatches = 0; const analysis: AnalysisOperationPort = { execute: () => { @@ -30,8 +27,6 @@ describe("MCP permission preflight", () => { const result = await client.callTool({ name: "extract_artifact", arguments: { - approved: true, - output_root: outputRoot, occurrence_ids: [`occ_${"0".repeat(64)}`], }, }); @@ -44,7 +39,7 @@ describe("MCP permission preflight", () => { code: "permission_required", details: { capability: "artifact_extract", - missing: { roots: [outputRoot] }, + missing: { roots: [expect.stringMatching(/rea-extracted-/u)] }, }, remediation: { restart_required: true, diff --git a/tests/boundary/mcp/providerSelectionMcp.test.ts b/tests/boundary/mcp/providerSelectionMcp.test.ts index 8a6b9833ae..eff0352e35 100644 --- a/tests/boundary/mcp/providerSelectionMcp.test.ts +++ b/tests/boundary/mcp/providerSelectionMcp.test.ts @@ -220,8 +220,6 @@ const capability = (provider: ProviderIdentity): CapabilityDescriptor => ({ operation: "address_name", available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: true, @@ -231,7 +229,6 @@ const capability = (provider: ProviderIdentity): CapabilityDescriptor => ({ changesPermissions: false, requiresRoot: false, }, - limits: { maxResults: null, maxPayloadBytes: 1_000, timeoutMs: 1_000 }, limitations: [], }); diff --git a/tests/boundary/mcp/reconstructionCoverageMcp.test.ts b/tests/boundary/mcp/reconstructionCoverageMcp.test.ts index 918aeb457a..b3f5e35aae 100644 --- a/tests/boundary/mcp/reconstructionCoverageMcp.test.ts +++ b/tests/boundary/mcp/reconstructionCoverageMcp.test.ts @@ -33,8 +33,8 @@ describe("reconstruction coverage MCP parity", () => { }; const authority = await permissionAuthorityForRoot( root, - ["investigation_workspace_read", "investigation_workspace_write"], - ["investigation_workspace_read", "investigation_workspace_write"], + ["reconstruction_coverage_read", "reconstruction_coverage_write"], + ["reconstruction_coverage_read", "reconstruction_coverage_write"], ); const session = createTestBinarySession(() => ({ execute: () => Promise.resolve(observed(null)), diff --git a/tests/boundary/mcp/reconstructionObligationLedgerMcp.test.ts b/tests/boundary/mcp/reconstructionObligationLedgerMcp.test.ts index 993023197c..d6a835e67f 100644 --- a/tests/boundary/mcp/reconstructionObligationLedgerMcp.test.ts +++ b/tests/boundary/mcp/reconstructionObligationLedgerMcp.test.ts @@ -7,7 +7,7 @@ import { createServer } from "../../../src/server/createServer.js"; import { observed } from "../../fixtures/analysisExecution.js"; describe("reconstruction obligation ledger MCP parity", () => { - it("returns an Evidence-backed page inline", async () => { + it("returns the complete Evidence-backed ledger inline", async () => { const session = createTestBinarySession(() => ({ execute: () => Promise.resolve(observed(null)), close: () => Promise.resolve(), @@ -28,7 +28,6 @@ describe("reconstruction obligation ledger MCP parity", () => { bindings: [], contradictions: [], }, - page: { offset: 0, limit: 50 }, }, }); expect(result.isError).not.toBe(true); diff --git a/tests/boundary/mcp/serverIdentity.test.ts b/tests/boundary/mcp/serverIdentity.test.ts index 8a32c401a6..e89b9ab90a 100644 --- a/tests/boundary/mcp/serverIdentity.test.ts +++ b/tests/boundary/mcp/serverIdentity.test.ts @@ -27,8 +27,6 @@ const availabilityProvider = (): AnalysisProvider => { operation: "current_address", available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: false, @@ -38,11 +36,6 @@ const availabilityProvider = (): AnalysisProvider => { changesPermissions: false, requiresRoot: false, }, - limits: { - maxResults: null, - maxPayloadBytes: null, - timeoutMs: null, - }, limitations: [], }; return { @@ -69,8 +62,6 @@ const statusCapability = ( operation, input_contract_version: 1, output_contract_version: 1, - pagination: "none" as const, - exhaustive: true, effects: { mutates_artifact: false, launches_process: false, @@ -80,11 +71,6 @@ const statusCapability = ( changes_permissions: false, requires_root: false, }, - limits: { - max_results: null, - max_payload_bytes: null, - timeout_ms: null, - }, limitations: [], ...(availability.available ? { available: true as const, reason: null, availability_code: null } @@ -109,10 +95,9 @@ describe("server and catalog identity", () => { expect(SDK_IDENTITY.server).toBe( packageJson.dependencies["@modelcontextprotocol/server"], ); - expect(CLI_COMMAND_NAMES).toHaveLength(68); - expect(new Set(CLI_COMMAND_NAMES).size).toBe(68); + expect(new Set(CLI_COMMAND_NAMES).size).toBe(CLI_COMMAND_NAMES.length); expect(CATALOG_IDENTITY.counts).toEqual({ - cli_commands: 68, + cli_commands: CLI_COMMAND_NAMES.length, mcp_tools: TOOL_CONTRACTS.length, mcp_prompts: 6, }); diff --git a/tests/boundary/mcp/sessionMcp.test.ts b/tests/boundary/mcp/sessionMcp.test.ts index f9f1d917b1..db6d5e52d3 100644 --- a/tests/boundary/mcp/sessionMcp.test.ts +++ b/tests/boundary/mcp/sessionMcp.test.ts @@ -300,8 +300,6 @@ const provider = (closed: string[]): AnalysisProvider => { operation: "current_document", available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: false, @@ -311,11 +309,6 @@ const provider = (closed: string[]): AnalysisProvider => { changesPermissions: false, requiresRoot: false, }, - limits: { - maxResults: null, - maxPayloadBytes: null, - timeoutMs: null, - }, limitations: [], }; return { diff --git a/tests/boundary/mcp/toolResult.test.ts b/tests/boundary/mcp/toolResult.test.ts index f918f71616..208da4d9af 100644 --- a/tests/boundary/mcp/toolResult.test.ts +++ b/tests/boundary/mcp/toolResult.test.ts @@ -51,7 +51,6 @@ describe("tool result projection", () => { const result = toCallToolResult( err( new HopperProcessError(80, { - schema_version: 1, component: "hopper_private_display", operation: "launch", status: "error", diff --git a/tests/boundary/providers/ghidra/ghidraTransport.test.ts b/tests/boundary/providers/ghidra/ghidraTransport.test.ts index 3b04363b10..083a58bdaf 100644 --- a/tests/boundary/providers/ghidra/ghidraTransport.test.ts +++ b/tests/boundary/providers/ghidra/ghidraTransport.test.ts @@ -36,7 +36,7 @@ describe("Ghidra local transport", () => { const path = join(root, "bridge-endpoint.json"); await writeFile( path, - `${JSON.stringify({ schema_version: 1, host: "127.0.0.1", port: 49152 })}\n`, + `${JSON.stringify({ host: "127.0.0.1", port: 49152 })}\n`, ); await expect( @@ -51,9 +51,9 @@ describe("Ghidra local transport", () => { }); it.each([ - { schema_version: 1, host: "0.0.0.0", port: 49152 }, - { schema_version: 1, host: "127.0.0.1", port: 0 }, - { schema_version: 1, host: "127.0.0.1", port: 49152, token: "leak" }, + { host: "0.0.0.0", port: 49152 }, + { host: "127.0.0.1", port: 0 }, + { host: "127.0.0.1", port: 49152, token: "leak" }, ])( "rejects an invalid or expanded TCP endpoint: $host:$port", async (value) => { diff --git a/tests/boundary/providers/hopper/hopperClient.startupFailures.test.ts b/tests/boundary/providers/hopper/hopperClient.startupFailures.test.ts index d1228742e2..a73c5a1c18 100644 --- a/tests/boundary/providers/hopper/hopperClient.startupFailures.test.ts +++ b/tests/boundary/providers/hopper/hopperClient.startupFailures.test.ts @@ -101,7 +101,6 @@ class ExitingLauncher implements BridgeLauncher { class DiagnosticExitingLauncher implements BridgeLauncher { launch() { const diagnostic: HopperStartupDiagnostic = { - schema_version: 1, component: "hopper_private_display", operation: "launch", status: "error", diff --git a/tests/boundary/providers/hopper/linuxPrivateDisplay.test.ts b/tests/boundary/providers/hopper/linuxPrivateDisplay.test.ts index e8b175c621..9e888c2fc1 100644 --- a/tests/boundary/providers/hopper/linuxPrivateDisplay.test.ts +++ b/tests/boundary/providers/hopper/linuxPrivateDisplay.test.ts @@ -39,7 +39,6 @@ type DiagnosticOverrides = Partial< const diagnostic = (overrides: DiagnosticOverrides = {}) => { const common = { - schema_version: 1, component: "hopper_private_display", operation: "probe", reason: "ready", diff --git a/tests/boundary/providers/managed/managedStaticProvider.test.ts b/tests/boundary/providers/managed/managedStaticProvider.test.ts index 523d993ed0..f34d38a3dd 100644 --- a/tests/boundary/providers/managed/managedStaticProvider.test.ts +++ b/tests/boundary/providers/managed/managedStaticProvider.test.ts @@ -52,7 +52,9 @@ describe("managed static provider path boundary", () => { ); expect(boundaries.ok).toBe(true); if (!boundaries.ok) return; - expect(asManagedNativeBoundaryResult(boundaries.value)).toMatchObject({ + const boundaryResult = asManagedNativeBoundaryResult(boundaries.value); + expect(boundaryResult).not.toHaveProperty("schema_version"); + expect(boundaryResult).toMatchObject({ artifact: { path, sha256: parsed.value.sha256, format: "pe" }, module_refs: [], pinvoke_imports: [], diff --git a/tests/boundary/providers/replay/javascriptReplay.test.ts b/tests/boundary/providers/replay/javascriptReplay.test.ts index f71695b185..cf67ae6cb5 100644 --- a/tests/boundary/providers/replay/javascriptReplay.test.ts +++ b/tests/boundary/providers/replay/javascriptReplay.test.ts @@ -508,7 +508,6 @@ describe("controlled JavaScript replay cancellation and export", () => { const metadata = await stat(path); expect(metadata.mode & 0o777).toBe(0o600); expect(JSON.parse(await readFile(path, "utf8"))).toMatchObject({ - schema_version: 1, sources: null, }); } finally { diff --git a/tests/composition/analysis-sessions/binarySession.01-returns-detached-provider-target-and.test.ts b/tests/composition/analysis-sessions/binarySession.01-returns-detached-provider-target-and.test.ts index 9dc2648104..ef9b39b83d 100644 --- a/tests/composition/analysis-sessions/binarySession.01-returns-detached-provider-target-and.test.ts +++ b/tests/composition/analysis-sessions/binarySession.01-returns-detached-provider-target-and.test.ts @@ -5,11 +5,9 @@ import { createCacheProvider, createTestBinarySession, } from "../../fixtures/binarySession.js"; -import { createEvidenceBundle } from "../../../src/domain/evidenceBundle.js"; -import { createInvestigationWorkspace } from "../../../src/domain/investigationWorkspace.js"; describe("binary session", () => { - it("returns detached provider, target, and workspace metadata", async () => { + it("returns detached provider and target metadata", async () => { const [first] = await createBinarySessionTargets(); const session = createTestBinarySession(createCacheProvider([])); expect((await session.open(first)).ok).toBe(true); @@ -29,19 +27,6 @@ describe("binary session", () => { if (active !== undefined) Reflect.set(active, "path", "/tmp/forged"); expect(session.activeTarget()?.path).toBe(first); - const workspace = createInvestigationWorkspace( - "Detached workspace", - createEvidenceBundle([]), - [], - ); - expect(session.retainInvestigationWorkspace(workspace)).toBe("added"); - const direct = session.investigationWorkspace(workspace.workspace_id, 1); - if (direct !== undefined) Reflect.set(direct, "revision", 999); - const listed = session.investigationWorkspaces()[0]; - if (listed !== undefined) Reflect.set(listed, "workspace_id", "forged"); - expect( - session.investigationWorkspace(workspace.workspace_id, 1), - ).toMatchObject({ revision: 1, workspace_id: workspace.workspace_id }); await session.close(); }); }); diff --git a/tests/composition/analysis-sessions/binarySession.02-runs-through-a-non-hopper.test.ts b/tests/composition/analysis-sessions/binarySession.02-runs-through-a-non-hopper.test.ts index 82423e17bd..0b7a649949 100644 --- a/tests/composition/analysis-sessions/binarySession.02-runs-through-a-non-hopper.test.ts +++ b/tests/composition/analysis-sessions/binarySession.02-runs-through-a-non-hopper.test.ts @@ -16,8 +16,6 @@ const nonHopperProvider = (operations: string[]): AnalysisProvider => { operation: "address_name", available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: false, @@ -27,11 +25,6 @@ const nonHopperProvider = (operations: string[]): AnalysisProvider => { changesPermissions: false, requiresRoot: false, }, - limits: { - maxResults: null, - maxPayloadBytes: null, - timeoutMs: null, - }, limitations: [], }, ], diff --git a/tests/composition/analysis-sessions/binarySession.06-returns-typed-unavailability-without-dispatching.test.ts b/tests/composition/analysis-sessions/binarySession.06-returns-typed-unavailability-without-dispatching.test.ts index 60bcd78bc3..17fbad3b27 100644 --- a/tests/composition/analysis-sessions/binarySession.06-returns-typed-unavailability-without-dispatching.test.ts +++ b/tests/composition/analysis-sessions/binarySession.06-returns-typed-unavailability-without-dispatching.test.ts @@ -30,8 +30,6 @@ describe("binary session", () => { operation: "address_name", available: false, reason: "fixture intentionally omits symbol lookup", - pagination: "none", - exhaustive: false, effects: { mutatesArtifact: false, launchesProcess: false, @@ -41,11 +39,6 @@ describe("binary session", () => { changesPermissions: false, requiresRoot: false, }, - limits: { - maxResults: null, - maxPayloadBytes: null, - timeoutMs: null, - }, limitations: ["No symbol lookup implementation."], }, ], diff --git a/tests/composition/analysis-sessions/compositeProvider.test.ts b/tests/composition/analysis-sessions/compositeProvider.test.ts index 5629136866..398a75cb14 100644 --- a/tests/composition/analysis-sessions/compositeProvider.test.ts +++ b/tests/composition/analysis-sessions/compositeProvider.test.ts @@ -202,8 +202,6 @@ const capability = ( operation, available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: true, @@ -213,6 +211,5 @@ const capability = ( changesPermissions: false, requiresRoot: false, }, - limits: { maxResults: null, maxPayloadBytes: 1_000_000, timeoutMs: 5_000 }, limitations: [], }); diff --git a/tests/composition/analysis-sessions/providerBinding.test.ts b/tests/composition/analysis-sessions/providerBinding.test.ts index 055dbb8289..f1598a80fc 100644 --- a/tests/composition/analysis-sessions/providerBinding.test.ts +++ b/tests/composition/analysis-sessions/providerBinding.test.ts @@ -296,8 +296,6 @@ const capability = ( operation, available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact: false, launchesProcess: operation === "address_name", @@ -307,7 +305,6 @@ const capability = ( changesPermissions: false, requiresRoot: false, }, - limits: { maxResults: null, maxPayloadBytes: 1_000, timeoutMs: 1_000 }, limitations: [], }); diff --git a/tests/conformance/contracts/analysisErrorProjection.test.ts b/tests/conformance/contracts/analysisErrorProjection.test.ts index a3633c8891..5f595eb7f1 100644 --- a/tests/conformance/contracts/analysisErrorProjection.test.ts +++ b/tests/conformance/contracts/analysisErrorProjection.test.ts @@ -6,7 +6,7 @@ import { ArtifactOperationError, EvidenceFileError, HopperRemoteError, - InvestigationWorkspaceError, + WorkspaceStorageError, UnknownRegistryError, projectAnalysisError, type AnalysisError, @@ -53,7 +53,7 @@ describe("analysis error projection contract", () => { "name-conflict", "io", ] as const - ).map((reason) => new InvestigationWorkspaceError("update", reason)), + ).map((reason) => new WorkspaceStorageError("update", reason)), ...( [ "not-found", diff --git a/tests/conformance/providers/conformancePackage.test.ts b/tests/conformance/providers/conformancePackage.test.ts index cb55490c96..cfbe786655 100644 --- a/tests/conformance/providers/conformancePackage.test.ts +++ b/tests/conformance/providers/conformancePackage.test.ts @@ -1,14 +1,12 @@ import { describe, expect, it } from "vitest"; import { - CONFORMANCE_PACKAGE_VERSION, createConformancePackage, parseConformancePackage, type ConformancePackageInput, } from "../../../src/domain/conformancePackage.js"; const validPackageInput: ConformancePackageInput = { - schema_version: CONFORMANCE_PACKAGE_VERSION, name: "test-fixture", description: "A test conformance fixture", created_at: "2026-07-28T00:00:00Z", @@ -72,7 +70,7 @@ describe("conformance package parsing", () => { it("rejects invalid package structure", () => { expect( - parseConformancePackage({ ...validPackage, schema_version: 999 }), + parseConformancePackage({ ...validPackage, name: "" }), ).toMatchObject({ ok: false, error: { kind: "invalid_package" } }); }); diff --git a/tests/conformance/providers/conformanceReplay.test.ts b/tests/conformance/providers/conformanceReplay.test.ts index 6df6497bb3..d40b3378fb 100644 --- a/tests/conformance/providers/conformanceReplay.test.ts +++ b/tests/conformance/providers/conformanceReplay.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from "vitest"; import { - CONFORMANCE_PACKAGE_VERSION, createConformancePackage, type ConformancePackageInput, } from "../../../src/domain/conformancePackage.js"; @@ -13,7 +12,6 @@ import { } from "../../../src/domain/conformanceReplay.js"; const validPackageInput: ConformancePackageInput = { - schema_version: CONFORMANCE_PACKAGE_VERSION, name: "test-fixture", description: "A test conformance fixture", created_at: "2026-07-28T00:00:00Z", diff --git a/tests/fixtures/binarySession.ts b/tests/fixtures/binarySession.ts index 0e1c04c54b..a118a609ac 100644 --- a/tests/fixtures/binarySession.ts +++ b/tests/fixtures/binarySession.ts @@ -138,8 +138,6 @@ const cacheCapability = ( operation, available: true, reason: null, - pagination: "none", - exhaustive: true, effects: { mutatesArtifact, launchesProcess: false, @@ -149,10 +147,5 @@ const cacheCapability = ( changesPermissions: false, requiresRoot: false, }, - limits: { - maxResults: null, - maxPayloadBytes: null, - timeoutMs: null, - }, limitations: [], }); diff --git a/tests/fixtures/fakeGhidra.mjs b/tests/fixtures/fakeGhidra.mjs index a63002d5a3..8b2eee1136 100644 --- a/tests/fixtures/fakeGhidra.mjs +++ b/tests/fixtures/fakeGhidra.mjs @@ -54,7 +54,6 @@ else { await writeFile( pending, `${JSON.stringify({ - schema_version: 1, host: "127.0.0.1", port: address.port, })}\n`, diff --git a/tests/process-global/verifierRun.test.ts b/tests/process-global/verifierRun.test.ts index ecd108e572..6558739146 100644 --- a/tests/process-global/verifierRun.test.ts +++ b/tests/process-global/verifierRun.test.ts @@ -19,7 +19,6 @@ describe.sequential("verifier run identity", () => { const nested = createVerifierRun(); expect(first).toEqual({ - schema_version: 1, run_id: expect.stringMatching( /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u, ), @@ -60,7 +59,6 @@ describe.sequential("verifier run identity", () => { const completed = await completeVerifierRun(run); expect(completed.process_lineage).toMatchObject({ status: "verified", - schema_version: 1, observed_at: expect.stringMatching(/Z$/u), launcher_pid: process.pid, launcher_parent_pid: process.ppid,