@veraanchor/verifier 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/CONTRIBUTING.md +33 -0
  3. package/LICENSE +21 -0
  4. package/NOTICE +4 -0
  5. package/README.md +263 -2
  6. package/SECURITY.md +21 -0
  7. package/dist/cli/commandV1.d.ts +5 -0
  8. package/dist/cli/commandV1.d.ts.map +1 -0
  9. package/dist/cli/commandV1.js +440 -0
  10. package/dist/cli/commandV1.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +5 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/contracts/verification.d.ts +77 -0
  16. package/dist/contracts/verification.d.ts.map +1 -0
  17. package/dist/contracts/verification.js +6 -0
  18. package/dist/contracts/verification.js.map +1 -0
  19. package/dist/crypto/sha3.d.ts +15 -0
  20. package/dist/crypto/sha3.d.ts.map +1 -0
  21. package/dist/crypto/sha3.js +27 -0
  22. package/dist/crypto/sha3.js.map +1 -0
  23. package/dist/crypto/streamSha3.d.ts +26 -0
  24. package/dist/crypto/streamSha3.d.ts.map +1 -0
  25. package/dist/crypto/streamSha3.js +52 -0
  26. package/dist/crypto/streamSha3.js.map +1 -0
  27. package/dist/hf/hashContractV1.d.ts +48 -0
  28. package/dist/hf/hashContractV1.d.ts.map +1 -0
  29. package/dist/hf/hashContractV1.js +185 -0
  30. package/dist/hf/hashContractV1.js.map +1 -0
  31. package/dist/index.d.ts +80 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +57 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/merkle/membership.d.ts +30 -0
  36. package/dist/merkle/membership.d.ts.map +1 -0
  37. package/dist/merkle/membership.js +105 -0
  38. package/dist/merkle/membership.js.map +1 -0
  39. package/dist/policy/contractV1.d.ts +37 -0
  40. package/dist/policy/contractV1.d.ts.map +1 -0
  41. package/dist/policy/contractV1.js +2 -0
  42. package/dist/policy/contractV1.js.map +1 -0
  43. package/dist/policy/evaluateV1.d.ts +24 -0
  44. package/dist/policy/evaluateV1.d.ts.map +1 -0
  45. package/dist/policy/evaluateV1.js +320 -0
  46. package/dist/policy/evaluateV1.js.map +1 -0
  47. package/dist/profiles/dataset/sourceV1.d.ts +22 -0
  48. package/dist/profiles/dataset/sourceV1.d.ts.map +1 -0
  49. package/dist/profiles/dataset/sourceV1.js +73 -0
  50. package/dist/profiles/dataset/sourceV1.js.map +1 -0
  51. package/dist/profiles/dataset/v1.d.ts +39 -0
  52. package/dist/profiles/dataset/v1.d.ts.map +1 -0
  53. package/dist/profiles/dataset/v1.js +362 -0
  54. package/dist/profiles/dataset/v1.js.map +1 -0
  55. package/dist/profiles/execution/contractV1.d.ts +279 -0
  56. package/dist/profiles/execution/contractV1.d.ts.map +1 -0
  57. package/dist/profiles/execution/contractV1.js +364 -0
  58. package/dist/profiles/execution/contractV1.js.map +1 -0
  59. package/dist/profiles/execution/independentStandardsV1.d.ts +44 -0
  60. package/dist/profiles/execution/independentStandardsV1.d.ts.map +1 -0
  61. package/dist/profiles/execution/independentStandardsV1.js +336 -0
  62. package/dist/profiles/execution/independentStandardsV1.js.map +1 -0
  63. package/dist/profiles/execution/reasonCodesV1.d.ts +30 -0
  64. package/dist/profiles/execution/reasonCodesV1.d.ts.map +1 -0
  65. package/dist/profiles/execution/reasonCodesV1.js +20 -0
  66. package/dist/profiles/execution/reasonCodesV1.js.map +1 -0
  67. package/dist/profiles/execution/recomputationV1.d.ts +11 -0
  68. package/dist/profiles/execution/recomputationV1.d.ts.map +1 -0
  69. package/dist/profiles/execution/recomputationV1.js +144 -0
  70. package/dist/profiles/execution/recomputationV1.js.map +1 -0
  71. package/dist/profiles/execution/rulesV1.d.ts +6 -0
  72. package/dist/profiles/execution/rulesV1.d.ts.map +1 -0
  73. package/dist/profiles/execution/rulesV1.js +855 -0
  74. package/dist/profiles/execution/rulesV1.js.map +1 -0
  75. package/dist/profiles/execution/standardsPlanV1.d.ts +18 -0
  76. package/dist/profiles/execution/standardsPlanV1.d.ts.map +1 -0
  77. package/dist/profiles/execution/standardsPlanV1.js +16 -0
  78. package/dist/profiles/execution/standardsPlanV1.js.map +1 -0
  79. package/dist/profiles/execution/verificationV1.d.ts +28 -0
  80. package/dist/profiles/execution/verificationV1.d.ts.map +1 -0
  81. package/dist/profiles/execution/verificationV1.js +188 -0
  82. package/dist/profiles/execution/verificationV1.js.map +1 -0
  83. package/dist/profiles/ingest/sourceV1.d.ts +36 -0
  84. package/dist/profiles/ingest/sourceV1.d.ts.map +1 -0
  85. package/dist/profiles/ingest/sourceV1.js +99 -0
  86. package/dist/profiles/ingest/sourceV1.js.map +1 -0
  87. package/dist/profiles/ingest/v1.d.ts +65 -0
  88. package/dist/profiles/ingest/v1.d.ts.map +1 -0
  89. package/dist/profiles/ingest/v1.js +477 -0
  90. package/dist/profiles/ingest/v1.js.map +1 -0
  91. package/dist/profiles/sourceV1Helpers.d.ts +48 -0
  92. package/dist/profiles/sourceV1Helpers.d.ts.map +1 -0
  93. package/dist/profiles/sourceV1Helpers.js +141 -0
  94. package/dist/profiles/sourceV1Helpers.js.map +1 -0
  95. package/dist/reports/coreV1.d.ts +7 -0
  96. package/dist/reports/coreV1.d.ts.map +1 -0
  97. package/dist/reports/coreV1.js +195 -0
  98. package/dist/reports/coreV1.js.map +1 -0
  99. package/dist/reports/portableV1.d.ts +48 -0
  100. package/dist/reports/portableV1.d.ts.map +1 -0
  101. package/dist/reports/portableV1.js +279 -0
  102. package/dist/reports/portableV1.js.map +1 -0
  103. package/dist/reports/validationV1.d.ts +19 -0
  104. package/dist/reports/validationV1.d.ts.map +1 -0
  105. package/dist/reports/validationV1.js +441 -0
  106. package/dist/reports/validationV1.js.map +1 -0
  107. package/dist/resolvers/executionMirrorV1.d.ts +15 -0
  108. package/dist/resolvers/executionMirrorV1.d.ts.map +1 -0
  109. package/dist/resolvers/executionMirrorV1.js +206 -0
  110. package/dist/resolvers/executionMirrorV1.js.map +1 -0
  111. package/dist/resolvers/explorerExecutionV1.d.ts +17 -0
  112. package/dist/resolvers/explorerExecutionV1.d.ts.map +1 -0
  113. package/dist/resolvers/explorerExecutionV1.js +61 -0
  114. package/dist/resolvers/explorerExecutionV1.js.map +1 -0
  115. package/dist/resolvers/explorerPublicV1.d.ts +37 -0
  116. package/dist/resolvers/explorerPublicV1.d.ts.map +1 -0
  117. package/dist/resolvers/explorerPublicV1.js +210 -0
  118. package/dist/resolvers/explorerPublicV1.js.map +1 -0
  119. package/dist/resolvers/explorerPublicationV1.d.ts +20 -0
  120. package/dist/resolvers/explorerPublicationV1.d.ts.map +1 -0
  121. package/dist/resolvers/explorerPublicationV1.js +195 -0
  122. package/dist/resolvers/explorerPublicationV1.js.map +1 -0
  123. package/dist/resolvers/explorerTransportV1.d.ts +17 -0
  124. package/dist/resolvers/explorerTransportV1.d.ts.map +1 -0
  125. package/dist/resolvers/explorerTransportV1.js +112 -0
  126. package/dist/resolvers/explorerTransportV1.js.map +1 -0
  127. package/dist/resolvers/hcs11MirrorV1.d.ts +49 -0
  128. package/dist/resolvers/hcs11MirrorV1.d.ts.map +1 -0
  129. package/dist/resolvers/hcs11MirrorV1.js +293 -0
  130. package/dist/resolvers/hcs11MirrorV1.js.map +1 -0
  131. package/dist/resolvers/hcs13MirrorV1.d.ts +35 -0
  132. package/dist/resolvers/hcs13MirrorV1.d.ts.map +1 -0
  133. package/dist/resolvers/hcs13MirrorV1.js +72 -0
  134. package/dist/resolvers/hcs13MirrorV1.js.map +1 -0
  135. package/dist/resolvers/hcs1MirrorV1.d.ts +28 -0
  136. package/dist/resolvers/hcs1MirrorV1.d.ts.map +1 -0
  137. package/dist/resolvers/hcs1MirrorV1.js +220 -0
  138. package/dist/resolvers/hcs1MirrorV1.js.map +1 -0
  139. package/dist/resolvers/hcs26MirrorV1.d.ts +67 -0
  140. package/dist/resolvers/hcs26MirrorV1.d.ts.map +1 -0
  141. package/dist/resolvers/hcs26MirrorV1.js +218 -0
  142. package/dist/resolvers/hcs26MirrorV1.js.map +1 -0
  143. package/dist/resolvers/hcs26RegistryMirrorV1.d.ts +26 -0
  144. package/dist/resolvers/hcs26RegistryMirrorV1.d.ts.map +1 -0
  145. package/dist/resolvers/hcs26RegistryMirrorV1.js +200 -0
  146. package/dist/resolvers/hcs26RegistryMirrorV1.js.map +1 -0
  147. package/dist/resolvers/hcs2MirrorV1.d.ts +26 -0
  148. package/dist/resolvers/hcs2MirrorV1.d.ts.map +1 -0
  149. package/dist/resolvers/hcs2MirrorV1.js +196 -0
  150. package/dist/resolvers/hcs2MirrorV1.js.map +1 -0
  151. package/dist/resolvers/hederaMirrorV1.d.ts +22 -0
  152. package/dist/resolvers/hederaMirrorV1.d.ts.map +1 -0
  153. package/dist/resolvers/hederaMirrorV1.js +338 -0
  154. package/dist/resolvers/hederaMirrorV1.js.map +1 -0
  155. package/dist/standards/hcs/hcs11V1.d.ts +51 -0
  156. package/dist/standards/hcs/hcs11V1.d.ts.map +1 -0
  157. package/dist/standards/hcs/hcs11V1.js +289 -0
  158. package/dist/standards/hcs/hcs11V1.js.map +1 -0
  159. package/dist/standards/hcs/hcs13V1.d.ts +39 -0
  160. package/dist/standards/hcs/hcs13V1.d.ts.map +1 -0
  161. package/dist/standards/hcs/hcs13V1.js +114 -0
  162. package/dist/standards/hcs/hcs13V1.js.map +1 -0
  163. package/dist/standards/hcs/hcs14V1.d.ts +35 -0
  164. package/dist/standards/hcs/hcs14V1.d.ts.map +1 -0
  165. package/dist/standards/hcs/hcs14V1.js +168 -0
  166. package/dist/standards/hcs/hcs14V1.js.map +1 -0
  167. package/dist/standards/hcs/hcs1V1.d.ts +30 -0
  168. package/dist/standards/hcs/hcs1V1.d.ts.map +1 -0
  169. package/dist/standards/hcs/hcs1V1.js +140 -0
  170. package/dist/standards/hcs/hcs1V1.js.map +1 -0
  171. package/dist/standards/hcs/hcs26V1.d.ts +58 -0
  172. package/dist/standards/hcs/hcs26V1.d.ts.map +1 -0
  173. package/dist/standards/hcs/hcs26V1.js +339 -0
  174. package/dist/standards/hcs/hcs26V1.js.map +1 -0
  175. package/dist/standards/hcs/hcs2V1.d.ts +36 -0
  176. package/dist/standards/hcs/hcs2V1.d.ts.map +1 -0
  177. package/dist/standards/hcs/hcs2V1.js +181 -0
  178. package/dist/standards/hcs/hcs2V1.js.map +1 -0
  179. package/dist/standards/hcs/jsonCanonicalV1.d.ts +15 -0
  180. package/dist/standards/hcs/jsonCanonicalV1.d.ts.map +1 -0
  181. package/dist/standards/hcs/jsonCanonicalV1.js +160 -0
  182. package/dist/standards/hcs/jsonCanonicalV1.js.map +1 -0
  183. package/dist/triangulation/compareV1.d.ts +50 -0
  184. package/dist/triangulation/compareV1.d.ts.map +1 -0
  185. package/dist/triangulation/compareV1.js +236 -0
  186. package/dist/triangulation/compareV1.js.map +1 -0
  187. package/dist/triangulation/executionPlanV1.d.ts +39 -0
  188. package/dist/triangulation/executionPlanV1.d.ts.map +1 -0
  189. package/dist/triangulation/executionPlanV1.js +208 -0
  190. package/dist/triangulation/executionPlanV1.js.map +1 -0
  191. package/dist/triangulation/executionPublicV1.d.ts +22 -0
  192. package/dist/triangulation/executionPublicV1.d.ts.map +1 -0
  193. package/dist/triangulation/executionPublicV1.js +39 -0
  194. package/dist/triangulation/executionPublicV1.js.map +1 -0
  195. package/dist/triangulation/messageObservationV1.d.ts +26 -0
  196. package/dist/triangulation/messageObservationV1.d.ts.map +1 -0
  197. package/dist/triangulation/messageObservationV1.js +69 -0
  198. package/dist/triangulation/messageObservationV1.js.map +1 -0
  199. package/dist/triangulation/publicV1.d.ts +29 -0
  200. package/dist/triangulation/publicV1.d.ts.map +1 -0
  201. package/dist/triangulation/publicV1.js +170 -0
  202. package/dist/triangulation/publicV1.js.map +1 -0
  203. package/dist/verification/sourceIntentV1.d.ts +15 -0
  204. package/dist/verification/sourceIntentV1.d.ts.map +1 -0
  205. package/dist/verification/sourceIntentV1.js +206 -0
  206. package/dist/verification/sourceIntentV1.js.map +1 -0
  207. package/docs/cli-v0.1.md +237 -0
  208. package/docs/conformance.md +38 -0
  209. package/docs/threat-model.md +37 -0
  210. package/docs/verification-semantics.md +65 -0
  211. package/examples/README.md +35 -0
  212. package/examples/dataset-offline.mjs +58 -0
  213. package/examples/dataset-policy.mjs +59 -0
  214. package/package.json +65 -4
@@ -0,0 +1,855 @@
1
+ // SDK-local pure port of Explorer executionVerificationRules.ts (Oct 7 baseline).
2
+ // ============================================================================
3
+ // File: src/verifier/execution/executionVerificationRules.ts
4
+ // Version: 1.4.0-exact-temporal-ordering | 2026-10-07
5
+ // Purpose:
6
+ // Ordered, deterministic rule registry for public standards-backed execution
7
+ // evidence. Rules verify explicit public facts only; no external resolution or
8
+ // cryptographic recomputation is implied where canonical payloads are absent.
9
+ // ============================================================================
10
+ import { cleanString, fail, hasTimestamp, isGitCommit, isHcs1Ref, isHcs13Ref, isHcsTransactionId, isHederaId, isPlainObject, isPositiveSafeInteger, isSha256, isSha3_512, isSupportedHederaNetwork, isUuid, isValidDate, normalizeIdentifier, notApplicable, pass, sameIdentifier, unavailable, } from "./contractV1.js";
11
+ import { EXECUTION_VERIFICATION_REASON_CODES as REASONS, } from "./reasonCodesV1.js";
12
+ import { computeExecutionDomainSeparatedSha3_512, hederaConsensusTimestampNanos, executionTimestampIso, executionTimestampNanos, } from "./recomputationV1.js";
13
+ import { buildStandardsResolutionPlan } from "./standardsPlanV1.js";
14
+ function present(value) {
15
+ return Boolean(cleanString(value));
16
+ }
17
+ function validSourceDocument(document) {
18
+ return Boolean(document &&
19
+ present(document.standard) &&
20
+ present(document.path) &&
21
+ isSha256(document.sha256));
22
+ }
23
+ function validAgentReference(agent) {
24
+ return Boolean(agent &&
25
+ present(agent.logical_id) &&
26
+ cleanString(agent.hcs14_uaid).startsWith("uaid:") &&
27
+ isHederaId(agent.hcs11?.account_id) &&
28
+ isHederaId(agent.hcs11?.profile_registry_topic_id) &&
29
+ isPositiveSafeInteger(agent.hcs11?.profile_registry_sequence) &&
30
+ isHcs1Ref(agent.hcs11?.profile_hcs1_ref) &&
31
+ isSha256(agent.hcs11?.profile_checksum_sha256));
32
+ }
33
+ function validCapabilityReference(capability) {
34
+ return Boolean(capability &&
35
+ cleanString(capability.standard) === "HCS-26" &&
36
+ isHederaId(capability.discovery_registry_topic_id) &&
37
+ present(capability.skill_uid) &&
38
+ present(capability.skill_version) &&
39
+ isHederaId(capability.version_registry_topic_id) &&
40
+ isPositiveSafeInteger(capability.version_sequence_number) &&
41
+ isHcs1Ref(capability.manifest_hcs1_ref) &&
42
+ isSha256(capability.manifest_checksum_sha256) &&
43
+ present(capability.repository_uri) &&
44
+ isGitCommit(capability.repository_commit));
45
+ }
46
+ function validSchemaReference(schema) {
47
+ return Boolean(schema &&
48
+ present(schema.role) &&
49
+ isHederaId(schema.registry_topic_id) &&
50
+ isPositiveSafeInteger(Number(schema.registry_sequence_number)) &&
51
+ isHcs13Ref(schema.hcs13_ref) &&
52
+ isSha256(schema.schema_checksum_sha256) &&
53
+ (!present(schema.instance_digest_sha3_512) ||
54
+ isSha3_512(schema.instance_digest_sha3_512)));
55
+ }
56
+ function recomputeReferenceComplete(evidence) {
57
+ const baseline = evidence?.standards?.baseline;
58
+ const documents = Array.isArray(baseline?.source_documents)
59
+ ? baseline.source_documents
60
+ : [];
61
+ const schemas = Array.isArray(evidence?.standards?.schemas)
62
+ ? evidence.standards.schemas
63
+ : [];
64
+ return Boolean(baseline &&
65
+ present(baseline.baseline_id) &&
66
+ isGitCommit(baseline.source_commit) &&
67
+ documents.length > 0 &&
68
+ documents.every(validSourceDocument) &&
69
+ validAgentReference(evidence?.agents?.requester) &&
70
+ validAgentReference(evidence?.agents?.executor) &&
71
+ validCapabilityReference(evidence?.capability) &&
72
+ schemas.length > 0 &&
73
+ schemas.every(validSchemaReference));
74
+ }
75
+ function expectedStandardsResolutionItems(evidence) {
76
+ const expected = new Map();
77
+ for (const item of buildStandardsResolutionPlan(evidence)) {
78
+ if (!item.key || expected.has(item.key))
79
+ return null;
80
+ expected.set(item.key, {
81
+ standard: item.standard,
82
+ reference: item.reference,
83
+ });
84
+ }
85
+ return expected;
86
+ }
87
+ function evaluateStandardsResolution(context) {
88
+ const material = context.verificationMaterial?.standards_resolution;
89
+ if (!material)
90
+ return unavailable(REASONS.STANDARDS_RESOLUTION_UNAVAILABLE);
91
+ if (cleanString(material.schema_version) !== "vera.standards-resolution.v1" ||
92
+ !isSupportedHederaNetwork(material.hedera_network) ||
93
+ !Array.isArray(material.items)) {
94
+ return fail(REASONS.MALFORMED_EVIDENCE);
95
+ }
96
+ if (context.expectedNetwork &&
97
+ normalizeIdentifier(material.hedera_network) !== context.expectedNetwork) {
98
+ return fail(REASONS.NETWORK_SCOPE_MISMATCH);
99
+ }
100
+ const expected = expectedStandardsResolutionItems(context.evidence);
101
+ if (!expected)
102
+ return fail(REASONS.MALFORMED_EVIDENCE);
103
+ // Legacy/foreign resolvers may still surface resolver-wide unavailability
104
+ // without materializing the expected item plan. Do not misclassify that as a
105
+ // reference-set integrity failure. Vera Anchor's resolver always preserves
106
+ // the full plan, including on failed/unavailable preflight paths.
107
+ if (material.items.length === 0) {
108
+ return material.state === "unavailable"
109
+ ? unavailable(REASONS.STANDARDS_RESOLUTION_UNAVAILABLE)
110
+ : fail(REASONS.MALFORMED_EVIDENCE);
111
+ }
112
+ const observed = new Map();
113
+ for (const item of material.items) {
114
+ const key = cleanString(item?.key);
115
+ if (!key || observed.has(key))
116
+ return fail(REASONS.MALFORMED_EVIDENCE);
117
+ observed.set(key, item);
118
+ }
119
+ if (observed.size !== expected.size)
120
+ return fail(REASONS.REFERENCE_SET_INCOMPLETE);
121
+ let hasUnavailable = false;
122
+ let hasFailed = false;
123
+ for (const [key, expectedItem] of expected.entries()) {
124
+ const item = observed.get(key);
125
+ if (!item)
126
+ return fail(REASONS.REFERENCE_SET_INCOMPLETE);
127
+ if (cleanString(item.standard) !== expectedItem.standard ||
128
+ cleanString(item.reference) !== expectedItem.reference) {
129
+ return fail(REASONS.MALFORMED_EVIDENCE);
130
+ }
131
+ if (item.state === "failed")
132
+ hasFailed = true;
133
+ else if (item.state === "unavailable")
134
+ hasUnavailable = true;
135
+ else if (item.state !== "verified")
136
+ return fail(REASONS.MALFORMED_EVIDENCE);
137
+ }
138
+ const derivedState = hasFailed
139
+ ? "failed"
140
+ : hasUnavailable
141
+ ? "unavailable"
142
+ : "verified";
143
+ if (material.state !== derivedState)
144
+ return fail(REASONS.MALFORMED_EVIDENCE);
145
+ if (derivedState === "failed")
146
+ return fail(REASONS.MALFORMED_EVIDENCE);
147
+ if (derivedState === "unavailable") {
148
+ return unavailable(REASONS.STANDARDS_RESOLUTION_UNAVAILABLE);
149
+ }
150
+ return pass();
151
+ }
152
+ function resultApplies(context) {
153
+ // Result-scoped checks are enabled only by an explicit verifier request.
154
+ // Public job-level standards evidence may legitimately include a latest
155
+ // ResultEvidence row for display/provenance purposes; that must not silently
156
+ // turn a job verification into verification of a particular result.
157
+ return Boolean(context.requestedResultId);
158
+ }
159
+ function missingOrMalformedDigest(value) {
160
+ return !present(value)
161
+ ? unavailable()
162
+ : !isSha3_512(value)
163
+ ? fail(REASONS.MALFORMED_EVIDENCE)
164
+ : null;
165
+ }
166
+ function exactMetadata(record, expected) {
167
+ if (!record)
168
+ return unavailable();
169
+ const required = [
170
+ ["schema", expected.schema],
171
+ ["canonicalization", expected.canonicalization],
172
+ ["digest_algorithm", expected.digestAlgorithm],
173
+ ["domain_separator", expected.domainSeparator],
174
+ ];
175
+ for (const [field, expectedValue] of required) {
176
+ if (!present(record[field]))
177
+ return unavailable();
178
+ if (record[field] !== expectedValue) {
179
+ return fail(REASONS.MALFORMED_EVIDENCE);
180
+ }
181
+ }
182
+ const digestState = missingOrMalformedDigest(record.digest);
183
+ if (digestState)
184
+ return digestState;
185
+ return pass();
186
+ }
187
+ function recomputePublicContractDigest(context, record, { domainSeparator, unavailableReason, mismatchReason, }) {
188
+ if (!record?.digest_payload) {
189
+ return unavailable(unavailableReason);
190
+ }
191
+ if (!isPlainObject(record.digest_payload)) {
192
+ return fail(REASONS.MALFORMED_EVIDENCE);
193
+ }
194
+ const digestState = missingOrMalformedDigest(record.digest);
195
+ if (digestState)
196
+ return digestState;
197
+ try {
198
+ const computedDigest = computeExecutionDomainSeparatedSha3_512(domainSeparator, record.digest_payload);
199
+ return computedDigest === record.digest
200
+ ? pass()
201
+ : fail(mismatchReason);
202
+ }
203
+ catch {
204
+ return fail(REASONS.MALFORMED_EVIDENCE);
205
+ }
206
+ }
207
+ function datasetRule(context) {
208
+ const dataset = context.evidence?.execution?.dataset;
209
+ if (!dataset)
210
+ return notApplicable();
211
+ const values = [
212
+ dataset.dataset_key,
213
+ dataset.dataset_version,
214
+ dataset.dataset_fingerprint_sha3_512,
215
+ dataset.dataset_manifest_sha3_512,
216
+ ];
217
+ if (values.every((value) => value == null || value === "")) {
218
+ return notApplicable();
219
+ }
220
+ if (!present(dataset.dataset_key) ||
221
+ !isPositiveSafeInteger(dataset.dataset_version) ||
222
+ !isSha3_512(dataset.dataset_fingerprint_sha3_512) ||
223
+ !isSha3_512(dataset.dataset_manifest_sha3_512)) {
224
+ return fail(REASONS.MALFORMED_EVIDENCE);
225
+ }
226
+ return pass();
227
+ }
228
+ export const EXECUTION_VERIFICATION_RULES = Object.freeze([
229
+ Object.freeze({
230
+ id: "public_evidence.available",
231
+ group: "contract",
232
+ label: "Standards-backed evidence is available",
233
+ requirement: "required",
234
+ evidenceRefs: ["public_standards_evidence"],
235
+ evaluate(context) {
236
+ if (context.evidence?.available === true)
237
+ return pass();
238
+ return unavailable(REASONS.REQUIRED_EVIDENCE_MISSING);
239
+ },
240
+ }),
241
+ Object.freeze({
242
+ id: "public_evidence.contract_version",
243
+ group: "contract",
244
+ label: "Public evidence contract version is supported",
245
+ requirement: "required",
246
+ evidenceRefs: ["public_standards_evidence"],
247
+ evaluate(context) {
248
+ const version = cleanString(context.evidence?.contract_version);
249
+ if (!version)
250
+ return unavailable();
251
+ return context.supportedContractVersions.includes(version)
252
+ ? pass()
253
+ : fail(REASONS.PUBLIC_CONTRACT_UNSUPPORTED);
254
+ },
255
+ }),
256
+ Object.freeze({
257
+ id: "execution.identity",
258
+ group: "execution",
259
+ label: "Execution identity is structurally valid",
260
+ requirement: "required",
261
+ evidenceRefs: ["execution"],
262
+ evaluate(context) {
263
+ const execution = context.evidence?.execution;
264
+ if (!execution)
265
+ return unavailable();
266
+ if (!isUuid(execution.job_id) ||
267
+ !present(execution.program) ||
268
+ !isValidDate(execution.proof_date) ||
269
+ !isSupportedHederaNetwork(execution.hedera_network)) {
270
+ return fail(REASONS.MALFORMED_EVIDENCE);
271
+ }
272
+ return pass();
273
+ },
274
+ }),
275
+ Object.freeze({
276
+ id: "execution.network_scope",
277
+ group: "execution",
278
+ label: "Execution network matches the requested verification scope",
279
+ requirement: "required",
280
+ evidenceRefs: ["execution"],
281
+ evaluate(context) {
282
+ const network = normalizeIdentifier(context.evidence?.execution?.hedera_network);
283
+ if (!network)
284
+ return unavailable();
285
+ if (!isSupportedHederaNetwork(network)) {
286
+ return fail(REASONS.MALFORMED_EVIDENCE);
287
+ }
288
+ if (context.expectedNetwork &&
289
+ network !== context.expectedNetwork) {
290
+ return fail(REASONS.NETWORK_SCOPE_MISMATCH);
291
+ }
292
+ return pass();
293
+ },
294
+ }),
295
+ Object.freeze({
296
+ id: "execution.dataset_commitment",
297
+ group: "execution",
298
+ label: "Execution dataset commitment is structurally valid",
299
+ requirement: "conditional",
300
+ evidenceRefs: ["execution.dataset"],
301
+ evaluate: datasetRule,
302
+ }),
303
+ Object.freeze({
304
+ id: "standards.baseline_reference",
305
+ group: "standards",
306
+ label: "Frozen standards baseline is complete",
307
+ requirement: "required",
308
+ evidenceRefs: ["standards.baseline"],
309
+ evaluate(context) {
310
+ const baseline = context.evidence?.standards?.baseline;
311
+ if (!baseline)
312
+ return unavailable();
313
+ const documents = Array.isArray(baseline.source_documents)
314
+ ? baseline.source_documents
315
+ : [];
316
+ if (!present(baseline.baseline_id) ||
317
+ !isGitCommit(baseline.source_commit) ||
318
+ documents.length === 0 ||
319
+ !documents.every(validSourceDocument)) {
320
+ return fail(REASONS.REFERENCE_SET_INCOMPLETE);
321
+ }
322
+ return pass();
323
+ },
324
+ }),
325
+ Object.freeze({
326
+ id: "standards.requester_reference",
327
+ group: "standards",
328
+ label: "Requester identity references are complete",
329
+ requirement: "required",
330
+ evidenceRefs: ["agents.requester"],
331
+ evaluate(context) {
332
+ const requester = context.evidence?.agents?.requester;
333
+ if (!requester)
334
+ return unavailable();
335
+ return validAgentReference(requester)
336
+ ? pass()
337
+ : fail(REASONS.REFERENCE_SET_INCOMPLETE);
338
+ },
339
+ }),
340
+ Object.freeze({
341
+ id: "standards.executor_reference",
342
+ group: "standards",
343
+ label: "Executor identity references are complete",
344
+ requirement: "required",
345
+ evidenceRefs: ["agents.executor"],
346
+ evaluate(context) {
347
+ const executor = context.evidence?.agents?.executor;
348
+ if (!executor)
349
+ return unavailable();
350
+ return validAgentReference(executor)
351
+ ? pass()
352
+ : fail(REASONS.REFERENCE_SET_INCOMPLETE);
353
+ },
354
+ }),
355
+ Object.freeze({
356
+ id: "standards.capability_reference",
357
+ group: "standards",
358
+ label: "HCS-26 capability reference is complete",
359
+ requirement: "required",
360
+ evidenceRefs: ["capability"],
361
+ evaluate(context) {
362
+ const capability = context.evidence?.capability;
363
+ if (!capability)
364
+ return unavailable();
365
+ return validCapabilityReference(capability)
366
+ ? pass()
367
+ : fail(REASONS.REFERENCE_SET_INCOMPLETE);
368
+ },
369
+ }),
370
+ Object.freeze({
371
+ id: "standards.schema_references",
372
+ group: "standards",
373
+ label: "HCS-13 schema references are complete",
374
+ requirement: "required",
375
+ evidenceRefs: ["standards.schemas"],
376
+ evaluate(context) {
377
+ const schemas = context.evidence?.standards?.schemas;
378
+ if (!Array.isArray(schemas) || schemas.length === 0) {
379
+ return unavailable();
380
+ }
381
+ return schemas.every(validSchemaReference)
382
+ ? pass()
383
+ : fail(REASONS.REFERENCE_SET_INCOMPLETE);
384
+ },
385
+ }),
386
+ Object.freeze({
387
+ id: "standards.reference_summary",
388
+ group: "standards",
389
+ label: "Reference completeness summary matches public evidence",
390
+ requirement: "required",
391
+ evidenceRefs: ["standards"],
392
+ evaluate(context) {
393
+ const reported = context.evidence?.standards?.reference_complete;
394
+ if (typeof reported !== "boolean")
395
+ return unavailable();
396
+ return reported === recomputeReferenceComplete(context.evidence)
397
+ ? pass()
398
+ : fail(REASONS.REFERENCE_SUMMARY_MISMATCH);
399
+ },
400
+ }),
401
+ Object.freeze({
402
+ id: "standards.references_resolved",
403
+ group: "standards",
404
+ label: "Standards references independently resolve",
405
+ requirement: "optional",
406
+ evidenceRefs: [
407
+ "standards.baseline",
408
+ "agents.requester",
409
+ "agents.executor",
410
+ "capability",
411
+ "standards.schemas",
412
+ ],
413
+ evaluate(context) {
414
+ return evaluateStandardsResolution(context);
415
+ },
416
+ }),
417
+ Object.freeze({
418
+ id: "binding.contract_metadata",
419
+ group: "binding",
420
+ label: "Execution binding contract metadata is valid",
421
+ requirement: "required",
422
+ evidenceRefs: ["binding"],
423
+ evaluate(context) {
424
+ const result = exactMetadata(context.evidence?.binding, {
425
+ schema: "ExecutionBindingV1",
426
+ canonicalization: "RFC8785-JCS",
427
+ digestAlgorithm: "SHA3-512",
428
+ domainSeparator: "vera-anchor:execution-binding:v1",
429
+ });
430
+ if (result.status !== "pass")
431
+ return result;
432
+ return hasTimestamp(context.evidence.binding?.finalized_at)
433
+ ? pass()
434
+ : unavailable();
435
+ },
436
+ }),
437
+ Object.freeze({
438
+ id: "binding.digest_recomputed",
439
+ group: "binding",
440
+ label: "Execution binding digest is recomputed from canonical content",
441
+ requirement: "conditional",
442
+ evidenceRefs: ["binding.digest_payload", "binding.digest"],
443
+ evaluate(context) {
444
+ return recomputePublicContractDigest(context, context.evidence?.binding, {
445
+ domainSeparator: "vera-anchor:execution-binding:v1",
446
+ unavailableReason: REASONS.BINDING_RECOMPUTATION_UNAVAILABLE,
447
+ mismatchReason: REASONS.BINDING_DIGEST_MISMATCH,
448
+ });
449
+ },
450
+ }),
451
+ Object.freeze({
452
+ id: "acceptance.contract_metadata",
453
+ group: "acceptance",
454
+ label: "Execution acceptance contract metadata is valid",
455
+ requirement: "required",
456
+ evidenceRefs: ["acceptance"],
457
+ evaluate(context) {
458
+ return exactMetadata(context.evidence?.acceptance, {
459
+ schema: "ExecutionAcceptanceV1",
460
+ canonicalization: "RFC8785-JCS",
461
+ digestAlgorithm: "SHA3-512",
462
+ domainSeparator: "vera-anchor:execution-acceptance:v1",
463
+ });
464
+ },
465
+ }),
466
+ Object.freeze({
467
+ id: "acceptance.digest_recomputed",
468
+ group: "acceptance",
469
+ label: "Execution acceptance digest is recomputed from canonical content",
470
+ requirement: "required",
471
+ evidenceRefs: ["execution", "binding", "acceptance"],
472
+ evaluate(context) {
473
+ const execution = context.evidence?.execution;
474
+ const binding = context.evidence?.binding;
475
+ const acceptance = context.evidence?.acceptance;
476
+ if (!execution || !binding || !acceptance)
477
+ return unavailable();
478
+ const acceptedAt = executionTimestampIso(acceptance.accepted_at);
479
+ if (!isUuid(execution.job_id) ||
480
+ !isValidDate(execution.proof_date) ||
481
+ !isSupportedHederaNetwork(execution.hedera_network) ||
482
+ !isSha3_512(binding.digest) ||
483
+ !isSha3_512(acceptance.digest) ||
484
+ !present(acceptance.admission_policy_id) ||
485
+ typeof acceptance.requires_hcs_confirmation !== "boolean" ||
486
+ !acceptedAt) {
487
+ return fail(REASONS.MALFORMED_EVIDENCE);
488
+ }
489
+ try {
490
+ const computedDigest = computeExecutionDomainSeparatedSha3_512("vera-anchor:execution-acceptance:v1", {
491
+ record_type: "vera_anchor.execution_acceptance",
492
+ acceptance_schema: "ExecutionAcceptanceV1",
493
+ binding_digest_sha3_512: binding.digest,
494
+ job_id: execution.job_id,
495
+ proof_date: execution.proof_date,
496
+ hedera_network: execution.hedera_network,
497
+ admission_policy: {
498
+ policy_id: acceptance.admission_policy_id,
499
+ require_hcs_confirmation_before_execution: acceptance.requires_hcs_confirmation,
500
+ },
501
+ accepted_at: acceptedAt,
502
+ });
503
+ return computedDigest === acceptance.digest
504
+ ? pass()
505
+ : fail(REASONS.ACCEPTANCE_RECOMPUTATION_MISMATCH);
506
+ }
507
+ catch {
508
+ return fail(REASONS.MALFORMED_EVIDENCE);
509
+ }
510
+ },
511
+ }),
512
+ Object.freeze({
513
+ id: "acceptance.binding_link",
514
+ group: "acceptance",
515
+ label: "Acceptance references the finalized execution binding",
516
+ requirement: "required",
517
+ evidenceRefs: ["binding", "acceptance"],
518
+ evaluate(context) {
519
+ const bindingDigest = context.evidence?.binding?.digest;
520
+ const acceptanceDigest = context.evidence?.acceptance?.binding_digest;
521
+ const bindingState = missingOrMalformedDigest(bindingDigest);
522
+ if (bindingState)
523
+ return bindingState;
524
+ const acceptanceState = missingOrMalformedDigest(acceptanceDigest);
525
+ if (acceptanceState)
526
+ return acceptanceState;
527
+ return bindingDigest === acceptanceDigest
528
+ ? pass()
529
+ : fail(REASONS.BINDING_DIGEST_MISMATCH);
530
+ },
531
+ }),
532
+ Object.freeze({
533
+ id: "acceptance.state_confirmed",
534
+ group: "acceptance",
535
+ label: "Pre-execution acceptance is confirmed",
536
+ requirement: "required",
537
+ evidenceRefs: ["acceptance"],
538
+ evaluate(context) {
539
+ const acceptance = context.evidence?.acceptance;
540
+ if (!acceptance || !present(acceptance.state))
541
+ return unavailable();
542
+ return acceptance.state === "confirmed"
543
+ ? pass()
544
+ : fail(REASONS.ACCEPTANCE_NOT_CONFIRMED);
545
+ },
546
+ }),
547
+ Object.freeze({
548
+ id: "acceptance.hcs_confirmation",
549
+ group: "acceptance",
550
+ label: "Required acceptance HCS confirmation is present",
551
+ requirement: "conditional",
552
+ evidenceRefs: ["acceptance.hcs"],
553
+ evaluate(context) {
554
+ const acceptance = context.evidence?.acceptance;
555
+ if (!acceptance)
556
+ return unavailable();
557
+ if (acceptance.requires_hcs_confirmation !== true) {
558
+ return notApplicable();
559
+ }
560
+ const hcs = acceptance.hcs;
561
+ if (!hcs)
562
+ return unavailable(REASONS.HCS_CONFIRMATION_REQUIRED);
563
+ if (!isHederaId(hcs.topic_id) ||
564
+ !isHcsTransactionId(hcs.transaction_id) ||
565
+ !present(hcs.message_id) ||
566
+ !isPositiveSafeInteger(hcs.sequence_number)) {
567
+ return fail(REASONS.HCS_CONFIRMATION_REQUIRED);
568
+ }
569
+ if (!present(hcs.consensus_timestamp_exact)) {
570
+ return unavailable(REASONS.HCS_CONFIRMATION_REQUIRED);
571
+ }
572
+ return hederaConsensusTimestampNanos(hcs.consensus_timestamp_exact) != null
573
+ ? pass()
574
+ : fail(REASONS.MALFORMED_EVIDENCE);
575
+ },
576
+ }),
577
+ Object.freeze({
578
+ id: "acceptance.precedes_execution",
579
+ group: "acceptance",
580
+ label: "Acceptance precedes authoritative execution time",
581
+ requirement: "optional",
582
+ evidenceRefs: ["acceptance", "acceptance.hcs", "verification_material.execution_start"],
583
+ evaluate(context) {
584
+ const acceptance = context.evidence?.acceptance;
585
+ const executionStart = context.verificationMaterial?.execution_start;
586
+ if (!acceptance || !executionStart) {
587
+ return unavailable(REASONS.AUTHORITATIVE_EXECUTION_TIME_UNAVAILABLE);
588
+ }
589
+ if (acceptance.requires_hcs_confirmation === true) {
590
+ const acceptanceExact = acceptance.hcs?.consensus_timestamp_exact;
591
+ const executionExact = executionStart.consensus_timestamp_exact;
592
+ if (!present(acceptanceExact)) {
593
+ return unavailable(REASONS.HCS_CONFIRMATION_REQUIRED);
594
+ }
595
+ if (!present(executionStart.hcs_transaction_id) ||
596
+ !present(executionStart.hcs_topic_id) ||
597
+ !present(executionExact)) {
598
+ return unavailable(REASONS.AUTHORITATIVE_EXECUTION_TIME_UNAVAILABLE);
599
+ }
600
+ if (!isHcsTransactionId(executionStart.hcs_transaction_id) ||
601
+ !isHederaId(executionStart.hcs_topic_id)) {
602
+ return fail(REASONS.MALFORMED_EVIDENCE);
603
+ }
604
+ const acceptanceNanos = hederaConsensusTimestampNanos(acceptanceExact);
605
+ const executionNanos = hederaConsensusTimestampNanos(executionExact);
606
+ if (acceptanceNanos == null || executionNanos == null) {
607
+ return fail(REASONS.MALFORMED_EVIDENCE);
608
+ }
609
+ return acceptanceNanos < executionNanos
610
+ ? pass()
611
+ : fail(REASONS.ACCEPTANCE_AFTER_EXECUTION_START);
612
+ }
613
+ const acceptedNanos = executionTimestampNanos(acceptance.accepted_at);
614
+ const startedNanos = executionTimestampNanos(executionStart.started_at);
615
+ if (acceptedNanos == null)
616
+ return fail(REASONS.MALFORMED_EVIDENCE);
617
+ if (startedNanos == null) {
618
+ return unavailable(REASONS.AUTHORITATIVE_EXECUTION_TIME_UNAVAILABLE);
619
+ }
620
+ if (acceptedNanos === startedNanos) {
621
+ return unavailable(REASONS.AUTHORITATIVE_EXECUTION_TIME_UNAVAILABLE);
622
+ }
623
+ return acceptedNanos < startedNanos
624
+ ? pass()
625
+ : fail(REASONS.ACCEPTANCE_AFTER_EXECUTION_START);
626
+ },
627
+ }),
628
+ Object.freeze({
629
+ id: "software.pipeline_link",
630
+ group: "software",
631
+ label: "Bound software release matches the execution pipeline",
632
+ requirement: "required",
633
+ evidenceRefs: ["software_release", "execution"],
634
+ evaluate(context) {
635
+ const release = context.evidence?.software_release;
636
+ const pipelineHash = context.evidence?.execution?.pipeline_hash;
637
+ if (!release || !present(pipelineHash))
638
+ return unavailable();
639
+ if (!present(release.repository_uri) ||
640
+ !isGitCommit(release.git_commit) ||
641
+ !isSha3_512(release.pipeline_hash_sha3_512) ||
642
+ !isSha3_512(pipelineHash)) {
643
+ return fail(REASONS.MALFORMED_EVIDENCE);
644
+ }
645
+ return release.pipeline_hash_sha3_512 === pipelineHash
646
+ ? pass()
647
+ : fail(REASONS.PIPELINE_HASH_MISMATCH);
648
+ },
649
+ }),
650
+ Object.freeze({
651
+ id: "parameters.commitment_matches",
652
+ group: "execution",
653
+ label: "Parameter instance commitment matches execution parameters",
654
+ requirement: "optional",
655
+ evidenceRefs: ["standards.schemas", "verification_material.parameter_instance"],
656
+ evaluate(context) {
657
+ const material = context.verificationMaterial?.parameter_instance;
658
+ if (!material) {
659
+ return unavailable(REASONS.PARAMETER_COMPARISON_UNAVAILABLE);
660
+ }
661
+ const role = cleanString(material.role);
662
+ const hcs13Ref = cleanString(material.hcs13_ref);
663
+ const domainSeparator = cleanString(material.domain_separator);
664
+ const schemas = Array.isArray(context.evidence?.standards?.schemas)
665
+ ? context.evidence.standards.schemas
666
+ : [];
667
+ const schema = schemas.find((entry) => cleanString(entry?.role) === role);
668
+ if (!role ||
669
+ !isHcs13Ref(hcs13Ref) ||
670
+ domainSeparator !== "vera-anchor:hcs13-instance:v1" ||
671
+ material.payload == null ||
672
+ !schema) {
673
+ return fail(REASONS.MALFORMED_EVIDENCE);
674
+ }
675
+ const expectedDigest = schema.instance_digest_sha3_512;
676
+ if (!present(expectedDigest)) {
677
+ return unavailable(REASONS.PARAMETER_COMPARISON_UNAVAILABLE);
678
+ }
679
+ if (!isSha3_512(expectedDigest) || cleanString(schema.hcs13_ref) !== hcs13Ref) {
680
+ return fail(REASONS.MALFORMED_EVIDENCE);
681
+ }
682
+ try {
683
+ const computedDigest = computeExecutionDomainSeparatedSha3_512(domainSeparator, { role, hcs13_ref: hcs13Ref, payload: material.payload });
684
+ return computedDigest === expectedDigest
685
+ ? pass()
686
+ : fail(REASONS.PARAMETER_COMMITMENT_MISMATCH);
687
+ }
688
+ catch {
689
+ return fail(REASONS.MALFORMED_EVIDENCE);
690
+ }
691
+ },
692
+ }),
693
+ Object.freeze({
694
+ id: "result_evidence.scope",
695
+ group: "result",
696
+ label: "Result evidence identifies the requested result",
697
+ requirement: "conditional",
698
+ evidenceRefs: ["execution", "result_evidence"],
699
+ evaluate(context) {
700
+ if (!resultApplies(context))
701
+ return notApplicable();
702
+ const resultEvidence = context.evidence?.result_evidence;
703
+ if (!resultEvidence)
704
+ return unavailable();
705
+ const actual = cleanString(resultEvidence.result_id);
706
+ const expected = context.requestedResultId;
707
+ if (!actual || !isUuid(actual)) {
708
+ return fail(REASONS.MALFORMED_EVIDENCE);
709
+ }
710
+ if (expected && !sameIdentifier(actual, expected)) {
711
+ return fail(REASONS.RESULT_SCOPE_MISMATCH);
712
+ }
713
+ return pass();
714
+ },
715
+ }),
716
+ Object.freeze({
717
+ id: "result_evidence.contract_metadata",
718
+ group: "result",
719
+ label: "Result evidence contract metadata is valid",
720
+ requirement: "conditional",
721
+ evidenceRefs: ["result_evidence"],
722
+ evaluate(context) {
723
+ if (!resultApplies(context))
724
+ return notApplicable();
725
+ return exactMetadata(context.evidence?.result_evidence, {
726
+ schema: "ResultEvidenceV1",
727
+ canonicalization: "RFC8785-JCS",
728
+ digestAlgorithm: "SHA3-512",
729
+ domainSeparator: "vera-anchor:result-evidence:v1",
730
+ });
731
+ },
732
+ }),
733
+ Object.freeze({
734
+ id: "result_evidence.sealed",
735
+ group: "result",
736
+ label: "Result evidence is sealed",
737
+ requirement: "conditional",
738
+ evidenceRefs: ["result_evidence"],
739
+ evaluate(context) {
740
+ if (!resultApplies(context))
741
+ return notApplicable();
742
+ const resultEvidence = context.evidence?.result_evidence;
743
+ if (!resultEvidence)
744
+ return unavailable();
745
+ return hasTimestamp(resultEvidence.sealed_at)
746
+ ? pass()
747
+ : fail(REASONS.RESULT_EVIDENCE_UNSEALED);
748
+ },
749
+ }),
750
+ Object.freeze({
751
+ id: "result_evidence.binding_link",
752
+ group: "result",
753
+ label: "Result evidence references the finalized execution binding",
754
+ requirement: "conditional",
755
+ evidenceRefs: ["binding", "result_evidence"],
756
+ evaluate(context) {
757
+ if (!resultApplies(context))
758
+ return notApplicable();
759
+ const bindingDigest = context.evidence?.binding?.digest;
760
+ const resultBindingDigest = context.evidence?.result_evidence?.binding_digest;
761
+ const bindingState = missingOrMalformedDigest(bindingDigest);
762
+ if (bindingState)
763
+ return bindingState;
764
+ const resultState = missingOrMalformedDigest(resultBindingDigest);
765
+ if (resultState)
766
+ return resultState;
767
+ return bindingDigest === resultBindingDigest
768
+ ? pass()
769
+ : fail(REASONS.BINDING_DIGEST_MISMATCH);
770
+ },
771
+ }),
772
+ Object.freeze({
773
+ id: "result_evidence.acceptance_link",
774
+ group: "result",
775
+ label: "Result evidence references the confirmed acceptance",
776
+ requirement: "conditional",
777
+ evidenceRefs: ["acceptance", "result_evidence"],
778
+ evaluate(context) {
779
+ if (!resultApplies(context))
780
+ return notApplicable();
781
+ const acceptanceDigest = context.evidence?.acceptance?.digest;
782
+ const resultAcceptanceDigest = context.evidence?.result_evidence?.acceptance_digest;
783
+ const acceptanceState = missingOrMalformedDigest(acceptanceDigest);
784
+ if (acceptanceState)
785
+ return acceptanceState;
786
+ const resultState = missingOrMalformedDigest(resultAcceptanceDigest);
787
+ if (resultState)
788
+ return resultState;
789
+ return acceptanceDigest === resultAcceptanceDigest
790
+ ? pass()
791
+ : fail(REASONS.ACCEPTANCE_DIGEST_MISMATCH);
792
+ },
793
+ }),
794
+ Object.freeze({
795
+ id: "result_evidence.pipeline_link",
796
+ group: "result",
797
+ label: "Result evidence references the executed software pipeline",
798
+ requirement: "conditional",
799
+ evidenceRefs: ["execution", "result_evidence"],
800
+ evaluate(context) {
801
+ if (!resultApplies(context))
802
+ return notApplicable();
803
+ const executionPipeline = context.evidence?.execution?.pipeline_hash;
804
+ const evidencePipeline = context.evidence?.result_evidence?.pipeline_hash;
805
+ if (!present(executionPipeline) || !present(evidencePipeline)) {
806
+ return unavailable();
807
+ }
808
+ if (!isSha3_512(executionPipeline) ||
809
+ !isSha3_512(evidencePipeline)) {
810
+ return fail(REASONS.MALFORMED_EVIDENCE);
811
+ }
812
+ return executionPipeline === evidencePipeline
813
+ ? pass()
814
+ : fail(REASONS.PIPELINE_HASH_MISMATCH);
815
+ },
816
+ }),
817
+ Object.freeze({
818
+ id: "result_evidence.hcs_receipt",
819
+ group: "result",
820
+ label: "Result evidence includes an HCS receipt reference",
821
+ requirement: "conditional",
822
+ evidenceRefs: ["result_evidence.hcs"],
823
+ evaluate(context) {
824
+ if (!resultApplies(context))
825
+ return notApplicable();
826
+ const hcs = context.evidence?.result_evidence?.hcs;
827
+ if (!hcs)
828
+ return unavailable();
829
+ return isHcsTransactionId(hcs.transaction_id) &&
830
+ isHederaId(hcs.topic_id)
831
+ ? pass()
832
+ : fail(REASONS.MALFORMED_EVIDENCE);
833
+ },
834
+ }),
835
+ Object.freeze({
836
+ id: "result_evidence.digest_recomputed",
837
+ group: "result",
838
+ label: "Result evidence digest is recomputed from canonical content",
839
+ requirement: "conditional",
840
+ evidenceRefs: ["result_evidence.digest_payload", "result_evidence.digest"],
841
+ evaluate(context) {
842
+ if (!resultApplies(context))
843
+ return notApplicable();
844
+ return recomputePublicContractDigest(context, context.evidence?.result_evidence, {
845
+ domainSeparator: "vera-anchor:result-evidence:v1",
846
+ unavailableReason: REASONS.RESULT_EVIDENCE_RECOMPUTATION_UNAVAILABLE,
847
+ mismatchReason: REASONS.RESULT_EVIDENCE_DIGEST_MISMATCH,
848
+ });
849
+ },
850
+ }),
851
+ ]);
852
+ export default EXECUTION_VERIFICATION_RULES;
853
+ /** Common Vera Anchor execution checks, excluding standards-backed SAGE rules. */
854
+ export const COMMON_EXECUTION_VERIFICATION_RULES = Object.freeze(EXECUTION_VERIFICATION_RULES.filter((rule) => rule.group !== "standards"));
855
+ //# sourceMappingURL=rulesV1.js.map