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 13c0e6c0e..aad482df5 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 d504a6667..88b0b5ea5 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 886527416..ffb0b9999 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 e32478226..fb714a0f8 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 d3fd13858..b27384143 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 b93537e68..0c80ee209 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 74ce9e57e..8aa5b03ac 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 089657242..e09adf514 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 b5e9aad04..3ad9e66fe 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 c00756858..0461eea9a 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 ba73622fc..7181ccbe1 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 d385d4582..1e9d41324 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 54175c1c8..c3e0d2c28 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 91f7abb25..f404b7915 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 e61e486e5..be29475ed 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 4d01f02cc..8332fddac 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 41a30df9e..775d328a6 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 855c05ea7..826c6f89f 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 cde5d7c15..333a57b8c 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 9050fb003..ecab092a3 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 547abcb83..d780e5135 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 4a98acd79..aa31d7d81 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 336e3851f..1752d1083 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 5c7644250..57e8af830 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 64ac9456d..d32920dfb 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 d776b22ae..baa5f54ac 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 34a738c62..96fa7bbb8 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 216884e2f..740481f40 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 da3b51fe9..ce1e07b3c 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 15fae4fdc..dee8efe79 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 815ce907e..b43735303 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 c7c1f6c97..c905ca361 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 52fbb49ba..e15a5a22b 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 b9c618e6e..b0df117b6 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 09284a6a6..cd8ccc053 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 864532f44..13274e850 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 713276fb3..954e3972b 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 e3d2ba749..f0d6b0a47 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 4214c2d8b..307ddc64e 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 a07ffdd07..7806ea3fd 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 526e5f364..906121a24 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 bbf96dcf2..a76e5e81d 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 b07427599..f9c5ec2ae 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 b2354c6da..ac626c3e8 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 e92dd349f..79a9e9eb1 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 c9514fbf2..9eaf4e431 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 ac87a36f2..46ca36940 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 95a2810c1..13daa240d 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 5a98fdf4d..6afc00847 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 0f2734814..1c740cba6 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 d62e67c18..405c8b729 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 bfaeb2187..565a098c0 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 f9289f033..be64195c4 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 312c604f3..56b47b2f5 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 d7538234f..4a89db62b 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 68819ec91..b03c3367b 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 602735b57..08d223c1a 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 4841225a6..0d2a54e65 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 44953094a..bc7082476 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 b83d6c6ef..3b7633de9 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 e7f3f90de..1797938eb 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 b81c3361f..21bd56c97 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 5ade6219b..99215f18c 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 06afae7af..5b650a41f 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 663d29928..59e287ea7 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 a7e8e39a3..eae5360fd 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 0d93c6518..33d1eebed 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 2434555d8..1c4679e1e 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 5df9f95d8..e7273fd28 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 dd2edd72c..5eee93ef9 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 57f796c71..b5a714002 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 90c7c24c9..a5aa295df 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 6dcc671b2..aa404200b 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 2f239138a..45aaaff5b 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 9bc797e67..730a2d4ea 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 d61332537..7cf4e440a 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 1cf13acd5..2c2276b54 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 65ef1641a..f4528b9f3 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 6acec4a8a..4597e587b 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 880f9d08d..f0adfe9bb 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 5ab23855e..0833af9c2 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 e3177464a..bf4360451 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 0506c1d47..acba15dee 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 eeb0a6032..81d0f42fa 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 600f83f95..153f23313 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 bd4865869..e74bba8c8 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 a3877eeb3..52c18d6c5 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 ded2b8453..a65f24213 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 07563b44c..e831a35e1 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 8764f89e4..a49a2211e 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 c01e5373e..16c79fdbc 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 bfed60a93..fd9ae02ba 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 a808442f4..b7eb49a5a 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 b36aeee5c..55a4f1a3b 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 5a554ab14..cb62bc43b 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 90f3f1504..99e76a45c 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 06abef8a0..555a2b65e 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 8726d01df..aa683fc02 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 aaf3a5fbe..0e4781d11 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 0687d0435..0ad817366 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 1270c031a..414dcb606 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 0453ff81b..635f63d13 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 bc5ed9e95..ad164e2c2 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 fa6cf96a2..dfd462c1d 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 b84bc47ac..6e1526cee 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 8a6b9833a..eff0352e3 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 918aeb457..b3f5e35aa 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 993023197..d6a835e67 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 8a32c401a..e89b9ab90 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 f9f1d917b..db6d5e52d 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 f918f7161..208da4d9a 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 3b04363b1..083a58bda 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 d1228742e..a73c5a1c1 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 e8b175c62..9e888c2fc 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 523d993ed..f34d38a3d 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 f71695b18..cf67ae6cb 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 9dc264810..ef9b39b83 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 82423e17b..0b7a64994 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 60bcd78bc..17fbad3b2 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 562913686..398a75cb1 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 055dbb828..f1598a80f 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 a3633c889..5f595eb7f 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 cb55490c9..cfbe78665 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 6df6497bb..d40b3378f 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 0e1c04c54..a118a609a 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 a63002d5a..8b2eee113 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 ecd108e57..655873914 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,