rea-agents 6.2.0 → 6.3.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 (297) hide show
  1. package/README.md +18 -20
  2. package/bridge/hopper_bridge.py +2 -0
  3. package/dist/android/JadxProvider.js +8 -2
  4. package/dist/android/JadxSession.js +51 -9
  5. package/dist/application/BinaryTargetResolver.js +63 -17
  6. package/dist/application/BrowserScenarioEvidence.js +2 -2
  7. package/dist/application/ClientConfigurationDocument.js +28 -0
  8. package/dist/application/ClientRegistrationStatus.js +19 -6
  9. package/dist/application/DirectAnalysis.js +12 -6
  10. package/dist/application/DirectAnalysisCleanup.js +0 -1
  11. package/dist/application/DirectAnalysisStatus.js +2 -5
  12. package/dist/application/Doctor.js +25 -34
  13. package/dist/application/DoctorDiagnostics.js +1 -1
  14. package/dist/application/EvidenceBundleFiles.js +1 -1
  15. package/dist/application/InvestigationProviders.js +4 -4
  16. package/dist/application/JsonFiles.js +15 -15
  17. package/dist/application/LinuxHopper.js +2 -1
  18. package/dist/application/ReconstructionObligationCandidates.js +9 -2
  19. package/dist/application/ReconstructionObligationLedgerProjection.js +3 -1
  20. package/dist/application/RegularFileRead.js +17 -0
  21. package/dist/application/Setup.js +18 -7
  22. package/dist/application/SetupClientConfiguration.js +18 -7
  23. package/dist/application/SetupHost.js +6 -4
  24. package/dist/application/SetupPlan.js +19 -15
  25. package/dist/application/SetupSkill.js +57 -8
  26. package/dist/application/SupportedClients.js +43 -0
  27. package/dist/application/Uninstall.js +18 -2
  28. package/dist/application/UpdateMaintenance.js +6 -2
  29. package/dist/application/Utf8JsonInput.js +64 -0
  30. package/dist/application/WebScriptExportService.js +13 -6
  31. package/dist/application/android/AndroidAnalysisService.js +1 -1
  32. package/dist/application/binary/AnalysisSnapshotCache.js +5 -4
  33. package/dist/application/binary/BinarySession.js +16 -0
  34. package/dist/application/binary/BinarySessionOpen.js +9 -1
  35. package/dist/application/javascript/ElectronActiveEvidence.js +2 -2
  36. package/dist/application/javascript/ElectronBoundaryAnalysis.js +2 -2
  37. package/dist/application/javascript/ElectronBoundaryGraphNative.js +5 -1
  38. package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -0
  39. package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +107 -46
  40. package/dist/application/javascript/JavaScriptApplicationService.js +1 -0
  41. package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +59 -45
  42. package/dist/application/javascript/JavaScriptArtifactAnalysis.js +0 -6
  43. package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +8 -18
  44. package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +34 -26
  45. package/dist/application/javascript/JavaScriptArtifactPathResolution.js +44 -12
  46. package/dist/application/javascript/JavaScriptArtifactReconstruction.js +6 -3
  47. package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +1 -0
  48. package/dist/application/javascript/JavaScriptJsonModules.js +2 -2
  49. package/dist/application/javascript/JavaScriptModuleRelationships.js +5 -17
  50. package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +11 -27
  51. package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -2
  52. package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +8 -6
  53. package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -1
  54. package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +7 -5
  55. package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +1 -1
  56. package/dist/application/javascript/JavaScriptSemanticGraphEvidence.js +1 -1
  57. package/dist/application/javascript/JavaScriptSemanticGraphFingerprintProjection.js +2 -2
  58. package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +2 -2
  59. package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +1 -1
  60. package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +4 -4
  61. package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +1 -1
  62. package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +10 -7
  63. package/dist/application/javascript/JavaScriptSemanticTraceService.js +15 -10
  64. package/dist/application/native/NativeCallRoutes.js +2 -4
  65. package/dist/artifacts/ArtifactProvider.js +14 -16
  66. package/dist/artifacts/ArtifactProviderMetadata.js +1 -4
  67. package/dist/artifacts/AsarArtifactReader.js +81 -17
  68. package/dist/artifacts/DirectoryArtifactReader.js +2 -2
  69. package/dist/artifacts/NativeDmgArtifactReader.js +152 -67
  70. package/dist/artifacts/NativeDmgOwnership.js +109 -0
  71. package/dist/artifacts/apple/KeyedArchiveReader.js +54 -46
  72. package/dist/artifacts/apple/MachoLoadCommandReader.js +36 -6
  73. package/dist/artifacts/extraction/ArtifactExtraction.js +29 -11
  74. package/dist/artifacts/inventory/ArtifactGraphConstruction.js +7 -8
  75. package/dist/artifacts/inventory/classify.js +33 -14
  76. package/dist/artifacts/inventory/hashStableRootArtifact.js +37 -0
  77. package/dist/artifacts/inventory/scanCanonical.js +28 -22
  78. package/dist/artifacts/inventory/scanReader.js +7 -11
  79. package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +65 -27
  80. package/dist/browser/CdpBrowserProvider.js +4 -3
  81. package/dist/browser/CdpCaptureStorageFingerprints.js +3 -3
  82. package/dist/browser/CdpElectronInspection.js +2 -2
  83. package/dist/browser/CdpElectronProvider.js +4 -3
  84. package/dist/browser/CdpElectronScripts.js +2 -2
  85. package/dist/browser/CdpWebMcpDiscovery.js +16 -13
  86. package/dist/browser/PlaywrightBrowserScenarioProvider.js +6 -6
  87. package/dist/browser/PlaywrightScenarioBrowser.js +145 -42
  88. package/dist/browser/PlaywrightScenarioSession.js +3 -11
  89. package/dist/browser/WebSourceMapFetcher.js +32 -6
  90. package/dist/browser/assets/ScenarioScriptCapture.js +8 -12
  91. package/dist/cli/coreAnalysisCommands.js +2 -2
  92. package/dist/cli/coreBinaryCommands.js +13 -9
  93. package/dist/cli/electronCommands.js +9 -10
  94. package/dist/cli/javascriptApplicationAnalysis.js +2 -12
  95. package/dist/cli/jsonOutput.js +3 -2
  96. package/dist/cli/streamedJsonOutput.js +83 -4
  97. package/dist/cli/utilityCommands.js +2 -4
  98. package/dist/cli.js +5 -2
  99. package/dist/cliJsonFile.js +179 -0
  100. package/dist/cliJsonInput.js +47 -34
  101. package/dist/cliObservationOptions.js +4 -0
  102. package/dist/composition/auxiliaryAnalysisProviders.js +5 -4
  103. package/dist/composition/browserScenario.js +2 -2
  104. package/dist/composition/directAnalysis.js +2 -3
  105. package/dist/contracts/artifactComparisonExample.js +5 -5
  106. package/dist/contracts/errorSchemas.js +3 -1
  107. package/dist/contracts/functionComparisonExample.js +8 -0
  108. package/dist/contracts/inputSchemaPresentation.js +94 -3
  109. package/dist/contracts/javascript/electronToolContracts.js +2 -1
  110. package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +3 -2
  111. package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +6 -3
  112. package/dist/contracts/javascript/javascriptRuntimeReconciliationExample.js +8 -7
  113. package/dist/contracts/managed/managedToolContracts.js +3 -2
  114. package/dist/contracts/mobileApplicationGraphExamples.js +5 -5
  115. package/dist/contracts/native/nativeToolContracts.js +1 -1
  116. package/dist/contracts/sessionLifecycleInputs.js +4 -3
  117. package/dist/contracts/sessionStatusContract.js +3 -2
  118. package/dist/contracts/sessionToolContracts.js +3 -2
  119. package/dist/contracts/sessionToolSchemas.js +3 -2
  120. package/dist/contracts/toolOutputSchemaGroups.js +2 -2
  121. package/dist/contracts/toolOutputSchemaPrimitives.js +2 -5
  122. package/dist/domain/analysisErrorBase.js +5 -0
  123. package/dist/domain/analysisErrorPresentation.js +4 -2
  124. package/dist/domain/analysisSnapshot.js +3 -1
  125. package/dist/domain/analysisView/analysisView.js +1 -3
  126. package/dist/domain/android/androidPartialObservation.js +36 -0
  127. package/dist/domain/apple/dylibResolution.js +1 -1
  128. package/dist/domain/artifactComparison.js +4 -4
  129. package/dist/domain/artifactGraph.js +1 -1
  130. package/dist/domain/artifactIdentity.js +8 -8
  131. package/dist/domain/artifactInspection.js +8 -8
  132. package/dist/domain/artifactInventoryEvidence.js +5 -5
  133. package/dist/domain/browserCompleteness.js +3 -2
  134. package/dist/domain/browserScenarioCaptureValues.js +2 -2
  135. package/dist/domain/browserScenarioNormalization.js +3 -3
  136. package/dist/domain/browserScenarioValues.js +3 -2
  137. package/dist/domain/callPath.js +8 -10
  138. package/dist/domain/canonicalDigest.js +7 -1
  139. package/dist/domain/canonicalOrdering.js +1 -13
  140. package/dist/domain/changedBehavior.js +2 -3
  141. package/dist/domain/comparisonSemantics.js +0 -5
  142. package/dist/domain/digests.js +0 -3
  143. package/dist/domain/evidence.js +10 -5
  144. package/dist/domain/evidenceBundle.js +51 -33
  145. package/dist/domain/firmware/firmwareAnalysis.js +4 -3
  146. package/dist/domain/functionComparison.js +2 -1
  147. package/dist/domain/functionComparisonNormalization.js +4 -3
  148. package/dist/domain/functionComparisonResults.js +2 -2
  149. package/dist/domain/functionDossierEvidence.js +2 -1
  150. package/dist/domain/hopperValues.js +11 -15
  151. package/dist/domain/javascript/electronActiveObservation.js +4 -3
  152. package/dist/domain/javascript/electronStaticAnalysisBrowser.js +2 -2
  153. package/dist/domain/javascript/electronStaticAnalysisIpc.js +9 -1
  154. package/dist/domain/javascript/electronStaticAnalysisNative.js +5 -3
  155. package/dist/domain/javascript/electronStaticAnalysisValues.js +8 -4
  156. package/dist/domain/javascript/javascriptApplicationAnalysis.js +3 -1
  157. package/dist/domain/javascript/javascriptApplicationChangeGraph.js +12 -8
  158. package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +4 -0
  159. package/dist/domain/javascript/javascriptApplicationGraph.js +15 -13
  160. package/dist/domain/javascript/javascriptApplicationVersionComparison.js +4 -4
  161. package/dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js +37 -22
  162. package/dist/domain/javascript/javascriptApplicationVersionItems.js +45 -34
  163. package/dist/domain/javascript/javascriptApplicationVersionKeys.js +7 -7
  164. package/dist/domain/javascript/javascriptAstFingerprint.js +2 -2
  165. package/dist/domain/javascript/javascriptAstValues.js +22 -0
  166. package/dist/domain/javascript/javascriptExportShapeComparison.js +3 -2
  167. package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +31 -23
  168. package/dist/domain/javascript/javascriptExportShapeSelection.js +2 -2
  169. package/dist/domain/javascript/javascriptExportShapeVariants.js +3 -2
  170. package/dist/domain/javascript/javascriptFeatureSeed.js +5 -3
  171. package/dist/domain/javascript/javascriptFeatureTrace.js +7 -6
  172. package/dist/domain/javascript/javascriptFeatureTraceSchemas.js +17 -9
  173. package/dist/domain/javascript/javascriptFeatureTraversal.js +4 -4
  174. package/dist/domain/javascript/javascriptNativeHandoff.js +6 -6
  175. package/dist/domain/javascript/javascriptRuntimeObservation.js +8 -5
  176. package/dist/domain/javascript/javascriptRuntimeReconciliation.js +12 -6
  177. package/dist/domain/javascript/javascriptRuntimeReconciliationActive.js +9 -8
  178. package/dist/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js +212 -0
  179. package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +5 -4
  180. package/dist/domain/javascript/javascriptRuntimeReconciliationInputValidation.js +28 -0
  181. package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +5 -5
  182. package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +12 -223
  183. package/dist/domain/javascript/javascriptRuntimeReconciliationResult.js +2 -2
  184. package/dist/domain/javascript/javascriptRuntimeReconciliationRuntime.js +15 -4
  185. package/dist/domain/javascript/javascriptRuntimeReconciliationSchemas.js +2 -2
  186. package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +7 -6
  187. package/dist/domain/javascript/javascriptSemanticAnalysis.js +200 -8
  188. package/dist/domain/javascript/javascriptSemanticCallResolution.js +9 -7
  189. package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -2
  190. package/dist/domain/javascript/javascriptSemanticCoverage.js +20 -0
  191. package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +7 -9
  192. package/dist/domain/javascript/javascriptSemanticDataEffects.js +4 -11
  193. package/dist/domain/javascript/javascriptSemanticFingerprints.js +2 -2
  194. package/dist/domain/javascript/javascriptSemanticGraph.js +142 -35
  195. package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +19 -1
  196. package/dist/domain/javascript/javascriptSemanticIr.js +0 -4
  197. package/dist/domain/javascript/javascriptSemanticIterationSources.js +106 -0
  198. package/dist/domain/javascript/javascriptSemanticMemberMutations.js +497 -113
  199. package/dist/domain/javascript/javascriptSemanticMutationInitializers.js +190 -0
  200. package/dist/domain/javascript/javascriptSemanticMutationValues.js +41 -27
  201. package/dist/domain/javascript/javascriptSemanticObjects.js +2 -6
  202. package/dist/domain/javascript/javascriptSemanticPrimitives.js +7 -2
  203. package/dist/domain/javascript/javascriptSemanticProjection.js +20 -14
  204. package/dist/domain/javascript/javascriptSemanticPromises.js +15 -21
  205. package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +23 -0
  206. package/dist/domain/javascript/javascriptSemanticProvenance.js +3 -3
  207. package/dist/domain/javascript/javascriptSemanticQuery.js +8 -2
  208. package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +3 -2
  209. package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -9
  210. package/dist/domain/javascript/javascriptSemanticRequireOrigin.js +16 -10
  211. package/dist/domain/javascript/javascriptSemanticReturns.js +23 -27
  212. package/dist/domain/javascript/javascriptSemanticTraversal.js +6 -1
  213. package/dist/domain/javascript/javascriptSemanticValues.js +135 -24
  214. package/dist/domain/javascript/javascriptSourceMapPaths.js +11 -1
  215. package/dist/domain/javascript/javascriptSourceParser.js +34 -9
  216. package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +5 -6
  217. package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +26 -15
  218. package/dist/domain/javascript/sourceToBundleComparison.js +7 -5
  219. package/dist/domain/javascript/sourceToBundleSignals.js +7 -7
  220. package/dist/domain/jsonSerialization.js +109 -55
  221. package/dist/domain/jsonShape.js +46 -19
  222. package/dist/domain/localPath.js +10 -4
  223. package/dist/domain/managed/managedApplicationGraph.js +10 -6
  224. package/dist/domain/managed/managedApplicationGraphNodes.js +82 -57
  225. package/dist/domain/managed/managedMemberComparisonMatch.js +6 -7
  226. package/dist/domain/native/nativeCallObservation.js +2 -4
  227. package/dist/domain/native/nativeValueFlow.js +5 -11
  228. package/dist/domain/native/objcSwiftMetadata.js +15 -17
  229. package/dist/domain/process/processCapture.js +11 -10
  230. package/dist/domain/process/processCaptureCoverage.js +8 -5
  231. package/dist/domain/process/processCaptureExample.js +43 -0
  232. package/dist/domain/process/processCaptureValidation.js +4 -3
  233. package/dist/domain/process/processComparison.js +0 -23
  234. package/dist/domain/process/processScenario.js +3 -3
  235. package/dist/domain/process/processTraceEvaluation.js +4 -4
  236. package/dist/domain/process/processTraceSpecification.js +1 -3
  237. package/dist/domain/providerCleanupError.js +6 -2
  238. package/dist/domain/reconstructionCoverage.js +2 -1
  239. package/dist/domain/reconstructionUnknowns.js +4 -3
  240. package/dist/domain/reconstructionVerification.js +3 -2
  241. package/dist/domain/referenceSourceGraph.js +7 -7
  242. package/dist/domain/referenceSourceImportParsing.js +34 -45
  243. package/dist/domain/residualUnknown.js +3 -2
  244. package/dist/domain/staticRuntimeCorrelation.js +2 -1
  245. package/dist/domain/swiftSymbolClassification.js +6 -1
  246. package/dist/domain/symbolAnalysis.js +17 -2
  247. package/dist/domain/unicodeCodePointOrder.js +6 -0
  248. package/dist/domain/webBundleAnalyzerInspection.js +9 -1
  249. package/dist/domain/webCaptureDiff.js +71 -29
  250. package/dist/domain/webCaptureDiffSchemas.js +2 -8
  251. package/dist/domain/webInventory.js +3 -2
  252. package/dist/domain/webMcpDiscovery.js +4 -3
  253. package/dist/domain/webScriptExport.js +1 -1
  254. package/dist/dotnet/ManagedMemberInstructionDecoder.js +1 -2
  255. package/dist/dotnet/ManagedStaticProvider.js +10 -7
  256. package/dist/dotnet/ManagedStaticProviderMetadata.js +1 -4
  257. package/dist/filesystem/RegularFile.js +41 -0
  258. package/dist/generatedPackageMetadata.js +1 -1
  259. package/dist/ghidra/GhidraClient.js +14 -4
  260. package/dist/ghidra/GhidraInstallation.js +111 -10
  261. package/dist/ghidra/GhidraLauncher.js +43 -19
  262. package/dist/hopper/HopperCleanup.js +1 -1
  263. package/dist/ida/IdaOperationRunner.js +2 -0
  264. package/dist/ida/IdaSessionClient.js +4 -2
  265. package/dist/inspector/JavaScriptRuntimeScope.js +9 -5
  266. package/dist/inspector/V8InspectorCaptureProjection.js +46 -13
  267. package/dist/inspector/V8InspectorProvider.js +60 -8
  268. package/dist/main/shutdown.js +76 -32
  269. package/dist/main/transport.js +1 -1
  270. package/dist/native/AppleObjcDispatchFacets.js +3 -3
  271. package/dist/native/AppleObjcProperties.js +17 -7
  272. package/dist/native/LldbCallTracer.js +241 -75
  273. package/dist/native/NativeMacOSProvider.js +10 -5
  274. package/dist/native/NativeMacOSProviderMetadata.js +1 -2
  275. package/dist/process/ProcessOwnershipObservation.js +9 -13
  276. package/dist/process/capture/FilesystemSnapshot.js +88 -18
  277. package/dist/process/capture/ProcessCaptureLifecycle.js +13 -27
  278. package/dist/process/capture/ProcessFilesystemEffects.js +19 -4
  279. package/dist/process/capture/ProcessHarness.js +8 -21
  280. package/dist/server/analysisAdmission.js +8 -0
  281. package/dist/server/createServer.js +22 -23
  282. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -1
  283. package/dist/server/registerApplicationTools/helpers.js +3 -2
  284. package/dist/server/registerArtifactTools.js +2 -2
  285. package/dist/server/registerCloseLifecycleTool.js +6 -4
  286. package/dist/server/registerEnhancedTools.js +78 -73
  287. package/dist/server/registerEvidenceTools.js +54 -46
  288. package/dist/server/registerManagedTools.js +7 -4
  289. package/dist/server/registerOfficialTools.js +31 -25
  290. package/dist/server/registerSessionTools.js +9 -3
  291. package/native/windows/build/manifest.json +1 -1
  292. package/package.json +6 -3
  293. package/skills/reverse-engineer-anything/SKILL.md +5 -5
  294. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
  295. package/dist/artifacts/inventory/policy.js +0 -2
  296. package/dist/domain/managed/managedApplicationGraphNodeCoverage.js +0 -6
  297. package/dist/server/registerNativeTools.js +0 -6
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { artifactInventoryResultSchema, } from "./artifactGraph.js";
3
- import { canonicalDigest } from "./comparisonSemantics.js";
3
+ import { digestCanonicalValue } from "./canonicalDigest.js";
4
4
  import { uniqueSorted } from "./canonicalOrdering.js";
5
5
  import { evidenceSchema, parseEvidence } from "./evidence.js";
6
6
  import { jsonValueSchema } from "./jsonValue.js";
@@ -137,7 +137,7 @@ export const createArtifactInspection = (inventoryInput) => {
137
137
  },
138
138
  substeps: [
139
139
  {
140
- substep_id: `ais_${canonicalDigest({
140
+ substep_id: `ais_${digestCanonicalValue({
141
141
  operation: "inventory_artifact",
142
142
  evidence_id: inventoryEvidence.evidence_id,
143
143
  }, "Artifact inspection")}`,
@@ -175,7 +175,7 @@ export const createArtifactInspection = (inventoryInput) => {
175
175
  };
176
176
  return artifactInspectionResultSchema.parse({
177
177
  ...semantic,
178
- inspection_id: `ai_${canonicalDigest(semantic, "Artifact inspection")}`,
178
+ inspection_id: `ai_${digestCanonicalValue(semantic, "Artifact inspection")}`,
179
179
  });
180
180
  };
181
181
  const parseInventoryEvidence = (input) => {
@@ -198,7 +198,7 @@ const observation = (kind, subject, value, evidenceId) => {
198
198
  evidence_id: evidenceId,
199
199
  };
200
200
  return {
201
- observation_id: `aio_${canonicalDigest(semantic, "Artifact inspection")}`,
201
+ observation_id: `aio_${digestCanonicalValue(semantic, "Artifact inspection")}`,
202
202
  ...semantic,
203
203
  };
204
204
  };
@@ -212,7 +212,7 @@ const allRelationships = (inventory, evidenceId) => inventory.edges.map((edge) =
212
212
  evidence_id: evidenceId,
213
213
  };
214
214
  return {
215
- relationship_id: `air_${canonicalDigest(semantic, "Artifact inspection")}`,
215
+ relationship_id: `air_${digestCanonicalValue(semantic, "Artifact inspection")}`,
216
216
  ...semantic,
217
217
  };
218
218
  });
@@ -234,7 +234,7 @@ const allHypotheses = (inventory, evidenceId) => {
234
234
  limitation: "Format classification proposes a bounded follow-up; it is not semantic proof.",
235
235
  };
236
236
  return {
237
- hypothesis_id: `aih_${canonicalDigest(semantic, "Artifact inspection")}`,
237
+ hypothesis_id: `aih_${digestCanonicalValue(semantic, "Artifact inspection")}`,
238
238
  ...semantic,
239
239
  };
240
240
  });
@@ -248,7 +248,7 @@ const contradictions = (inventory, evidenceId) => inventory.integrity_contradict
248
248
  evidence_id: evidenceId,
249
249
  };
250
250
  return {
251
- contradiction_id: `aic_${canonicalDigest(semantic, "Artifact inspection")}`,
251
+ contradiction_id: `aic_${digestCanonicalValue(semantic, "Artifact inspection")}`,
252
252
  ...semantic,
253
253
  };
254
254
  });
@@ -308,7 +308,7 @@ const branch = (reason, detail, nextProbe, evidenceId) => {
308
308
  evidence_id: evidenceId,
309
309
  };
310
310
  return {
311
- branch_id: `aib_${canonicalDigest(semantic, "Artifact inspection")}`,
311
+ branch_id: `aib_${digestCanonicalValue(semantic, "Artifact inspection")}`,
312
312
  ...semantic,
313
313
  };
314
314
  };
@@ -1,5 +1,5 @@
1
1
  import { artifactInventoryResultSchema, } from "./artifactGraph.js";
2
- import { compareCodePoints } from "./canonicalOrdering.js";
2
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
3
3
  import { canonicalJson } from "./comparisonSemantics.js";
4
4
  import { artifactContradictionId, artifactEdgeId, artifactGraphDigest, artifactIdForContent, artifactManifestId, occurrenceIdForLocation, } from "./artifactIdentity.js";
5
5
  import { parseEvidence } from "./evidence.js";
@@ -68,9 +68,9 @@ const assembleInventorySet = (pages) => {
68
68
  return { evidence: pages.map(({ evidence }) => evidence), inventory };
69
69
  };
70
70
  const orderedInventory = (first, pages, values) => {
71
- const nodes = [...values.nodes.values()].sort((left, right) => compareCodePoints(left.artifact_id, right.artifact_id));
72
- const occurrences = [...values.occurrences.values()].sort((left, right) => compareCodePoints(left.logical_path, right.logical_path));
73
- const edges = [...values.edges.values()].sort((left, right) => compareCodePoints(left.edge_id, right.edge_id));
71
+ const nodes = [...values.nodes.values()].sort((left, right) => compareUnicodeCodePoints(left.artifact_id, right.artifact_id));
72
+ const occurrences = [...values.occurrences.values()].sort((left, right) => compareUnicodeCodePoints(left.logical_path, right.logical_path));
73
+ const edges = [...values.edges.values()].sort((left, right) => compareUnicodeCodePoints(left.edge_id, right.edge_id));
74
74
  return {
75
75
  manifest: first.manifest,
76
76
  nodes,
@@ -79,7 +79,7 @@ const orderedInventory = (first, pages, values) => {
79
79
  integrityContradictions: first.integrity_contradictions,
80
80
  limitations: [
81
81
  ...new Set(pages.flatMap(({ inventory }) => inventory.limitations)),
82
- ].sort(compareCodePoints),
82
+ ].sort(compareUnicodeCodePoints),
83
83
  complete: nodes.length === first.manifest.node_count &&
84
84
  occurrences.length === first.manifest.occurrence_count &&
85
85
  edges.length === first.manifest.edge_count,
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
2
3
  /** Stable browser sections used by coverage and omission accounting. */
3
4
  const browserSectionSchema = z.enum([
4
5
  "frames",
@@ -98,5 +99,5 @@ export const classifyBrowserCompleteness = (input) => {
98
99
  });
99
100
  };
100
101
  const sortedSections = (sections) => [...sections].sort();
101
- const canonicalExclusions = (exclusions) => [...exclusions].sort((left, right) => left.section.localeCompare(right.section) ||
102
- left.reason.localeCompare(right.reason));
102
+ const canonicalExclusions = (exclusions) => [...exclusions].sort((left, right) => compareUnicodeCodePoints(left.section, right.section) ||
103
+ compareUnicodeCodePoints(left.reason, right.reason));
@@ -103,8 +103,8 @@ const eventBase = {
103
103
  const eventUrl = sanitizedBrowserUrlSchema.nullable();
104
104
  const networkEventShape = {
105
105
  ...eventBase,
106
- transaction_id: z.string().min(1).optional(),
107
- redirected_from_transaction_id: z.string().min(1).nullable().optional(),
106
+ transaction_id: z.string().min(1),
107
+ redirected_from_transaction_id: z.string().min(1).nullable(),
108
108
  method: z.string().min(1),
109
109
  url: sanitizedBrowserUrlSchema,
110
110
  resource_type: z.string().min(1),
@@ -1,4 +1,4 @@
1
- import { canonicalDigest } from "./comparisonSemantics.js";
1
+ import { digestCanonicalValue } from "./canonicalDigest.js";
2
2
  const BUILT_IN_RULES = [
3
3
  "ignore_step_elapsed_ms",
4
4
  "ignore_event_sequence",
@@ -17,11 +17,11 @@ export const commitBrowserScenarioNormalization = (input) => {
17
17
  const commitment = { built_in_rules: [...BUILT_IN_RULES], rules };
18
18
  return {
19
19
  ...commitment,
20
- sha256: canonicalDigest(commitment, "Browser scenario"),
20
+ sha256: digestCanonicalValue(commitment, "Browser scenario"),
21
21
  };
22
22
  };
23
23
  /** Digest one artifact after applying committed exact-literal rules. */
24
- export const digestNormalizedScenarioValue = (value, artifact, rules) => canonicalDigest(normalize(value, artifact, rules), "Browser scenario");
24
+ export const digestNormalizedScenarioValue = (value, artifact, rules) => digestCanonicalValue(normalize(value, artifact, rules), "Browser scenario");
25
25
  const normalize = (value, artifact, rules) => {
26
26
  if (artifact === "screenshot")
27
27
  return value;
@@ -1,10 +1,11 @@
1
1
  import { z } from "zod";
2
+ import { isAbsolute } from "node:path";
2
3
  import { IDENTIFIER_PATTERN } from "./stringPatterns.js";
3
- import { isAbsoluteLocalPath, localPathStringSchema } from "./localPath.js";
4
+ import { localPathStringSchema } from "./localPath.js";
4
5
  import { browserNetworkContentSelectionSchema } from "./browserNetworkEvidence.js";
5
6
  import { browserEndpointSchema, browserOriginSchema, } from "./browserObservation.js";
6
7
  export const scenarioIdentifierSchema = z.string().regex(IDENTIFIER_PATTERN);
7
- const browserExecutablePathSchema = localPathStringSchema.refine(isAbsoluteLocalPath, {
8
+ const browserExecutablePathSchema = localPathStringSchema.refine(isAbsolute, {
8
9
  message: "executable_path must be an absolute local filesystem path (for example /opt/chromium/chrome or C:\\chromium\\chrome.exe)",
9
10
  });
10
11
  const browserScenarioBaseUrlSchema = z
@@ -1,5 +1,6 @@
1
1
  import { callPathInputSchema, callPathResultSchema, parseCallPathAddress, } from "./callPathSchemas.js";
2
2
  import { parseFunctionEvidence, } from "./functionDossierEvidence.js";
3
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
3
4
  /** Minimal directed caller-to-callee adjacency for call-path search. */
4
5
  class CallGraph {
5
6
  successors = new Map();
@@ -76,7 +77,7 @@ export const buildCallPath = (input) => {
76
77
  goal: parsed.goal.address,
77
78
  explored: summarizeSearch(graph, search.reached),
78
79
  evidence_links: uniqueEvidence(snapshots.values()),
79
- limitations: [...new Set(limitations)].sort((left, right) => left.localeCompare(right)),
80
+ limitations: [...new Set(limitations)].sort(compareUnicodeCodePoints),
80
81
  };
81
82
  const searchScope = { exhaustive };
82
83
  if (found)
@@ -111,9 +112,9 @@ const parseSnapshots = (groups) => {
111
112
  const snapshots = new Map();
112
113
  for (const group of groups) {
113
114
  const snapshot = parseFunctionEvidence(group);
114
- const address = normalizeAddress(snapshot.dossier.procedure.address);
115
+ const address = parseCallPathAddress(snapshot.dossier.procedure.address);
115
116
  for (const callee of snapshot.dossier.callees)
116
- normalizeAddress(callee.address);
117
+ parseCallPathAddress(callee.address);
117
118
  if (snapshots.has(address))
118
119
  throw new TypeError(`Duplicate function Evidence for ${address}`);
119
120
  snapshots.set(address, snapshot);
@@ -141,7 +142,7 @@ const createGraph = (snapshots) => {
141
142
  for (const [address, snapshot] of snapshots) {
142
143
  graph.mergeNode(address);
143
144
  for (const callee of snapshot.dossier.callees) {
144
- const calleeAddress = normalizeAddress(callee.address);
145
+ const calleeAddress = parseCallPathAddress(callee.address);
145
146
  graph.mergeNode(calleeAddress);
146
147
  graph.mergeDirectedEdge(address, calleeAddress);
147
148
  }
@@ -174,9 +175,7 @@ const inspectSearch = ({ graph, snapshots, start, goal, }) => {
174
175
  limitations.push(`No analyze_function Evidence covers reachable function ${node}`);
175
176
  continue;
176
177
  }
177
- const neighbors = graph
178
- .outNeighbors(node)
179
- .sort((left, right) => left.localeCompare(right));
178
+ const neighbors = graph.outNeighbors(node).sort(compareUnicodeCodePoints);
180
179
  for (const neighbor of neighbors)
181
180
  if (!reached.has(neighbor)) {
182
181
  reached.set(neighbor, depth + 1);
@@ -203,7 +202,7 @@ const enumeratePaths = ({ graph, start, goal, goalDistances, }) => {
203
202
  .outNeighbors(node)
204
203
  .filter((neighbor) => distance !== undefined &&
205
204
  goalDistances.get(neighbor) === distance - 1)
206
- .sort((left, right) => left.localeCompare(right));
205
+ .sort(compareUnicodeCodePoints);
207
206
  neighbors.set(node, candidates);
208
207
  }
209
208
  return { neighbors: candidates, nextIndex: 0 };
@@ -270,5 +269,4 @@ const snapshotLinks = (snapshot) => {
270
269
  };
271
270
  const uniqueEvidence = (snapshots) => [
272
271
  ...new Set([...snapshots].flatMap((snapshot) => snapshotLinks(snapshot))),
273
- ].sort((left, right) => left.localeCompare(right));
274
- const normalizeAddress = (input) => parseCallPathAddress(input);
272
+ ].sort(compareUnicodeCodePoints);
@@ -1,5 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
- /** Hash canonicalize-compatible JSON without assembling an aggregate string. */
2
+ /**
3
+ * Streaming SHA-256 over canonical JSON. Hashing owner (avoids assembling
4
+ * aggregate strings); `comparisonSemantics.canonicalJson` (canonicalize lib)
5
+ * is the string-comparison owner. JSON object keys follow RFC 8785's UTF-16
6
+ * code-unit order in both; entity-list ordering is a separate concern.
7
+ */
3
8
  export const digestCanonicalValue = (value, context = "Comparison") => {
4
9
  const hash = createHash("sha256");
5
10
  // Batch small emitted parts to cut hash.update crossings.
@@ -54,6 +59,7 @@ const emitCanonical = (value, emit, ancestors) => {
54
59
  else {
55
60
  emit("{");
56
61
  let first = true;
62
+ // Match canonicalize/RFC 8785, including supplementary-plane keys.
57
63
  for (const key of Object.keys(value).sort()) {
58
64
  if (Reflect.get(value, key) === undefined ||
59
65
  typeof Reflect.get(value, key) === "symbol")
@@ -1,15 +1,3 @@
1
1
  import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
2
- /**
3
- * Canonical code-point ordering shared across domain and application layers.
4
- *
5
- * Compares strings by Unicode code point so graph ordering, fingerprints, and
6
- * deterministic tie-breaks stay stable regardless of locale. Prefer this over
7
- * `String.prototype.localeCompare`, which is locale-dependent.
8
- *
9
- * Ordering by code point differs from ordering by UTF-16 code unit for astral
10
- * code points (above U+FFFF), whose lead surrogate is numerically below the
11
- * BMP tail U+E000-U+FFFF.
12
- */
13
- export const compareCodePoints = (left, right) => compareUnicodeCodePoints(left, right);
14
2
  /** Deduplicate and sort strings with canonical code-point ordering. */
15
- export const uniqueSorted = (values) => [...new Set(values)].sort(compareCodePoints);
3
+ export const uniqueSorted = (values) => [...new Set(values)].sort(compareUnicodeCodePoints);
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { artifactComparisonResultSchema } from "./artifactComparison.js";
3
3
  import { uniqueSorted } from "./canonicalOrdering.js";
4
+ import { compositeKey, compareUnicodeCodePoints, } from "./unicodeCodePointOrder.js";
4
5
  import { comparisonSourceEvidenceIds } from "./comparisonSourceEvidence.js";
5
6
  import { evidenceSchema, parseEvidence } from "./evidence.js";
6
7
  import { functionComparisonResultSchema } from "./functionComparisonSchemas.js";
@@ -274,9 +275,7 @@ const behaviorStatus = (statuses) => {
274
275
  const isChange = (status) => status === "added" || status === "removed" || status === "changed";
275
276
  const count = (findings, classification) => findings.filter((finding) => finding.classification === classification)
276
277
  .length;
277
- const compareFindings = (left, right) => [left.scope, left.dimension, left.source_comparison_id]
278
- .join("\0")
279
- .localeCompare([right.scope, right.dimension, right.source_comparison_id].join("\0"), "en");
278
+ const compareFindings = (left, right) => compareUnicodeCodePoints(compositeKey([left.scope, left.dimension, left.source_comparison_id]), compositeKey([right.scope, right.dimension, right.source_comparison_id]));
280
279
  const assertUnique = (values, label) => {
281
280
  if (new Set(values).size !== values.length)
282
281
  throw new TypeError(`Changed-behavior analysis rejects duplicate ${label}`);
@@ -1,13 +1,8 @@
1
1
  import canonicalize from "canonicalize";
2
- import { digestCanonicalValue } from "./canonicalDigest.js";
3
2
  /** Whether an inventory can support a claim that an item is absent. */
4
3
  export const absenceClaimable = (coverage) => coverage.status === "complete" &&
5
4
  coverage.truncated !== true &&
6
5
  (coverage.omitted_count === undefined || coverage.omitted_count === 0);
7
- /** SHA-256 of canonical JSON for stable, provider-neutral comparison IDs. */
8
- export const canonicalDigest = (value, context = "Comparison") => {
9
- return digestCanonicalValue(value, context);
10
- };
11
6
  /** Canonical JSON used for deterministic tie breaking and stable digests. */
12
7
  export const canonicalJson = (value, context = "Comparison") => {
13
8
  const encoded = canonicalize(value);
@@ -25,6 +25,3 @@ export const prefixedDigestSchema = (prefix) => z
25
25
  .regex(new RegExp(`^${prefix}_[a-f0-9]{64}$`, "u"), `Expected a ${prefix}_ prefixed lowercase sha256 digest`);
26
26
  /** True when `value` is a bare digest. */
27
27
  export const isDigest = (value) => typeof value === "string" && SHA256_PATTERN.test(value);
28
- /** True when `value` is a digest carrying `prefix`. */
29
- export const isPrefixedDigest = (value, prefix) => typeof value === "string" &&
30
- prefixedDigestSchema(prefix).safeParse(value).success;
@@ -108,6 +108,15 @@ export const validateAnalysisProfileProvider = (evidence, context) => {
108
108
  };
109
109
  /** Strict, provider-neutral record for one successful public observation. */
110
110
  export const evidenceSchema = evidenceBaseSchema.superRefine(validateAnalysisProfileProvider);
111
+ const authenticatedEvidenceSchema = evidenceSchema.superRefine((evidence, context) => {
112
+ const { evidence_id: evidenceId, ...withoutId } = evidence;
113
+ if (computeEvidenceId(withoutId) !== evidenceId)
114
+ context.addIssue({
115
+ code: "custom",
116
+ path: ["evidence_id"],
117
+ message: "Evidence semantic identifier does not match its record",
118
+ });
119
+ });
111
120
  const immutableEvidenceSnapshots = new WeakMap();
112
121
  const immutableResultSchema = z
113
122
  .custom(isImmutableJsonSnapshot)
@@ -147,11 +156,7 @@ export const parseEvidence = (input) => {
147
156
  : undefined;
148
157
  if (immutable !== undefined)
149
158
  return immutable;
150
- const evidence = evidenceSchema.parse(input);
151
- const { evidence_id: evidenceId, ...withoutId } = evidence;
152
- if (computeEvidenceId(withoutId) !== evidenceId)
153
- throw new TypeError("Evidence semantic identifier does not match its record");
154
- return evidence;
159
+ return authenticatedEvidenceSchema.parse(input);
155
160
  };
156
161
  /** Authenticate and seal a ledger-owned snapshot; external mutable values are copied first. */
157
162
  export const immutableEvidence = (input) => rememberImmutableEvidence(parseEvidence(input));
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import canonicalize from "canonicalize";
3
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
3
4
  import { evidenceSchema, immutableEvidence, parseEvidence, providerSchema, } from "./evidence.js";
4
5
  import { residualUnknownSchema, } from "./residualUnknown.js";
5
6
  import { freezeJsonSnapshot } from "./immutableJson.js";
@@ -43,7 +44,7 @@ export const createImmutableEvidenceBundle = (records, unknowns = []) => {
43
44
  };
44
45
  /** Project records into a deterministic bundle whose order has no semantics. */
45
46
  export const createEvidenceBundle = (records, unknowns = []) => {
46
- const sortedRecords = [...records].sort((left, right) => left.evidence_id.localeCompare(right.evidence_id));
47
+ const sortedRecords = [...records].sort((left, right) => compareUnicodeCodePoints(left.evidence_id, right.evidence_id));
47
48
  return {
48
49
  artifacts: uniqueSorted(sortedRecords.flatMap(({ subject }) => subject === null
49
50
  ? []
@@ -73,55 +74,60 @@ export const createEvidenceBundle = (records, unknowns = []) => {
73
74
  },
74
75
  ]
75
76
  : []),
76
- unknowns: [...unknowns].sort((left, right) => left.unknown_id.localeCompare(right.unknown_id) ||
77
+ unknowns: [...unknowns].sort((left, right) => compareUnicodeCodePoints(left.unknown_id, right.unknown_id) ||
77
78
  left.revision - right.revision),
78
79
  records: sortedRecords,
79
80
  };
80
81
  };
81
- /** Restrict a bundle to records and complete unknown histories for one artifact. */
82
+ /** Retain target records and eligible complete unknown histories with their mutation evidence. */
82
83
  export const evidenceBundleForTarget = (bundle, sha256) => {
83
84
  const recordsById = new Map(bundle.records.map((record) => [record.evidence_id, record]));
84
- const candidates = bundle.unknowns.filter(({ scope_digest: scopeDigest }) => scopeDigest === sha256);
85
+ const histories = new Map();
86
+ for (const unknown of bundle.unknowns) {
87
+ const history = histories.get(unknown.unknown_id) ?? [];
88
+ history.push(unknown);
89
+ histories.set(unknown.unknown_id, history);
90
+ }
85
91
  const retained = new Set();
86
- const revisionsById = new Map();
87
92
  const dependents = new Map();
88
- for (const unknown of candidates) {
89
- const mutationEvidenceIds = new Set(unknown.mutation_evidence_ids);
90
- const evidenceAvailable = referencedEvidenceIds(unknown).every((id) => {
91
- const record = recordsById.get(id);
92
- return (record?.subject?.digest.sha256 === sha256 ||
93
- (mutationEvidenceIds.has(id) &&
94
- record?.subject === null &&
95
- record.predicate_type === "rea.residual-unknown-mutation"));
93
+ const relationships = new Map();
94
+ for (const [id, history] of histories) {
95
+ const eligible = history.every((unknown) => {
96
+ if (unknown.scope_digest !== sha256)
97
+ return false;
98
+ const mutationEvidenceIds = new Set(unknown.mutation_evidence_ids);
99
+ return referencedEvidenceIds(unknown).every((evidenceId) => {
100
+ const record = recordsById.get(evidenceId);
101
+ // Mutation subjects record the target active at the time of an edit,
102
+ // which need not be the question's immutable investigation scope.
103
+ return (record?.subject?.digest.sha256 === sha256 ||
104
+ (mutationEvidenceIds.has(evidenceId) &&
105
+ record?.predicate_type === "rea.residual-unknown-mutation"));
106
+ });
96
107
  });
97
- if (!evidenceAvailable)
108
+ if (!eligible)
98
109
  continue;
99
- retained.add(unknown);
100
- revisionsById.set(unknown.unknown_id, (revisionsById.get(unknown.unknown_id) ?? 0) + 1);
101
- for (const relatedId of new Set(unknown.relationships.map(({ unknown_id: id }) => id))) {
110
+ retained.add(id);
111
+ const relatedIds = new Set(history.flatMap((unknown) => unknown.relationships.map(({ unknown_id }) => unknown_id)));
112
+ relationships.set(id, relatedIds);
113
+ for (const relatedId of relatedIds) {
102
114
  const references = dependents.get(relatedId) ?? new Set();
103
- references.add(unknown);
115
+ references.add(id);
104
116
  dependents.set(relatedId, references);
105
117
  }
106
118
  }
107
119
  const pending = [];
108
- for (const unknown of retained)
109
- if (unknown.relationships.some(({ unknown_id: id }) => !revisionsById.has(id)))
110
- pending.push(unknown);
120
+ for (const [id, relatedIds] of relationships)
121
+ if ([...relatedIds].some((relatedId) => !retained.has(relatedId)))
122
+ pending.push(id);
111
123
  for (let index = 0; index < pending.length; index += 1) {
112
- const unknown = pending[index];
113
- if (unknown === undefined || !retained.delete(unknown))
124
+ const id = pending[index];
125
+ if (id === undefined || !retained.delete(id))
114
126
  continue;
115
- const remaining = (revisionsById.get(unknown.unknown_id) ?? 1) - 1;
116
- if (remaining > 0) {
117
- revisionsById.set(unknown.unknown_id, remaining);
118
- continue;
119
- }
120
- revisionsById.delete(unknown.unknown_id);
121
- for (const dependent of dependents.get(unknown.unknown_id) ?? [])
127
+ for (const dependent of dependents.get(id) ?? [])
122
128
  pending.push(dependent);
123
129
  }
124
- const unknowns = candidates.filter((unknown) => retained.has(unknown));
130
+ const unknowns = bundle.unknowns.filter((unknown) => retained.has(unknown.unknown_id));
125
131
  const mutationIds = new Set(unknowns.flatMap(({ mutation_evidence_ids: ids }) => ids));
126
132
  return createEvidenceBundle(bundle.records.filter((record) => record.subject?.digest.sha256 === sha256 ||
127
133
  mutationIds.has(record.evidence_id)), unknowns);
@@ -166,7 +172,19 @@ export const parseEvidenceBundle = (input) => {
166
172
  if (new Set(recordIds).size !== recordIds.length)
167
173
  throw new TypeError("Evidence bundle contains duplicate record IDs");
168
174
  validateUnknownGraph(parsed.unknowns, parsed.records);
169
- const canonical = createEvidenceBundle(parsed.records.map(parseEvidence), parsed.unknowns);
175
+ const canonical = createEvidenceBundle(parsed.records.map((record, index) => {
176
+ try {
177
+ return parseEvidence(record);
178
+ }
179
+ catch (cause) {
180
+ if (cause instanceof z.ZodError)
181
+ throw new z.ZodError(cause.issues.map((issue) => ({
182
+ ...issue,
183
+ path: ["records", index, ...issue.path],
184
+ })));
185
+ throw cause;
186
+ }
187
+ }), parsed.unknowns);
170
188
  if (JSON.stringify(parsed) !== JSON.stringify(canonical))
171
189
  throw new TypeError("Evidence bundle manifests are not canonical");
172
190
  return canonical;
@@ -364,6 +382,6 @@ const uniqueSorted = (values) => {
364
382
  for (const value of values)
365
383
  unique.set(JSON.stringify(value), value);
366
384
  return [...unique.entries()]
367
- .sort(([left], [right]) => left.localeCompare(right))
385
+ .sort(([left], [right]) => compareUnicodeCodePoints(left, right))
368
386
  .map(([, value]) => value);
369
387
  };
@@ -1,12 +1,13 @@
1
1
  import { z } from "zod";
2
+ import { isAbsolute } from "node:path";
2
3
  import { digestSchema } from "../digests.js";
3
4
  import { jsonValueSchema } from "../jsonValue.js";
4
- import { isAbsoluteLocalPath, localPathStringSchema } from "../localPath.js";
5
+ import { localPathStringSchema } from "../localPath.js";
5
6
  const bytes = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
6
7
  const range = z.strictObject({ offset: bytes, length: bytes.positive() });
7
8
  const target = {
8
9
  path: localPathStringSchema
9
- .refine(isAbsoluteLocalPath, {
10
+ .refine(isAbsolute, {
10
11
  message: "path must be an absolute local filesystem path (for example /tmp/firmware.bin or C:\\firmware\\firmware.bin)",
11
12
  })
12
13
  .describe("Absolute local firmware file; never executed. Relative paths are rejected."),
@@ -17,7 +18,7 @@ export const firmwareInputSchemas = {
17
18
  extract_firmware: z.strictObject({
18
19
  ...target,
19
20
  output_directory: localPathStringSchema
20
- .refine(isAbsoluteLocalPath, {
21
+ .refine(isAbsolute, {
21
22
  message: "output_directory must be an absolute local filesystem path",
22
23
  })
23
24
  .describe("Absolute, absent output directory; parent must exist"),
@@ -1,4 +1,5 @@
1
1
  import { canonicalJson } from "./comparisonSemantics.js";
2
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
2
3
  import { parseFunctionEvidence } from "./functionDossierEvidence.js";
3
4
  import { functionMatch } from "./functionComparisonNormalization.js";
4
5
  import { functionComparisonResultSchema, } from "./functionComparisonSchemas.js";
@@ -32,6 +33,6 @@ export const compareFunctions = (leftInput, rightInput) => {
32
33
  ]
33
34
  : []),
34
35
  ]),
35
- ].sort((a, b) => a.localeCompare(b)),
36
+ ].sort((a, b) => compareUnicodeCodePoints(a, b)),
36
37
  });
37
38
  };
@@ -1,5 +1,5 @@
1
1
  import { canonicalJson } from "./comparisonSemantics.js";
2
- import { compareCodePoints } from "./canonicalOrdering.js";
2
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
3
3
  export const identityProjection = (snapshot) => ({
4
4
  name: snapshot.dossier.procedure.name,
5
5
  signature: snapshot.dossier.procedure.signature,
@@ -136,9 +136,10 @@ export const sorted = (values) => values
136
136
  value,
137
137
  json: canonicalJson(value, "Function normalization"),
138
138
  }))
139
- .sort((left, right) => compareCodePoints(left.json, right.json))
139
+ .sort((left, right) => compareUnicodeCodePoints(left.json, right.json))
140
140
  .map(({ value }) => value);
141
- export const isAutoName = (name) => /^(?:sub_[0-9a-f]+|fcn\.[0-9a-f]+)$/iu.test(name);
141
+ /** Recognize address-derived procedure names without excluding named FUN_ symbols. */
142
+ export const isAutoName = (name) => /^(?:sub_[0-9a-f]+|fcn\.[0-9a-f]+|FUN_[0-9a-f]+)$/iu.test(name);
142
143
  const parseAddress = (value) => /^0x[0-9a-f]+$/iu.test(value) ? BigInt(value) : null;
143
144
  const relativeAddress = (value, base) => {
144
145
  const parsed = parseAddress(value);
@@ -1,4 +1,4 @@
1
- import { canonicalDigest } from "./comparisonSemantics.js";
1
+ import { digestCanonicalValue } from "./canonicalDigest.js";
2
2
  export const dimensionResult = (input) => {
3
3
  const context = {
4
4
  dimension: input.dimension,
@@ -51,4 +51,4 @@ export const summarize = (dimensions) => ({
51
51
  changed: dimensions.filter(({ status }) => status === "changed").length,
52
52
  unknown: dimensions.filter(({ status }) => status === "unknown").length,
53
53
  });
54
- const digest = (value) => canonicalDigest(value, "Function comparison");
54
+ const digest = (value) => digestCanonicalValue(value, "Function comparison");
@@ -1,4 +1,5 @@
1
1
  import { parseEvidence } from "./evidence.js";
2
+ import { compareUnicodeCodePoints } from "./unicodeCodePointOrder.js";
2
3
  import { functionDossierSchema } from "./hopperValues.js";
3
4
  /** Parse one complete analyze_function Evidence record for comparison workflows. */
4
5
  export const parseFunctionEvidence = (input) => {
@@ -14,6 +15,6 @@ export const parseFunctionEvidence = (input) => {
14
15
  dossier,
15
16
  limitations: [
16
17
  ...new Set([...evidence.limitations, ...dossier.limitations]),
17
- ].sort((left, right) => left.localeCompare(right)),
18
+ ].sort((left, right) => compareUnicodeCodePoints(left, right)),
18
19
  };
19
20
  };
@@ -29,12 +29,12 @@ const procedureMapSchema = z.record(z.string(), z.string());
29
29
  const addressedNamesSchema = z.array(z.object({ address: z.string(), name: z.string() }));
30
30
  const addressedNameMapSchema = z.record(z.string(), z.string());
31
31
  const segmentSchema = z.object({
32
- name: z.string().default(""),
33
- start: z.string().default(""),
34
- end: z.string().default(""),
35
- readable: z.boolean().nullable().default(null),
36
- writable: z.boolean().nullable().default(null),
37
- executable: z.boolean().nullable().default(null),
32
+ name: z.string(),
33
+ start: z.string(),
34
+ end: z.string(),
35
+ readable: z.boolean().nullable(),
36
+ writable: z.boolean().nullable(),
37
+ executable: z.boolean().nullable(),
38
38
  });
39
39
  const unavailableAnalysisFactSchema = z
40
40
  .object({ available: z.literal(false), reason: z.string() })
@@ -142,10 +142,6 @@ export const functionBodySchema = z.discriminatedUnion("available", [
142
142
  });
143
143
  }),
144
144
  ]);
145
- const unknownFunctionBody = () => functionBodySchema.default({
146
- available: false,
147
- reason: "The provider did not report complete function body ranges.",
148
- });
149
145
  /** Check the declared entry membership against complete, inclusive body ranges. */
150
146
  export const functionBodyEntryAgrees = (body, address) => {
151
147
  if (!body.available)
@@ -176,8 +172,8 @@ export const procedureIdentitySchema = z
176
172
  .object({
177
173
  address: z.string(),
178
174
  name: z.string(),
179
- classification: procedureClassificationSchema.nullable().default(null),
180
- body: unknownFunctionBody(),
175
+ classification: procedureClassificationSchema.nullable(),
176
+ body: functionBodySchema,
181
177
  })
182
178
  .strict()
183
179
  .superRefine((identity, context) => {
@@ -289,9 +285,9 @@ export const functionDossierSchema = z
289
285
  successors: z.array(z.string()),
290
286
  })
291
287
  .strict()),
292
- native_api: nativeApiBoundarySchema.nullable().default(null),
293
- native_value_flow: nativeValueFlowSchema.nullable().default(null),
294
- limitations: z.array(z.string()).default([]),
288
+ native_api: nativeApiBoundarySchema.nullable(),
289
+ native_value_flow: nativeValueFlowSchema.nullable(),
290
+ limitations: z.array(z.string()),
295
291
  })
296
292
  .strict();
297
293
  /** Strictly parse a complete provider-neutral function dossier. */
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
- import { isAbsoluteLocalPath, localPathStringSchema } from "../localPath.js";
3
- const pathInputSchema = localPathStringSchema.refine(isAbsoluteLocalPath, {
2
+ import { isAbsolute } from "node:path";
3
+ import { localPathStringSchema } from "../localPath.js";
4
+ const pathInputSchema = localPathStringSchema.refine(isAbsolute, {
4
5
  message: "Electron executable, application, and root paths must be absolute local filesystem paths (for example /Applications/Electron.app/Contents/MacOS/Electron)",
5
6
  });
6
7
  const absolutePathSchema = z
@@ -63,7 +64,7 @@ export const electronActiveObservationInputSchema = z.strictObject({
63
64
  args: z
64
65
  .array(z
65
66
  .string()
66
- .regex(/^[^\u0000]*$/u, "Electron arguments must not contain NUL"))
67
+ .regex(/^[^\x00]*$/u, "Electron arguments must not contain NUL"))
67
68
  .default([]),
68
69
  actions: z.array(actionSchema).default([]),
69
70
  });