rea-agents 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -38
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +148 -260
- package/dist/application/SetupClientConfiguration.js +224 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +124 -12
- package/dist/application/SetupSkill.js +54 -36
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +12 -3
- package/dist/application/Upgrade.js +16 -1
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +113 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +306 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/electronToolContracts.js +51 -3
- package/dist/contracts/managedToolContracts.js +8 -3
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +5 -12
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +274 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +328 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/processComparison.js +19 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/replayMachine.js +316 -0
- package/dist/domain/replayMachineRuntime.js +215 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/evaluation/CodexAgentEval.js +132 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +4 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +124 -56
- package/dist/server/javascriptApplicationResult.js +85 -0
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +48 -49
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +56 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +97 -26
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +15 -4
- package/package.json +11 -11
- package/skills/reverse-engineer-anything/SKILL.md +76 -0
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +25 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
- package/skills/rea-analysis/SKILL.md +0 -222
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import { parseBinaryTarget } from "../domain/binaryTarget.js";
|
|
2
1
|
import { analysisProfilesEqual, } from "../domain/analysisProfile.js";
|
|
3
|
-
import {
|
|
2
|
+
import { AnalysisCancelledError, ProviderAdapterError, } from "../domain/errors.js";
|
|
4
3
|
import { err, ok } from "../domain/result.js";
|
|
5
|
-
import { createEvidence } from "../domain/evidence.js";
|
|
6
|
-
import { evidenceBundleForTarget } from "../domain/evidenceBundle.js";
|
|
7
|
-
import { EvidenceLedger } from "./EvidenceLedger.js";
|
|
8
|
-
import { UnknownRegistryError } from "../domain/errors.js";
|
|
9
4
|
import { enhancedToolNameSchema } from "../contracts/enhancedInputs.js";
|
|
10
5
|
import { OFFICIAL_TOOL_CONTRACTS } from "../contracts/toolContracts.js";
|
|
11
|
-
import { snapshotMatchesBinding, snapshotMatchesTarget, snapshotTarget, } from "../domain/analysisSnapshot.js";
|
|
12
|
-
import { AnalysisSnapshotCache, isSnapshotCacheable, } from "./AnalysisSnapshotCache.js";
|
|
13
|
-
import { UNKNOWN_REGISTRY_PROVIDER, unknownEvidenceLinks, unknownMutationEvidence, } from "./UnknownEvidence.js";
|
|
14
|
-
import { parseInvestigationWorkspace, } from "../domain/investigationWorkspace.js";
|
|
15
6
|
import { SessionProviderRouter, } from "./SessionProviderRouter.js";
|
|
7
|
+
import { BinarySessionRecords } from "./BinarySessionRecords.js";
|
|
8
|
+
import { binarySessionStatus } from "./BinarySessionStatus.js";
|
|
9
|
+
import { resolveSessionOpen, } from "./BinarySessionOpen.js";
|
|
10
|
+
import { prepareSessionExecution } from "./BinarySessionExecution.js";
|
|
16
11
|
const OFFICIAL_OPERATIONS = new Set(OFFICIAL_TOOL_CONTRACTS.map(({ name }) => name));
|
|
17
12
|
/**
|
|
18
13
|
* Owns the single active target shared by CLI and MCP adapters.
|
|
@@ -21,22 +16,16 @@ const OFFICIAL_OPERATIONS = new Set(OFFICIAL_TOOL_CONTRACTS.map(({ name }) => na
|
|
|
21
16
|
* active provider client. A failed switch recreates the previous target instead
|
|
22
17
|
* of retaining a client whose resources were already shut down.
|
|
23
18
|
*/
|
|
24
|
-
export class BinarySession {
|
|
19
|
+
export class BinarySession extends BinarySessionRecords {
|
|
25
20
|
provider;
|
|
26
21
|
#active;
|
|
27
22
|
#transition = Promise.resolve();
|
|
28
23
|
#calls = new Set();
|
|
29
24
|
#providerRouter;
|
|
30
|
-
#evidence = new EvidenceLedger({
|
|
31
|
-
maxRecords: 10_000,
|
|
32
|
-
maxBytes: 64 * 1024 * 1024,
|
|
33
|
-
});
|
|
34
|
-
#snapshot = new AnalysisSnapshotCache();
|
|
35
|
-
#investigationWorkspaces = new Map();
|
|
36
25
|
#runtimeAvailability = new Map();
|
|
37
26
|
#availabilityListeners = new Set();
|
|
38
|
-
#snapshotInvalidated = false;
|
|
39
27
|
constructor(provider, options = {}) {
|
|
28
|
+
super();
|
|
40
29
|
this.provider = provider;
|
|
41
30
|
this.#providerRouter =
|
|
42
31
|
provider instanceof SessionProviderRouter
|
|
@@ -90,104 +79,6 @@ export class BinarySession {
|
|
|
90
79
|
this.#availabilityListeners.add(listener);
|
|
91
80
|
return () => this.#availabilityListeners.delete(listener);
|
|
92
81
|
}
|
|
93
|
-
/** Add one successful public observation to the session ledger. */
|
|
94
|
-
recordEvidence(evidence) {
|
|
95
|
-
return this.#evidence.record(evidence);
|
|
96
|
-
}
|
|
97
|
-
/** Check that comparison input Evidence is already session-owned. */
|
|
98
|
-
hasEvidence(evidenceId) {
|
|
99
|
-
return this.#evidence.has(evidenceId);
|
|
100
|
-
}
|
|
101
|
-
/** Read one detached session-owned Evidence record by semantic ID. */
|
|
102
|
-
evidenceById(evidenceId) {
|
|
103
|
-
return this.#evidence.get(evidenceId);
|
|
104
|
-
}
|
|
105
|
-
/** Return a deterministic snapshot without clearing session evidence. */
|
|
106
|
-
exportEvidenceBundle() {
|
|
107
|
-
return this.#evidence.export();
|
|
108
|
-
}
|
|
109
|
-
/** Atomically merge a validated evidence bundle into this session. */
|
|
110
|
-
importEvidenceBundle(bundle) {
|
|
111
|
-
return this.#evidence.import(bundle);
|
|
112
|
-
}
|
|
113
|
-
/** Export immutable cached calls and session evidence for the active target. */
|
|
114
|
-
exportAnalysisSnapshot() {
|
|
115
|
-
if (this.#snapshotInvalidated)
|
|
116
|
-
return err(new EvidenceIntegrityError("Analysis snapshots are unavailable after analysis metadata mutations"));
|
|
117
|
-
const target = this.#active?.target;
|
|
118
|
-
const profile = this.#active?.profile ?? undefined;
|
|
119
|
-
if (target !== undefined && profile === undefined)
|
|
120
|
-
return err(new EvidenceIntegrityError("Analysis snapshots require a concrete provider analysis profile"));
|
|
121
|
-
return this.#snapshot.export(target, profile, target === undefined
|
|
122
|
-
? this.#evidence.export()
|
|
123
|
-
: evidenceBundleForTarget(this.#evidence.export(), target.sha256));
|
|
124
|
-
}
|
|
125
|
-
/** Stage validated cached calls for an identical binary and merge its evidence. */
|
|
126
|
-
importAnalysisSnapshot(snapshot) {
|
|
127
|
-
const active = this.#active;
|
|
128
|
-
if (active?.profile === null)
|
|
129
|
-
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: the active target has no concrete analysis profile"));
|
|
130
|
-
return this.#snapshot.import(snapshot, active === undefined
|
|
131
|
-
? undefined
|
|
132
|
-
: { target: active.target, profile: active.profile }, (bundle) => this.#evidence.import(bundle));
|
|
133
|
-
}
|
|
134
|
-
/** Retain one validated immutable workspace revision for session resources. */
|
|
135
|
-
retainInvestigationWorkspace(workspace) {
|
|
136
|
-
const parsed = parseInvestigationWorkspace(workspace);
|
|
137
|
-
const key = `${parsed.workspace_id}:${String(parsed.revision)}`;
|
|
138
|
-
if (this.#investigationWorkspaces.has(key))
|
|
139
|
-
return "duplicate";
|
|
140
|
-
this.#investigationWorkspaces.set(key, parsed);
|
|
141
|
-
return "added";
|
|
142
|
-
}
|
|
143
|
-
/** Read one session-retained immutable workspace revision. */
|
|
144
|
-
investigationWorkspace(workspaceId, revision) {
|
|
145
|
-
const workspace = this.#investigationWorkspaces.get(`${workspaceId}:${String(revision)}`);
|
|
146
|
-
return workspace === undefined ? undefined : structuredClone(workspace);
|
|
147
|
-
}
|
|
148
|
-
/** List retained workspace revisions in canonical identity order. */
|
|
149
|
-
investigationWorkspaces() {
|
|
150
|
-
return [...this.#investigationWorkspaces.values()]
|
|
151
|
-
.sort((left, right) => left.workspace_id.localeCompare(right.workspace_id) ||
|
|
152
|
-
left.revision - right.revision)
|
|
153
|
-
.map((workspace) => structuredClone(workspace));
|
|
154
|
-
}
|
|
155
|
-
/** Create an approved residual unknown and immutable mutation evidence. */
|
|
156
|
-
recordUnknown(input) {
|
|
157
|
-
const evidence = unknownMutationEvidence(this.#active?.target, input);
|
|
158
|
-
return this.#evidence.recordUnknown(input, evidence);
|
|
159
|
-
}
|
|
160
|
-
/** Atomically record derived Evidence and its approved residual unknown. */
|
|
161
|
-
recordEvidenceWithUnknown(evidence, input) {
|
|
162
|
-
return this.#evidence.recordWithUnknown(evidence, input, unknownMutationEvidence(undefined, input));
|
|
163
|
-
}
|
|
164
|
-
/** Update one unknown using compare-and-swap revision semantics. */
|
|
165
|
-
updateUnknown(input) {
|
|
166
|
-
const evidence = createEvidence(this.#active?.target, UNKNOWN_REGISTRY_PROVIDER, {
|
|
167
|
-
predicateType: "rea.residual-unknown-mutation/v1",
|
|
168
|
-
operation: "update_unknown",
|
|
169
|
-
parameters: {
|
|
170
|
-
unknown_id: input.unknown_id,
|
|
171
|
-
expected_revision: input.expected_revision,
|
|
172
|
-
},
|
|
173
|
-
result: { action: "update", status: input.status },
|
|
174
|
-
confidence: "derived",
|
|
175
|
-
authority: "analyst-inference",
|
|
176
|
-
evidenceLinks: unknownEvidenceLinks(input),
|
|
177
|
-
limitations: [
|
|
178
|
-
"Registry mutation evidence records analyst intent, not proof of the answer.",
|
|
179
|
-
],
|
|
180
|
-
});
|
|
181
|
-
return this.#evidence.updateUnknown(input, evidence);
|
|
182
|
-
}
|
|
183
|
-
/** Query stable current residual-unknown heads. */
|
|
184
|
-
listUnknowns(filters = {}) {
|
|
185
|
-
return this.#evidence.listUnknowns(filters);
|
|
186
|
-
}
|
|
187
|
-
/** Check whether current head is a bundle-valid resolved state. */
|
|
188
|
-
verifyUnknownResolution(unknownId) {
|
|
189
|
-
return this.#evidence.verifyUnknownResolution(unknownId);
|
|
190
|
-
}
|
|
191
82
|
/**
|
|
192
83
|
* Open or switch targets after draining calls against the current target.
|
|
193
84
|
* Returns the switch failure even if best-effort restoration also fails.
|
|
@@ -196,27 +87,17 @@ export class BinarySession {
|
|
|
196
87
|
return this.#serialize(async () => {
|
|
197
88
|
if (isAborted(options.signal))
|
|
198
89
|
return err(new AnalysisCancelledError("open_binary"));
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (!resolvedRoute.ok)
|
|
210
|
-
return resolvedRoute;
|
|
211
|
-
const route = resolvedRoute.value;
|
|
90
|
+
const resolved = await resolveSessionOpen({
|
|
91
|
+
router: this.#providerRouter,
|
|
92
|
+
current: this.#active,
|
|
93
|
+
path,
|
|
94
|
+
options,
|
|
95
|
+
stagedSnapshotMatches: (target, profile) => this.matchesSnapshot(target, profile),
|
|
96
|
+
});
|
|
97
|
+
if (!resolved.ok)
|
|
98
|
+
return resolved;
|
|
99
|
+
const { target, route, sameTarget } = resolved.value;
|
|
212
100
|
const { profile, compatibility } = route;
|
|
213
|
-
if (options.snapshot !== undefined &&
|
|
214
|
-
(profile === null ||
|
|
215
|
-
!snapshotMatchesBinding(options.snapshot, parsed.value, profile)))
|
|
216
|
-
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: target, provider, or analysis profile does not match the requested binary"));
|
|
217
|
-
if (this.#active === undefined &&
|
|
218
|
-
!this.#snapshot.matches(parsed.value, profile ?? undefined))
|
|
219
|
-
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: staged target, provider, or analysis profile does not match"));
|
|
220
101
|
if (isAborted(options.signal))
|
|
221
102
|
return err(new AnalysisCancelledError("open_binary"));
|
|
222
103
|
const activeProfile = this.#active?.profile;
|
|
@@ -229,13 +110,13 @@ export class BinarySession {
|
|
|
229
110
|
if (!imported.ok)
|
|
230
111
|
return imported;
|
|
231
112
|
}
|
|
232
|
-
return ok(
|
|
113
|
+
return ok(target);
|
|
233
114
|
}
|
|
234
115
|
await this.#drainCalls();
|
|
235
116
|
const previous = this.#active;
|
|
236
117
|
this.#active = undefined;
|
|
237
118
|
await previous?.client.close();
|
|
238
|
-
const client = route.createClient(
|
|
119
|
+
const client = route.createClient(target);
|
|
239
120
|
const started = await client.execute("health", {}, options);
|
|
240
121
|
if (!started.ok) {
|
|
241
122
|
await client.close();
|
|
@@ -248,7 +129,7 @@ export class BinarySession {
|
|
|
248
129
|
return err(new AnalysisCancelledError("open_binary"));
|
|
249
130
|
}
|
|
250
131
|
this.#active = {
|
|
251
|
-
target
|
|
132
|
+
target,
|
|
252
133
|
client,
|
|
253
134
|
profile,
|
|
254
135
|
compatibility: structuredClone(compatibility),
|
|
@@ -256,9 +137,9 @@ export class BinarySession {
|
|
|
256
137
|
};
|
|
257
138
|
this.#clearRuntimeAvailability();
|
|
258
139
|
if (profile === null)
|
|
259
|
-
this
|
|
140
|
+
this.clearSnapshot();
|
|
260
141
|
else
|
|
261
|
-
this
|
|
142
|
+
this.selectSnapshot(target, profile);
|
|
262
143
|
if (options.snapshot !== undefined) {
|
|
263
144
|
const imported = this.importAnalysisSnapshot(options.snapshot);
|
|
264
145
|
if (!imported.ok) {
|
|
@@ -268,8 +149,8 @@ export class BinarySession {
|
|
|
268
149
|
return imported;
|
|
269
150
|
}
|
|
270
151
|
}
|
|
271
|
-
this
|
|
272
|
-
return ok(
|
|
152
|
+
this.resetSnapshotInvalidation();
|
|
153
|
+
return ok(target);
|
|
273
154
|
});
|
|
274
155
|
}
|
|
275
156
|
/** Close the active target, if any. */
|
|
@@ -279,90 +160,19 @@ export class BinarySession {
|
|
|
279
160
|
this.#active = undefined;
|
|
280
161
|
await this.#drainCalls();
|
|
281
162
|
await previous?.client.close();
|
|
282
|
-
this
|
|
283
|
-
this.#snapshot.clear();
|
|
284
|
-
this.#snapshotInvalidated = false;
|
|
163
|
+
this.clearSessionRecords();
|
|
285
164
|
this.#clearRuntimeAvailability();
|
|
286
165
|
return ok(null);
|
|
287
166
|
});
|
|
288
167
|
}
|
|
289
168
|
/** Describe the active binary session. */
|
|
290
169
|
status() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
version: configuredProvider.version,
|
|
298
|
-
};
|
|
299
|
-
const providerList = this.#providerRouter
|
|
300
|
-
.providerIdentities(route)
|
|
301
|
-
.map(({ id, name, version }) => ({ id, name, version }));
|
|
302
|
-
const capabilities = route.capabilities === undefined
|
|
303
|
-
? []
|
|
304
|
-
: [...route.capabilities.values()]
|
|
305
|
-
.sort((left, right) => left.operation.localeCompare(right.operation))
|
|
306
|
-
.map((descriptor) => ({
|
|
307
|
-
...descriptor,
|
|
308
|
-
...this.#runtimeAvailability.get(descriptor.operation),
|
|
309
|
-
}))
|
|
310
|
-
.map((descriptor) => capabilityStatus(descriptor));
|
|
311
|
-
const analysisProviderBinding = route.binding === null
|
|
312
|
-
? null
|
|
313
|
-
: {
|
|
314
|
-
provider: {
|
|
315
|
-
id: route.binding.identity.id,
|
|
316
|
-
name: route.binding.identity.name,
|
|
317
|
-
version: route.binding.identity.version,
|
|
318
|
-
},
|
|
319
|
-
selection_source: route.binding.selectionSource,
|
|
320
|
-
analysis_profile: structuredClone(route.binding.profile),
|
|
321
|
-
};
|
|
322
|
-
const analysisProviderCandidates = this.#providerRouter
|
|
323
|
-
.candidateStatuses(route)
|
|
324
|
-
.map((candidate) => ({
|
|
325
|
-
provider: {
|
|
326
|
-
id: candidate.provider.id,
|
|
327
|
-
name: candidate.provider.name,
|
|
328
|
-
version: candidate.provider.version,
|
|
329
|
-
},
|
|
330
|
-
availability: {
|
|
331
|
-
status: candidate.availability.status,
|
|
332
|
-
code: candidate.availability.code,
|
|
333
|
-
reason: candidate.availability.reason,
|
|
334
|
-
diagnostics: structuredClone(candidate.availability.diagnostics),
|
|
335
|
-
},
|
|
336
|
-
target_support: {
|
|
337
|
-
status: candidate.targetSupport.status,
|
|
338
|
-
code: candidate.targetSupport.code,
|
|
339
|
-
reason: candidate.targetSupport.reason,
|
|
340
|
-
diagnostics: structuredClone(candidate.targetSupport.diagnostics),
|
|
341
|
-
},
|
|
342
|
-
selected: candidate.selected,
|
|
343
|
-
capabilities: candidate.capabilities
|
|
344
|
-
.slice()
|
|
345
|
-
.sort((left, right) => left.operation.localeCompare(right.operation))
|
|
346
|
-
.map((descriptor) => capabilityStatus(descriptor)),
|
|
347
|
-
}));
|
|
348
|
-
const common = {
|
|
349
|
-
provider,
|
|
350
|
-
providers: providerList,
|
|
351
|
-
capabilities,
|
|
352
|
-
analysis_provider_binding: analysisProviderBinding,
|
|
353
|
-
analysis_provider_candidates: analysisProviderCandidates,
|
|
354
|
-
};
|
|
355
|
-
return target === undefined
|
|
356
|
-
? { open: false, ...common }
|
|
357
|
-
: {
|
|
358
|
-
open: true,
|
|
359
|
-
...common,
|
|
360
|
-
path: target.path,
|
|
361
|
-
sha256: target.sha256,
|
|
362
|
-
format: target.format,
|
|
363
|
-
kind: target.kind,
|
|
364
|
-
architecture: target.architecture ?? null,
|
|
365
|
-
};
|
|
170
|
+
return binarySessionStatus({
|
|
171
|
+
target: this.#active?.target,
|
|
172
|
+
route: this.#currentRoute(),
|
|
173
|
+
router: this.#providerRouter,
|
|
174
|
+
runtimeAvailability: this.#runtimeAvailability,
|
|
175
|
+
});
|
|
366
176
|
}
|
|
367
177
|
/** Return the immutable artifact identity captured before its provider started. */
|
|
368
178
|
activeTarget() {
|
|
@@ -370,6 +180,9 @@ export class BinarySession {
|
|
|
370
180
|
? undefined
|
|
371
181
|
: structuredClone(this.#active.target);
|
|
372
182
|
}
|
|
183
|
+
activeAnalysisBinding() {
|
|
184
|
+
return this.#active;
|
|
185
|
+
}
|
|
373
186
|
/**
|
|
374
187
|
* Invoke a provider operation against the active target.
|
|
375
188
|
* Calls may overlap, but a pending target transition prevents new calls from
|
|
@@ -379,27 +192,16 @@ export class BinarySession {
|
|
|
379
192
|
const transitioned = await this.#waitForTransition(name, options?.signal);
|
|
380
193
|
if (!transitioned.ok)
|
|
381
194
|
return transitioned;
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
const profile = active.profile !== null &&
|
|
394
|
-
(capability === undefined ||
|
|
395
|
-
capability.provider.id === active.profile.provider.id)
|
|
396
|
-
? active.profile
|
|
397
|
-
: undefined;
|
|
398
|
-
const cacheable = profile !== undefined &&
|
|
399
|
-
isSnapshotCacheable(name, capability, arguments_);
|
|
400
|
-
const cached = cacheable
|
|
401
|
-
? this.#snapshot.lookup(active.target, profile, name, arguments_)
|
|
402
|
-
: undefined;
|
|
195
|
+
const prepared = prepareSessionExecution({
|
|
196
|
+
active: this.#active,
|
|
197
|
+
operation: name,
|
|
198
|
+
parameters: arguments_,
|
|
199
|
+
unboundOperationError: (operation, route) => this.#providerRouter.unboundOperationError(operation, route),
|
|
200
|
+
lookupSnapshot: (target, profile, operation, parameters) => this.lookupSnapshot(target, profile, operation, parameters),
|
|
201
|
+
});
|
|
202
|
+
if (!prepared.ok)
|
|
203
|
+
return prepared;
|
|
204
|
+
const { active, capability, profile, cacheable, cached } = prepared.value;
|
|
403
205
|
if (cached !== undefined)
|
|
404
206
|
return ok(cached);
|
|
405
207
|
const call = active.client.execute(name, arguments_, options);
|
|
@@ -408,8 +210,8 @@ export class BinarySession {
|
|
|
408
210
|
const result = await call;
|
|
409
211
|
const profiled = commitExecutionProfile(name, result, profile);
|
|
410
212
|
this.#observeRuntimeAvailability(name, profiled);
|
|
411
|
-
if (profiled.ok && cacheable)
|
|
412
|
-
this
|
|
213
|
+
if (profiled.ok && cacheable && profile !== undefined)
|
|
214
|
+
this.recordSnapshot({
|
|
413
215
|
target: active.target,
|
|
414
216
|
profile,
|
|
415
217
|
operation: name,
|
|
@@ -417,8 +219,7 @@ export class BinarySession {
|
|
|
417
219
|
execution: profiled.value,
|
|
418
220
|
});
|
|
419
221
|
else if (profiled.ok && capability?.effects.mutatesArtifact === true) {
|
|
420
|
-
this
|
|
421
|
-
this.#snapshotInvalidated = true;
|
|
222
|
+
this.invalidateSnapshot();
|
|
422
223
|
}
|
|
423
224
|
return profiled;
|
|
424
225
|
}
|
|
@@ -552,27 +353,3 @@ const commitExecutionProfile = (operation, result, profile) => {
|
|
|
552
353
|
analysisProfile: structuredClone(profile),
|
|
553
354
|
});
|
|
554
355
|
};
|
|
555
|
-
const capabilityStatus = (descriptor) => ({
|
|
556
|
-
operation: descriptor.operation,
|
|
557
|
-
available: descriptor.available,
|
|
558
|
-
reason: descriptor.reason,
|
|
559
|
-
input_contract_version: descriptor.inputContractVersion,
|
|
560
|
-
output_contract_version: descriptor.outputContractVersion,
|
|
561
|
-
pagination: descriptor.pagination,
|
|
562
|
-
exhaustive: descriptor.exhaustive,
|
|
563
|
-
effects: {
|
|
564
|
-
mutates_artifact: descriptor.effects.mutatesArtifact,
|
|
565
|
-
launches_process: descriptor.effects.launchesProcess,
|
|
566
|
-
may_show_ui: descriptor.effects.mayShowUi,
|
|
567
|
-
may_access_network: descriptor.effects.mayAccessNetwork,
|
|
568
|
-
may_write_filesystem: descriptor.effects.mayWriteFilesystem,
|
|
569
|
-
changes_permissions: descriptor.effects.changesPermissions,
|
|
570
|
-
requires_root: descriptor.effects.requiresRoot,
|
|
571
|
-
},
|
|
572
|
-
limits: {
|
|
573
|
-
max_results: descriptor.limits.maxResults,
|
|
574
|
-
max_payload_bytes: descriptor.limits.maxPayloadBytes,
|
|
575
|
-
timeout_ms: descriptor.limits.timeoutMs,
|
|
576
|
-
},
|
|
577
|
-
limitations: [...descriptor.limitations],
|
|
578
|
-
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AnalysisCapabilityUnavailableError, NoBinaryOpenError, } from "../domain/errors.js";
|
|
2
|
+
import { err, ok } from "../domain/result.js";
|
|
3
|
+
import { isSnapshotCacheable } from "./AnalysisSnapshotCache.js";
|
|
4
|
+
/** Resolve capability, profile, and snapshot state before invoking a provider. */
|
|
5
|
+
export const prepareSessionExecution = (input) => {
|
|
6
|
+
const { active, operation, parameters, unboundOperationError, lookupSnapshot, } = input;
|
|
7
|
+
if (active === undefined)
|
|
8
|
+
return err(new NoBinaryOpenError());
|
|
9
|
+
const capability = active.route.capabilities?.get(operation);
|
|
10
|
+
if (active.route.capabilities !== undefined &&
|
|
11
|
+
capability?.available !== true) {
|
|
12
|
+
const selectionError = unboundOperationError(operation, active.route);
|
|
13
|
+
if (selectionError !== undefined)
|
|
14
|
+
return err(selectionError);
|
|
15
|
+
return err(new AnalysisCapabilityUnavailableError(active.route.binding?.identity.id ?? active.route.identity.id, operation, capability?.reason ?? "operation is not declared by this provider"));
|
|
16
|
+
}
|
|
17
|
+
const profile = active.profile !== null &&
|
|
18
|
+
(capability === undefined ||
|
|
19
|
+
capability.provider.id === active.profile.provider.id)
|
|
20
|
+
? active.profile
|
|
21
|
+
: undefined;
|
|
22
|
+
const cacheable = profile !== undefined &&
|
|
23
|
+
isSnapshotCacheable(operation, capability, parameters);
|
|
24
|
+
const cached = cacheable
|
|
25
|
+
? lookupSnapshot(active.target, profile, operation, parameters)
|
|
26
|
+
: undefined;
|
|
27
|
+
return ok({ active, capability, profile, cacheable, cached });
|
|
28
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { snapshotMatchesBinding, snapshotMatchesTarget, snapshotTarget, } from "../domain/analysisSnapshot.js";
|
|
2
|
+
import { parseBinaryTarget, } from "../domain/binaryTarget.js";
|
|
3
|
+
import { EvidenceIntegrityError, } from "../domain/errors.js";
|
|
4
|
+
import { err } from "../domain/result.js";
|
|
5
|
+
import { SessionProviderRouter } from "./SessionProviderRouter.js";
|
|
6
|
+
/** Parse a target, resolve its provider route, and validate snapshot binding. */
|
|
7
|
+
export const resolveSessionOpen = async (input) => {
|
|
8
|
+
const { router, current, path, options, stagedSnapshotMatches } = input;
|
|
9
|
+
const parsed = await parseBinaryTarget(path, process.cwd(), process.arch, options.targetKind);
|
|
10
|
+
if (!parsed.ok)
|
|
11
|
+
return parsed;
|
|
12
|
+
const target = parsed.value;
|
|
13
|
+
const sameTarget = current?.target.path === target.path &&
|
|
14
|
+
snapshotMatchesTarget(snapshotTarget(current.target), target);
|
|
15
|
+
const resolvedRoute = sameTarget && options.providerId === undefined && current !== undefined
|
|
16
|
+
? { ok: true, value: current.route }
|
|
17
|
+
: await router.resolve(target, options.providerId, options.signal);
|
|
18
|
+
if (!resolvedRoute.ok)
|
|
19
|
+
return resolvedRoute;
|
|
20
|
+
const route = resolvedRoute.value;
|
|
21
|
+
const snapshotError = validateSnapshot({
|
|
22
|
+
snapshot: options.snapshot,
|
|
23
|
+
target,
|
|
24
|
+
profile: route.profile,
|
|
25
|
+
current,
|
|
26
|
+
stagedSnapshotMatches,
|
|
27
|
+
});
|
|
28
|
+
if (snapshotError !== undefined)
|
|
29
|
+
return err(snapshotError);
|
|
30
|
+
return { ok: true, value: { target, route, sameTarget } };
|
|
31
|
+
};
|
|
32
|
+
const validateSnapshot = ({ snapshot, target, profile, current, stagedSnapshotMatches, }) => {
|
|
33
|
+
if (snapshot !== undefined &&
|
|
34
|
+
(profile === null || !snapshotMatchesBinding(snapshot, target, profile)))
|
|
35
|
+
return new EvidenceIntegrityError("Analysis snapshot profile_mismatch: target, provider, or analysis profile does not match the requested binary");
|
|
36
|
+
if (current === undefined && !stagedSnapshotMatches(target, profile))
|
|
37
|
+
return new EvidenceIntegrityError("Analysis snapshot profile_mismatch: staged target, provider, or analysis profile does not match");
|
|
38
|
+
return undefined;
|
|
39
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { createEvidence } from "../domain/evidence.js";
|
|
2
|
+
import { evidenceBundleForTarget } from "../domain/evidenceBundle.js";
|
|
3
|
+
import { EvidenceIntegrityError, } from "../domain/errors.js";
|
|
4
|
+
import { parseInvestigationWorkspace, } from "../domain/investigationWorkspace.js";
|
|
5
|
+
import { parseReconstructionCoverageWorkspace, } from "../domain/reconstructionCoverage.js";
|
|
6
|
+
import { err } from "../domain/result.js";
|
|
7
|
+
import { AnalysisSnapshotCache } from "./AnalysisSnapshotCache.js";
|
|
8
|
+
import { EvidenceLedger } from "./EvidenceLedger.js";
|
|
9
|
+
import { UNKNOWN_REGISTRY_PROVIDER, unknownEvidenceLinks, unknownMutationEvidence, } from "./UnknownEvidence.js";
|
|
10
|
+
/** Owns session evidence, snapshots, workspaces, and residual unknowns. */
|
|
11
|
+
export class BinarySessionRecords {
|
|
12
|
+
#evidence = new EvidenceLedger({
|
|
13
|
+
maxRecords: 10_000,
|
|
14
|
+
maxBytes: 64 * 1024 * 1024,
|
|
15
|
+
});
|
|
16
|
+
#snapshot = new AnalysisSnapshotCache();
|
|
17
|
+
#investigationWorkspaces = new Map();
|
|
18
|
+
#coverageWorkspaces = new Map();
|
|
19
|
+
#snapshotInvalidated = false;
|
|
20
|
+
recordEvidence(evidence) {
|
|
21
|
+
return this.#evidence.record(evidence);
|
|
22
|
+
}
|
|
23
|
+
hasEvidence(evidenceId) {
|
|
24
|
+
return this.#evidence.has(evidenceId);
|
|
25
|
+
}
|
|
26
|
+
evidenceById(evidenceId) {
|
|
27
|
+
return this.#evidence.get(evidenceId);
|
|
28
|
+
}
|
|
29
|
+
exportEvidenceBundle() {
|
|
30
|
+
return this.#evidence.export();
|
|
31
|
+
}
|
|
32
|
+
importEvidenceBundle(bundle) {
|
|
33
|
+
return this.#evidence.import(bundle);
|
|
34
|
+
}
|
|
35
|
+
exportAnalysisSnapshot() {
|
|
36
|
+
const active = this.activeAnalysisBinding();
|
|
37
|
+
if (this.#snapshotInvalidated)
|
|
38
|
+
return err(new EvidenceIntegrityError("Analysis snapshots are unavailable after analysis metadata mutations"));
|
|
39
|
+
const target = active?.target;
|
|
40
|
+
const profile = active?.profile ?? undefined;
|
|
41
|
+
if (target !== undefined && profile === undefined)
|
|
42
|
+
return err(new EvidenceIntegrityError("Analysis snapshots require a concrete provider analysis profile"));
|
|
43
|
+
return this.#snapshot.export(target, profile, target === undefined
|
|
44
|
+
? this.#evidence.export()
|
|
45
|
+
: evidenceBundleForTarget(this.#evidence.export(), target.sha256));
|
|
46
|
+
}
|
|
47
|
+
importAnalysisSnapshot(snapshot) {
|
|
48
|
+
const active = this.activeAnalysisBinding();
|
|
49
|
+
if (active?.profile === null)
|
|
50
|
+
return err(new EvidenceIntegrityError("Analysis snapshot profile_mismatch: the active target has no concrete analysis profile"));
|
|
51
|
+
return this.#snapshot.import(snapshot, active === undefined
|
|
52
|
+
? undefined
|
|
53
|
+
: { target: active.target, profile: active.profile }, (bundle) => this.#evidence.import(bundle));
|
|
54
|
+
}
|
|
55
|
+
matchesSnapshot(target, profile) {
|
|
56
|
+
return this.#snapshot.matches(target, profile ?? undefined);
|
|
57
|
+
}
|
|
58
|
+
selectSnapshot(target, profile) {
|
|
59
|
+
this.#snapshot.select(target, profile);
|
|
60
|
+
}
|
|
61
|
+
lookupSnapshot(target, profile, operation, parameters) {
|
|
62
|
+
return this.#snapshot.lookup(target, profile, operation, parameters);
|
|
63
|
+
}
|
|
64
|
+
recordSnapshot(input) {
|
|
65
|
+
this.#snapshot.record(input);
|
|
66
|
+
}
|
|
67
|
+
invalidateSnapshot() {
|
|
68
|
+
this.#snapshot.clear();
|
|
69
|
+
this.#snapshotInvalidated = true;
|
|
70
|
+
}
|
|
71
|
+
resetSnapshotInvalidation() {
|
|
72
|
+
this.#snapshotInvalidated = false;
|
|
73
|
+
}
|
|
74
|
+
clearSnapshot() {
|
|
75
|
+
this.#snapshot.clear();
|
|
76
|
+
}
|
|
77
|
+
clearSessionRecords() {
|
|
78
|
+
this.#evidence.clear();
|
|
79
|
+
this.#snapshot.clear();
|
|
80
|
+
this.#snapshotInvalidated = false;
|
|
81
|
+
}
|
|
82
|
+
retainInvestigationWorkspace(workspace) {
|
|
83
|
+
const parsed = parseInvestigationWorkspace(workspace);
|
|
84
|
+
const key = workspaceKey(parsed.workspace_id, parsed.revision);
|
|
85
|
+
if (this.#investigationWorkspaces.has(key))
|
|
86
|
+
return "duplicate";
|
|
87
|
+
this.#investigationWorkspaces.set(key, parsed);
|
|
88
|
+
return "added";
|
|
89
|
+
}
|
|
90
|
+
investigationWorkspace(workspaceId, revision) {
|
|
91
|
+
const workspace = this.#investigationWorkspaces.get(workspaceKey(workspaceId, revision));
|
|
92
|
+
return workspace === undefined ? undefined : structuredClone(workspace);
|
|
93
|
+
}
|
|
94
|
+
investigationWorkspaces() {
|
|
95
|
+
return sortedWorkspaces(this.#investigationWorkspaces.values());
|
|
96
|
+
}
|
|
97
|
+
retainReconstructionCoverageWorkspace(workspace) {
|
|
98
|
+
const parsed = parseReconstructionCoverageWorkspace(workspace);
|
|
99
|
+
const key = workspaceKey(parsed.workspace_id, parsed.revision);
|
|
100
|
+
if (this.#coverageWorkspaces.has(key))
|
|
101
|
+
return "duplicate";
|
|
102
|
+
this.#coverageWorkspaces.set(key, parsed);
|
|
103
|
+
return "added";
|
|
104
|
+
}
|
|
105
|
+
reconstructionCoverageWorkspace(workspaceId, revision) {
|
|
106
|
+
const workspace = this.#coverageWorkspaces.get(workspaceKey(workspaceId, revision));
|
|
107
|
+
return workspace === undefined ? undefined : structuredClone(workspace);
|
|
108
|
+
}
|
|
109
|
+
reconstructionCoverageWorkspaces() {
|
|
110
|
+
return sortedWorkspaces(this.#coverageWorkspaces.values());
|
|
111
|
+
}
|
|
112
|
+
recordUnknown(input) {
|
|
113
|
+
const target = this.activeAnalysisBinding()?.target;
|
|
114
|
+
return this.#evidence.recordUnknown(input, unknownMutationEvidence(target, input));
|
|
115
|
+
}
|
|
116
|
+
recordEvidenceWithUnknown(evidence, input) {
|
|
117
|
+
return this.#evidence.recordWithUnknown(evidence, input, unknownMutationEvidence(undefined, input));
|
|
118
|
+
}
|
|
119
|
+
updateUnknown(input) {
|
|
120
|
+
const target = this.activeAnalysisBinding()?.target;
|
|
121
|
+
const evidence = createEvidence(target, UNKNOWN_REGISTRY_PROVIDER, {
|
|
122
|
+
predicateType: "rea.residual-unknown-mutation/v1",
|
|
123
|
+
operation: "update_unknown",
|
|
124
|
+
parameters: {
|
|
125
|
+
unknown_id: input.unknown_id,
|
|
126
|
+
expected_revision: input.expected_revision,
|
|
127
|
+
},
|
|
128
|
+
result: { action: "update", status: input.status },
|
|
129
|
+
confidence: "derived",
|
|
130
|
+
authority: "analyst-inference",
|
|
131
|
+
evidenceLinks: unknownEvidenceLinks(input),
|
|
132
|
+
limitations: [
|
|
133
|
+
"Registry mutation evidence records analyst intent, not proof of the answer.",
|
|
134
|
+
],
|
|
135
|
+
});
|
|
136
|
+
return this.#evidence.updateUnknown(input, evidence);
|
|
137
|
+
}
|
|
138
|
+
listUnknowns(filters = {}) {
|
|
139
|
+
return this.#evidence.listUnknowns(filters);
|
|
140
|
+
}
|
|
141
|
+
verifyUnknownResolution(unknownId) {
|
|
142
|
+
return this.#evidence.verifyUnknownResolution(unknownId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const workspaceKey = (workspaceId, revision) => `${workspaceId}:${String(revision)}`;
|
|
146
|
+
const sortedWorkspaces = (workspaces) => [...workspaces]
|
|
147
|
+
.sort((left, right) => left.workspace_id.localeCompare(right.workspace_id) ||
|
|
148
|
+
left.revision - right.revision)
|
|
149
|
+
.map((workspace) => structuredClone(workspace));
|