settld 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/README.md +93 -3
  2. package/SETTLD_VERSION +1 -1
  3. package/bin/settld-mcp +2 -0
  4. package/bin/settld.js +71 -0
  5. package/conformance/kernel-v0/README.md +7 -0
  6. package/conformance/kernel-v0/run.mjs +292 -4
  7. package/docs/ACCESS.md +57 -0
  8. package/docs/ADOPTION_CHECKLIST.md +44 -0
  9. package/docs/ALERTS.md +198 -0
  10. package/docs/ARCHITECTURE.md +69 -0
  11. package/docs/ARCHITECTURE_FOUNDER_GUIDE.md +284 -0
  12. package/docs/ARTIFACTS.md +60 -0
  13. package/docs/CERTIFICATION_CHECKLIST.md +33 -0
  14. package/docs/CIRCLE_SANDBOX_E2E.md +152 -0
  15. package/docs/CONFIG.md +297 -0
  16. package/docs/CONTRACTS_APIS.md +23 -0
  17. package/docs/DEPRECATION.md +31 -0
  18. package/docs/DOMAIN_MODEL.md +92 -0
  19. package/docs/EVENT_ENVELOPE.md +53 -0
  20. package/docs/FINANCE_PACK_FORMAT.md +53 -0
  21. package/docs/INCIDENT_TAXONOMY.md +30 -0
  22. package/docs/JOB_STATE_MACHINE.md +66 -0
  23. package/docs/KERNEL_COMPATIBLE.md +60 -0
  24. package/docs/KERNEL_V0.md +40 -0
  25. package/docs/KEY_ROTATION.md +80 -0
  26. package/docs/LEDGER.md +82 -0
  27. package/docs/LIVENESS.md +76 -0
  28. package/docs/MVP_BUILD_ORDER.md +36 -0
  29. package/docs/ONCALL_PLAYBOOK.md +39 -0
  30. package/docs/OPERATIONS_SIGNING.md +20 -0
  31. package/docs/OVERVIEW.md +190 -0
  32. package/docs/PERF_BASELINE.md +85 -0
  33. package/docs/PRD.md +77 -0
  34. package/docs/QUICKSTART_KERNEL_V0.md +96 -0
  35. package/docs/QUICKSTART_MCP.md +377 -0
  36. package/docs/QUICKSTART_MCP_HOSTS.md +210 -0
  37. package/docs/QUICKSTART_POLICY_PACKS.md +65 -0
  38. package/docs/QUICKSTART_PRODUCE.md +61 -0
  39. package/docs/QUICKSTART_PROFILES.md +198 -0
  40. package/docs/QUICKSTART_RELEASE_VERIFY.md +39 -0
  41. package/docs/QUICKSTART_SDK.md +125 -0
  42. package/docs/QUICKSTART_SDK_PYTHON.md +111 -0
  43. package/docs/QUICKSTART_VERIFY.md +54 -0
  44. package/docs/QUICKSTART_X402_GATEWAY.md +317 -0
  45. package/docs/README.md +33 -0
  46. package/docs/RELEASE_CHECKLIST.md +182 -0
  47. package/docs/RELEASING.md +82 -0
  48. package/docs/REPO_SETTINGS.md +37 -0
  49. package/docs/RUNBOOK.md +86 -0
  50. package/docs/SKILLS.md +42 -0
  51. package/docs/SKILL_BUNDLE_FORMAT.md +48 -0
  52. package/docs/SLO.md +131 -0
  53. package/docs/SUMMARY.md +17 -0
  54. package/docs/SUPPORT.md +31 -0
  55. package/docs/THREAT_MODEL.md +36 -0
  56. package/docs/TRUST.md +59 -0
  57. package/docs/WORKFLOW.md +35 -0
  58. package/docs/X402_BATCH_SETTLEMENT.md +126 -0
  59. package/docs/blog/2026-02-14-your-ai-agent-just-spent-500-where-is-the-receipt.md +73 -0
  60. package/docs/examples/x402-provider-payout-registry.example.json +14 -0
  61. package/docs/gitbook/README.md +64 -0
  62. package/docs/gitbook/SETUP.md +25 -0
  63. package/docs/gitbook/SUMMARY.md +15 -0
  64. package/docs/gitbook/api-reference.md +73 -0
  65. package/docs/gitbook/closepacks.md +55 -0
  66. package/docs/gitbook/conformance.md +59 -0
  67. package/docs/gitbook/core-primitives.md +85 -0
  68. package/docs/gitbook/dispute-lifecycle.md +33 -0
  69. package/docs/gitbook/faq.md +21 -0
  70. package/docs/gitbook/guides.md +49 -0
  71. package/docs/gitbook/operations-runbook.md +36 -0
  72. package/docs/gitbook/quickstart.md +103 -0
  73. package/docs/gitbook/replay-and-audit.md +30 -0
  74. package/docs/gitbook/sdk-reference.md +35 -0
  75. package/docs/gitbook/security-model.md +58 -0
  76. package/docs/integrations/README.md +15 -0
  77. package/docs/integrations/github-actions-verify.yml +31 -0
  78. package/docs/integrations/github-actions.md +34 -0
  79. package/docs/integrations/openclaw/CLAWHUB_PUBLISH_CHECKLIST.md +65 -0
  80. package/docs/integrations/openclaw/PUBLIC_QUICKSTART.md +95 -0
  81. package/docs/integrations/openclaw/settld-mcp-skill/SKILL.md +69 -0
  82. package/docs/integrations/openclaw/settld-mcp-skill/mcp-server.example.json +12 -0
  83. package/docs/kernel-compatible/capabilities.json +36 -0
  84. package/docs/marketing/agent-commerce-substrate.md +78 -0
  85. package/docs/marketing/hn-repost-2026-02-17.md +102 -0
  86. package/docs/marketing/show-hn-post.md +45 -0
  87. package/docs/ops/ARTIFACT_VERIFICATION_STATUS.md +43 -0
  88. package/docs/ops/BILLING_WEBHOOK_REPLAY.md +105 -0
  89. package/docs/ops/CI_FLAKE_BUDGET.md +31 -0
  90. package/docs/ops/DISPUTE_FINANCE_RECONCILIATION_PACKET.md +56 -0
  91. package/docs/ops/GO_LIVE_GATE_S13.md +27 -0
  92. package/docs/ops/HOSTED_BASELINE_R2.md +129 -0
  93. package/docs/ops/KERNEL_V0_SHIP_GATE.md +69 -0
  94. package/docs/ops/LIGHTHOUSE_PRODUCTION_CLOSE.md +51 -0
  95. package/docs/ops/MCP_COMPATIBILITY_MATRIX.md +30 -0
  96. package/docs/ops/MINIMUM_PRODUCTION_TOPOLOGY.md +89 -0
  97. package/docs/ops/P0_BACKEND_PROGRESS.md +150 -0
  98. package/docs/ops/PAYMENTS_ALPHA_R5.md +105 -0
  99. package/docs/ops/PILOT_ONBOARDING_RUNBOOK.md +112 -0
  100. package/docs/ops/PRODUCTION_DEPLOYMENT_CHECKLIST.md +140 -0
  101. package/docs/ops/R1_SLOS.md +66 -0
  102. package/docs/ops/RELEASE_SIGNING_INCIDENT.md +58 -0
  103. package/docs/ops/SELF_SERVE_LAUNCH_AUTOMATION.md +89 -0
  104. package/docs/ops/THROUGHPUT_DRILL_10X.md +48 -0
  105. package/docs/ops/TRUST_CONFIG_WIZARD.md +60 -0
  106. package/docs/ops/X402_PILOT_WEEKLY_METRICS.md +76 -0
  107. package/docs/ops/tool-call-disputes-holdback.md +52 -0
  108. package/docs/pilot-kit/PILOT_PACKAGE_SCORECARD_X402.md +46 -0
  109. package/docs/pilot-kit/README.md +29 -0
  110. package/docs/pilot-kit/architecture-one-pager.md +48 -0
  111. package/docs/pilot-kit/buyer-email.txt +19 -0
  112. package/docs/pilot-kit/buyer-one-pager.md +31 -0
  113. package/docs/pilot-kit/gtm-pilot-playbook.md +182 -0
  114. package/docs/pilot-kit/offline-verify.md +33 -0
  115. package/docs/pilot-kit/procurement-one-pager.md +50 -0
  116. package/docs/pilot-kit/rfp-clause.md +46 -0
  117. package/docs/pilot-kit/roi-calculator-template.csv +2 -0
  118. package/docs/pilot-kit/security-qa.md +153 -0
  119. package/docs/pilot-kit/security-summary.md +35 -0
  120. package/docs/plans/2026-02-13-mcp-spike-design.md +113 -0
  121. package/docs/plans/2026-02-20-trust-os-v1-jira-backlog.md +348 -0
  122. package/docs/plans/2026-02-21-agent-economic-actor-operating-model.md +169 -0
  123. package/docs/plans/2026-02-21-trust-os-v1-strategy.md +241 -0
  124. package/docs/research/2026-02-21-agent-spend-host-landscape.md +57 -0
  125. package/docs/spec/AcceptanceCriteria.v1.md +17 -0
  126. package/docs/spec/AcceptanceEvaluation.v1.md +10 -0
  127. package/docs/spec/AgentEvent.v1.md +47 -0
  128. package/docs/spec/AgentIdentity.v1.md +62 -0
  129. package/docs/spec/AgentPassport.v1.md +95 -0
  130. package/docs/spec/AgentReputation.v1.md +59 -0
  131. package/docs/spec/AgentReputation.v2.md +52 -0
  132. package/docs/spec/AgentRun.v1.md +47 -0
  133. package/docs/spec/AgentRunSettlement.v1.md +52 -0
  134. package/docs/spec/AgentWallet.v1.md +43 -0
  135. package/docs/spec/AgreementDelegation.v1.md +109 -0
  136. package/docs/spec/ArbitrationCase.v1.md +67 -0
  137. package/docs/spec/ArbitrationOutcomeMapping.v1.md +62 -0
  138. package/docs/spec/ArbitrationVerdict.v1.md +60 -0
  139. package/docs/spec/BundleHeadAttestation.v1.md +32 -0
  140. package/docs/spec/CANONICAL_JSON.md +31 -0
  141. package/docs/spec/CRYPTOGRAPHY.md +61 -0
  142. package/docs/spec/ClosePack.v1.md +49 -0
  143. package/docs/spec/ClosePackManifest.v1.md +24 -0
  144. package/docs/spec/DelegationGrant.v1.md +90 -0
  145. package/docs/spec/DisputeCaseLifecycle.v1.md +51 -0
  146. package/docs/spec/DisputeOpenEnvelope.v1.md +43 -0
  147. package/docs/spec/ERRORS.md +76 -0
  148. package/docs/spec/ESCROW_NETTING_INVARIANTS.md +71 -0
  149. package/docs/spec/EvidenceIndex.v1.md +20 -0
  150. package/docs/spec/ExecutionIntent.v1.md +90 -0
  151. package/docs/spec/FinancePackBundleManifest.v1.md +24 -0
  152. package/docs/spec/FundingHold.v1.md +60 -0
  153. package/docs/spec/GovernancePolicy.v1.md +34 -0
  154. package/docs/spec/GovernancePolicy.v2.md +30 -0
  155. package/docs/spec/INVARIANTS.md +389 -0
  156. package/docs/spec/InteractionDirectionMatrix.v1.md +30 -0
  157. package/docs/spec/InvoiceBundleManifest.v1.md +24 -0
  158. package/docs/spec/InvoiceClaim.v1.md +11 -0
  159. package/docs/spec/MONEY_RAIL_STATE_MACHINE.md +58 -0
  160. package/docs/spec/MarketplaceAcceptance.v2.md +46 -0
  161. package/docs/spec/MarketplaceOffer.v2.md +54 -0
  162. package/docs/spec/MeteringReport.v1.md +18 -0
  163. package/docs/spec/OperatorAction.v1.md +90 -0
  164. package/docs/spec/PRODUCER_ERRORS.md +42 -0
  165. package/docs/spec/PolicyDecision.v1.md +83 -0
  166. package/docs/spec/PricingMatrix.v1.md +20 -0
  167. package/docs/spec/PricingMatrixSignatures.v1.md +30 -0
  168. package/docs/spec/PricingMatrixSignatures.v2.md +29 -0
  169. package/docs/spec/ProduceCliOutput.v1.md +46 -0
  170. package/docs/spec/ProofBundleManifest.v1.md +24 -0
  171. package/docs/spec/README.md +109 -0
  172. package/docs/spec/REFERENCE_IMPLEMENTATIONS.md +29 -0
  173. package/docs/spec/REFERENCE_VERIFIER_BEHAVIOR.md +68 -0
  174. package/docs/spec/REMOTE_SIGNER.md +66 -0
  175. package/docs/spec/ReleaseIndex.v1.md +32 -0
  176. package/docs/spec/ReleaseIndexSignatures.v1.md +17 -0
  177. package/docs/spec/ReleaseTrust.v1.md +13 -0
  178. package/docs/spec/ReleaseTrust.v2.md +26 -0
  179. package/docs/spec/RemoteSignerRequest.v1.md +21 -0
  180. package/docs/spec/RemoteSignerResponse.v1.md +16 -0
  181. package/docs/spec/ReputationEvent.v1.md +63 -0
  182. package/docs/spec/RevocationList.v1.md +28 -0
  183. package/docs/spec/SIGNER_PROVIDER_PLUGIN.md +32 -0
  184. package/docs/spec/STRICTNESS.md +68 -0
  185. package/docs/spec/SUPPLY_CHAIN.md +33 -0
  186. package/docs/spec/SettlementAdjustment.v1.md +45 -0
  187. package/docs/spec/SettlementDecisionRecord.v1.md +48 -0
  188. package/docs/spec/SettlementDecisionRecord.v2.md +53 -0
  189. package/docs/spec/SettlementDecisionReport.v1.md +44 -0
  190. package/docs/spec/SettlementKernel.v1.md +59 -0
  191. package/docs/spec/SettlementReceipt.v1.md +63 -0
  192. package/docs/spec/SlaDefinition.v1.md +24 -0
  193. package/docs/spec/SlaEvaluation.v1.md +12 -0
  194. package/docs/spec/THREAT_MODEL.md +113 -0
  195. package/docs/spec/TOOL_PROVENANCE.md +30 -0
  196. package/docs/spec/TRUST_ANCHORS.md +84 -0
  197. package/docs/spec/TenantSettings.v1.md +90 -0
  198. package/docs/spec/TenantSettings.v2.md +99 -0
  199. package/docs/spec/TimestampProof.v1.md +25 -0
  200. package/docs/spec/ToolCallAgreement.v1.md +34 -0
  201. package/docs/spec/ToolCallEvidence.v1.md +47 -0
  202. package/docs/spec/ToolManifest.v1.md +47 -0
  203. package/docs/spec/VERIFIER_ENVIRONMENT.md +38 -0
  204. package/docs/spec/VERSIONING.md +107 -0
  205. package/docs/spec/VerificationReport.v1.md +50 -0
  206. package/docs/spec/VerifyAboutOutput.v1.md +10 -0
  207. package/docs/spec/VerifyCliOutput.v1.md +28 -0
  208. package/docs/spec/WARNINGS.md +83 -0
  209. package/docs/spec/error-codes.v1.txt +285 -0
  210. package/docs/spec/examples/agreement_delegation_v1.example.json +21 -0
  211. package/docs/spec/examples/arbitration_case_v1.example.json +26 -0
  212. package/docs/spec/examples/arbitration_verdict_v1.example.json +32 -0
  213. package/docs/spec/examples/dispute_open_envelope_v1.example.json +18 -0
  214. package/docs/spec/examples/produce_cli_output_v1.example.json +32 -0
  215. package/docs/spec/examples/release_index_signature_v1.example.json +9 -0
  216. package/docs/spec/examples/release_index_signatures_v1.example.json +14 -0
  217. package/docs/spec/examples/release_index_v1.example.json +15 -0
  218. package/docs/spec/examples/release_trust_v1.example.json +7 -0
  219. package/docs/spec/examples/release_trust_v2.example.json +22 -0
  220. package/docs/spec/examples/remote_signer_request_v1.example.json +18 -0
  221. package/docs/spec/examples/remote_signer_response_v1.example.json +8 -0
  222. package/docs/spec/examples/reputation_event_v1.example.json +29 -0
  223. package/docs/spec/examples/verification_report_v1.example.json +24 -0
  224. package/docs/spec/examples/verify_about_output_v1.example.json +29 -0
  225. package/docs/spec/examples/verify_cli_output_v1.example.json +13 -0
  226. package/docs/spec/legacy/MarketplaceAcceptance.v1.md +48 -0
  227. package/docs/spec/legacy/MarketplaceOffer.v1.md +56 -0
  228. package/docs/spec/legacy/schemas/MarketplaceAcceptance.v1.schema.json +53 -0
  229. package/docs/spec/legacy/schemas/MarketplaceOffer.v1.schema.json +61 -0
  230. package/docs/spec/producer-error-codes.v1.txt +14 -0
  231. package/docs/spec/schemas/AcceptanceCriteria.v1.schema.json +24 -0
  232. package/docs/spec/schemas/AcceptanceEvaluation.v1.schema.json +26 -0
  233. package/docs/spec/schemas/AgentEvent.v1.schema.json +49 -0
  234. package/docs/spec/schemas/AgentIdentity.v1.schema.json +129 -0
  235. package/docs/spec/schemas/AgentPassport.v1.schema.json +112 -0
  236. package/docs/spec/schemas/AgentReputation.v1.schema.json +151 -0
  237. package/docs/spec/schemas/AgentReputation.v2.schema.json +120 -0
  238. package/docs/spec/schemas/AgentRun.v1.schema.json +71 -0
  239. package/docs/spec/schemas/AgentRunSettlement.v1.schema.json +75 -0
  240. package/docs/spec/schemas/AgentWallet.v1.schema.json +54 -0
  241. package/docs/spec/schemas/AgreementDelegation.v1.schema.json +50 -0
  242. package/docs/spec/schemas/ArbitrationCase.v1.schema.json +133 -0
  243. package/docs/spec/schemas/ArbitrationVerdict.v1.schema.json +149 -0
  244. package/docs/spec/schemas/BundleHeadAttestation.v1.schema.json +21 -0
  245. package/docs/spec/schemas/ClosePackManifest.v1.schema.json +38 -0
  246. package/docs/spec/schemas/DelegationGrant.v1.schema.json +102 -0
  247. package/docs/spec/schemas/DisputeOpenEnvelope.v1.schema.json +78 -0
  248. package/docs/spec/schemas/EvidenceIndex.v1.schema.json +41 -0
  249. package/docs/spec/schemas/ExecutionIntent.v1.schema.json +85 -0
  250. package/docs/spec/schemas/FinancePackBundleManifest.v1.schema.json +38 -0
  251. package/docs/spec/schemas/FundingHold.v1.schema.json +46 -0
  252. package/docs/spec/schemas/GovernancePolicy.v1.schema.json +45 -0
  253. package/docs/spec/schemas/GovernancePolicy.v2.schema.json +70 -0
  254. package/docs/spec/schemas/InteractionDirectionMatrix.v1.schema.json +43 -0
  255. package/docs/spec/schemas/InvoiceBundleManifest.v1.schema.json +38 -0
  256. package/docs/spec/schemas/InvoiceClaim.v1.schema.json +39 -0
  257. package/docs/spec/schemas/MarketplaceAcceptance.v2.schema.json +53 -0
  258. package/docs/spec/schemas/MarketplaceOffer.v2.schema.json +61 -0
  259. package/docs/spec/schemas/MeteringReport.v1.schema.json +45 -0
  260. package/docs/spec/schemas/OperatorAction.v1.schema.json +113 -0
  261. package/docs/spec/schemas/PolicyDecision.v1.schema.json +74 -0
  262. package/docs/spec/schemas/PricingMatrix.v1.schema.json +24 -0
  263. package/docs/spec/schemas/PricingMatrixSignatures.v1.schema.json +24 -0
  264. package/docs/spec/schemas/PricingMatrixSignatures.v2.schema.json +24 -0
  265. package/docs/spec/schemas/ProduceCliOutput.v1.schema.json +107 -0
  266. package/docs/spec/schemas/ProofBundleManifest.v1.schema.json +37 -0
  267. package/docs/spec/schemas/PublicKeys.v1.schema.json +33 -0
  268. package/docs/spec/schemas/ReleaseIndex.v1.schema.json +45 -0
  269. package/docs/spec/schemas/ReleaseIndexSignature.v1.schema.json +16 -0
  270. package/docs/spec/schemas/ReleaseIndexSignatures.v1.schema.json +16 -0
  271. package/docs/spec/schemas/ReleaseTrust.v1.schema.json +15 -0
  272. package/docs/spec/schemas/ReleaseTrust.v2.schema.json +37 -0
  273. package/docs/spec/schemas/RemoteSignerPublicKeyResponse.v1.schema.json +14 -0
  274. package/docs/spec/schemas/RemoteSignerRequest.v1.schema.json +24 -0
  275. package/docs/spec/schemas/RemoteSignerResponse.v1.schema.json +10 -0
  276. package/docs/spec/schemas/RemoteSignerSignRequest.v1.schema.json +27 -0
  277. package/docs/spec/schemas/RemoteSignerSignResponse.v1.schema.json +16 -0
  278. package/docs/spec/schemas/ReputationEvent.v1.schema.json +164 -0
  279. package/docs/spec/schemas/RevocationList.v1.schema.json +51 -0
  280. package/docs/spec/schemas/SettlementAdjustment.v1.schema.json +44 -0
  281. package/docs/spec/schemas/SettlementDecisionRecord.v1.schema.json +66 -0
  282. package/docs/spec/schemas/SettlementDecisionRecord.v2.schema.json +149 -0
  283. package/docs/spec/schemas/SettlementDecisionReport.v1.schema.json +61 -0
  284. package/docs/spec/schemas/SettlementReceipt.v1.schema.json +135 -0
  285. package/docs/spec/schemas/SlaDefinition.v1.schema.json +33 -0
  286. package/docs/spec/schemas/SlaEvaluation.v1.schema.json +26 -0
  287. package/docs/spec/schemas/TenantSettings.v1.schema.json +90 -0
  288. package/docs/spec/schemas/TenantSettings.v2.schema.json +161 -0
  289. package/docs/spec/schemas/TimestampProof.v1.schema.json +17 -0
  290. package/docs/spec/schemas/ToolCallAgreement.v1.schema.json +34 -0
  291. package/docs/spec/schemas/ToolCallEvidence.v1.schema.json +45 -0
  292. package/docs/spec/schemas/ToolManifest.v1.schema.json +54 -0
  293. package/docs/spec/schemas/VerificationReport.v1.schema.json +83 -0
  294. package/docs/spec/schemas/VerifyAboutOutput.v1.schema.json +54 -0
  295. package/docs/spec/schemas/VerifyCliOutput.v1.schema.json +75 -0
  296. package/docs/spec/schemas/VerifyReleaseOutput.v1.schema.json +47 -0
  297. package/docs/spec/x402-error-codes.v1.txt +35 -0
  298. package/docs/templates/buyer-email.txt +18 -0
  299. package/docs/templates/buyer-one-pager.md +24 -0
  300. package/package.json +53 -6
  301. package/scripts/acceptance/full-stack.mjs +734 -0
  302. package/scripts/acceptance/full-stack.sh +99 -0
  303. package/scripts/audit/build-audit-packet.mjs +242 -0
  304. package/scripts/backup-pg.sh +45 -0
  305. package/scripts/backup-restore/README.md +18 -0
  306. package/scripts/backup-restore/capture-state.mjs +130 -0
  307. package/scripts/backup-restore/client.mjs +97 -0
  308. package/scripts/backup-restore/seed-workload.mjs +235 -0
  309. package/scripts/backup-restore/verify-state.mjs +139 -0
  310. package/scripts/backup-restore-test.sh +217 -0
  311. package/scripts/chaos.js +221 -0
  312. package/scripts/ci/build-launch-cutover-packet.mjs +304 -0
  313. package/scripts/ci/build-self-serve-benchmark-report.mjs +122 -0
  314. package/scripts/ci/changelog-guard.mjs +145 -0
  315. package/scripts/ci/check-kernel-v0-launch-gate.mjs +233 -0
  316. package/scripts/ci/check-secret-hygiene.mjs +78 -0
  317. package/scripts/ci/check-version-consistency.mjs +42 -0
  318. package/scripts/ci/cli-pack-smoke.mjs +160 -0
  319. package/scripts/ci/flake-budget-guard.mjs +68 -0
  320. package/scripts/ci/generate-error-codes.mjs +54 -0
  321. package/scripts/ci/lib/lighthouse-tracker.mjs +90 -0
  322. package/scripts/ci/lib/self-serve-launch-gate.mjs +89 -0
  323. package/scripts/ci/npm-pack-smoke.mjs +454 -0
  324. package/scripts/ci/run-10x-throughput-drill.mjs +318 -0
  325. package/scripts/ci/run-10x-throughput-incident-rehearsal.mjs +368 -0
  326. package/scripts/ci/run-arbitration-workspace-browser-e2e.sh +22 -0
  327. package/scripts/ci/run-circle-sandbox-smoke.mjs +237 -0
  328. package/scripts/ci/run-go-live-gate.mjs +150 -0
  329. package/scripts/ci/run-kernel-v0-ship-gate.mjs +97 -0
  330. package/scripts/ci/run-mcp-host-cert-matrix.mjs +201 -0
  331. package/scripts/ci/run-mcp-host-smoke.mjs +473 -0
  332. package/scripts/ci/run-offline-verification-parity-gate.mjs +762 -0
  333. package/scripts/ci/run-onboarding-host-success-gate.mjs +516 -0
  334. package/scripts/ci/run-onboarding-policy-slo-gate.mjs +537 -0
  335. package/scripts/ci/run-production-cutover-gate.mjs +540 -0
  336. package/scripts/ci/run-public-openclaw-npx-smoke.mjs +148 -0
  337. package/scripts/ci/run-release-promotion-guard.mjs +756 -0
  338. package/scripts/ci/run-self-serve-launch-gate.mjs +56 -0
  339. package/scripts/ci/runtime-import-smoke.mjs +58 -0
  340. package/scripts/ci/update-lighthouse-tracker.mjs +112 -0
  341. package/scripts/closepack/lib.mjs +286 -0
  342. package/scripts/collect-debug.sh +263 -0
  343. package/scripts/demo/compositional-settlement-3hop.mjs +237 -0
  344. package/scripts/demo/delivery-robot/export-ui-fixture.mjs +188 -0
  345. package/scripts/demo/delivery-robot/generate.mjs +377 -0
  346. package/scripts/demo/kernel-agent-goes-shopping.mjs +202 -0
  347. package/scripts/demo/magic-link-first-green.mjs +118 -0
  348. package/scripts/demo/magic-link-kind-smoke.mjs +577 -0
  349. package/scripts/demo/mcp-paid-exa.mjs +1110 -0
  350. package/scripts/dev/billing-doctor.sh +145 -0
  351. package/scripts/dev/billing-smoke-prod.sh +219 -0
  352. package/scripts/dev/billing-webhook-replay.sh +161 -0
  353. package/scripts/dev/env.dev.example +29 -0
  354. package/scripts/dev/env.sh +37 -0
  355. package/scripts/dev/new-sdk-key.sh +81 -0
  356. package/scripts/dev/sdk-first-run.sh +21 -0
  357. package/scripts/dev/smoke-x402-gateway.sh +115 -0
  358. package/scripts/dev/start-api.sh +24 -0
  359. package/scripts/doctor/mcp-host.mjs +120 -0
  360. package/scripts/examples/produce-and-verify-jobproof.mjs +191 -0
  361. package/scripts/examples/sdk-first-paid-rfq.py +105 -0
  362. package/scripts/examples/sdk-first-verified-run.mjs +85 -0
  363. package/scripts/examples/sdk-first-verified-run.py +99 -0
  364. package/scripts/examples/sdk-tenant-analytics.mjs +103 -0
  365. package/scripts/examples/sdk-tenant-analytics.py +118 -0
  366. package/scripts/finance-pack/bundle.mjs +284 -0
  367. package/scripts/fixtures/generate-bundle-fixtures.mjs +877 -0
  368. package/scripts/governance/export.mjs +169 -0
  369. package/scripts/load/delivery-stress.k6.js +183 -0
  370. package/scripts/load/ingest-burst.k6.js +236 -0
  371. package/scripts/load/run-delivery-load.js +66 -0
  372. package/scripts/load/webhook-receiver.js +131 -0
  373. package/scripts/magic-link/migrate-run-records-to-db.mjs +35 -0
  374. package/scripts/mcp/probe.mjs +238 -0
  375. package/scripts/mcp/settld-mcp-http-gateway.mjs +178 -0
  376. package/scripts/mcp/settld-mcp-server.mjs +1511 -0
  377. package/scripts/openapi/write.mjs +13 -0
  378. package/scripts/ops/bootstrap-tenant-conformance.mjs +185 -0
  379. package/scripts/ops/build-x402-pilot-reliability-report.mjs +489 -0
  380. package/scripts/ops/check-x402-receipt-sample.mjs +181 -0
  381. package/scripts/ops/design-partner-run-packet.mjs +466 -0
  382. package/scripts/ops/dispute-finance-reconciliation-packet.mjs +313 -0
  383. package/scripts/ops/hosted-baseline-evidence.mjs +890 -0
  384. package/scripts/ops/money-rails-chargeback-evidence.mjs +509 -0
  385. package/scripts/ops/money-rails-reconcile-evidence.mjs +180 -0
  386. package/scripts/ops/p0-seed-money-rail-operation.mjs +432 -0
  387. package/scripts/ops/run-x402-hitl-smoke.mjs +607 -0
  388. package/scripts/pilot/finance-pack.mjs +495 -0
  389. package/scripts/pilot/fixtures/robot-keypair.json +4 -0
  390. package/scripts/pilot/fixtures/server-signer.json +4 -0
  391. package/scripts/policy/cli.mjs +600 -0
  392. package/scripts/profile/cli.mjs +1324 -0
  393. package/scripts/proof-bundle/job.mjs +109 -0
  394. package/scripts/proof-bundle/lib.mjs +92 -0
  395. package/scripts/proof-bundle/month.mjs +103 -0
  396. package/scripts/provider/conformance-run.mjs +159 -0
  397. package/scripts/provider/keys-generate.mjs +135 -0
  398. package/scripts/provider/publish.mjs +420 -0
  399. package/scripts/quickstart/x402.mjs +334 -0
  400. package/scripts/register-entity-secret.mjs +102 -0
  401. package/scripts/release/build-artifacts.mjs +181 -0
  402. package/scripts/release/generate-release-index.mjs +112 -0
  403. package/scripts/release/release-index-lib.mjs +232 -0
  404. package/scripts/release/sign-release-index.mjs +85 -0
  405. package/scripts/release/validate-release-assets.mjs +170 -0
  406. package/scripts/release/verify-release.mjs +261 -0
  407. package/scripts/restore-pg.sh +34 -0
  408. package/scripts/scaffold/create-settld-paid-tool.mjs +19 -0
  409. package/scripts/sdk/smoke-python.py +30 -0
  410. package/scripts/sdk/smoke.mjs +16 -0
  411. package/scripts/settlement/x402-batch-worker.mjs +1091 -0
  412. package/scripts/setup/circle-bootstrap.mjs +310 -0
  413. package/scripts/setup/host-config.mjs +617 -0
  414. package/scripts/setup/onboard.mjs +1337 -0
  415. package/scripts/setup/openclaw-onboard.mjs +423 -0
  416. package/scripts/setup/wizard.mjs +986 -0
  417. package/scripts/slo/check.mjs +239 -0
  418. package/scripts/smoke/k8s-smoke.mjs +214 -0
  419. package/scripts/spec/generate-protocol-vectors.mjs +1019 -0
  420. package/scripts/test/check-no-generated-artifacts.sh +12 -0
  421. package/scripts/test/run.sh +59 -0
  422. package/scripts/trust/validate-trust-file.mjs +57 -0
  423. package/scripts/trust-config/rotate-settld-pay.mjs +277 -0
  424. package/scripts/trust-config/wizard.mjs +161 -0
  425. package/scripts/vendor-contract-test-lib.mjs +182 -0
  426. package/scripts/vendor-contract-test.mjs +55 -0
  427. package/scripts/vercel/build-mkdocs.sh +9 -0
  428. package/scripts/vercel/ignore-mkdocs.sh +25 -0
  429. package/scripts/vercel/install-mkdocs.sh +6 -0
  430. package/scripts/verify-pg.js +217 -0
  431. package/scripts/x402/receipt-verify.mjs +289 -0
  432. package/services/finance-sink/src/dedupe-store.js +29 -6
  433. package/services/receiver/src/dedupe-store.js +29 -5
  434. package/services/x402-gateway/Dockerfile +13 -0
  435. package/services/x402-gateway/README.md +58 -0
  436. package/services/x402-gateway/examples/upstream-mock.js +337 -0
  437. package/services/x402-gateway/src/server.js +1058 -0
  438. package/src/api/app.js +34658 -16940
  439. package/src/api/maintenance.js +70 -0
  440. package/src/api/middleware/trust-kernel.js +114 -0
  441. package/src/api/openapi.js +1778 -70
  442. package/src/api/persistence.js +456 -0
  443. package/src/api/server.js +81 -5
  444. package/src/api/store.js +1581 -62
  445. package/src/api/workers/deliveries.js +99 -4
  446. package/src/api/workers/insolvency-sweep.js +159 -0
  447. package/src/core/agent-card.js +69 -0
  448. package/src/core/agent-wallets.js +231 -0
  449. package/src/core/agreement-delegation.js +549 -0
  450. package/src/core/billing-plans.js +40 -6
  451. package/src/core/circle-reserve-adapter.js +845 -0
  452. package/src/core/event-policy.js +21 -2
  453. package/src/core/maintenance-locks.js +1 -0
  454. package/src/core/operator-action.js +303 -0
  455. package/src/core/paid-tool-manifest.js +318 -0
  456. package/src/core/policy-decision.js +322 -0
  457. package/src/core/policy-packs.js +207 -0
  458. package/src/core/profile-fingerprint.js +27 -0
  459. package/src/core/profile-simulation-reasons.js +84 -0
  460. package/src/core/profile-templates.js +242 -0
  461. package/src/core/provider-publish-conformance.js +525 -0
  462. package/src/core/provider-publish-proof.js +396 -0
  463. package/src/core/provider-quote-signature.js +170 -0
  464. package/src/core/settld-keys.js +112 -0
  465. package/src/core/settld-pay-token.js +344 -0
  466. package/src/core/settlement-kernel.js +239 -2
  467. package/src/core/settlement-verifier.js +335 -0
  468. package/src/core/tool-call-agreement.js +112 -0
  469. package/src/core/tool-call-evidence.js +144 -0
  470. package/src/core/tool-provider-signature.js +98 -0
  471. package/src/core/wallet-assignment-resolver.js +129 -0
  472. package/src/core/wallet-provider-bootstrap.js +365 -0
  473. package/src/core/x402-escalation-override.js +258 -0
  474. package/src/core/x402-gate.js +118 -0
  475. package/src/core/x402-provider-refund-decision.js +220 -0
  476. package/src/core/x402-receipt-verifier.js +708 -0
  477. package/src/core/x402-reversal-command.js +251 -0
  478. package/src/core/x402-wallet-issuer-decision.js +252 -0
  479. package/src/core/zk-verifier.js +300 -0
  480. package/src/db/migrations/029_reputation_event_index.sql +54 -0
  481. package/src/db/migrations/030_artifacts_source_event_unique_job_only.sql +15 -0
  482. package/src/db/pg.js +18 -7
  483. package/src/db/store-pg.js +1508 -111
@@ -0,0 +1,344 @@
1
+ import { canonicalJsonStringify, normalizeForCanonicalJson } from "./canonical-json.js";
2
+ import { keyIdFromPublicKeyPem, sha256Hex, signHashHexEd25519, verifyHashHexEd25519 } from "./crypto.js";
3
+ import { keyMapFromSettldKeyset } from "./settld-keys.js";
4
+
5
+ export const SETTLD_PAY_TOKEN_VERSION = 1;
6
+ export const SETTLD_PAY_TOKEN_TTL_SECONDS = 300;
7
+
8
+ function assertNonEmptyString(value, name) {
9
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
10
+ return String(value).trim();
11
+ }
12
+
13
+ function normalizeCurrency(value, name) {
14
+ const raw = typeof value === "string" && value.trim() !== "" ? value : "USD";
15
+ const out = raw.trim().toUpperCase();
16
+ if (!/^[A-Z][A-Z0-9_]{2,11}$/.test(out)) throw new TypeError(`${name} must match ^[A-Z][A-Z0-9_]{2,11}$`);
17
+ return out;
18
+ }
19
+
20
+ function normalizePositiveSafeInt(value, name) {
21
+ const n = Number(value);
22
+ if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer`);
23
+ return n;
24
+ }
25
+
26
+ function normalizeUnixSeconds(value, name) {
27
+ const n = Number(value);
28
+ if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer unix timestamp`);
29
+ return n;
30
+ }
31
+
32
+ function normalizeHexHash(value, name) {
33
+ const s = assertNonEmptyString(value, name).toLowerCase();
34
+ if (!/^[0-9a-f]{64}$/.test(s)) throw new TypeError(`${name} must be a 64-hex sha256`);
35
+ return s;
36
+ }
37
+
38
+ function normalizeOptionalHexHash(value, name) {
39
+ if (value === null || value === undefined || String(value).trim() === "") return null;
40
+ return normalizeHexHash(value, name);
41
+ }
42
+
43
+ function normalizeOptionalRequestBindingMode(value, name) {
44
+ if (value === null || value === undefined || String(value).trim() === "") return null;
45
+ const mode = String(value).trim().toLowerCase();
46
+ if (mode !== "strict") throw new TypeError(`${name} must be strict when provided`);
47
+ return mode;
48
+ }
49
+
50
+ function normalizeOptionalId(value, name, { max = 200 } = {}) {
51
+ if (value === null || value === undefined || String(value).trim() === "") return null;
52
+ const out = String(value).trim();
53
+ if (out.length > max) throw new TypeError(`${name} must be <= ${max} chars`);
54
+ if (!/^[A-Za-z0-9:_-]+$/.test(out)) throw new TypeError(`${name} must match ^[A-Za-z0-9:_-]+$`);
55
+ return out;
56
+ }
57
+
58
+ function normalizeOptionalString(value, name, { max = 256 } = {}) {
59
+ if (value === null || value === undefined || String(value).trim() === "") return null;
60
+ const out = String(value).trim();
61
+ if (out.length > max) throw new TypeError(`${name} must be <= ${max} chars`);
62
+ return out;
63
+ }
64
+
65
+ function normalizeOptionalPositiveSafeInt(value, name) {
66
+ if (value === null || value === undefined || String(value).trim() === "") return null;
67
+ return normalizePositiveSafeInt(value, name);
68
+ }
69
+
70
+ function decodeEnvelope(token) {
71
+ const raw = assertNonEmptyString(token, "token");
72
+ let decoded = null;
73
+ try {
74
+ decoded = Buffer.from(raw, "base64url").toString("utf8");
75
+ } catch (err) {
76
+ throw new TypeError(`token is not valid base64url: ${err?.message ?? String(err ?? "")}`);
77
+ }
78
+ let parsed;
79
+ try {
80
+ parsed = JSON.parse(decoded);
81
+ } catch (err) {
82
+ throw new TypeError(`token is not valid JSON envelope: ${err?.message ?? String(err ?? "")}`);
83
+ }
84
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new TypeError("token envelope must be an object");
85
+ if (Number(parsed.v) !== SETTLD_PAY_TOKEN_VERSION) throw new TypeError(`token envelope version must be ${SETTLD_PAY_TOKEN_VERSION}`);
86
+ const kid = assertNonEmptyString(parsed.kid, "token.kid");
87
+ if (!parsed.payload || typeof parsed.payload !== "object" || Array.isArray(parsed.payload)) {
88
+ throw new TypeError("token.payload must be an object");
89
+ }
90
+ const sig = assertNonEmptyString(parsed.sig, "token.sig");
91
+ return { envelope: parsed, kid, payload: parsed.payload, sig };
92
+ }
93
+
94
+ export function buildSettldPayPayloadV1({
95
+ iss = "settld",
96
+ aud,
97
+ gateId,
98
+ authorizationRef,
99
+ amountCents,
100
+ currency = "USD",
101
+ payeeProviderId,
102
+ requestBindingMode = null,
103
+ requestBindingSha256 = null,
104
+ quoteId = null,
105
+ quoteSha256 = null,
106
+ idempotencyKey = null,
107
+ nonce = null,
108
+ sponsorRef = null,
109
+ sponsorWalletRef = null,
110
+ agentKeyId = null,
111
+ delegationRef = null,
112
+ rootDelegationRef = null,
113
+ rootDelegationHash = null,
114
+ effectiveDelegationRef = null,
115
+ effectiveDelegationHash = null,
116
+ policyVersion = null,
117
+ policyFingerprint = null,
118
+ spendAuthorizationVersion = null,
119
+ iat,
120
+ exp
121
+ } = {}) {
122
+ const normalizedIat = normalizeUnixSeconds(iat, "iat");
123
+ const normalizedExp = normalizeUnixSeconds(exp, "exp");
124
+ if (normalizedExp <= normalizedIat) throw new TypeError("exp must be greater than iat");
125
+ const normalizedRequestBindingSha256 = normalizeOptionalHexHash(requestBindingSha256, "requestBindingSha256");
126
+ const normalizedRequestBindingMode =
127
+ normalizeOptionalRequestBindingMode(requestBindingMode, "requestBindingMode") ??
128
+ (normalizedRequestBindingSha256 ? "strict" : null);
129
+ if (normalizedRequestBindingMode === "strict" && !normalizedRequestBindingSha256) {
130
+ throw new TypeError("requestBindingSha256 is required when requestBindingMode=strict");
131
+ }
132
+ const normalizedQuoteId = normalizeOptionalId(quoteId, "quoteId", { max: 200 });
133
+ const normalizedQuoteSha256 = normalizeOptionalHexHash(quoteSha256, "quoteSha256");
134
+ const normalizedIdempotencyKey = normalizeOptionalString(idempotencyKey, "idempotencyKey", { max: 256 });
135
+ const normalizedNonce = normalizeOptionalString(nonce, "nonce", { max: 256 });
136
+ const normalizedSponsorRef = normalizeOptionalId(sponsorRef, "sponsorRef", { max: 200 });
137
+ const normalizedSponsorWalletRef = normalizeOptionalId(sponsorWalletRef, "sponsorWalletRef", { max: 200 });
138
+ const normalizedAgentKeyId = normalizeOptionalId(agentKeyId, "agentKeyId", { max: 200 });
139
+ const normalizedDelegationRef = normalizeOptionalId(delegationRef, "delegationRef", { max: 200 });
140
+ const normalizedRootDelegationRef = normalizeOptionalId(rootDelegationRef, "rootDelegationRef", { max: 200 });
141
+ const normalizedRootDelegationHash = normalizeOptionalHexHash(rootDelegationHash, "rootDelegationHash");
142
+ const normalizedEffectiveDelegationRef = normalizeOptionalId(effectiveDelegationRef, "effectiveDelegationRef", { max: 200 });
143
+ const normalizedEffectiveDelegationHash = normalizeOptionalHexHash(effectiveDelegationHash, "effectiveDelegationHash");
144
+ const normalizedPolicyVersion = normalizeOptionalPositiveSafeInt(policyVersion, "policyVersion");
145
+ const normalizedPolicyFingerprint = normalizeOptionalHexHash(policyFingerprint, "policyFingerprint");
146
+ const normalizedSpendAuthorizationVersion = normalizeOptionalString(spendAuthorizationVersion, "spendAuthorizationVersion", {
147
+ max: 64
148
+ });
149
+ const hasSpendAuthorizationClaims =
150
+ normalizedQuoteId !== null ||
151
+ normalizedQuoteSha256 !== null ||
152
+ normalizedIdempotencyKey !== null ||
153
+ normalizedNonce !== null ||
154
+ normalizedSponsorRef !== null ||
155
+ normalizedSponsorWalletRef !== null ||
156
+ normalizedAgentKeyId !== null ||
157
+ normalizedDelegationRef !== null ||
158
+ normalizedRootDelegationRef !== null ||
159
+ normalizedRootDelegationHash !== null ||
160
+ normalizedEffectiveDelegationRef !== null ||
161
+ normalizedEffectiveDelegationHash !== null ||
162
+ normalizedPolicyVersion !== null ||
163
+ normalizedPolicyFingerprint !== null ||
164
+ normalizedSpendAuthorizationVersion !== null;
165
+ const spendAuthorizationVersionOut = hasSpendAuthorizationClaims
166
+ ? normalizedSpendAuthorizationVersion ?? "SpendAuthorization.v1"
167
+ : null;
168
+
169
+ return normalizeForCanonicalJson(
170
+ {
171
+ iss: assertNonEmptyString(iss, "iss"),
172
+ aud: assertNonEmptyString(aud, "aud"),
173
+ gateId: assertNonEmptyString(gateId, "gateId"),
174
+ authorizationRef: assertNonEmptyString(authorizationRef, "authorizationRef"),
175
+ amountCents: normalizePositiveSafeInt(amountCents, "amountCents"),
176
+ currency: normalizeCurrency(currency, "currency"),
177
+ payeeProviderId: assertNonEmptyString(payeeProviderId, "payeeProviderId"),
178
+ ...(normalizedRequestBindingMode ? { requestBindingMode: normalizedRequestBindingMode } : {}),
179
+ ...(normalizedRequestBindingSha256 ? { requestBindingSha256: normalizedRequestBindingSha256 } : {}),
180
+ ...(normalizedQuoteId ? { quoteId: normalizedQuoteId } : {}),
181
+ ...(normalizedQuoteSha256 ? { quoteSha256: normalizedQuoteSha256 } : {}),
182
+ ...(normalizedIdempotencyKey ? { idempotencyKey: normalizedIdempotencyKey } : {}),
183
+ ...(normalizedNonce ? { nonce: normalizedNonce } : {}),
184
+ ...(normalizedSponsorRef ? { sponsorRef: normalizedSponsorRef } : {}),
185
+ ...(normalizedSponsorWalletRef ? { sponsorWalletRef: normalizedSponsorWalletRef } : {}),
186
+ ...(normalizedAgentKeyId ? { agentKeyId: normalizedAgentKeyId } : {}),
187
+ ...(normalizedDelegationRef ? { delegationRef: normalizedDelegationRef } : {}),
188
+ ...(normalizedRootDelegationRef ? { rootDelegationRef: normalizedRootDelegationRef } : {}),
189
+ ...(normalizedRootDelegationHash ? { rootDelegationHash: normalizedRootDelegationHash } : {}),
190
+ ...(normalizedEffectiveDelegationRef ? { effectiveDelegationRef: normalizedEffectiveDelegationRef } : {}),
191
+ ...(normalizedEffectiveDelegationHash ? { effectiveDelegationHash: normalizedEffectiveDelegationHash } : {}),
192
+ ...(normalizedPolicyVersion ? { policyVersion: normalizedPolicyVersion } : {}),
193
+ ...(normalizedPolicyFingerprint ? { policyFingerprint: normalizedPolicyFingerprint } : {}),
194
+ ...(spendAuthorizationVersionOut ? { spendAuthorizationVersion: spendAuthorizationVersionOut } : {}),
195
+ iat: normalizedIat,
196
+ exp: normalizedExp
197
+ },
198
+ { path: "$" }
199
+ );
200
+ }
201
+
202
+ export function computeSettldPayRequestBindingSha256V1({ method, host, pathWithQuery, bodySha256 } = {}) {
203
+ const normalizedMethod = assertNonEmptyString(method, "method").toUpperCase();
204
+ const normalizedHost = assertNonEmptyString(host, "host").toLowerCase();
205
+ const normalizedPathWithQuery = assertNonEmptyString(pathWithQuery, "pathWithQuery");
206
+ if (!normalizedPathWithQuery.startsWith("/")) {
207
+ throw new TypeError("pathWithQuery must start with /");
208
+ }
209
+ const normalizedBodySha256 = normalizeHexHash(bodySha256, "bodySha256");
210
+ return sha256Hex(`${normalizedMethod}\n${normalizedHost}\n${normalizedPathWithQuery}\n${normalizedBodySha256}`);
211
+ }
212
+
213
+ export function computeSettldPayPayloadHashV1(payload) {
214
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new TypeError("payload must be an object");
215
+ return sha256Hex(canonicalJsonStringify(payload));
216
+ }
217
+
218
+ export function computeSettldPayTokenSha256(token) {
219
+ return sha256Hex(assertNonEmptyString(token, "token"));
220
+ }
221
+
222
+ export function mintSettldPayTokenV1({ payload, keyId = null, publicKeyPem = null, privateKeyPem } = {}) {
223
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new TypeError("payload must be an object");
224
+ const normalizedPayload = normalizeForCanonicalJson(payload, { path: "$" });
225
+ const privatePem = assertNonEmptyString(privateKeyPem, "privateKeyPem");
226
+ const publicPem = (() => {
227
+ if (publicKeyPem === null || publicKeyPem === undefined) return null;
228
+ if (typeof publicKeyPem !== "string" || publicKeyPem.trim() === "") throw new TypeError("publicKeyPem must be a non-empty string");
229
+ return publicKeyPem;
230
+ })();
231
+ const derivedKeyId = publicPem ? keyIdFromPublicKeyPem(publicPem) : null;
232
+ const normalizedKeyId = keyId === null || keyId === undefined || String(keyId).trim() === "" ? derivedKeyId : String(keyId).trim();
233
+ if (!normalizedKeyId) throw new TypeError("keyId is required (or provide publicKeyPem)");
234
+ if (derivedKeyId && normalizedKeyId !== derivedKeyId) throw new TypeError("keyId does not match publicKeyPem");
235
+
236
+ const payloadHashHex = computeSettldPayPayloadHashV1(normalizedPayload);
237
+ const signatureBase64 = signHashHexEd25519(payloadHashHex, privatePem);
238
+ const envelope = normalizeForCanonicalJson(
239
+ {
240
+ v: SETTLD_PAY_TOKEN_VERSION,
241
+ kid: normalizedKeyId,
242
+ payload: normalizedPayload,
243
+ sig: Buffer.from(signatureBase64, "base64").toString("base64url")
244
+ },
245
+ { path: "$" }
246
+ );
247
+ const token = Buffer.from(canonicalJsonStringify(envelope), "utf8").toString("base64url");
248
+ return {
249
+ token,
250
+ envelope,
251
+ kid: normalizedKeyId,
252
+ payloadHashHex,
253
+ tokenSha256: computeSettldPayTokenSha256(token)
254
+ };
255
+ }
256
+
257
+ export function parseSettldPayTokenV1(token) {
258
+ const { envelope, kid, payload, sig } = decodeEnvelope(token);
259
+ return { envelope, kid, payload, sig };
260
+ }
261
+
262
+ export function verifySettldPayTokenV1({
263
+ token,
264
+ keyset,
265
+ nowUnixSeconds = Math.floor(Date.now() / 1000),
266
+ expectedAudience = null,
267
+ expectedPayeeProviderId = null,
268
+ expectedRequestBindingSha256 = null
269
+ } = {}) {
270
+ const { envelope, kid, payload, sig } = decodeEnvelope(token);
271
+ const keyMap = keyMapFromSettldKeyset(keyset);
272
+ const keyEntry = keyMap.get(kid) ?? null;
273
+ if (!keyEntry?.publicKeyPem) return { ok: false, code: "SETTLD_PAY_UNKNOWN_KID", kid };
274
+
275
+ const payloadHashHex = computeSettldPayPayloadHashV1(payload);
276
+ const signatureBase64 = (() => {
277
+ try {
278
+ return Buffer.from(sig, "base64url").toString("base64");
279
+ } catch {
280
+ return null;
281
+ }
282
+ })();
283
+ if (!signatureBase64) return { ok: false, code: "SETTLD_PAY_SIGNATURE_INVALID", kid };
284
+
285
+ let signatureValid = false;
286
+ try {
287
+ signatureValid = verifyHashHexEd25519({ hashHex: payloadHashHex, signatureBase64, publicKeyPem: keyEntry.publicKeyPem });
288
+ } catch {
289
+ signatureValid = false;
290
+ }
291
+ if (!signatureValid) return { ok: false, code: "SETTLD_PAY_SIGNATURE_INVALID", kid };
292
+
293
+ let normalizedPayload;
294
+ try {
295
+ normalizedPayload = buildSettldPayPayloadV1(payload);
296
+ } catch (err) {
297
+ return { ok: false, code: "SETTLD_PAY_PAYLOAD_INVALID", kid, message: err?.message ?? String(err ?? "") };
298
+ }
299
+
300
+ const nowSec = normalizeUnixSeconds(nowUnixSeconds, "nowUnixSeconds");
301
+ if (nowSec > Number(normalizedPayload.exp)) return { ok: false, code: "SETTLD_PAY_EXPIRED", kid, payload: normalizedPayload };
302
+ if (expectedAudience !== null && expectedAudience !== undefined && String(expectedAudience) !== String(normalizedPayload.aud)) {
303
+ return { ok: false, code: "SETTLD_PAY_AUDIENCE_MISMATCH", kid, payload: normalizedPayload };
304
+ }
305
+ if (
306
+ expectedPayeeProviderId !== null &&
307
+ expectedPayeeProviderId !== undefined &&
308
+ String(expectedPayeeProviderId) !== String(normalizedPayload.payeeProviderId)
309
+ ) {
310
+ return { ok: false, code: "SETTLD_PAY_PAYEE_MISMATCH", kid, payload: normalizedPayload };
311
+ }
312
+
313
+ const expectedRequestBinding =
314
+ expectedRequestBindingSha256 === null || expectedRequestBindingSha256 === undefined || String(expectedRequestBindingSha256).trim() === ""
315
+ ? null
316
+ : normalizeHexHash(expectedRequestBindingSha256, "expectedRequestBindingSha256");
317
+ const payloadRequestBindingMode =
318
+ typeof normalizedPayload.requestBindingMode === "string" ? String(normalizedPayload.requestBindingMode).trim().toLowerCase() : null;
319
+ const payloadRequestBindingSha256 =
320
+ typeof normalizedPayload.requestBindingSha256 === "string" ? String(normalizedPayload.requestBindingSha256).trim().toLowerCase() : null;
321
+ if (payloadRequestBindingMode === "strict") {
322
+ if (!payloadRequestBindingSha256 || !/^[0-9a-f]{64}$/.test(payloadRequestBindingSha256)) {
323
+ return { ok: false, code: "SETTLD_PAY_REQUEST_BINDING_MISSING", kid, payload: normalizedPayload };
324
+ }
325
+ if (!expectedRequestBinding) {
326
+ return { ok: false, code: "SETTLD_PAY_REQUEST_BINDING_REQUIRED", kid, payload: normalizedPayload };
327
+ }
328
+ if (payloadRequestBindingSha256 !== expectedRequestBinding) {
329
+ return { ok: false, code: "SETTLD_PAY_REQUEST_BINDING_MISMATCH", kid, payload: normalizedPayload };
330
+ }
331
+ } else if (expectedRequestBinding && payloadRequestBindingSha256 && payloadRequestBindingSha256 !== expectedRequestBinding) {
332
+ return { ok: false, code: "SETTLD_PAY_REQUEST_BINDING_MISMATCH", kid, payload: normalizedPayload };
333
+ }
334
+
335
+ return {
336
+ ok: true,
337
+ kid,
338
+ payload: normalizedPayload,
339
+ envelope,
340
+ payloadHashHex: normalizeHexHash(payloadHashHex, "payloadHashHex"),
341
+ tokenSha256: computeSettldPayTokenSha256(token),
342
+ key: keyEntry
343
+ };
344
+ }
@@ -29,6 +29,7 @@ export const SETTLEMENT_KERNEL_VERIFICATION_CODE = Object.freeze({
29
29
  DECISION_RECORD_DECIDED_AT_INVALID: "decision_record_decided_at_invalid",
30
30
  DECISION_RECORD_POLICY_HASH_USED_MISSING: "decision_record_policy_hash_used_missing",
31
31
  DECISION_RECORD_POLICY_HASH_USED_INVALID: "decision_record_policy_hash_used_invalid",
32
+ DECISION_RECORD_PROFILE_HASH_USED_INVALID: "decision_record_profile_hash_used_invalid",
32
33
  DECISION_RECORD_POLICY_NORMALIZATION_VERSION_INVALID: "decision_record_policy_normalization_version_invalid",
33
34
  DECISION_RECORD_VERIFICATION_METHOD_HASH_USED_INVALID: "decision_record_verification_method_hash_used_invalid",
34
35
 
@@ -84,6 +85,223 @@ function normalizeHexHash(value, name, { allowNull = false } = {}) {
84
85
  return out;
85
86
  }
86
87
 
88
+ function normalizeNullableString(value, name, { max = 256 } = {}) {
89
+ if (value === null || value === undefined) return null;
90
+ const out = String(value);
91
+ if (out.length > max) throw new TypeError(`${name} must be <= ${max} chars`);
92
+ return out;
93
+ }
94
+
95
+ function normalizeNullableBoolean(value, name) {
96
+ if (value === null || value === undefined) return null;
97
+ if (typeof value !== "boolean") throw new TypeError(`${name} must be boolean`);
98
+ return value;
99
+ }
100
+
101
+ function normalizeNullableHttpStatus(value, name) {
102
+ if (value === null || value === undefined) return null;
103
+ const n = Number(value);
104
+ if (!Number.isSafeInteger(n) || n < 100 || n > 999) throw new TypeError(`${name} must be a 3-digit integer status code`);
105
+ return n;
106
+ }
107
+
108
+ function normalizeNullableSafeInt(value, name, { min = 0, max = Number.MAX_SAFE_INTEGER } = {}) {
109
+ if (value === null || value === undefined) return null;
110
+ const n = Number(value);
111
+ if (!Number.isSafeInteger(n) || n < min || n > max) {
112
+ throw new TypeError(`${name} must be an integer in range ${min}..${max}`);
113
+ }
114
+ return n;
115
+ }
116
+
117
+ function normalizeSettlementBindings(value, name, { allowNull = true } = {}) {
118
+ if (value === null || value === undefined) {
119
+ if (allowNull) return null;
120
+ throw new TypeError(`${name} is required`);
121
+ }
122
+ assertPlainObject(value, name);
123
+ return normalizeForCanonicalJson(
124
+ {
125
+ authorizationRef: normalizeNullableString(value.authorizationRef, `${name}.authorizationRef`, { max: 200 }),
126
+ token: value.token
127
+ ? {
128
+ kid: normalizeNullableString(value.token.kid, `${name}.token.kid`, { max: 200 }),
129
+ sha256: normalizeHexHash(value.token.sha256, `${name}.token.sha256`, { allowNull: true }),
130
+ expiresAt: value.token.expiresAt === null || value.token.expiresAt === undefined ? null : String(value.token.expiresAt)
131
+ }
132
+ : null,
133
+ request: value.request
134
+ ? {
135
+ sha256: normalizeHexHash(value.request.sha256, `${name}.request.sha256`, { allowNull: true })
136
+ }
137
+ : null,
138
+ response: value.response
139
+ ? {
140
+ status: normalizeNullableHttpStatus(value.response.status, `${name}.response.status`),
141
+ sha256: normalizeHexHash(value.response.sha256, `${name}.response.sha256`, { allowNull: true })
142
+ }
143
+ : null,
144
+ providerSig: value.providerSig
145
+ ? {
146
+ required: normalizeNullableBoolean(value.providerSig.required, `${name}.providerSig.required`),
147
+ present: normalizeNullableBoolean(value.providerSig.present, `${name}.providerSig.present`),
148
+ verified: normalizeNullableBoolean(value.providerSig.verified, `${name}.providerSig.verified`),
149
+ providerKeyId: normalizeNullableString(value.providerSig.providerKeyId, `${name}.providerSig.providerKeyId`, { max: 200 }),
150
+ keyJwkThumbprintSha256: normalizeHexHash(value.providerSig.keyJwkThumbprintSha256, `${name}.providerSig.keyJwkThumbprintSha256`, {
151
+ allowNull: true
152
+ }),
153
+ error: normalizeNullableString(value.providerSig.error, `${name}.providerSig.error`, { max: 4000 })
154
+ }
155
+ : null,
156
+ providerQuoteSig: value.providerQuoteSig
157
+ ? {
158
+ required: normalizeNullableBoolean(value.providerQuoteSig.required, `${name}.providerQuoteSig.required`),
159
+ present: normalizeNullableBoolean(value.providerQuoteSig.present, `${name}.providerQuoteSig.present`),
160
+ verified: normalizeNullableBoolean(value.providerQuoteSig.verified, `${name}.providerQuoteSig.verified`),
161
+ providerKeyId: normalizeNullableString(value.providerQuoteSig.providerKeyId, `${name}.providerQuoteSig.providerKeyId`, {
162
+ max: 200
163
+ }),
164
+ quoteId: normalizeNullableString(value.providerQuoteSig.quoteId, `${name}.providerQuoteSig.quoteId`, { max: 200 }),
165
+ quoteSha256: normalizeHexHash(value.providerQuoteSig.quoteSha256, `${name}.providerQuoteSig.quoteSha256`, { allowNull: true }),
166
+ keyJwkThumbprintSha256: normalizeHexHash(
167
+ value.providerQuoteSig.keyJwkThumbprintSha256,
168
+ `${name}.providerQuoteSig.keyJwkThumbprintSha256`,
169
+ { allowNull: true }
170
+ ),
171
+ error: normalizeNullableString(value.providerQuoteSig.error, `${name}.providerQuoteSig.error`, { max: 4000 })
172
+ }
173
+ : null,
174
+ reserve: value.reserve
175
+ ? {
176
+ adapter: normalizeNullableString(value.reserve.adapter, `${name}.reserve.adapter`, { max: 200 }),
177
+ mode: normalizeNullableString(value.reserve.mode, `${name}.reserve.mode`, { max: 200 }),
178
+ reserveId: normalizeNullableString(value.reserve.reserveId, `${name}.reserve.reserveId`, { max: 256 }),
179
+ status: normalizeNullableString(value.reserve.status, `${name}.reserve.status`, { max: 64 })
180
+ }
181
+ : null,
182
+ quote: value.quote
183
+ ? {
184
+ quoteId: normalizeNullableString(value.quote.quoteId, `${name}.quote.quoteId`, { max: 200 }),
185
+ quoteSha256: normalizeHexHash(value.quote.quoteSha256, `${name}.quote.quoteSha256`, { allowNull: true }),
186
+ expiresAt: value.quote.expiresAt === null || value.quote.expiresAt === undefined ? null : String(value.quote.expiresAt),
187
+ requestBindingMode: normalizeNullableString(value.quote.requestBindingMode, `${name}.quote.requestBindingMode`, {
188
+ max: 32
189
+ }),
190
+ requestBindingSha256: normalizeHexHash(value.quote.requestBindingSha256, `${name}.quote.requestBindingSha256`, {
191
+ allowNull: true
192
+ })
193
+ }
194
+ : null,
195
+ spendAuthorization: value.spendAuthorization
196
+ ? {
197
+ spendAuthorizationVersion: normalizeNullableString(
198
+ value.spendAuthorization.spendAuthorizationVersion,
199
+ `${name}.spendAuthorization.spendAuthorizationVersion`,
200
+ { max: 64 }
201
+ ),
202
+ idempotencyKey: normalizeNullableString(value.spendAuthorization.idempotencyKey, `${name}.spendAuthorization.idempotencyKey`, {
203
+ max: 256
204
+ }),
205
+ nonce: normalizeNullableString(value.spendAuthorization.nonce, `${name}.spendAuthorization.nonce`, { max: 256 }),
206
+ sponsorRef: normalizeNullableString(value.spendAuthorization.sponsorRef, `${name}.spendAuthorization.sponsorRef`, { max: 200 }),
207
+ sponsorWalletRef: normalizeNullableString(value.spendAuthorization.sponsorWalletRef, `${name}.spendAuthorization.sponsorWalletRef`, {
208
+ max: 200
209
+ }),
210
+ ...(Object.prototype.hasOwnProperty.call(value.spendAuthorization, "policyRef")
211
+ ? {
212
+ policyRef: normalizeNullableString(value.spendAuthorization.policyRef, `${name}.spendAuthorization.policyRef`, {
213
+ max: 200
214
+ })
215
+ }
216
+ : {}),
217
+ agentKeyId: normalizeNullableString(value.spendAuthorization.agentKeyId, `${name}.spendAuthorization.agentKeyId`, { max: 200 }),
218
+ delegationRef: normalizeNullableString(value.spendAuthorization.delegationRef, `${name}.spendAuthorization.delegationRef`, { max: 200 }),
219
+ rootDelegationRef: normalizeNullableString(value.spendAuthorization.rootDelegationRef, `${name}.spendAuthorization.rootDelegationRef`, {
220
+ max: 200
221
+ }),
222
+ rootDelegationHash: normalizeHexHash(value.spendAuthorization.rootDelegationHash, `${name}.spendAuthorization.rootDelegationHash`, {
223
+ allowNull: true
224
+ }),
225
+ effectiveDelegationRef: normalizeNullableString(
226
+ value.spendAuthorization.effectiveDelegationRef,
227
+ `${name}.spendAuthorization.effectiveDelegationRef`,
228
+ { max: 200 }
229
+ ),
230
+ effectiveDelegationHash: normalizeHexHash(
231
+ value.spendAuthorization.effectiveDelegationHash,
232
+ `${name}.spendAuthorization.effectiveDelegationHash`,
233
+ { allowNull: true }
234
+ ),
235
+ policyVersion: normalizeNullableSafeInt(value.spendAuthorization.policyVersion, `${name}.spendAuthorization.policyVersion`, {
236
+ min: 1,
237
+ max: 1_000_000_000
238
+ }),
239
+ policyFingerprint: normalizeHexHash(value.spendAuthorization.policyFingerprint, `${name}.spendAuthorization.policyFingerprint`, {
240
+ allowNull: true
241
+ })
242
+ }
243
+ : null,
244
+ executionIntent: value.executionIntent
245
+ ? {
246
+ schemaVersion: normalizeNullableString(value.executionIntent.schemaVersion, `${name}.executionIntent.schemaVersion`, { max: 64 }),
247
+ intentId: normalizeNullableString(value.executionIntent.intentId, `${name}.executionIntent.intentId`, { max: 200 }),
248
+ intentHash: normalizeHexHash(value.executionIntent.intentHash, `${name}.executionIntent.intentHash`, { allowNull: true }),
249
+ idempotencyKey: normalizeNullableString(value.executionIntent.idempotencyKey, `${name}.executionIntent.idempotencyKey`, {
250
+ max: 256
251
+ }),
252
+ nonce: normalizeNullableString(value.executionIntent.nonce, `${name}.executionIntent.nonce`, { max: 256 }),
253
+ expiresAt:
254
+ value.executionIntent.expiresAt === null || value.executionIntent.expiresAt === undefined
255
+ ? null
256
+ : String(value.executionIntent.expiresAt),
257
+ requestSha256: normalizeHexHash(value.executionIntent.requestSha256, `${name}.executionIntent.requestSha256`, {
258
+ allowNull: true
259
+ }),
260
+ policyHash: normalizeHexHash(value.executionIntent.policyHash, `${name}.executionIntent.policyHash`, { allowNull: true }),
261
+ verificationMethodHash: normalizeHexHash(
262
+ value.executionIntent.verificationMethodHash,
263
+ `${name}.executionIntent.verificationMethodHash`,
264
+ { allowNull: true }
265
+ )
266
+ }
267
+ : null,
268
+ policyDecisionFingerprint: value.policyDecisionFingerprint
269
+ ? {
270
+ fingerprintVersion: normalizeNullableString(
271
+ value.policyDecisionFingerprint.fingerprintVersion,
272
+ `${name}.policyDecisionFingerprint.fingerprintVersion`,
273
+ { max: 64 }
274
+ ),
275
+ policyId: normalizeNullableString(value.policyDecisionFingerprint.policyId, `${name}.policyDecisionFingerprint.policyId`, {
276
+ max: 200
277
+ }),
278
+ policyVersion: normalizeNullableSafeInt(value.policyDecisionFingerprint.policyVersion, `${name}.policyDecisionFingerprint.policyVersion`, {
279
+ min: 1,
280
+ max: 1_000_000_000
281
+ }),
282
+ policyHash: normalizeHexHash(value.policyDecisionFingerprint.policyHash, `${name}.policyDecisionFingerprint.policyHash`, {
283
+ allowNull: true
284
+ }),
285
+ verificationMethodHash: normalizeHexHash(
286
+ value.policyDecisionFingerprint.verificationMethodHash,
287
+ `${name}.policyDecisionFingerprint.verificationMethodHash`,
288
+ { allowNull: true }
289
+ ),
290
+ evaluationHash: normalizeHexHash(
291
+ value.policyDecisionFingerprint.evaluationHash,
292
+ `${name}.policyDecisionFingerprint.evaluationHash`,
293
+ { allowNull: true }
294
+ )
295
+ }
296
+ : null,
297
+ ...(value.metadata && typeof value.metadata === "object" && !Array.isArray(value.metadata)
298
+ ? { metadata: normalizeForCanonicalJson(value.metadata, { path: `${name}.metadata` }) }
299
+ : {})
300
+ },
301
+ { path: "$" }
302
+ );
303
+ }
304
+
87
305
  function assertNonNegativeSafeInt(value, name, { min = 0 } = {}) {
88
306
  const n = Number(value);
89
307
  if (!Number.isSafeInteger(n) || n < min) throw new TypeError(`${name} must be a safe integer >= ${min}`);
@@ -120,6 +338,7 @@ export function buildSettlementDecisionRecord({
120
338
  verificationStatus = null,
121
339
  policyNormalizationVersion = undefined,
122
340
  policyHashUsed,
341
+ profileHashUsed = undefined,
123
342
  verificationMethodHashUsed = undefined,
124
343
  policyRef,
125
344
  verifierRef,
@@ -127,7 +346,8 @@ export function buildSettlementDecisionRecord({
127
346
  runLastEventId = null,
128
347
  runLastChainHash = null,
129
348
  resolutionEventId = null,
130
- decidedAt
349
+ decidedAt,
350
+ bindings = undefined
131
351
  } = {}) {
132
352
  assertIsoDate(decidedAt, "decidedAt");
133
353
  const resolvedSchemaVersion = String(schemaVersion ?? "").trim();
@@ -153,6 +373,13 @@ export function buildSettlementDecisionRecord({
153
373
  ? SETTLEMENT_POLICY_NORMALIZATION_VERSION_V1
154
374
  : String(policyNormalizationVersion ?? "").trim(),
155
375
  policyHashUsed: normalizeHexHash(policyHashUsed, "policyHashUsed", { allowNull: false }),
376
+ ...(profileHashUsed === null || profileHashUsed === undefined
377
+ ? {}
378
+ : {
379
+ profileHashUsed: normalizeHexHash(profileHashUsed, "profileHashUsed", {
380
+ allowNull: false
381
+ })
382
+ }),
156
383
  ...(verificationMethodHashUsed === null || verificationMethodHashUsed === undefined
157
384
  ? {}
158
385
  : {
@@ -178,6 +405,7 @@ export function buildSettlementDecisionRecord({
178
405
  runLastChainHash: runLastChainHash === null ? null : String(runLastChainHash),
179
406
  resolutionEventId: resolutionEventId === null ? null : String(resolutionEventId)
180
407
  },
408
+ ...(bindings === null || bindings === undefined ? {} : { bindings: normalizeSettlementBindings(bindings, "bindings", { allowNull: false }) }),
181
409
  decidedAt: String(decidedAt)
182
410
  },
183
411
  { path: "$" }
@@ -212,7 +440,8 @@ export function buildSettlementReceipt({
212
440
  finalityProvider = SETTLEMENT_FINALITY_PROVIDER.INTERNAL_LEDGER,
213
441
  finalityState = undefined,
214
442
  settledAt = null,
215
- createdAt
443
+ createdAt,
444
+ bindings = undefined
216
445
  } = {}) {
217
446
  assertPlainObject(decisionRecord, "decisionRecord");
218
447
  assertIsoDate(createdAt, "createdAt");
@@ -245,6 +474,7 @@ export function buildSettlementReceipt({
245
474
  finalityProvider: String(finalityProvider ?? SETTLEMENT_FINALITY_PROVIDER.INTERNAL_LEDGER),
246
475
  finalityState: resolvedFinalityState,
247
476
  settledAt: settledAt === null ? null : String(settledAt),
477
+ ...(bindings === null || bindings === undefined ? {} : { bindings: normalizeSettlementBindings(bindings, "bindings", { allowNull: false }) }),
248
478
  createdAt: String(createdAt)
249
479
  },
250
480
  { path: "$" }
@@ -304,6 +534,13 @@ export function verifySettlementKernelArtifacts({ settlement, runId = null } = {
304
534
  } else if (!/^[0-9a-f]{64}$/.test(policyHashUsed)) {
305
535
  errors.push(SETTLEMENT_KERNEL_VERIFICATION_CODE.DECISION_RECORD_POLICY_HASH_USED_INVALID);
306
536
  }
537
+ const profileHashUsedRaw = decisionRecord.profileHashUsed;
538
+ if (profileHashUsedRaw !== undefined) {
539
+ const profileHashUsed = typeof profileHashUsedRaw === "string" ? profileHashUsedRaw.trim().toLowerCase() : "";
540
+ if (!profileHashUsed || !/^[0-9a-f]{64}$/.test(profileHashUsed)) {
541
+ errors.push(SETTLEMENT_KERNEL_VERIFICATION_CODE.DECISION_RECORD_PROFILE_HASH_USED_INVALID);
542
+ }
543
+ }
307
544
  const methodHashUsedRaw = decisionRecord.verificationMethodHashUsed;
308
545
  if (methodHashUsedRaw !== undefined) {
309
546
  const methodHashUsed = typeof methodHashUsedRaw === "string" ? methodHashUsedRaw.trim().toLowerCase() : "";