rea-agents 2.4.0 → 3.0.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 (231) hide show
  1. package/README.md +91 -19
  2. package/bridge/ghidra/ReaGhidraBridge.java +524 -4
  3. package/bridge/hopper_bridge.py +313 -28
  4. package/dist/application/AnalysisClientCleanup.js +14 -0
  5. package/dist/application/AnalysisContextQueries.js +130 -0
  6. package/dist/application/AnalysisSnapshotCache.js +4 -2
  7. package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
  8. package/dist/application/ArtifactInventory/scanCanonical.js +1 -1
  9. package/dist/application/BinarySession.js +20 -8
  10. package/dist/application/BinarySessionComposition.js +21 -0
  11. package/dist/application/BinarySessionRecords.js +79 -9
  12. package/dist/application/BinarySessionStatus.js +31 -1
  13. package/dist/application/BrowserEvidence.js +14 -0
  14. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  15. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  16. package/dist/application/BrowserScenarioEvidence.js +40 -0
  17. package/dist/application/CallPathTracing.js +160 -0
  18. package/dist/application/CapabilityInventory.js +84 -14
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CompositeProvider.js +10 -1
  21. package/dist/application/DirectAnalysis.js +13 -4
  22. package/dist/application/EnhancedLiteralTracing.js +118 -0
  23. package/dist/application/EnhancedTools.js +71 -127
  24. package/dist/application/EvidenceLedger.js +45 -16
  25. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  26. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  27. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  28. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  29. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  30. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  31. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  32. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  33. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  34. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  35. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  36. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  37. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  38. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  39. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  40. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  41. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  42. package/dist/application/LazyAnalysisProvider.js +77 -0
  43. package/dist/application/LoopbackReplay.js +1 -1
  44. package/dist/application/NativeApiInspection.js +80 -0
  45. package/dist/application/ProcessReactiveEffects.js +6 -0
  46. package/dist/application/ProcessReactiveHarness.js +16 -1
  47. package/dist/application/ProjectPermissionStore.js +1 -0
  48. package/dist/application/ReconstructionObligationAuthority.js +72 -0
  49. package/dist/application/ReconstructionObligationCandidates.js +265 -0
  50. package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
  51. package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
  52. package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
  53. package/dist/application/ReconstructionObligationLedgerService.js +72 -0
  54. package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
  55. package/dist/application/ReconstructionObligationPolicies.js +132 -0
  56. package/dist/application/ReconstructionReadinessService.js +48 -0
  57. package/dist/application/SessionProviderRouter.js +6 -6
  58. package/dist/application/SetupClientConfiguration.js +4 -2
  59. package/dist/application/runtime.js +26 -9
  60. package/dist/artifacts/ArtifactProvider.js +87 -22
  61. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  62. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  63. package/dist/browser/CdpBrowserProvider.js +2 -2
  64. package/dist/browser/CdpCaptureDocuments.js +57 -0
  65. package/dist/browser/CdpCaptureStorage.js +71 -29
  66. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  67. package/dist/browser/CdpEndpoint.js +8 -6
  68. package/dist/browser/CdpPageCapture.js +2 -0
  69. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  70. package/dist/browser/PlaywrightBrowserScenarioProvider.js +259 -0
  71. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  72. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  73. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  74. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  75. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  76. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  77. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  78. package/dist/browser/V8InspectorEndpoint.js +72 -0
  79. package/dist/browser/V8InspectorProvider.js +267 -0
  80. package/dist/catalogIdentity.js +11 -3
  81. package/dist/cli/artifactCommands.js +44 -3
  82. package/dist/cli/coreAnalysisCommands.js +78 -0
  83. package/dist/cli.js +4 -0
  84. package/dist/cliApplicationCommands.js +30 -2
  85. package/dist/cliBrowserAdvancedCommands.js +17 -5
  86. package/dist/cliBrowserCommands.js +1 -0
  87. package/dist/cliBrowserScenarioCommands.js +43 -0
  88. package/dist/cliCommandNames.js +9 -0
  89. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  90. package/dist/cliObservationOptions.js +4 -0
  91. package/dist/cliPolicyCommands.js +1 -0
  92. package/dist/config/environment.js +12 -0
  93. package/dist/config/parseConfig.js +88 -17
  94. package/dist/contracts/analysisSearchContract.js +14 -0
  95. package/dist/contracts/applicationToolContracts.js +86 -2
  96. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  97. package/dist/contracts/artifactToolContracts.js +29 -2
  98. package/dist/contracts/browserProviderToolContracts.js +7 -0
  99. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  100. package/dist/contracts/browserToolContracts.js +88 -98
  101. package/dist/contracts/enhancedInputs.js +35 -6
  102. package/dist/contracts/functionInstructionContract.js +8 -0
  103. package/dist/contracts/functionWorkflowToolContracts.js +30 -0
  104. package/dist/contracts/hopperMemoryContracts.js +22 -0
  105. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  106. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  107. package/dist/contracts/promptContracts.js +14 -15
  108. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  109. package/dist/contracts/toolContractExamples.js +8 -0
  110. package/dist/contracts/toolContractTypes.js +1 -0
  111. package/dist/contracts/toolContracts.js +34 -25
  112. package/dist/contracts/toolEffects.js +25 -0
  113. package/dist/contracts/toolOutputSchemaGroups.js +120 -30
  114. package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
  115. package/dist/domain/analysisErrorPresentation.js +8 -2
  116. package/dist/domain/analysisErrorProjection.js +9 -0
  117. package/dist/domain/artifactInspection.js +347 -0
  118. package/dist/domain/browserCaptureComparison.js +82 -0
  119. package/dist/domain/browserObservation.js +8 -1
  120. package/dist/domain/browserObservationErrors.js +1 -0
  121. package/dist/domain/browserObservationSchemas.js +26 -0
  122. package/dist/domain/browserScenario.js +165 -0
  123. package/dist/domain/browserScenarioCapture.js +57 -0
  124. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  125. package/dist/domain/browserScenarioDiff.js +324 -0
  126. package/dist/domain/browserScenarioDiffValues.js +157 -0
  127. package/dist/domain/browserScenarioNormalization.js +45 -0
  128. package/dist/domain/browserScenarioValues.js +372 -0
  129. package/dist/domain/bytecodeProvider.js +179 -0
  130. package/dist/domain/conformancePackage.js +169 -0
  131. package/dist/domain/conformanceReplay.js +104 -0
  132. package/dist/domain/conformanceTrustGate.js +193 -0
  133. package/dist/domain/customProtocolCapture.js +137 -0
  134. package/dist/domain/eventProcessTree.js +214 -0
  135. package/dist/domain/evidenceBundle.js +47 -0
  136. package/dist/domain/hopperStartupFailure.js +1 -1
  137. package/dist/domain/hopperValues.js +14 -1
  138. package/dist/domain/inputIssueProjection.js +7 -1
  139. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  140. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  141. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  142. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  143. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +13 -16
  145. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  146. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  147. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  148. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  149. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  150. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  151. package/dist/domain/javascriptSemanticIr.js +21 -1
  152. package/dist/domain/javascriptSemanticObjects.js +115 -0
  153. package/dist/domain/javascriptSemanticPromises.js +290 -0
  154. package/dist/domain/javascriptSemanticResources.js +136 -0
  155. package/dist/domain/javascriptSourceParser.js +15 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +12 -15
  157. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  158. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  159. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  160. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  161. package/dist/domain/nativeApiBoundary.js +130 -0
  162. package/dist/domain/objcSwiftMetadata.js +150 -0
  163. package/dist/domain/packageAnalysis.js +123 -0
  164. package/dist/domain/peInspection.js +196 -0
  165. package/dist/domain/processCapture.js +8 -2
  166. package/dist/domain/processReactiveScenario.js +1 -0
  167. package/dist/domain/processReactiveTransition.js +9 -4
  168. package/dist/domain/protocolCapture.js +243 -0
  169. package/dist/domain/providerCleanupError.js +11 -0
  170. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  171. package/dist/domain/reconstructionReadiness.js +121 -0
  172. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  173. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  174. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  175. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  176. package/dist/domain/sourceToBundleComparison.js +335 -0
  177. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  178. package/dist/domain/sourceToBundleSignals.js +202 -0
  179. package/dist/domain/webCaptureDiff.js +141 -27
  180. package/dist/domain/webScreenshot.js +1 -1
  181. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  182. package/dist/generatedMcpToolCatalog.js +37 -0
  183. package/dist/generatedPackageMetadata.js +4 -4
  184. package/dist/ghidra/GhidraDefaults.js +1 -1
  185. package/dist/ghidra/GhidraFunctionValues.js +40 -2
  186. package/dist/ghidra/GhidraProviderCapabilities.js +47 -38
  187. package/dist/hopper/HopperCleanup.js +158 -0
  188. package/dist/hopper/HopperClient.js +93 -99
  189. package/dist/hopper/HopperProvider.js +61 -30
  190. package/dist/hopper/HopperRequestQueue.js +215 -0
  191. package/dist/hopper/HopperResponseStream.js +46 -0
  192. package/dist/hopper/protocol.js +63 -20
  193. package/dist/main/transport.js +24 -27
  194. package/dist/main.js +14 -6
  195. package/dist/mcpDoctor.js +27 -4
  196. package/dist/mcpStartupPolicy.js +14 -0
  197. package/dist/process/ProcessCommandIdentity.js +19 -0
  198. package/dist/process/ProcessOwnership.js +11 -8
  199. package/dist/server/DynamicToolAvailability.js +70 -0
  200. package/dist/server/LazyToolCatalog.js +134 -0
  201. package/dist/server/createServer.js +92 -154
  202. package/dist/server/hydrateServerTools.js +191 -0
  203. package/dist/server/lifecycleProgress.js +10 -0
  204. package/dist/server/permissionFailure.js +12 -0
  205. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  206. package/dist/server/registerApplicationTools/helpers.js +11 -7
  207. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  208. package/dist/server/registerApplicationTools/readiness.js +55 -0
  209. package/dist/server/registerApplicationTools.js +6 -0
  210. package/dist/server/registerArtifactTools.js +9 -1
  211. package/dist/server/registerBrowserScenarioTool.js +25 -0
  212. package/dist/server/registerBrowserTools.js +2 -2
  213. package/dist/server/registerCloseLifecycleTool.js +57 -0
  214. package/dist/server/registerEnhancedTools.js +28 -7
  215. package/dist/server/registerEvidenceResources.js +54 -101
  216. package/dist/server/registerEvidenceTools.js +9 -2
  217. package/dist/server/registerInvestigationTools.js +1 -2
  218. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  219. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  220. package/dist/server/registerReconstructionObligationLedgerResource.js +32 -0
  221. package/dist/server/registerReconstructionReadinessResource.js +32 -0
  222. package/dist/server/registerSessionRecordTools.js +82 -12
  223. package/dist/server/registerSessionStatusTool.js +11 -8
  224. package/dist/server/registerSessionTools.js +32 -58
  225. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  226. package/dist/server/toolRegistrationOptions.js +21 -6
  227. package/dist/server/toolResult.js +12 -0
  228. package/package.json +28 -11
  229. package/scripts/package-runner-bootstrap.mjs +72 -0
  230. package/scripts/rea.mjs +11 -1
  231. package/skills/reverse-engineer-anything/SKILL.md +10 -3
@@ -0,0 +1,72 @@
1
+ const proofEvidenceAuthorities = {
2
+ unit: ["shipped-artifact", "controlled-replay"],
3
+ integration: ["controlled-replay"],
4
+ protocol: ["controlled-replay", "external-service"],
5
+ renderer: ["controlled-replay", "external-service"],
6
+ "packaged-process": ["controlled-replay"],
7
+ "native-abi": ["shipped-artifact", "controlled-replay"],
8
+ "live-observation": ["controlled-replay", "external-service"],
9
+ external: ["external-service"],
10
+ };
11
+ /** Return whether an actual reconstruction proof is comparable to a requirement. */
12
+ export const proofAuthoritySatisfies = (actual, required) => {
13
+ const accepted = {
14
+ unit: [
15
+ "unit",
16
+ "integration",
17
+ "protocol",
18
+ "renderer",
19
+ "packaged-process",
20
+ "native-abi",
21
+ "live-observation",
22
+ "external",
23
+ ],
24
+ integration: [
25
+ "integration",
26
+ "protocol",
27
+ "renderer",
28
+ "packaged-process",
29
+ "native-abi",
30
+ "live-observation",
31
+ ],
32
+ protocol: ["protocol", "packaged-process", "live-observation"],
33
+ renderer: ["renderer", "packaged-process", "live-observation"],
34
+ "packaged-process": ["packaged-process", "live-observation"],
35
+ "native-abi": ["native-abi"],
36
+ "live-observation": ["live-observation"],
37
+ external: ["external"],
38
+ };
39
+ return accepted[required].includes(actual);
40
+ };
41
+ /** Check that Evidence can authenticate the declared reconstruction authority. */
42
+ export const evidenceAuthoritySupportsProof = (evidence, authority, expected) => {
43
+ if (evidence.confidence !== "observed" ||
44
+ !proofEvidenceAuthorities[authority].includes(evidence.authority) ||
45
+ evidence.predicate_type !== "rea.reconstruction-proof/v1" ||
46
+ evidence.operation !== "verify_reconstruction_obligations")
47
+ return false;
48
+ const result = evidence.normalized_result;
49
+ if (typeof result !== "object" || result === null || Array.isArray(result))
50
+ return false;
51
+ const includes = (key, value) => value === undefined ||
52
+ (Array.isArray(result[key]) && result[key].includes(value));
53
+ return (result.passed === true &&
54
+ includes("obligation_ids", expected.obligationId) &&
55
+ includes("fixture_ids", expected.fixtureId) &&
56
+ includes("case_kinds", expected.caseKind) &&
57
+ includes("verifier_ids", expected.verifierId) &&
58
+ includes("claim_ids", expected.claimId));
59
+ };
60
+ /** Check that Evidence observes the original at the required boundary. */
61
+ export const evidenceSupportsOriginalAuthority = (evidence, authority) => {
62
+ if (evidence.confidence !== "observed")
63
+ return false;
64
+ if (authority === "static")
65
+ return evidence.authority === "shipped-artifact";
66
+ if (authority === "runtime")
67
+ return ["controlled-replay", "external-service"].includes(evidence.authority);
68
+ if (authority === "process")
69
+ return (evidence.operation === "capture_process_scenario" &&
70
+ evidence.predicate_type === "rea.process-capture/v4");
71
+ return evidence.authority === "external-service";
72
+ };
@@ -0,0 +1,265 @@
1
+ import { createHash } from "node:crypto";
2
+ import canonicalize from "canonicalize";
3
+ import { parseEvidenceBundle, } from "../domain/evidenceBundle.js";
4
+ import { parseProcessCapture } from "../domain/processCapture.js";
5
+ import { parseApplicationGraphEvidence } from "./JavaScriptApplicationEvidenceGraph.js";
6
+ import { applicationObligationPolicy, semanticObligationPolicy, } from "./ReconstructionObligationPolicies.js";
7
+ /** Derive conservative candidates from graph, process, and reviewed inputs. */
8
+ export const deriveReconstructionObligationCandidates = (bundleInput, reviewed) => {
9
+ const bundle = parseEvidenceBundle(bundleInput);
10
+ const records = new Map(bundle.records.map((record) => [record.evidence_id, record]));
11
+ const candidates = new Map();
12
+ const limitations = new Set();
13
+ for (const evidence of bundle.records) {
14
+ deriveApplicationCandidates(evidence, records, candidates, limitations);
15
+ deriveProcessCandidate(evidence, candidates, limitations);
16
+ }
17
+ for (const obligation of reviewed)
18
+ addCandidate(candidates, reviewedCandidate(obligation, records));
19
+ return {
20
+ candidates: [...candidates.values()].sort((left, right) => left.obligation_id.localeCompare(right.obligation_id)),
21
+ limitations: [...limitations].sort(),
22
+ };
23
+ };
24
+ const deriveApplicationCandidates = (evidence, records, candidates, limitations) => {
25
+ if (![
26
+ "analyze_javascript_application",
27
+ "reconcile_javascript_runtime",
28
+ "project_managed_application_graph",
29
+ ].includes(evidence.operation))
30
+ return;
31
+ try {
32
+ const source = parseApplicationGraphEvidence(evidence);
33
+ for (const node of source.graph.nodes) {
34
+ const candidatePolicy = applicationObligationPolicy(node.kind);
35
+ if (candidatePolicy === undefined)
36
+ continue;
37
+ const reference = node.observations.map((observation) => graphReference(evidence, records, observation.evidence, `${source.graph.graph_id}/node/${node.node_id}/observation/${observation.observation_id}`));
38
+ addCandidate(candidates, generatedCandidate({
39
+ key: `application:${node.node_id}:${candidatePolicy.family}`,
40
+ title: node.observations[0]?.label ?? `${node.kind} boundary`,
41
+ policy: candidatePolicy,
42
+ artifactSha256: source.rootArtifactSha256,
43
+ applicationNodeId: node.node_id,
44
+ semanticNodeId: null,
45
+ location: `application-graph:${source.graph.graph_id}/nodes/${node.node_id}`,
46
+ authorityReferences: reference,
47
+ }));
48
+ }
49
+ if (source.semanticGraph !== null)
50
+ for (const node of source.semanticGraph.nodes) {
51
+ const candidatePolicy = semanticObligationPolicy(node.kind);
52
+ if (candidatePolicy === undefined)
53
+ continue;
54
+ addCandidate(candidates, generatedCandidate({
55
+ key: `semantic:${node.node_id}:${candidatePolicy.family}`,
56
+ title: node.label ?? `${node.kind} semantic boundary`,
57
+ policy: candidatePolicy,
58
+ artifactSha256: node.identity.artifact_sha256,
59
+ applicationNodeId: node.application_node_ids[0] ?? null,
60
+ semanticNodeId: node.node_id,
61
+ location: `semantic-graph:${source.semanticGraph.graph_id}/nodes/${node.node_id}`,
62
+ authorityReferences: [
63
+ graphReference(evidence, records, node.evidence, `${source.semanticGraph.graph_id}/node/${node.node_id}`),
64
+ ],
65
+ }));
66
+ }
67
+ if (source.graph.coverage.status !== "complete")
68
+ limitations.add(`Application graph ${source.graph.graph_id} coverage is ${source.graph.coverage.status}; omitted candidates remain unknown.`);
69
+ }
70
+ catch (cause) {
71
+ limitations.add(`Application Evidence ${evidence.evidence_id} could not generate candidates: ${errorMessage(cause)}`);
72
+ }
73
+ };
74
+ const deriveProcessCandidate = (evidence, candidates, limitations) => {
75
+ if (evidence.operation !== "capture_process_scenario" ||
76
+ evidence.predicate_type !== "rea.process-capture/v4")
77
+ return;
78
+ try {
79
+ const capture = parseProcessCapture(evidence.normalized_result);
80
+ const observedCases = [
81
+ {
82
+ kind: capture.exit.code === 0 ? "positive" : "negative",
83
+ evidence_id: evidence.evidence_id,
84
+ location: "/normalized_result/exit",
85
+ },
86
+ {
87
+ kind: "teardown",
88
+ evidence_id: evidence.evidence_id,
89
+ location: "/normalized_result/settlement",
90
+ },
91
+ ...(capture.exit.signal !== null || capture.exit.reason !== "exited"
92
+ ? [
93
+ {
94
+ kind: "cancellation",
95
+ evidence_id: evidence.evidence_id,
96
+ location: "/normalized_result/exit",
97
+ },
98
+ ]
99
+ : []),
100
+ ];
101
+ addCandidate(candidates, {
102
+ obligation_id: obligationId(`process:${capture.manifest.executable_sha256}:${capture.manifest.full_scenario_sha256}`),
103
+ obligation_version: 1,
104
+ title: "Captured packaged-process lifecycle",
105
+ origin: "generated",
106
+ application_layer: "process",
107
+ family: "packaged-process-lifecycle",
108
+ target: {
109
+ artifact_sha256: capture.manifest.executable_sha256,
110
+ application_node_id: null,
111
+ semantic_node_id: null,
112
+ location: `/evidence/${evidence.evidence_id}/normalized_result`,
113
+ },
114
+ authority_references: [
115
+ {
116
+ evidence_id: evidence.evidence_id,
117
+ authority: evidence.authority,
118
+ state: "observed",
119
+ location: "/normalized_result",
120
+ },
121
+ ],
122
+ source_state: "observed",
123
+ observed_cases: observedCases,
124
+ required: true,
125
+ required_case_kinds: ["positive", "negative", "cancellation", "teardown"],
126
+ required_original_authority: "process",
127
+ required_fixture_authority: "packaged-process",
128
+ required_verifier_authority: "packaged-process",
129
+ requires_parser_type: false,
130
+ dependency_obligation_ids: [],
131
+ residual_unknown_ids: [],
132
+ unavailable_authority: capture.residual_unknowns.map(({ scope, reason }) => `${scope}: ${reason}`),
133
+ required_next_evidence: capture.truncated
134
+ ? ["Repeat the packaged-process capture without truncation."]
135
+ : [],
136
+ definitionCount: 1,
137
+ disposition: "active",
138
+ });
139
+ if (capture.truncated)
140
+ limitations.add(`Process Evidence ${evidence.evidence_id} is truncated; absence and upper bounds remain unknown.`);
141
+ }
142
+ catch (cause) {
143
+ limitations.add(`Process Evidence ${evidence.evidence_id} could not generate candidates: ${errorMessage(cause)}`);
144
+ }
145
+ };
146
+ const generatedCandidate = ({ key, title, policy: candidatePolicy, artifactSha256, applicationNodeId, semanticNodeId, location, authorityReferences, }) => ({
147
+ obligation_id: obligationId(key),
148
+ obligation_version: 1,
149
+ title: title.slice(0, 500),
150
+ origin: "generated",
151
+ application_layer: candidatePolicy.applicationLayer,
152
+ family: candidatePolicy.family,
153
+ target: {
154
+ artifact_sha256: artifactSha256,
155
+ application_node_id: applicationNodeId,
156
+ semantic_node_id: semanticNodeId,
157
+ location,
158
+ },
159
+ authority_references: authorityReferences,
160
+ source_state: sourceState(authorityReferences),
161
+ observed_cases: [],
162
+ required: true,
163
+ required_case_kinds: candidatePolicy.cases,
164
+ required_original_authority: candidatePolicy.originalAuthority,
165
+ required_fixture_authority: candidatePolicy.fixtureAuthority,
166
+ required_verifier_authority: candidatePolicy.verifierAuthority,
167
+ requires_parser_type: candidatePolicy.requiresParserType,
168
+ dependency_obligation_ids: [],
169
+ residual_unknown_ids: [],
170
+ unavailable_authority: [],
171
+ required_next_evidence: [
172
+ `Obtain ${candidatePolicy.originalAuthority} authority for this finite ${candidatePolicy.family} claim.`,
173
+ ],
174
+ definitionCount: 1,
175
+ disposition: "active",
176
+ });
177
+ const reviewedCandidate = (obligation, records) => {
178
+ const { review_evidence_ids: reviewEvidenceIds, disposition, ...definition } = obligation;
179
+ return {
180
+ ...definition,
181
+ origin: "reviewed",
182
+ authority_references: reviewEvidenceIds.map((evidenceId) => {
183
+ const evidence = records.get(evidenceId);
184
+ if (evidence === undefined)
185
+ throw new TypeError(`Reviewed obligation Evidence is missing: ${evidenceId}`);
186
+ return {
187
+ evidence_id: evidenceId,
188
+ authority: evidence.authority,
189
+ state: reviewedEvidenceState(evidence),
190
+ location: `/evidence/${evidenceId}`,
191
+ };
192
+ }),
193
+ source_state: "reviewed",
194
+ observed_cases: [],
195
+ definitionCount: 1,
196
+ disposition,
197
+ };
198
+ };
199
+ const graphReference = (envelope, records, graphEvidence, location) => {
200
+ const linkedId = graphEvidence.evidence_ids.find((evidenceId) => records.has(evidenceId)) ??
201
+ envelope.evidence_id;
202
+ const linked = records.get(linkedId) ?? envelope;
203
+ const runtimeAuthority = [
204
+ "passive-cdp-runtime",
205
+ "controlled-replay",
206
+ ].includes(graphEvidence.authority);
207
+ return {
208
+ evidence_id: linked.evidence_id,
209
+ authority: linked.authority,
210
+ state: runtimeAuthority && graphEvidence.state === "observed"
211
+ ? "observed"
212
+ : graphEvidence.state === "unknown" ||
213
+ graphEvidence.state === "unavailable"
214
+ ? "unknown"
215
+ : "candidate",
216
+ location,
217
+ };
218
+ };
219
+ const reviewedEvidenceState = (evidence) => {
220
+ if (evidence.operation === "capture_process_scenario" &&
221
+ evidence.predicate_type === "rea.process-capture/v4" &&
222
+ evidence.confidence === "observed")
223
+ return "observed";
224
+ if (evidence.authority === "external-service" &&
225
+ evidence.confidence === "observed")
226
+ return "observed";
227
+ if (evidence.authority === "shipped-artifact")
228
+ return "candidate";
229
+ return "reviewed";
230
+ };
231
+ const addCandidate = (candidates, candidate) => {
232
+ const current = candidates.get(candidate.obligation_id);
233
+ if (current === undefined) {
234
+ candidates.set(candidate.obligation_id, candidate);
235
+ return;
236
+ }
237
+ candidates.set(candidate.obligation_id, {
238
+ ...current,
239
+ authority_references: uniqueBy([...current.authority_references, ...candidate.authority_references], (reference) => `${reference.evidence_id}:${reference.state}:${reference.location}`),
240
+ observed_cases: uniqueBy([...current.observed_cases, ...candidate.observed_cases], (item) => `${item.kind}:${item.evidence_id}:${item.location}`),
241
+ source_state: sourceState([
242
+ ...current.authority_references,
243
+ ...candidate.authority_references,
244
+ ]),
245
+ definitionCount: current.definitionCount + candidate.definitionCount,
246
+ });
247
+ };
248
+ const sourceState = (references) => {
249
+ if (references.some(({ state }) => state === "observed"))
250
+ return "observed";
251
+ if (references.some(({ state }) => state === "candidate"))
252
+ return "candidate";
253
+ if (references.some(({ state }) => state === "reviewed"))
254
+ return "reviewed";
255
+ return "unknown";
256
+ };
257
+ const uniqueBy = (values, key) => [...new Map(values.map((value) => [key(value), value])).values()].sort((left, right) => key(left).localeCompare(key(right)));
258
+ const obligationId = (key) => `obl_${digest({ schema: "rea.reconstruction-obligation/v1", key })}`;
259
+ const digest = (value) => {
260
+ const encoded = canonicalize(value);
261
+ if (encoded === undefined)
262
+ throw new TypeError("Reconstruction obligation key is not canonical JSON");
263
+ return createHash("sha256").update(encoded).digest("hex");
264
+ };
265
+ const errorMessage = (cause) => cause instanceof Error ? cause.message : "unknown validation failure";
@@ -0,0 +1,47 @@
1
+ export const groupManifestBindings = (manifest) => {
2
+ const grouped = new Map();
3
+ for (const binding of manifest.bindings)
4
+ grouped.set(binding.obligation_id, [
5
+ ...(grouped.get(binding.obligation_id) ?? []),
6
+ binding,
7
+ ]);
8
+ return grouped;
9
+ };
10
+ export const groupManifestContradictions = (manifest) => {
11
+ const grouped = new Map();
12
+ for (const contradiction of manifest.contradictions)
13
+ grouped.set(contradiction.obligation_id, [
14
+ ...(grouped.get(contradiction.obligation_id) ?? []),
15
+ ...contradiction.evidence_ids,
16
+ ]);
17
+ return grouped;
18
+ };
19
+ export const addObligationDiagnostic = (diagnostics, code, detail) => {
20
+ diagnostics.push({ code, detail });
21
+ };
22
+ export const uniqueObligationDiagnostics = (diagnostics) => [
23
+ ...new Map(diagnostics.map((diagnostic) => [
24
+ `${diagnostic.code}:${diagnostic.detail}`,
25
+ diagnostic,
26
+ ])).values(),
27
+ ].sort((left, right) => `${left.code}:${left.detail}`.localeCompare(`${right.code}:${right.detail}`));
28
+ export const hasObligationDiagnostic = (diagnostics, code) => diagnostics.some((diagnostic) => diagnostic.code === code);
29
+ export const contradictionDiagnostics = (obligationId, contradictions, evidenceById) => {
30
+ const evidenceIds = contradictions.get(obligationId) ?? [];
31
+ if (evidenceIds.length === 0)
32
+ return [];
33
+ const missing = evidenceIds.filter((evidenceId) => !evidenceById.has(evidenceId));
34
+ return missing.length > 0
35
+ ? [
36
+ {
37
+ code: "contradiction-evidence-missing",
38
+ detail: `Contradiction references missing Evidence: ${missing.join(", ")}.`,
39
+ },
40
+ ]
41
+ : [
42
+ {
43
+ code: "contradiction",
44
+ detail: "Authenticated contradictory Evidence reopens this obligation.",
45
+ },
46
+ ];
47
+ };
@@ -0,0 +1,263 @@
1
+ import { parseEvidenceBundle, } from "../domain/evidenceBundle.js";
2
+ import { reconstructionObligationLedgerSchema, } from "../domain/reconstructionObligationLedgerSchemas.js";
3
+ import { evidenceAuthoritySupportsProof, evidenceSupportsOriginalAuthority, proofAuthoritySatisfies, } from "./ReconstructionObligationAuthority.js";
4
+ import { addObligationDiagnostic as addDiagnostic, contradictionDiagnostics, groupManifestBindings, groupManifestContradictions, hasObligationDiagnostic as hasDiagnostic, uniqueObligationDiagnostics as uniqueDiagnostics, } from "./ReconstructionObligationLedgerDiagnostics.js";
5
+ import { originalCaseDiagnostics, originalCasesFor, } from "./ReconstructionObligationOriginalCases.js";
6
+ import { digestObligationLedgerValue, obligationLedgerCoverage, obligationEdgeOrder, obligationLedgerEvidenceLinks, obligationLedgerStatus, obligationReports, summarizeObligations, } from "./ReconstructionObligationLedgerProjection.js";
7
+ export const evaluateReconstructionObligationLedger = ({ candidates: candidatesInput, bundle: bundleInput, manifest, maxObligations, generationLimitations, }) => {
8
+ const bundle = parseEvidenceBundle(bundleInput);
9
+ const allCandidates = [...candidatesInput].sort((left, right) => left.obligation_id.localeCompare(right.obligation_id));
10
+ const orphanManifestIds = findOrphanManifestIds(allCandidates, manifest);
11
+ const candidates = allCandidates.slice(0, maxObligations);
12
+ const omittedCount = allCandidates.length - candidates.length;
13
+ const context = createEvaluationContext(candidates, bundle, manifest);
14
+ const obligations = applyDependencyDiagnostics(candidates.map((candidate) => evaluateObligation(candidate, context)), context);
15
+ const ownershipGraph = obligations
16
+ .flatMap((obligation) => obligation.binding === null
17
+ ? []
18
+ : [
19
+ {
20
+ obligation_id: obligation.obligation_id,
21
+ module_path: obligation.binding.owner.module_path,
22
+ symbol: obligation.binding.owner.symbol,
23
+ },
24
+ ])
25
+ .sort(obligationEdgeOrder);
26
+ const dependencyGraph = obligations
27
+ .flatMap((obligation) => obligation.dependency_obligation_ids.map((dependencyId) => ({
28
+ obligation_id: obligation.obligation_id,
29
+ depends_on_obligation_id: dependencyId,
30
+ })))
31
+ .sort(obligationEdgeOrder);
32
+ const evidenceLinks = obligationLedgerEvidenceLinks(obligations, manifest);
33
+ const limitations = ledgerLimitations(generationLimitations, allCandidates.length, omittedCount, orphanManifestIds);
34
+ const coverage = obligationLedgerCoverage(omittedCount, maxObligations, limitations.length > 0);
35
+ const semantic = {
36
+ coverage,
37
+ summary: summarizeObligations(obligations),
38
+ reports: obligationReports(obligations),
39
+ ownership_graph: ownershipGraph,
40
+ dependency_graph: dependencyGraph,
41
+ obligations,
42
+ evidence_links: evidenceLinks,
43
+ limitations,
44
+ };
45
+ const evaluatedStatus = obligationLedgerStatus(obligations, omittedCount);
46
+ const status = evaluatedStatus === "failed"
47
+ ? evaluatedStatus
48
+ : limitations.length > 0
49
+ ? "unknown"
50
+ : evaluatedStatus;
51
+ const closureDigest = digestObligationLedgerValue({
52
+ schema: "rea.reconstruction-obligation-closure/v1",
53
+ status,
54
+ ...semantic,
55
+ });
56
+ return reconstructionObligationLedgerSchema.parse({
57
+ schema: "ReconstructionObligationLedger",
58
+ schema_version: 1,
59
+ ledger_id: `rol_${digestObligationLedgerValue({
60
+ schema: "rea.reconstruction-obligation-ledger/v1",
61
+ evidence_ids: bundle.records.map(({ evidence_id: id }) => id),
62
+ obligation_ids: obligations.map(({ obligation_id: id }) => id),
63
+ closure_digest: closureDigest,
64
+ })}`,
65
+ closure_digest: closureDigest,
66
+ status,
67
+ ...semantic,
68
+ });
69
+ };
70
+ const createEvaluationContext = (candidates, bundle, manifest) => ({
71
+ candidates: new Map(candidates.map((candidate) => [candidate.obligation_id, candidate])),
72
+ evidence: new Map(bundle.records.map((evidence) => [evidence.evidence_id, evidence])),
73
+ bindings: groupManifestBindings(manifest),
74
+ contradictions: groupManifestContradictions(manifest),
75
+ });
76
+ const findOrphanManifestIds = (candidates, manifest) => {
77
+ const candidateIds = new Set(candidates.map(({ obligation_id: obligationId }) => obligationId));
78
+ return [
79
+ ...new Set([
80
+ ...manifest.bindings.map(({ obligation_id: obligationId }) => obligationId),
81
+ ...manifest.contradictions.map(({ obligation_id: obligationId }) => obligationId),
82
+ ].filter((obligationId) => !candidateIds.has(obligationId))),
83
+ ].sort();
84
+ };
85
+ const ledgerLimitations = (generationLimitations, candidateCount, omittedCount, orphanManifestIds) => [
86
+ ...new Set([
87
+ ...generationLimitations,
88
+ ...(candidateCount === 0
89
+ ? [
90
+ "No reconstruction obligations were derived; closure cannot be claimed.",
91
+ ]
92
+ : []),
93
+ ...(omittedCount > 0
94
+ ? [
95
+ `${String(omittedCount)} obligation candidates were omitted by max_obligations; closure is unknown.`,
96
+ ]
97
+ : []),
98
+ ...(orphanManifestIds.length > 0
99
+ ? [
100
+ `Manifest entries reference unknown obligations: ${orphanManifestIds.join(", ")}.`,
101
+ ]
102
+ : []),
103
+ ]),
104
+ ].sort();
105
+ const evaluateObligation = (candidate, context) => {
106
+ const bindings = context.bindings.get(candidate.obligation_id) ?? [];
107
+ const binding = bindings.length === 1 ? (bindings[0] ?? null) : null;
108
+ const diagnostics = [];
109
+ if (candidate.definitionCount > 1)
110
+ addDiagnostic(diagnostics, "duplicate-definition", "Multiple candidate definitions share this obligation ID.");
111
+ if (bindings.length === 0)
112
+ addDiagnostic(diagnostics, "missing-owner", "No reconstruction manifest binding owns this obligation.");
113
+ if (bindings.length > 1)
114
+ addDiagnostic(diagnostics, "ambiguous-owner", "Multiple reconstruction manifest bindings claim this obligation.");
115
+ if (binding !== null)
116
+ evaluateBinding(candidate, binding, context, diagnostics);
117
+ diagnostics.push(...originalCaseDiagnostics(candidate, binding, context.evidence));
118
+ evaluateAuthority(candidate, binding, context, diagnostics);
119
+ evaluateDisposition(candidate, diagnostics);
120
+ diagnostics.push(...contradictionDiagnostics(candidate.obligation_id, context.contradictions, context.evidence));
121
+ for (const unknownId of candidate.residual_unknown_ids)
122
+ addDiagnostic(diagnostics, "residual-unknown", `Residual unknown remains visible: ${unknownId}.`);
123
+ for (const unavailable of candidate.unavailable_authority)
124
+ addDiagnostic(diagnostics, "unavailable-authority", unavailable);
125
+ return {
126
+ obligation_id: candidate.obligation_id,
127
+ obligation_version: candidate.obligation_version,
128
+ title: candidate.title,
129
+ origin: candidate.origin,
130
+ application_layer: candidate.application_layer,
131
+ family: candidate.family,
132
+ target: candidate.target,
133
+ authority_references: candidate.authority_references,
134
+ source_state: candidate.source_state,
135
+ observed_cases: originalCasesFor(candidate, binding),
136
+ required: candidate.required,
137
+ required_case_kinds: candidate.required_case_kinds,
138
+ required_original_authority: candidate.required_original_authority,
139
+ required_fixture_authority: candidate.required_fixture_authority,
140
+ required_verifier_authority: candidate.required_verifier_authority,
141
+ requires_parser_type: candidate.requires_parser_type,
142
+ dependency_obligation_ids: candidate.dependency_obligation_ids,
143
+ residual_unknown_ids: candidate.residual_unknown_ids,
144
+ unavailable_authority: candidate.unavailable_authority,
145
+ required_next_evidence: candidate.required_next_evidence,
146
+ binding,
147
+ status: obligationStatus(candidate, binding, diagnostics),
148
+ diagnostics: uniqueDiagnostics(diagnostics),
149
+ };
150
+ };
151
+ const evaluateBinding = (candidate, binding, context, diagnostics) => {
152
+ if (candidate.requires_parser_type && binding.parser_type === null)
153
+ addDiagnostic(diagnostics, "missing-parser-type", "This boundary requires an explicit parser, schema, and domain type.");
154
+ for (const caseKind of candidate.required_case_kinds) {
155
+ const fixtures = binding.fixtures.filter(({ case_kind: fixtureCase }) => fixtureCase === caseKind);
156
+ if (fixtures.length === 0) {
157
+ addDiagnostic(diagnostics, "missing-case", `Required ${caseKind} fixture is missing.`);
158
+ continue;
159
+ }
160
+ if (!fixtures.some((fixture) => proofAuthoritySatisfies(fixture.authority, candidate.required_fixture_authority) &&
161
+ fixture.evidence_ids.every((id) => {
162
+ const evidence = context.evidence.get(id);
163
+ return (evidence !== undefined &&
164
+ evidenceAuthoritySupportsProof(evidence, fixture.authority, {
165
+ obligationId: candidate.obligation_id,
166
+ fixtureId: fixture.fixture_id,
167
+ caseKind: fixture.case_kind,
168
+ }));
169
+ })))
170
+ addDiagnostic(diagnostics, "weak-fixture-authority", `${caseKind} fixture lacks ${candidate.required_fixture_authority} authority or authenticated Evidence.`);
171
+ }
172
+ evaluateVerifier(candidate, binding, context, diagnostics);
173
+ };
174
+ const evaluateVerifier = (candidate, binding, context, diagnostics) => {
175
+ const verifier = binding.verifier;
176
+ if (verifier === null) {
177
+ addDiagnostic(diagnostics, "missing-verifier", "No verifier claim is bound to this obligation.");
178
+ return;
179
+ }
180
+ if (!verifier.enumerated_obligation_ids.includes(candidate.obligation_id))
181
+ addDiagnostic(diagnostics, "verifier-does-not-enumerate", "The verifier claim does not enumerate this obligation ID.");
182
+ const resultEvidence = context.evidence.get(verifier.result_evidence_id);
183
+ if (resultEvidence === undefined)
184
+ addDiagnostic(diagnostics, "missing-verifier-result", "The latest verifier result Evidence is absent from the bundle.");
185
+ if (!proofAuthoritySatisfies(verifier.authority, candidate.required_verifier_authority) ||
186
+ (resultEvidence !== undefined &&
187
+ !evidenceAuthoritySupportsProof(resultEvidence, verifier.authority, {
188
+ obligationId: candidate.obligation_id,
189
+ verifierId: verifier.verifier_id,
190
+ claimId: verifier.claim_id,
191
+ })))
192
+ addDiagnostic(diagnostics, "weak-verifier-authority", `Verifier authority does not satisfy ${candidate.required_verifier_authority}.`);
193
+ if (verifier.status !== "pass")
194
+ addDiagnostic(diagnostics, "verifier-failed", `Latest verifier status is ${verifier.status}.`);
195
+ };
196
+ const evaluateAuthority = (candidate, binding, context, diagnostics) => {
197
+ const referenceSatisfied = candidate.authority_references.some((reference) => {
198
+ const evidence = context.evidence.get(reference.evidence_id);
199
+ return (evidence !== undefined &&
200
+ (candidate.required_original_authority === "static"
201
+ ? ["candidate", "observed"].includes(reference.state)
202
+ : reference.state === "observed") &&
203
+ evidenceSupportsOriginalAuthority(evidence, candidate.required_original_authority));
204
+ });
205
+ const caseSatisfied = originalCasesFor(candidate, binding).some(({ evidence_id: evidenceId }) => {
206
+ const evidence = context.evidence.get(evidenceId);
207
+ return (evidence !== undefined &&
208
+ evidenceSupportsOriginalAuthority(evidence, candidate.required_original_authority));
209
+ });
210
+ const satisfied = referenceSatisfied || caseSatisfied;
211
+ if (!satisfied)
212
+ addDiagnostic(diagnostics, "static-only", `No ${candidate.required_original_authority} authority characterizes the original finite behavior.`);
213
+ };
214
+ const evaluateDisposition = (candidate, diagnostics) => {
215
+ if (candidate.disposition === "blocked")
216
+ addDiagnostic(diagnostics, "blocked", "Reviewed disposition marks this obligation blocked.");
217
+ if (candidate.disposition === "out-of-scope")
218
+ addDiagnostic(diagnostics, "out-of-scope", "Reviewed disposition marks this obligation out of scope; it remains visible.");
219
+ };
220
+ const applyDependencyDiagnostics = (obligations, context) => {
221
+ let evaluated = [...obligations];
222
+ for (let pass = 0; pass < obligations.length; pass += 1) {
223
+ const statuses = new Map(evaluated.map(({ obligation_id: id, status }) => [id, status]));
224
+ let changed = false;
225
+ evaluated = evaluated.map((obligation) => {
226
+ const diagnostics = [...obligation.diagnostics];
227
+ for (const dependencyId of obligation.dependency_obligation_ids) {
228
+ const missing = !context.candidates.has(dependencyId);
229
+ if (missing || statuses.get(dependencyId) !== "verified")
230
+ addDiagnostic(diagnostics, missing ? "dependency-missing" : "dependency-open", `Dependency obligation is ${missing ? "missing" : "not verified"}: ${dependencyId}.`);
231
+ }
232
+ const normalized = uniqueDiagnostics(diagnostics);
233
+ const status = dependencyStatus(obligation.status, normalized);
234
+ changed ||= status !== obligation.status;
235
+ return { ...obligation, status, diagnostics: normalized };
236
+ });
237
+ if (!changed)
238
+ break;
239
+ }
240
+ return evaluated;
241
+ };
242
+ const obligationStatus = (candidate, binding, diagnostics) => {
243
+ if (hasDiagnostic(diagnostics, "out-of-scope"))
244
+ return "out-of-scope";
245
+ if (hasDiagnostic(diagnostics, "blocked"))
246
+ return "blocked";
247
+ if (hasDiagnostic(diagnostics, "contradiction"))
248
+ return "contradicted";
249
+ if (hasDiagnostic(diagnostics, "duplicate-definition") ||
250
+ hasDiagnostic(diagnostics, "residual-unknown") ||
251
+ hasDiagnostic(diagnostics, "unavailable-authority"))
252
+ return "unknown";
253
+ if (binding === null)
254
+ return "unowned";
255
+ if (diagnostics.length === 0)
256
+ return "verified";
257
+ return "implemented";
258
+ };
259
+ const dependencyStatus = (status, diagnostics) => (hasDiagnostic(diagnostics, "dependency-missing") ||
260
+ hasDiagnostic(diagnostics, "dependency-open")) &&
261
+ !["contradicted", "out-of-scope"].includes(status)
262
+ ? "blocked"
263
+ : status;