rea-agents 1.7.0 → 2.1.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.
Files changed (333) hide show
  1. package/README.md +112 -59
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/ArtifactExtraction.js +1 -1
  4. package/dist/application/ArtifactInventory/classify.js +42 -0
  5. package/dist/application/ArtifactInventory/hash.js +43 -0
  6. package/dist/application/ArtifactInventory/reader.js +41 -0
  7. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  8. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  9. package/dist/application/ArtifactInventory/types.js +10 -0
  10. package/dist/application/ArtifactInventory.js +9 -351
  11. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  12. package/dist/application/BinarySession.js +47 -270
  13. package/dist/application/BinarySessionExecution.js +28 -0
  14. package/dist/application/BinarySessionOpen.js +39 -0
  15. package/dist/application/BinarySessionRecords.js +149 -0
  16. package/dist/application/BinarySessionStatus.js +75 -0
  17. package/dist/application/CapabilityInventory.js +42 -2
  18. package/dist/application/ClientRegistrationStatus.js +1 -1
  19. package/dist/application/CrossVersionInventory.js +8 -2
  20. package/dist/application/CrossVersionInvestigation.js +11 -29
  21. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  22. package/dist/application/DirectAnalysis.js +47 -44
  23. package/dist/application/Doctor.js +165 -197
  24. package/dist/application/DoctorDiagnostics.js +180 -0
  25. package/dist/application/ElectronBoundaryAnalysis.js +112 -0
  26. package/dist/application/ElectronBoundaryGraph.js +9 -0
  27. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  28. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  29. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  30. package/dist/application/ElectronBoundaryGraphWindows.js +223 -0
  31. package/dist/application/EnhancedToolPagination.js +22 -0
  32. package/dist/application/EnhancedToolTypes.js +4 -0
  33. package/dist/application/EnhancedTools.js +58 -50
  34. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  35. package/dist/application/InvestigationProviders.js +30 -0
  36. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  37. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  38. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  39. package/dist/application/JavaScriptApplicationService.js +74 -0
  40. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  41. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  42. package/dist/application/JavaScriptArtifactAnalysis.js +52 -7
  43. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  44. package/dist/application/JavaScriptArtifactGraphBuilder.js +82 -17
  45. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  46. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  47. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  48. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  49. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  50. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  51. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  52. package/dist/application/JavaScriptArtifactReconstruction.js +4 -1
  53. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  54. package/dist/application/JavaScriptJsonModules.js +39 -0
  55. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  56. package/dist/application/JavaScriptReplayPermission.js +16 -0
  57. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  58. package/dist/application/JavaScriptReplayService.js +292 -0
  59. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  60. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  61. package/dist/application/LinuxHopper.js +10 -0
  62. package/dist/application/MacHopper.js +22 -11
  63. package/dist/application/ManagedApplicationGraphService.js +55 -0
  64. package/dist/application/ManagedMemberComparisonService.js +122 -0
  65. package/dist/application/ManagedNativeVerificationService.js +39 -0
  66. package/dist/application/ManagedReconstructionService.js +58 -0
  67. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  68. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  69. package/dist/application/PermissionAuthority.js +106 -63
  70. package/dist/application/ProcessCaptureCapability.js +1 -1
  71. package/dist/application/ProcessCapturePermission.js +13 -0
  72. package/dist/application/ProcessCli.js +2 -12
  73. package/dist/application/ProcessHarness.js +1 -1
  74. package/dist/application/ProcessSampling.js +15 -11
  75. package/dist/application/ProjectPermissionStore.js +49 -9
  76. package/dist/application/RealHopperAssertions.js +76 -0
  77. package/dist/application/ReconstructionCoverageService.js +69 -0
  78. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  79. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  80. package/dist/application/Setup.js +147 -259
  81. package/dist/application/SetupClientConfiguration.js +220 -0
  82. package/dist/application/SetupClients.js +24 -2
  83. package/dist/application/SetupPlan.js +123 -12
  84. package/dist/application/SetupSkill.js +26 -12
  85. package/dist/application/SupportedClients.js +1 -0
  86. package/dist/application/Uninstall.js +6 -3
  87. package/dist/application/WindowsCapabilities.js +86 -0
  88. package/dist/application/runtime.js +2 -0
  89. package/dist/artifacts/AsarArtifactReader.js +11 -0
  90. package/dist/browser/BrowserProcessStartup.js +88 -0
  91. package/dist/browser/CdpCaptureDocuments.js +12 -8
  92. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  93. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  94. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  95. package/dist/browser/CdpCaptureEventState.js +1 -0
  96. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  97. package/dist/browser/CdpCaptureEvents.js +46 -464
  98. package/dist/browser/CdpElectronInspection.js +106 -162
  99. package/dist/browser/CdpElectronProvider.js +5 -1
  100. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  101. package/dist/browser/CdpElectronScripts.js +94 -0
  102. package/dist/browser/CdpElectronWorkers.js +56 -0
  103. package/dist/browser/CdpObservationSession.js +51 -8
  104. package/dist/browser/CdpPageCapture.js +12 -129
  105. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  106. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  107. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  108. package/dist/browser/PngVisualDiff.js +9 -2
  109. package/dist/catalogIdentity.js +8 -1
  110. package/dist/cli/artifactCommands.js +82 -0
  111. package/dist/cli/coreAnalysisCommands.js +232 -0
  112. package/dist/cli/managedCommands.js +397 -0
  113. package/dist/cli/managedProjectGraphCommand.js +24 -0
  114. package/dist/cli/options.js +9 -0
  115. package/dist/cli/setupCommands.js +108 -0
  116. package/dist/cli/types.js +1 -0
  117. package/dist/cli/utilityCommands.js +122 -0
  118. package/dist/cli.js +13 -383
  119. package/dist/cliApplicationCommands.js +176 -0
  120. package/dist/cliBrowserAdvancedCommands.js +73 -16
  121. package/dist/cliBrowserCommands.js +39 -115
  122. package/dist/cliCommandNames.js +17 -0
  123. package/dist/cliElectronCommands.js +100 -27
  124. package/dist/cliEvidenceCommands.js +13 -2
  125. package/dist/cliInvestigationCommands.js +53 -10
  126. package/dist/cliJsonInput.js +54 -0
  127. package/dist/cliObservationOptions.js +137 -0
  128. package/dist/cliPolicyCommands.js +80 -46
  129. package/dist/cliSetup.js +289 -0
  130. package/dist/config/environment.js +107 -0
  131. package/dist/config/parseConfig.js +228 -0
  132. package/dist/config/parsers.js +68 -0
  133. package/dist/config/permissions.js +30 -0
  134. package/dist/config/types.js +1 -0
  135. package/dist/config.js +1 -292
  136. package/dist/contracts/applicationToolContracts.js +225 -0
  137. package/dist/contracts/artifactToolContracts.js +5 -9
  138. package/dist/contracts/browserToolContracts.js +14 -62
  139. package/dist/contracts/electronToolContracts.js +45 -19
  140. package/dist/contracts/errorSchemas.js +1 -0
  141. package/dist/contracts/investigationExamples.js +0 -6
  142. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  143. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  144. package/dist/contracts/managedToolContracts.js +153 -0
  145. package/dist/contracts/managedWorkflowExamples.js +346 -0
  146. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  147. package/dist/contracts/nativeToolContracts.js +2 -6
  148. package/dist/contracts/promptContracts.js +18 -2
  149. package/dist/contracts/providerSelection.js +2 -0
  150. package/dist/contracts/toolContractExamples.js +10 -25
  151. package/dist/contracts/toolContracts.js +49 -47
  152. package/dist/contracts/toolEffects.js +174 -0
  153. package/dist/contracts/toolOutputSchemaGroups.js +232 -0
  154. package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
  155. package/dist/contracts/toolOutputSchemas.js +2 -535
  156. package/dist/doctorRuntime.js +42 -1
  157. package/dist/domain/analysisErrorPresentation.js +234 -0
  158. package/dist/domain/analysisErrorProjection.js +284 -0
  159. package/dist/domain/artifactComparison.js +37 -19
  160. package/dist/domain/binaryTarget.js +87 -37
  161. package/dist/domain/browserObservation.js +1 -282
  162. package/dist/domain/browserObservationSchemas.js +286 -0
  163. package/dist/domain/bundleComparison.js +4 -4
  164. package/dist/domain/electronObservation.js +13 -0
  165. package/dist/domain/electronStaticAnalysis.js +9 -0
  166. package/dist/domain/electronStaticAnalysisBrowser.js +206 -0
  167. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  168. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  169. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  170. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  171. package/dist/domain/errors.js +32 -448
  172. package/dist/domain/functionComparison.js +4 -165
  173. package/dist/domain/functionComparisonDimensions.js +164 -0
  174. package/dist/domain/functionComparisonSchemas.js +3 -8
  175. package/dist/domain/inputIssueProjection.js +52 -0
  176. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  177. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  178. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  179. package/dist/domain/javascriptApplicationGraph.js +2 -1
  180. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  181. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  182. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  183. package/dist/domain/javascriptApplicationVersionItems.js +233 -0
  184. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  185. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  186. package/dist/domain/javascriptFeatureSeed.js +140 -0
  187. package/dist/domain/javascriptFeatureTrace.js +232 -0
  188. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  189. package/dist/domain/javascriptFeatureTraversal.js +100 -0
  190. package/dist/domain/javascriptNativeHandoff.js +85 -0
  191. package/dist/domain/javascriptReplay.js +361 -0
  192. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  193. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  194. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  195. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  196. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  197. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  198. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  199. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  200. package/dist/domain/javascriptRuntimeStaticCandidates.js +193 -0
  201. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  202. package/dist/domain/javascriptSemanticIr.js +30 -0
  203. package/dist/domain/javascriptSemanticProjection.js +366 -0
  204. package/dist/domain/javascriptSemanticState.js +40 -0
  205. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  206. package/dist/domain/javascriptSemanticValues.js +352 -0
  207. package/dist/domain/javascriptStaticAnalysis.js +26 -254
  208. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  209. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  210. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  211. package/dist/domain/javascriptStaticAnalysisHelpers.js +81 -2
  212. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  213. package/dist/domain/knownPageCoverage.js +21 -0
  214. package/dist/domain/managedApplicationGraph.js +206 -0
  215. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  216. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  217. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  218. package/dist/domain/managedArtifact.js +452 -0
  219. package/dist/domain/managedMemberComparison.js +211 -0
  220. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  221. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  222. package/dist/domain/managedNativeVerification.js +46 -0
  223. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  224. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  225. package/dist/domain/managedReconstruction.js +196 -0
  226. package/dist/domain/managedRuntimeCorrelation.js +184 -0
  227. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  228. package/dist/domain/permissionPolicy.js +2 -0
  229. package/dist/domain/reconstructionCoverage.js +387 -0
  230. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  231. package/dist/domain/reconstructionVerificationSchemas.js +9 -3
  232. package/dist/domain/runtimeCharacterization.js +85 -0
  233. package/dist/domain/webBundleAnalyzer.js +3 -409
  234. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  235. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  236. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  237. package/dist/dotnet/ManagedArtifactInspector.js +339 -0
  238. package/dist/dotnet/ManagedMemberInspector.js +153 -0
  239. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  240. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  241. package/dist/dotnet/ManagedMemberRows.js +120 -0
  242. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  243. package/dist/dotnet/ManagedMetadataInventory.js +104 -0
  244. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  245. package/dist/dotnet/ManagedMetadataLayout.js +259 -0
  246. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  247. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  248. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  249. package/dist/dotnet/ManagedNativeBoundaryInspector.js +143 -0
  250. package/dist/dotnet/ManagedPeReader.js +188 -0
  251. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  252. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  253. package/dist/generatedPackageMetadata.js +2 -2
  254. package/dist/ghidra/GhidraClient.js +76 -91
  255. package/dist/ghidra/GhidraClientStartup.js +29 -0
  256. package/dist/ghidra/GhidraClientWire.js +34 -0
  257. package/dist/ghidra/GhidraDefaults.js +1 -1
  258. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  259. package/dist/ghidra/GhidraInstallation.js +20 -15
  260. package/dist/ghidra/GhidraLauncher.js +93 -29
  261. package/dist/ghidra/GhidraProvider.js +67 -161
  262. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  263. package/dist/ghidra/GhidraSessionValues.js +2 -0
  264. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  265. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  266. package/dist/ghidra/GhidraTransport.js +71 -0
  267. package/dist/identity.js +3 -2
  268. package/dist/main/messages.js +5 -0
  269. package/dist/main/reload.js +49 -0
  270. package/dist/main/shutdown.js +25 -0
  271. package/dist/main/startup.js +14 -0
  272. package/dist/main/state.js +26 -0
  273. package/dist/main/transport.js +61 -0
  274. package/dist/main/types.js +1 -0
  275. package/dist/main.js +35 -132
  276. package/dist/process/PrivateRuntimeRoot.js +3 -2
  277. package/dist/process/ProcessOwnership.js +35 -0
  278. package/dist/process/ProviderProcess.js +2 -0
  279. package/dist/replay/JavaScriptReplayWorker.js +300 -0
  280. package/dist/replay/LinuxJavaScriptReplayRunner.js +217 -0
  281. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  282. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  283. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  284. package/dist/replay/ReplayOutcome.js +95 -0
  285. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  286. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  287. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  288. package/dist/server/ProcessCaptureElicitation.js +157 -0
  289. package/dist/server/createServer.js +158 -41
  290. package/dist/server/registerApplicationTools/characterization.js +57 -0
  291. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  292. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  293. package/dist/server/registerApplicationTools/coverage.js +84 -0
  294. package/dist/server/registerApplicationTools/helpers.js +42 -0
  295. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  296. package/dist/server/registerApplicationTools/types.js +1 -0
  297. package/dist/server/registerApplicationTools.js +13 -0
  298. package/dist/server/registerArtifactComparisonTool.js +16 -9
  299. package/dist/server/registerBrowserTools.js +61 -60
  300. package/dist/server/registerBundleComparisonTool.js +17 -20
  301. package/dist/server/registerElectronTools.js +39 -12
  302. package/dist/server/registerEnhancedTools.js +52 -15
  303. package/dist/server/registerEvidenceResources.js +54 -0
  304. package/dist/server/registerEvidenceTools.js +5 -1
  305. package/dist/server/registerFunctionComparisonTool.js +14 -7
  306. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  307. package/dist/server/registerInvestigationTools/types.js +1 -0
  308. package/dist/server/registerInvestigationTools.js +103 -132
  309. package/dist/server/registerManagedTools.js +6 -0
  310. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  311. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  312. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  313. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  314. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  315. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  316. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  317. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  318. package/dist/server/registerManagedWorkflowTools.js +13 -0
  319. package/dist/server/registerOfficialTools.js +81 -67
  320. package/dist/server/registerProcessComparisonTool.js +25 -47
  321. package/dist/server/registerSessionRecordTools.js +137 -0
  322. package/dist/server/registerSessionStatusTool.js +9 -8
  323. package/dist/server/registerSessionTools.js +77 -216
  324. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  325. package/dist/server/sessionEvidence.js +14 -19
  326. package/dist/server/toolInputValidation.js +77 -0
  327. package/dist/server/toolRegistrationOptions.js +177 -2
  328. package/dist/server/toolResult.js +30 -17
  329. package/package.json +21 -14
  330. package/scripts/rea.mjs +1 -1
  331. package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +75 -6
  332. package/scripts/prepare-node-pty.mjs +0 -35
  333. package/scripts/rebuild-native.mjs +0 -22
@@ -0,0 +1,231 @@
1
+ import { compareCodePoints, createJavaScriptApplicationEdge, createJavaScriptApplicationGraph, createJavaScriptApplicationNode, } from "./javascriptApplicationGraph.js";
2
+ /** Merge compared nodes and add inferred right-to-left changed_from edges. */
3
+ export const buildJavaScriptApplicationChangeGraph = (input) => {
4
+ const allNodes = nodeCandidates(input);
5
+ const preferredRoots = uniqueSorted([
6
+ ...input.right.root_node_ids,
7
+ ...input.left.root_node_ids,
8
+ ]).filter((nodeId) => allNodes.has(nodeId));
9
+ const orderedNodeIds = uniqueSorted([
10
+ ...preferredRoots,
11
+ ...input.items.flatMap(({ left_node_id: left, right_node_id: right }) => [
12
+ ...(right === null ? [] : [right]),
13
+ ...(left === null ? [] : [left]),
14
+ ]),
15
+ ]);
16
+ const retainedIds = orderedNodeIds.slice(0, input.limits.max_graph_nodes);
17
+ const retained = new Set(retainedIds);
18
+ const merged = mergeNodes(retainedIds.flatMap((nodeId) => allNodes.get(nodeId) ?? []));
19
+ const sourceEdges = uniqueEdges([
20
+ ...input.left.edges,
21
+ ...input.right.edges,
22
+ ]).filter(({ source_node_id: source, target_node_id: target }) => retained.has(source) && retained.has(target));
23
+ const comparisonEdges = input.items.flatMap((item) => changedFromEdge(item, input, retained));
24
+ const candidateEdges = uniqueEdges([...sourceEdges, ...comparisonEdges]);
25
+ const edges = candidateEdges.slice(0, input.limits.max_graph_edges);
26
+ const omittedNodes = Math.max(0, orderedNodeIds.length - retainedIds.length);
27
+ const omittedEdges = Math.max(0, candidateEdges.length - edges.length);
28
+ const graphOmissions = omittedNodes + omittedEdges + merged.omittedObservations;
29
+ const rootNodeIds = preferredRoots
30
+ .filter((nodeId) => retained.has(nodeId))
31
+ .slice(0, 1_000);
32
+ const fallbackRoot = merged.nodes[0]?.node_id;
33
+ const graph = createJavaScriptApplicationGraph({
34
+ schema: "JavaScriptApplicationGraph",
35
+ schema_version: 1,
36
+ root_node_ids: rootNodeIds.length > 0
37
+ ? rootNodeIds
38
+ : fallbackRoot === undefined
39
+ ? []
40
+ : [fallbackRoot],
41
+ nodes: merged.nodes,
42
+ edges,
43
+ coverage: changeGraphCoverage(input, graphOmissions),
44
+ limitations: uniqueSorted([
45
+ ...input.left.limitations.map((value) => `Left: ${value}`),
46
+ ...input.right.limitations.map((value) => `Right: ${value}`),
47
+ "changed_from edges are cross-version inferences and never promote structural or semantic matches to exact identity.",
48
+ "The change graph contains compared entities and their retained relationships; it is not an executable application.",
49
+ ...(graphOmissions === 0
50
+ ? []
51
+ : ["The change graph omitted content at explicit caller bounds."]),
52
+ ]),
53
+ });
54
+ return {
55
+ graph,
56
+ omittedNodes,
57
+ omittedEdges,
58
+ omittedObservations: merged.omittedObservations,
59
+ };
60
+ };
61
+ const nodeCandidates = (input) => {
62
+ const required = new Set([
63
+ ...input.left.root_node_ids,
64
+ ...input.right.root_node_ids,
65
+ ...input.items.flatMap(({ left_node_id: left, right_node_id: right }) => [
66
+ ...(left === null ? [] : [left]),
67
+ ...(right === null ? [] : [right]),
68
+ ]),
69
+ ]);
70
+ const output = new Map();
71
+ for (const node of [...input.left.nodes, ...input.right.nodes])
72
+ if (required.has(node.node_id))
73
+ output.set(node.node_id, [...(output.get(node.node_id) ?? []), node]);
74
+ return output;
75
+ };
76
+ const changedFromEdge = (item, input, retained) => {
77
+ const left = item.left_node_id;
78
+ const right = item.right_node_id;
79
+ if (item.match.status !== "matched" ||
80
+ item.status === "unchanged" ||
81
+ left === null ||
82
+ right === null ||
83
+ left === right ||
84
+ !retained.has(left) ||
85
+ !retained.has(right))
86
+ return [];
87
+ const evidence = comparisonEvidence(item, input);
88
+ return [
89
+ createJavaScriptApplicationEdge({
90
+ source_node_id: right,
91
+ target_node_id: left,
92
+ relation: "changed_from",
93
+ properties: {
94
+ comparison_item_id: item.item_id,
95
+ status: item.status,
96
+ match_basis: item.match.basis,
97
+ match_confidence: item.match.confidence,
98
+ dimensions: item.dimensions,
99
+ },
100
+ evidence,
101
+ }),
102
+ ];
103
+ };
104
+ const comparisonEvidence = (item, input) => {
105
+ const right = input.right.nodes.find(({ node_id: id }) => id === item.right_node_id);
106
+ const left = input.left.nodes.find(({ node_id: id }) => id === item.left_node_id);
107
+ const source = right?.observations[0]?.evidence ?? left?.observations[0]?.evidence;
108
+ const complete = input.left.coverage.status === "complete" &&
109
+ input.right.coverage.status === "complete" &&
110
+ input.omittedComparisonItems === 0;
111
+ return {
112
+ authority: "cross-version-comparison",
113
+ state: "inferred",
114
+ confidence: item.match.confidence === "medium" ? "medium" : "high",
115
+ artifact: source?.artifact ?? {
116
+ available: false,
117
+ reason: "unresolved",
118
+ detail: "Compared node has no artifact-backed observation.",
119
+ },
120
+ location: source?.location ?? {
121
+ available: false,
122
+ reason: "unresolved",
123
+ detail: "Compared node has no actionable source location.",
124
+ },
125
+ extractor: {
126
+ name: "rea-application-version-comparison",
127
+ version: "1",
128
+ operation: "compare_application_versions",
129
+ executable_sha256: null,
130
+ },
131
+ coverage: complete
132
+ ? { status: "complete", truncated: false, omitted_count: 0, limits: [] }
133
+ : {
134
+ status: "partial",
135
+ truncated: input.omittedComparisonItems > 0,
136
+ omitted_count: input.omittedComparisonItems > 0
137
+ ? input.omittedComparisonItems
138
+ : (source?.coverage.omitted_count ?? null),
139
+ limits: input.omittedComparisonItems > 0
140
+ ? [
141
+ {
142
+ name: "max-comparison-items",
143
+ value: input.limits.max_comparison_items,
144
+ unit: "items",
145
+ },
146
+ ]
147
+ : [],
148
+ },
149
+ limitations: [
150
+ "Cross-version pairing is inferred from the stated match basis; changed_from does not prove runtime reachability.",
151
+ ...item.limitations,
152
+ ],
153
+ evidence_ids: [input.leftEvidenceId, input.rightEvidenceId],
154
+ };
155
+ };
156
+ const changeGraphCoverage = (input, graphOmissions) => {
157
+ const outputOmissions = graphOmissions + input.omittedComparisonItems;
158
+ if (outputOmissions > 0)
159
+ return {
160
+ status: "partial",
161
+ truncated: true,
162
+ omitted_count: outputOmissions,
163
+ limits: [
164
+ {
165
+ name: "max-comparison-items",
166
+ value: input.limits.max_comparison_items,
167
+ unit: "items",
168
+ },
169
+ {
170
+ name: "max-graph-nodes",
171
+ value: input.limits.max_graph_nodes,
172
+ unit: "items",
173
+ },
174
+ {
175
+ name: "max-graph-edges",
176
+ value: input.limits.max_graph_edges,
177
+ unit: "items",
178
+ },
179
+ ],
180
+ };
181
+ if (input.left.coverage.status === "complete" &&
182
+ input.right.coverage.status === "complete")
183
+ return {
184
+ status: "complete",
185
+ truncated: false,
186
+ omitted_count: 0,
187
+ limits: [],
188
+ };
189
+ const counts = [
190
+ input.left.coverage.omitted_count,
191
+ input.right.coverage.omitted_count,
192
+ ];
193
+ return {
194
+ status: "partial",
195
+ truncated: false,
196
+ omitted_count: counts.every((value) => value !== null)
197
+ ? counts.reduce((total, value) => total + (value ?? 0), 0)
198
+ : null,
199
+ limits: [],
200
+ };
201
+ };
202
+ const mergeNodes = (nodes) => {
203
+ const groups = new Map();
204
+ for (const node of nodes)
205
+ groups.set(node.node_id, [...(groups.get(node.node_id) ?? []), node]);
206
+ let omittedObservations = 0;
207
+ const merged = [...groups.values()].map((group) => {
208
+ const first = group[0];
209
+ if (first === undefined)
210
+ throw new TypeError("Empty change-graph node group");
211
+ const observations = [
212
+ ...new Map(group
213
+ .flatMap(({ observations: values }) => values)
214
+ .map((observation) => [observation.observation_id, observation])).values(),
215
+ ].sort((left, right) => compareCodePoints(left.observation_id, right.observation_id));
216
+ omittedObservations += Math.max(0, observations.length - 64);
217
+ return createJavaScriptApplicationNode({
218
+ kind: first.kind,
219
+ identity: first.identity,
220
+ observations: observations
221
+ .slice(0, 64)
222
+ .map(({ observation_id: _id, identifier_strategy: _strategy, ...value }) => value),
223
+ });
224
+ });
225
+ return {
226
+ nodes: merged.sort((left, right) => compareCodePoints(left.node_id, right.node_id)),
227
+ omittedObservations,
228
+ };
229
+ };
230
+ const uniqueEdges = (edges) => [...new Map(edges.map((edge) => [edge.edge_id, edge])).values()].sort((left, right) => compareCodePoints(left.edge_id, right.edge_id));
231
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);
@@ -19,8 +19,11 @@ const applicationEvidenceAuthoritySchema = z.enum([
19
19
  "ast-static-analysis",
20
20
  "static-relationship-inference",
21
21
  "passive-cdp-runtime",
22
+ "cross-layer-reconciliation",
23
+ "cross-version-comparison",
22
24
  "controlled-replay",
23
25
  "native-analysis-provider",
26
+ "managed-static-analysis",
24
27
  "historical-reference",
25
28
  "user-assertion",
26
29
  "unknown",
@@ -223,6 +226,20 @@ const checkAuthorityState = (evidence, context) => {
223
226
  path: ["state"],
224
227
  message: "Static relationship authority must remain inferred",
225
228
  });
229
+ if (evidence.authority === "cross-layer-reconciliation" &&
230
+ evidence.state !== "inferred")
231
+ context.addIssue({
232
+ code: "custom",
233
+ path: ["state"],
234
+ message: "Cross-layer reconciliation authority must remain inferred",
235
+ });
236
+ if (evidence.authority === "cross-version-comparison" &&
237
+ evidence.state !== "inferred")
238
+ context.addIssue({
239
+ code: "custom",
240
+ path: ["state"],
241
+ message: "Cross-version comparison authority must remain inferred",
242
+ });
226
243
  if (evidence.authority === "unknown" &&
227
244
  !["unknown", "unavailable"].includes(evidence.state))
228
245
  context.addIssue({
@@ -285,6 +302,7 @@ const checkArtifactBacking = (evidence, context) => {
285
302
  "ast-static-analysis",
286
303
  "controlled-replay",
287
304
  "native-analysis-provider",
305
+ "managed-static-analysis",
288
306
  ].includes(evidence.authority);
289
307
  if (artifactBacked &&
290
308
  evidence.state !== "unavailable" &&
@@ -2,7 +2,8 @@ import { createHash } from "node:crypto";
2
2
  import canonicalize from "canonicalize";
3
3
  import { z } from "zod";
4
4
  import { applicationEdgeInputSchema, applicationEdgeSchema, applicationNodeInputSchema, applicationNodeObservationSchema, applicationNodeSchema, javascriptApplicationGraphInputSchema, javascriptApplicationGraphRecordSchema, } from "./javascriptApplicationGraphSchemas.js";
5
- const compareCodePoints = (left, right) => left < right ? -1 : left > right ? 1 : 0;
5
+ /** Compare strings by Unicode code point for canonical graph ordering. */
6
+ export const compareCodePoints = (left, right) => left < right ? -1 : left > right ? 1 : 0;
6
7
  const canonicalJson = (value) => {
7
8
  const encoded = canonicalize(value);
8
9
  if (encoded === undefined)
@@ -30,6 +30,13 @@ export const JAVASCRIPT_APPLICATION_NODE_KINDS = [
30
30
  "storage",
31
31
  "native-addon",
32
32
  "native-export",
33
+ "managed-assembly",
34
+ "managed-module",
35
+ "managed-type",
36
+ "managed-method",
37
+ "managed-field",
38
+ "managed-pinvoke-import",
39
+ "managed-native-implementation",
33
40
  "runtime-script-instance",
34
41
  "unknown",
35
42
  ];
@@ -0,0 +1,116 @@
1
+ import { createHash } from "node:crypto";
2
+ import canonicalize from "canonicalize";
3
+ import { buildJavaScriptApplicationChangeGraph } from "./javascriptApplicationChangeGraph.js";
4
+ import { applicationVersionComparisonResultSchema, } from "./javascriptApplicationVersionComparisonSchemas.js";
5
+ import { compareCodePoints } from "./javascriptApplicationGraph.js";
6
+ import { classifyJavaScriptApplicationVersions } from "./javascriptApplicationVersionItems.js";
7
+ import { matchJavaScriptApplicationVersions } from "./javascriptApplicationVersionKeys.js";
8
+ /** Compare application entities with ordered unique-only identity tiers. */
9
+ export const compareJavaScriptApplicationVersions = (input) => {
10
+ const matching = matchJavaScriptApplicationVersions(input.left.graph.nodes, input.right.graph.nodes);
11
+ const projection = classifyJavaScriptApplicationVersions(matching, {
12
+ leftGraph: input.left.graph,
13
+ rightGraph: input.right.graph,
14
+ leftEvidenceId: input.left.evidenceId,
15
+ rightEvidenceId: input.right.evidenceId,
16
+ leftNativeEvidence: input.leftNativeEvidence,
17
+ rightNativeEvidence: input.rightNativeEvidence,
18
+ maxCandidates: input.limits.max_candidate_nodes,
19
+ });
20
+ const items = projection.items.slice(0, input.limits.max_comparison_items);
21
+ const omittedComparisonItems = projection.items.length - items.length;
22
+ const changeGraph = buildJavaScriptApplicationChangeGraph({
23
+ left: input.left.graph,
24
+ right: input.right.graph,
25
+ leftEvidenceId: input.left.evidenceId,
26
+ rightEvidenceId: input.right.evidenceId,
27
+ items,
28
+ omittedComparisonItems,
29
+ limits: input.limits,
30
+ });
31
+ const evidenceLinks = uniqueSorted(projection.items.flatMap(({ evidence_links: links }) => links));
32
+ const omissions = {
33
+ omitted_comparison_items: omittedComparisonItems,
34
+ omitted_candidate_references: projection.omittedCandidateReferences,
35
+ omitted_graph_nodes: changeGraph.omittedNodes,
36
+ omitted_graph_edges: changeGraph.omittedEdges,
37
+ omitted_graph_observations: changeGraph.omittedObservations,
38
+ };
39
+ const semantic = {
40
+ schema_version: 1,
41
+ left: {
42
+ evidence_id: input.left.evidenceId,
43
+ graph_id: input.left.graph.graph_id,
44
+ root_artifact_sha256: input.left.rootArtifactSha256,
45
+ },
46
+ right: {
47
+ evidence_id: input.right.evidenceId,
48
+ graph_id: input.right.graph.graph_id,
49
+ root_artifact_sha256: input.right.rootArtifactSha256,
50
+ },
51
+ summary: summary(projection.items),
52
+ matching: matchingSummary(projection.items),
53
+ items,
54
+ graph: changeGraph.graph,
55
+ coverage: {
56
+ status: comparisonCoverageStatus(input, omissions),
57
+ left_graph_status: input.left.graph.coverage.status,
58
+ right_graph_status: input.right.graph.coverage.status,
59
+ ...omissions,
60
+ },
61
+ evidence_links: evidenceLinks,
62
+ limitations: comparisonLimitations(input, omissions),
63
+ };
64
+ return applicationVersionComparisonResultSchema.parse({
65
+ ...semantic,
66
+ comparison_id: `javc_${digestCanonical(semantic)}`,
67
+ });
68
+ };
69
+ const summary = (items) => ({
70
+ unchanged: countStatus(items, "unchanged"),
71
+ added: countStatus(items, "added"),
72
+ removed: countStatus(items, "removed"),
73
+ changed: countStatus(items, "changed"),
74
+ unknown: countStatus(items, "unknown"),
75
+ });
76
+ const countStatus = (items, status) => items.filter((item) => item.status === status).length;
77
+ const matchingSummary = (items) => ({
78
+ exact_node_identity: countBasis(items, "exact-node-identity"),
79
+ exact_content_digest: countBasis(items, "exact-content-digest"),
80
+ exact_module_source_digest: countBasis(items, "exact-module-source-digest"),
81
+ source_map_identity: countBasis(items, "source-map-identity"),
82
+ structural_fingerprint: countBasis(items, "structural-fingerprint"),
83
+ semantic_key: countBasis(items, "semantic-key"),
84
+ ambiguous: items.filter(({ match }) => match.status === "ambiguous").length,
85
+ unmatched: items.filter(({ match }) => match.status === "unmatched").length,
86
+ });
87
+ const countBasis = (items, basis) => items.filter(({ match }) => match.basis === basis).length;
88
+ const comparisonCoverageStatus = (input, omissions) => Object.values(omissions).some((value) => value > 0)
89
+ ? "truncated"
90
+ : input.left.graph.coverage.status === "complete" &&
91
+ input.right.graph.coverage.status === "complete"
92
+ ? "complete-within-inputs"
93
+ : "partial";
94
+ const comparisonLimitations = (input, omissions) => uniqueSorted([
95
+ "Application comparison never uses bundler module ordinals as persistent identity and performs no fuzzy pairing.",
96
+ "Exact digest equality proves byte identity only; source-map, structural-fingerprint, and semantic-key matches retain inferred confidence.",
97
+ "Minified names and chunk locations are not assumed stable across versions.",
98
+ "The comparison reads retained graphs and Evidence only; it does not execute either application.",
99
+ "Native Evidence is linked only by exact subject digest; provider snapshot reuse remains target/provider/profile exact.",
100
+ ...(input.left.graph.coverage.status === "complete" &&
101
+ input.right.graph.coverage.status === "complete"
102
+ ? []
103
+ : [
104
+ "At least one source graph is incomplete; unmatched entities on the opposite side remain unknown rather than added or removed.",
105
+ ]),
106
+ ...(Object.values(omissions).some((value) => value > 0)
107
+ ? ["Comparison output was truncated at explicit caller limits."]
108
+ : []),
109
+ ]);
110
+ const digestCanonical = (value) => {
111
+ const encoded = canonicalize(value);
112
+ if (encoded === undefined)
113
+ throw new TypeError("Application version comparison could not canonicalize data");
114
+ return createHash("sha256").update(encoded).digest("hex");
115
+ };
116
+ const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);
@@ -0,0 +1,139 @@
1
+ import { z } from "zod";
2
+ import { evidenceSchema } from "./evidence.js";
3
+ import { javascriptApplicationGraphSchema } from "./javascriptApplicationGraph.js";
4
+ import { JAVASCRIPT_APPLICATION_NODE_KINDS } from "./javascriptApplicationGraphSchemas.js";
5
+ const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
6
+ const nodeIdSchema = z.string().regex(/^jag_node_[a-f0-9]{64}$/u);
7
+ const boundedTextSchema = z.string().min(1).max(4_096);
8
+ const comparisonLimitsSchema = z.strictObject({
9
+ max_comparison_items: z.number().int().min(1).max(50_000).default(20_000),
10
+ max_candidate_nodes: z.number().int().min(1).max(1_000).default(100),
11
+ max_graph_nodes: z.number().int().min(1).max(100_000).default(20_000),
12
+ max_graph_edges: z.number().int().min(1).max(200_000).default(40_000),
13
+ });
14
+ /** Two authenticated application versions and deterministic output bounds. */
15
+ export const compareApplicationVersionsInputSchema = z
16
+ .strictObject({
17
+ left: evidenceSchema,
18
+ right: evidenceSchema,
19
+ left_native_observations: z.array(evidenceSchema).max(64).default([]),
20
+ right_native_observations: z.array(evidenceSchema).max(64).default([]),
21
+ limits: comparisonLimitsSchema.default({
22
+ max_comparison_items: 20_000,
23
+ max_candidate_nodes: 100,
24
+ max_graph_nodes: 20_000,
25
+ max_graph_edges: 40_000,
26
+ }),
27
+ unknown_registry_approved: z.literal(true).optional(),
28
+ })
29
+ .superRefine((input, context) => {
30
+ if (input.left.evidence_id === input.right.evidence_id)
31
+ context.addIssue({
32
+ code: "custom",
33
+ path: ["right"],
34
+ message: "Application version Evidence must be distinct",
35
+ });
36
+ for (const side of [
37
+ "left_native_observations",
38
+ "right_native_observations",
39
+ ]) {
40
+ const ids = input[side].map(({ evidence_id: id }) => id);
41
+ if (new Set(ids).size !== ids.length)
42
+ context.addIssue({
43
+ code: "custom",
44
+ path: [side],
45
+ message: "Native observations must be unique on each side",
46
+ });
47
+ }
48
+ });
49
+ const applicationVersionMatchBasisSchema = z.enum([
50
+ "exact-node-identity",
51
+ "exact-content-digest",
52
+ "exact-module-source-digest",
53
+ "source-map-identity",
54
+ "structural-fingerprint",
55
+ "semantic-key",
56
+ "none",
57
+ ]);
58
+ const comparisonItemSchema = z.strictObject({
59
+ item_id: z.string().regex(/^javc_item_[a-f0-9]{64}$/u),
60
+ status: z.enum(["unchanged", "added", "removed", "changed", "unknown"]),
61
+ node_kind: z.enum(JAVASCRIPT_APPLICATION_NODE_KINDS),
62
+ left_node_id: nodeIdSchema.nullable(),
63
+ right_node_id: nodeIdSchema.nullable(),
64
+ match: z.strictObject({
65
+ status: z.enum(["matched", "unmatched", "ambiguous"]),
66
+ basis: applicationVersionMatchBasisSchema,
67
+ confidence: z.enum(["exact", "high", "medium", "unknown"]),
68
+ candidate_left_node_ids: z.array(nodeIdSchema).max(1_000),
69
+ candidate_right_node_ids: z.array(nodeIdSchema).max(1_000),
70
+ }),
71
+ dimensions: z
72
+ .array(z.enum([
73
+ "content",
74
+ "location",
75
+ "properties",
76
+ "relationships",
77
+ "availability",
78
+ "coverage",
79
+ ]))
80
+ .max(6),
81
+ evidence_links: z.array(evidenceIdSchema).min(2).max(130),
82
+ limitations: z.array(boundedTextSchema).max(100),
83
+ });
84
+ /** Tiered module/entity matching plus a bounded cross-version change graph. */
85
+ export const applicationVersionComparisonResultSchema = z.strictObject({
86
+ schema_version: z.literal(1),
87
+ comparison_id: z.string().regex(/^javc_[a-f0-9]{64}$/u),
88
+ left: z.strictObject({
89
+ evidence_id: evidenceIdSchema,
90
+ graph_id: z.string().regex(/^jag_[a-f0-9]{64}$/u),
91
+ root_artifact_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
92
+ }),
93
+ right: z.strictObject({
94
+ evidence_id: evidenceIdSchema,
95
+ graph_id: z.string().regex(/^jag_[a-f0-9]{64}$/u),
96
+ root_artifact_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
97
+ }),
98
+ summary: z.strictObject({
99
+ unchanged: z.number().int().min(0),
100
+ added: z.number().int().min(0),
101
+ removed: z.number().int().min(0),
102
+ changed: z.number().int().min(0),
103
+ unknown: z.number().int().min(0),
104
+ }),
105
+ matching: z.strictObject({
106
+ exact_node_identity: z.number().int().min(0),
107
+ exact_content_digest: z.number().int().min(0),
108
+ exact_module_source_digest: z.number().int().min(0),
109
+ source_map_identity: z.number().int().min(0),
110
+ structural_fingerprint: z.number().int().min(0),
111
+ semantic_key: z.number().int().min(0),
112
+ ambiguous: z.number().int().min(0),
113
+ unmatched: z.number().int().min(0),
114
+ }),
115
+ items: z.array(comparisonItemSchema).max(50_000),
116
+ graph: javascriptApplicationGraphSchema,
117
+ coverage: z.strictObject({
118
+ status: z.enum(["complete-within-inputs", "partial", "truncated"]),
119
+ left_graph_status: z.enum([
120
+ "complete",
121
+ "partial",
122
+ "unknown",
123
+ "unavailable",
124
+ ]),
125
+ right_graph_status: z.enum([
126
+ "complete",
127
+ "partial",
128
+ "unknown",
129
+ "unavailable",
130
+ ]),
131
+ omitted_comparison_items: z.number().int().min(0),
132
+ omitted_candidate_references: z.number().int().min(0),
133
+ omitted_graph_nodes: z.number().int().min(0),
134
+ omitted_graph_edges: z.number().int().min(0),
135
+ omitted_graph_observations: z.number().int().min(0),
136
+ }),
137
+ evidence_links: z.array(evidenceIdSchema).min(2).max(130),
138
+ limitations: z.array(boundedTextSchema).max(1_000),
139
+ });