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,734 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import net from "node:net";
5
+ import { spawn, spawnSync } from "node:child_process";
6
+
7
+ import { createEd25519Keypair, keyIdFromPublicKeyPem } from "../../src/core/crypto.js";
8
+ import { createChainedEvent, finalizeChainedEvent } from "../../src/core/event-chain.js";
9
+ import { buildPolicySnapshot, computePolicyHash } from "../../src/core/policy.js";
10
+ import { computeSlaPolicy } from "../../src/core/sla.js";
11
+ import { presignS3Url } from "../../src/core/s3-presign.js";
12
+ import { verifyArtifactHash, verifyArtifactVersion, verifySettlementBalances } from "../../packages/artifact-verify/src/index.js";
13
+
14
+ const API_BASE_URL = process.env.ACCEPTANCE_API_BASE_URL ?? "http://127.0.0.1:3000";
15
+ const RECEIVER_BASE_URL = process.env.ACCEPTANCE_RECEIVER_BASE_URL ?? "http://127.0.0.1:4000";
16
+
17
+ const TENANT_ID = process.env.ACCEPTANCE_TENANT_ID ?? "tenant_default";
18
+ // docker-compose.yml configures tok_ops by default via PROXY_OPS_TOKENS.
19
+ const OPS_TOKEN = process.env.ACCEPTANCE_OPS_TOKEN ?? "tok_ops";
20
+ const PROTOCOL = process.env.ACCEPTANCE_PROTOCOL ?? "1.0";
21
+
22
+ const MINIO_ENDPOINT = process.env.ACCEPTANCE_MINIO_ENDPOINT ?? "http://127.0.0.1:9000";
23
+ const MINIO_REGION = process.env.ACCEPTANCE_MINIO_REGION ?? "us-east-1";
24
+ const MINIO_BUCKET = process.env.ACCEPTANCE_MINIO_BUCKET ?? "proxy-artifacts";
25
+ const MINIO_ACCESS_KEY_ID = process.env.ACCEPTANCE_MINIO_ACCESS_KEY_ID ?? "proxy";
26
+ const MINIO_SECRET_ACCESS_KEY = process.env.ACCEPTANCE_MINIO_SECRET_ACCESS_KEY ?? "proxysecret";
27
+ const MINIO_PREFIX = process.env.ACCEPTANCE_MINIO_PREFIX ?? "settld/";
28
+ const MINIO_FORCE_PATH_STYLE = process.env.ACCEPTANCE_MINIO_FORCE_PATH_STYLE === "0" ? false : true;
29
+
30
+ const ART_DIR = process.env.ACCEPTANCE_ARTIFACT_DIR ?? null;
31
+
32
+ function sleep(ms) {
33
+ return new Promise((r) => setTimeout(r, ms));
34
+ }
35
+
36
+ async function waitFor(fn, { timeoutMs = 45_000, intervalMs = 250 } = {}) {
37
+ const deadline = Date.now() + timeoutMs;
38
+ let lastErr = null;
39
+ while (Date.now() < deadline) {
40
+ try {
41
+ const v = await fn();
42
+ if (v) return v;
43
+ } catch (err) {
44
+ lastErr = err;
45
+ }
46
+ await sleep(intervalMs);
47
+ }
48
+ if (lastErr) throw lastErr;
49
+ throw new Error("timeout");
50
+ }
51
+
52
+ async function httpJson({ baseUrl, method, path, headers, body }) {
53
+ const res = await fetch(`${baseUrl}${path}`, {
54
+ method,
55
+ headers: {
56
+ ...(headers ?? {}),
57
+ ...(body !== undefined ? { "content-type": "application/json; charset=utf-8" } : {})
58
+ },
59
+ body: body === undefined ? undefined : JSON.stringify(body)
60
+ });
61
+ const text = await res.text();
62
+ const json = text && res.headers.get("content-type")?.includes("json") ? JSON.parse(text) : null;
63
+ return { status: res.status, json, text, headers: res.headers };
64
+ }
65
+
66
+ async function pickPort() {
67
+ return await new Promise((resolve, reject) => {
68
+ const s = net.createServer();
69
+ s.listen(0, "127.0.0.1", () => {
70
+ const addr = s.address();
71
+ if (!addr || typeof addr === "string") {
72
+ s.close();
73
+ reject(new Error("unexpected server address"));
74
+ return;
75
+ }
76
+ const port = addr.port;
77
+ s.close((err) => {
78
+ if (err) reject(err);
79
+ else resolve(port);
80
+ });
81
+ });
82
+ s.on("error", reject);
83
+ });
84
+ }
85
+
86
+ function spawnNodeProcess(scriptPath, { name, env }) {
87
+ const child = spawn(process.execPath, [scriptPath], {
88
+ cwd: process.cwd(),
89
+ env,
90
+ stdio: ["ignore", "pipe", "pipe"]
91
+ });
92
+ let logs = "";
93
+ const append = (chunk) => {
94
+ logs += String(chunk ?? "");
95
+ if (logs.length > 64_000) logs = logs.slice(-64_000);
96
+ };
97
+ child.stdout?.on("data", append);
98
+ child.stderr?.on("data", append);
99
+ child.on("exit", (code, signal) => {
100
+ if (code === 0 || signal === "SIGTERM") return;
101
+ // eslint-disable-next-line no-console
102
+ console.error(`[acceptance] ${name} exited unexpectedly (code=${code ?? "null"} signal=${signal ?? ""})`);
103
+ });
104
+ return {
105
+ child,
106
+ name,
107
+ logs: () => logs
108
+ };
109
+ }
110
+
111
+ async function writeArtifactFile(name, contents) {
112
+ if (!ART_DIR) return null;
113
+ await fs.mkdir(ART_DIR, { recursive: true });
114
+ const fp = path.join(ART_DIR, name);
115
+ await fs.writeFile(fp, contents, "utf8");
116
+ return fp;
117
+ }
118
+
119
+ function objectKeyForArtifact({ artifactHash, artifactType }) {
120
+ const typeSeg = String(artifactType ?? "")
121
+ .trim()
122
+ .replaceAll("/", "_")
123
+ .replaceAll("\\", "_")
124
+ .replaceAll("\0", "");
125
+ const hashSeg = String(artifactHash ?? "").trim();
126
+ if (!hashSeg) throw new Error("missing artifactHash");
127
+ const prefix = MINIO_PREFIX.endsWith("/") ? MINIO_PREFIX : `${MINIO_PREFIX}/`;
128
+ return `${prefix}artifacts/${typeSeg}/${hashSeg}.json`.replaceAll(/\/{2,}/g, "/");
129
+ }
130
+
131
+ async function getMinioJson({ key }) {
132
+ const url = presignS3Url({
133
+ endpoint: MINIO_ENDPOINT,
134
+ region: MINIO_REGION,
135
+ bucket: MINIO_BUCKET,
136
+ key,
137
+ method: "GET",
138
+ accessKeyId: MINIO_ACCESS_KEY_ID,
139
+ secretAccessKey: MINIO_SECRET_ACCESS_KEY,
140
+ forcePathStyle: MINIO_FORCE_PATH_STYLE,
141
+ expiresInSeconds: 60
142
+ });
143
+ const res = await fetch(url);
144
+ const text = await res.text();
145
+ if (res.status !== 200) throw new Error(`minio GET failed: http ${res.status} ${text.slice(0, 200)}`);
146
+ return JSON.parse(text);
147
+ }
148
+
149
+ async function main() {
150
+ await writeArtifactFile(
151
+ "inputs.json",
152
+ JSON.stringify(
153
+ {
154
+ apiBaseUrl: API_BASE_URL,
155
+ receiverBaseUrl: RECEIVER_BASE_URL,
156
+ tenantId: TENANT_ID,
157
+ protocol: PROTOCOL,
158
+ minio: { endpoint: MINIO_ENDPOINT, region: MINIO_REGION, bucket: MINIO_BUCKET, prefix: MINIO_PREFIX, forcePathStyle: MINIO_FORCE_PATH_STYLE }
159
+ },
160
+ null,
161
+ 2
162
+ )
163
+ );
164
+
165
+ await waitFor(async () => {
166
+ const r = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: "/healthz" }).catch(() => null);
167
+ return r && r.status === 200;
168
+ });
169
+ await waitFor(async () => {
170
+ const r = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: "/capabilities" }).catch(() => null);
171
+ if (!r || r.status !== 200) return false;
172
+ if (r.json?.protocol?.current !== PROTOCOL) return false;
173
+ if (r.headers?.get?.("x-settld-protocol") !== PROTOCOL) return false;
174
+ return true;
175
+ });
176
+ await waitFor(async () => {
177
+ const r = await httpJson({ baseUrl: RECEIVER_BASE_URL, method: "GET", path: "/ready" }).catch(() => null);
178
+ return r && r.status === 200;
179
+ });
180
+
181
+ const createKey = await httpJson({
182
+ baseUrl: API_BASE_URL,
183
+ method: "POST",
184
+ path: "/ops/api-keys",
185
+ headers: { "x-proxy-tenant-id": TENANT_ID, "x-proxy-ops-token": OPS_TOKEN, "x-settld-protocol": PROTOCOL },
186
+ body: { scopes: ["ops_read", "ops_write", "finance_read", "finance_write", "audit_read"] }
187
+ });
188
+ assert.equal(createKey.status, 201, createKey.text);
189
+ const bearer = `Bearer ${createKey.json.keyId}.${createKey.json.secret}`;
190
+ await writeArtifactFile(
191
+ "context.json",
192
+ JSON.stringify({ tenantId: TENANT_ID, protocol: PROTOCOL, apiBaseUrl: API_BASE_URL, receiverBaseUrl: RECEIVER_BASE_URL, bearer }, null, 2)
193
+ );
194
+
195
+ const headersBase = { "x-proxy-tenant-id": TENANT_ID, authorization: bearer, "x-settld-protocol": PROTOCOL };
196
+
197
+ // Primitive checks: A2A discovery, agreement delegation CRUD, x402 verification gate.
198
+ {
199
+ const agentCard = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: "/.well-known/agent.json" });
200
+ assert.equal(agentCard.status, 200, agentCard.text);
201
+ assert.equal(typeof agentCard.json?.name, "string");
202
+ assert.equal(typeof agentCard.json?.url, "string");
203
+ assert.ok(Array.isArray(agentCard.json?.skills), "agent card skills must be an array");
204
+
205
+ const parentAgreementHash = "a".repeat(64);
206
+ const childAgreementHash = "b".repeat(64);
207
+
208
+ const createDelegation = await httpJson({
209
+ baseUrl: API_BASE_URL,
210
+ method: "POST",
211
+ path: `/agreements/${parentAgreementHash}/delegations`,
212
+ headers: { ...headersBase, "x-idempotency-key": `dlg_create_${Date.now()}` },
213
+ body: {
214
+ childAgreementHash,
215
+ delegatorAgentId: "agt_acceptance_delegator",
216
+ delegateeAgentId: "agt_acceptance_delegatee",
217
+ budgetCapCents: 1234,
218
+ currency: "USD",
219
+ ancestorChain: [parentAgreementHash],
220
+ delegationDepth: 1,
221
+ maxDelegationDepth: 3
222
+ }
223
+ });
224
+ assert.equal(createDelegation.status, 201, createDelegation.text);
225
+ const delegationId = String(createDelegation.json?.delegation?.delegationId ?? "");
226
+ assert.ok(delegationId, "delegationId missing from create response");
227
+
228
+ const listDelegations = await httpJson({
229
+ baseUrl: API_BASE_URL,
230
+ method: "GET",
231
+ path: `/agreements/${parentAgreementHash}/delegations`,
232
+ headers: headersBase
233
+ });
234
+ assert.equal(listDelegations.status, 200, listDelegations.text);
235
+ assert.ok(Array.isArray(listDelegations.json?.delegations), "delegations list missing");
236
+ assert.ok(
237
+ listDelegations.json.delegations.some((d) => String(d?.delegationId ?? "") === delegationId),
238
+ "created delegation missing from list"
239
+ );
240
+
241
+ const getDelegation = await httpJson({
242
+ baseUrl: API_BASE_URL,
243
+ method: "GET",
244
+ path: `/delegations/${delegationId}`,
245
+ headers: headersBase
246
+ });
247
+ assert.equal(getDelegation.status, 200, getDelegation.text);
248
+ assert.equal(String(getDelegation.json?.delegation?.delegationId ?? ""), delegationId);
249
+ assert.equal(String(getDelegation.json?.delegation?.parentAgreementHash ?? ""), parentAgreementHash);
250
+ assert.equal(String(getDelegation.json?.delegation?.childAgreementHash ?? ""), childAgreementHash);
251
+
252
+ const gateCreate = await httpJson({
253
+ baseUrl: API_BASE_URL,
254
+ method: "POST",
255
+ path: "/x402/gate/create",
256
+ headers: { ...headersBase, "x-idempotency-key": `x402_create_${Date.now()}` },
257
+ body: {
258
+ payerAgentId: "agt_acceptance_x402_payer",
259
+ payeeAgentId: "agt_acceptance_x402_payee",
260
+ amountCents: 500,
261
+ currency: "USD",
262
+ autoFundPayerCents: 5000,
263
+ disputeWindowDays: 7
264
+ }
265
+ });
266
+ assert.equal(gateCreate.status, 201, gateCreate.text);
267
+ const gateId = String(gateCreate.json?.gate?.gateId ?? "");
268
+ assert.ok(gateId, "gateId missing from x402 create response");
269
+
270
+ const gateAuthorize = await httpJson({
271
+ baseUrl: API_BASE_URL,
272
+ method: "POST",
273
+ path: "/x402/gate/authorize-payment",
274
+ headers: { ...headersBase, "x-idempotency-key": `x402_authorize_${Date.now()}` },
275
+ body: { gateId }
276
+ });
277
+ assert.equal(gateAuthorize.status, 200, gateAuthorize.text);
278
+
279
+ const gateVerify = await httpJson({
280
+ baseUrl: API_BASE_URL,
281
+ method: "POST",
282
+ path: "/x402/gate/verify",
283
+ headers: { ...headersBase, "x-idempotency-key": `x402_verify_${Date.now()}` },
284
+ body: { gateId, verificationStatus: "green", runStatus: "completed", evidenceRefs: ["acceptance:evidence#1"] }
285
+ });
286
+ assert.equal(gateVerify.status, 200, gateVerify.text);
287
+ assert.equal(String(gateVerify.json?.gate?.status ?? ""), "resolved");
288
+ assert.notEqual(String(gateVerify.json?.settlement?.status ?? "").toLowerCase(), "locked");
289
+
290
+ const gateGet = await httpJson({
291
+ baseUrl: API_BASE_URL,
292
+ method: "GET",
293
+ path: `/x402/gate/${gateId}`,
294
+ headers: headersBase
295
+ });
296
+ assert.equal(gateGet.status, 200, gateGet.text);
297
+ assert.equal(String(gateGet.json?.gate?.gateId ?? ""), gateId);
298
+ }
299
+
300
+ // Gateway proxy smoke: upstream 402 -> gate create -> paid retry -> verify + settlement headers.
301
+ {
302
+ const upstreamPort = await pickPort();
303
+ const gatewayPort = await pickPort();
304
+ const apiKeyForGateway = `${createKey.json.keyId}.${createKey.json.secret}`;
305
+ const upstreamUrl = `http://127.0.0.1:${upstreamPort}/`;
306
+ const gatewayUrl = `http://127.0.0.1:${gatewayPort}`;
307
+
308
+ const services = [];
309
+ try {
310
+ const upstream = spawnNodeProcess("services/x402-gateway/examples/upstream-mock.js", {
311
+ name: "upstream-mock",
312
+ env: {
313
+ ...process.env,
314
+ PORT: String(upstreamPort),
315
+ BIND_HOST: "127.0.0.1",
316
+ SETTLD_PAY_KEYSET_URL: `${API_BASE_URL}/.well-known/settld-keys.json`
317
+ }
318
+ });
319
+ services.push(upstream);
320
+ await waitFor(async () => {
321
+ const r = await httpJson({ baseUrl: `http://127.0.0.1:${upstreamPort}`, method: "GET", path: "/healthz" }).catch(() => null);
322
+ return r && r.status === 200;
323
+ });
324
+
325
+ const gateway = spawnNodeProcess("services/x402-gateway/src/server.js", {
326
+ name: "x402-gateway",
327
+ env: {
328
+ ...process.env,
329
+ PORT: String(gatewayPort),
330
+ BIND_HOST: "127.0.0.1",
331
+ SETTLD_API_URL: API_BASE_URL,
332
+ SETTLD_API_KEY: apiKeyForGateway,
333
+ UPSTREAM_URL: upstreamUrl,
334
+ X402_AUTOFUND: "1"
335
+ }
336
+ });
337
+ services.push(gateway);
338
+ await waitFor(async () => {
339
+ const r = await httpJson({ baseUrl: gatewayUrl, method: "GET", path: "/healthz" }).catch(() => null);
340
+ return r && r.status === 200;
341
+ });
342
+
343
+ const first = await httpJson({
344
+ baseUrl: gatewayUrl,
345
+ method: "GET",
346
+ path: "/exa/search?q=acceptance+gateway+smoke",
347
+ headers: { "x-proxy-tenant-id": TENANT_ID }
348
+ });
349
+ assert.equal(first.status, 402, first.text);
350
+ const gateId = String(first.headers.get("x-settld-gate-id") ?? "").trim();
351
+ assert.ok(gateId, "gateway response missing x-settld-gate-id");
352
+
353
+ const paid = await httpJson({
354
+ baseUrl: gatewayUrl,
355
+ method: "GET",
356
+ path: "/exa/search?q=acceptance+gateway+smoke",
357
+ headers: { "x-proxy-tenant-id": TENANT_ID, "x-settld-gate-id": gateId }
358
+ });
359
+ assert.equal(paid.status, 200, paid.text);
360
+ const settlementStatus = String(paid.headers.get("x-settld-settlement-status") ?? "").toLowerCase();
361
+ assert.ok(settlementStatus === "released" || settlementStatus === "resolved", `unexpected settlement status: ${settlementStatus}`);
362
+
363
+ const gate = await httpJson({
364
+ baseUrl: API_BASE_URL,
365
+ method: "GET",
366
+ path: `/x402/gate/${gateId}`,
367
+ headers: headersBase
368
+ });
369
+ assert.equal(gate.status, 200, gate.text);
370
+ assert.equal(String(gate.json?.gate?.gateId ?? ""), gateId);
371
+ assert.equal(String(gate.json?.gate?.status ?? "").toLowerCase(), "resolved");
372
+
373
+ await writeArtifactFile(
374
+ "x402-gateway-smoke.json",
375
+ JSON.stringify(
376
+ {
377
+ ok: true,
378
+ upstreamPort,
379
+ gatewayPort,
380
+ gateId,
381
+ firstStatus: first.status,
382
+ paidStatus: paid.status,
383
+ settlementStatus: paid.headers.get("x-settld-settlement-status") ?? null
384
+ },
385
+ null,
386
+ 2
387
+ )
388
+ );
389
+ } finally {
390
+ for (const svc of services.reverse()) {
391
+ if (!svc?.child || svc.child.exitCode !== null) continue;
392
+ svc.child.kill("SIGTERM");
393
+ await Promise.race([
394
+ new Promise((resolve) => svc.child.once("exit", resolve)),
395
+ sleep(750).then(() => {
396
+ if (svc.child.exitCode === null) svc.child.kill("SIGKILL");
397
+ })
398
+ ]);
399
+ await writeArtifactFile(`x402-gateway-smoke.${svc.name}.log`, svc.logs());
400
+ }
401
+ }
402
+ }
403
+
404
+ // Robot setup
405
+ const { publicKeyPem: robotPublicKeyPem, privateKeyPem: robotPrivateKeyPem } = createEd25519Keypair();
406
+ const robotKeyId = keyIdFromPublicKeyPem(robotPublicKeyPem);
407
+ const robotId = `rob_acceptance_${Date.now()}`;
408
+
409
+ const regRobot = await httpJson({
410
+ baseUrl: API_BASE_URL,
411
+ method: "POST",
412
+ path: "/robots/register",
413
+ headers: { ...headersBase, "x-idempotency-key": `robot_reg_${robotId}` },
414
+ body: { robotId, publicKeyPem: robotPublicKeyPem }
415
+ });
416
+ assert.equal(regRobot.status, 201, regRobot.text);
417
+
418
+ const nowMs = Date.now();
419
+ const avail = await httpJson({
420
+ baseUrl: API_BASE_URL,
421
+ method: "POST",
422
+ path: `/robots/${robotId}/availability`,
423
+ headers: {
424
+ ...headersBase,
425
+ "x-idempotency-key": `robot_avail_${robotId}`,
426
+ "x-proxy-expected-prev-chain-hash": regRobot.json.robot.lastChainHash
427
+ },
428
+ body: {
429
+ availability: [{ startAt: new Date(nowMs - 2 * 60 * 60_000).toISOString(), endAt: new Date(nowMs + 2 * 60 * 60_000).toISOString() }]
430
+ }
431
+ });
432
+ assert.equal(avail.status, 201, avail.text);
433
+
434
+ // Job setup
435
+ const createJob = await httpJson({
436
+ baseUrl: API_BASE_URL,
437
+ method: "POST",
438
+ path: "/jobs",
439
+ headers: { ...headersBase, "x-idempotency-key": `job_create_${robotId}` },
440
+ body: { templateId: "reset_lite", constraints: {} }
441
+ });
442
+ assert.equal(createJob.status, 201, createJob.text);
443
+ const jobId = createJob.json.job.id;
444
+ let lastChainHash = createJob.json.job.lastChainHash;
445
+
446
+ // Book a window in the past so SLA breach+credit are auto-recorded after settlement.
447
+ const bookingStartAt = new Date(nowMs - 30 * 60_000).toISOString();
448
+ const bookingEndAt = new Date(nowMs - 20 * 60_000).toISOString();
449
+ const environmentTier = "ENV_MANAGED_BUILDING";
450
+
451
+ const quote = await httpJson({
452
+ baseUrl: API_BASE_URL,
453
+ method: "POST",
454
+ path: `/jobs/${jobId}/quote`,
455
+ headers: { ...headersBase, "x-idempotency-key": `job_quote_${jobId}`, "x-proxy-expected-prev-chain-hash": lastChainHash },
456
+ body: { startAt: bookingStartAt, endAt: bookingEndAt, environmentTier, requiresOperatorCoverage: false }
457
+ });
458
+ assert.equal(quote.status, 201, quote.text);
459
+ lastChainHash = quote.json.job.lastChainHash;
460
+
461
+ const creditPolicy = { enabled: true, defaultAmountCents: 100, maxAmountCents: 200, currency: "USD" };
462
+ const evidencePolicy = { retentionDays: 0 };
463
+ const sla = computeSlaPolicy({ environmentTier });
464
+ const policySnapshot = buildPolicySnapshot({
465
+ contractId: "contract_default",
466
+ contractVersion: 1,
467
+ environmentTier,
468
+ requiresOperatorCoverage: false,
469
+ sla,
470
+ creditPolicy,
471
+ evidencePolicy,
472
+ claimPolicy: null,
473
+ coveragePolicy: null
474
+ });
475
+ const policyHash = computePolicyHash(policySnapshot);
476
+
477
+ const book = await httpJson({
478
+ baseUrl: API_BASE_URL,
479
+ method: "POST",
480
+ path: `/jobs/${jobId}/book`,
481
+ headers: { ...headersBase, "x-idempotency-key": `job_book_${jobId}`, "x-proxy-expected-prev-chain-hash": lastChainHash },
482
+ body: {
483
+ paymentHoldId: `hold_${jobId}`,
484
+ startAt: bookingStartAt,
485
+ endAt: bookingEndAt,
486
+ environmentTier,
487
+ requiresOperatorCoverage: false,
488
+ contractId: "contract_default",
489
+ contractVersion: 1,
490
+ sla,
491
+ creditPolicy,
492
+ evidencePolicy,
493
+ policySnapshot,
494
+ policyHash
495
+ }
496
+ });
497
+ assert.equal(book.status, 201, book.text);
498
+ lastChainHash = book.json.job.lastChainHash;
499
+
500
+ async function postServerJobEvent(type, payload, idempotencyKey) {
501
+ for (let attempt = 0; attempt < 3; attempt += 1) {
502
+ const r = await httpJson({
503
+ baseUrl: API_BASE_URL,
504
+ method: "POST",
505
+ path: `/jobs/${jobId}/events`,
506
+ headers: { ...headersBase, "x-idempotency-key": idempotencyKey, "x-proxy-expected-prev-chain-hash": lastChainHash },
507
+ body: { type, actor: { type: "system", id: "proxy" }, payload }
508
+ });
509
+ if (r.status === 201) {
510
+ lastChainHash = r.json.job.lastChainHash;
511
+ return r.json.event;
512
+ }
513
+ if (r.status === 409) {
514
+ const latest = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/jobs/${jobId}/events`, headers: headersBase });
515
+ const events = Array.isArray(latest.json?.events) ? latest.json.events : [];
516
+ const tailHash = events.length ? events[events.length - 1]?.chainHash ?? null : null;
517
+ if (typeof tailHash === "string" && tailHash.trim()) {
518
+ lastChainHash = tailHash;
519
+ continue;
520
+ }
521
+ }
522
+ assert.equal(r.status, 201, r.text);
523
+ }
524
+ throw new Error(`failed to append server event ${type} after retry`);
525
+ }
526
+
527
+ async function postRobotJobEvent(type, payload) {
528
+ for (let attempt = 0; attempt < 3; attempt += 1) {
529
+ const draft = createChainedEvent({ streamId: jobId, type, actor: { type: "robot", id: robotId }, payload });
530
+ const finalized = finalizeChainedEvent({
531
+ event: draft,
532
+ prevChainHash: lastChainHash,
533
+ signer: { keyId: robotKeyId, privateKeyPem: robotPrivateKeyPem }
534
+ });
535
+ const r = await httpJson({
536
+ baseUrl: API_BASE_URL,
537
+ method: "POST",
538
+ path: `/jobs/${jobId}/events`,
539
+ headers: { ...headersBase, "x-idempotency-key": `robot_evt_${jobId}_${type}` },
540
+ body: finalized
541
+ });
542
+ if (r.status === 201) {
543
+ lastChainHash = r.json.job.lastChainHash;
544
+ return r.json.event;
545
+ }
546
+ if (r.status === 409) {
547
+ const latest = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/jobs/${jobId}/events`, headers: headersBase });
548
+ const events = Array.isArray(latest.json?.events) ? latest.json.events : [];
549
+ const tailHash = events.length ? events[events.length - 1]?.chainHash ?? null : null;
550
+ if (typeof tailHash === "string" && tailHash.trim()) {
551
+ lastChainHash = tailHash;
552
+ continue;
553
+ }
554
+ }
555
+ assert.equal(r.status, 201, r.text);
556
+ }
557
+ throw new Error(`failed to append robot event ${type} after retry`);
558
+ }
559
+
560
+ await postServerJobEvent("MATCHED", { robotId }, `m_${jobId}`);
561
+ await postServerJobEvent("RESERVED", { robotId, startAt: bookingStartAt, endAt: bookingEndAt, reservationId: `rsv_${jobId}` }, `r_${jobId}`);
562
+
563
+ const accessPlanId = `ap_${jobId}`;
564
+ const nowIso = new Date().toISOString();
565
+ await postServerJobEvent(
566
+ "ACCESS_PLAN_ISSUED",
567
+ {
568
+ jobId,
569
+ accessPlanId,
570
+ method: "DOCKED_IN_BUILDING",
571
+ credentialRef: `vault://access/${accessPlanId}/v1`,
572
+ scope: { areas: ["ENTRYWAY"], noGo: [] },
573
+ validFrom: new Date(Date.parse(nowIso) - 5 * 60_000).toISOString(),
574
+ validTo: new Date(Date.parse(nowIso) + 30 * 60_000).toISOString(),
575
+ revocable: true,
576
+ requestedBy: "acceptance"
577
+ },
578
+ `ap_${jobId}`
579
+ );
580
+
581
+ await postServerJobEvent(
582
+ "INCIDENT_REPORTED",
583
+ {
584
+ jobId,
585
+ incidentId: `inc_${jobId}`,
586
+ type: "ACCESS_FAILURE",
587
+ severity: 2,
588
+ summary: "acceptance incident",
589
+ reportedBy: "ops"
590
+ },
591
+ `inc_${jobId}`
592
+ );
593
+
594
+ await postRobotJobEvent("EN_ROUTE", { etaSeconds: 60 });
595
+ await postRobotJobEvent("ACCESS_GRANTED", { jobId, accessPlanId, method: "DOCKED_IN_BUILDING" });
596
+ await postRobotJobEvent("EXECUTION_STARTED", { plan: ["acceptance_task"] });
597
+ await postRobotJobEvent("EXECUTION_COMPLETED", { report: { durationSeconds: 5 } });
598
+
599
+ const settledEvent = await postServerJobEvent("SETTLED", { settlement: "acceptance" }, `s_${jobId}`);
600
+
601
+ // Best-effort: accounting worker may append SLA events asynchronously.
602
+ // Keep this non-fatal in acceptance; downstream artifact/delivery checks are the hard gate.
603
+ let settlementEvents = [];
604
+ const slaEventsAutoRecorded = await waitFor(async () => {
605
+ const res = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/jobs/${jobId}/events`, headers: headersBase });
606
+ if (res.status !== 200) return false;
607
+ settlementEvents = Array.isArray(res.json?.events) ? res.json.events : [];
608
+ const hasBreach = settlementEvents.some((e) => e?.type === "SLA_BREACH_DETECTED" && e?.payload?.settledEventId === settledEvent.id);
609
+ const hasCredit = settlementEvents.some((e) => e?.type === "SLA_CREDIT_ISSUED" && e?.payload?.settledEventId === settledEvent.id);
610
+ return hasBreach && hasCredit;
611
+ }, { timeoutMs: 45_000 }).then(() => true).catch(() => false);
612
+
613
+ if (!slaEventsAutoRecorded) {
614
+ const latest = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/jobs/${jobId}/events`, headers: headersBase });
615
+ if (latest.status === 200) settlementEvents = Array.isArray(latest.json?.events) ? latest.json.events : settlementEvents;
616
+ }
617
+ await writeArtifactFile("events.after-settlement.json", JSON.stringify(settlementEvents, null, 2));
618
+
619
+ // Wait for artifacts to be built and stored.
620
+ const artifacts = await waitFor(async () => {
621
+ const res = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/jobs/${jobId}/artifacts`, headers: headersBase });
622
+ if (res.status !== 200) return false;
623
+ const list = Array.isArray(res.json?.artifacts) ? res.json.artifacts : [];
624
+ const hasSettlement = list.some((a) => (a?.artifactType ?? a?.schemaVersion) === "SettlementStatement.v1" && a?.artifactHash);
625
+ if (!hasSettlement) return false;
626
+ return list;
627
+ });
628
+ await writeArtifactFile("artifacts.list.json", JSON.stringify(artifacts, null, 2));
629
+
630
+ // Wait for deliveries to be acked.
631
+ const deliveries = await waitFor(async () => {
632
+ const res = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: "/ops/deliveries", headers: headersBase });
633
+ if (res.status !== 200) return false;
634
+ const list = Array.isArray(res.json?.deliveries) ? res.json.deliveries : [];
635
+ const delivered = list.filter((d) => d?.state === "delivered" && d?.destinationId === "receiver_v1");
636
+ if (!delivered.length) return false;
637
+ const allAcked = delivered.every((d) => d?.ackReceivedAt);
638
+ if (!allAcked) return false;
639
+ return delivered;
640
+ });
641
+ assert.ok(deliveries.length >= 1);
642
+ await writeArtifactFile("deliveries.acked.json", JSON.stringify(deliveries, null, 2));
643
+
644
+ // Verify receiver stored by hash in MinIO (content-addressed key).
645
+ const pick = artifacts.find((a) => (a?.artifactType ?? a?.schemaVersion) === "SettlementStatement.v1") ?? artifacts[0];
646
+ assert.ok(pick?.artifactHash, "missing artifactHash");
647
+ assert.ok(pick?.artifactType, "missing artifactType");
648
+ const key = objectKeyForArtifact({ artifactHash: pick.artifactHash, artifactType: pick.artifactType });
649
+ const stored = await getMinioJson({ key });
650
+ const storedFp = await writeArtifactFile(`minio.${pick.artifactHash}.json`, JSON.stringify(stored, null, 2));
651
+ const ver = verifyArtifactVersion(stored);
652
+ assert.equal(ver.ok, true, JSON.stringify(ver));
653
+ const hash = verifyArtifactHash(stored);
654
+ assert.equal(hash.ok, true, JSON.stringify(hash));
655
+ const bal = verifySettlementBalances(stored);
656
+ assert.equal(bal.ok, true, JSON.stringify(bal));
657
+
658
+ // Also run verifier CLI on the exact stored bytes (ga-style smoke test).
659
+ if (storedFp) {
660
+ const cli = spawnSync("node", ["packages/artifact-verify/bin/settld-verify.js", storedFp], { encoding: "utf8" });
661
+ await writeArtifactFile("settld-verify.stdout.txt", cli.stdout ?? "");
662
+ await writeArtifactFile("settld-verify.stderr.txt", cli.stderr ?? "");
663
+ assert.equal(cli.status, 0, `settld-verify failed: ${cli.stderr ?? cli.stdout ?? ""}`.trim());
664
+ }
665
+
666
+ // Month close: request and wait until closed with a statement artifact.
667
+ const month = new Date().toISOString().slice(0, 7);
668
+ const closeReq = await httpJson({
669
+ baseUrl: API_BASE_URL,
670
+ method: "POST",
671
+ path: "/ops/month-close",
672
+ headers: { ...headersBase, "x-idempotency-key": `month_close_${month}` },
673
+ body: { month }
674
+ });
675
+ assert.ok(closeReq.status === 202 || closeReq.status === 200, closeReq.text);
676
+
677
+ const monthClose = await waitFor(async () => {
678
+ const res = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/ops/month-close?month=${month}`, headers: headersBase });
679
+ if (res.status !== 200) return false;
680
+ const mc = res.json?.monthClose ?? null;
681
+ const stmt = res.json?.statementArtifact ?? null;
682
+ if (!mc || mc.status !== "CLOSED") return false;
683
+ if (!stmt || !stmt.artifactHash) return false;
684
+ return { mc, stmt };
685
+ });
686
+ await writeArtifactFile("month-close.json", JSON.stringify(monthClose, null, 2));
687
+
688
+ {
689
+ const ver2 = verifyArtifactVersion(monthClose.stmt);
690
+ assert.equal(ver2.ok, true, JSON.stringify(ver2));
691
+ const hash2 = verifyArtifactHash(monthClose.stmt);
692
+ assert.equal(hash2.ok, true, JSON.stringify(hash2));
693
+ }
694
+
695
+ // Immutability check: second fetch must match hash.
696
+ const monthClose2 = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: `/ops/month-close?month=${month}`, headers: headersBase });
697
+ assert.equal(monthClose2.status, 200, monthClose2.text);
698
+ assert.equal(monthClose2.json?.statementArtifact?.artifactHash, monthClose.stmt.artifactHash, "month statement hash changed across fetch");
699
+
700
+ // Retention cleanup (audited) + ops status sanity.
701
+ const retention = await httpJson({
702
+ baseUrl: API_BASE_URL,
703
+ method: "POST",
704
+ path: "/ops/maintenance/retention/run",
705
+ headers: { ...headersBase, "x-idempotency-key": `retention_${Date.now()}` },
706
+ body: { dryRun: true, batchSize: 1, maxMillis: 500 }
707
+ });
708
+ assert.equal(retention.status, 200, retention.text);
709
+
710
+ const status = await httpJson({ baseUrl: API_BASE_URL, method: "GET", path: "/ops/status", headers: headersBase });
711
+ assert.equal(status.status, 200, status.text);
712
+ await writeArtifactFile("ops.status.json", JSON.stringify(status.json, null, 2));
713
+ assert.equal(status.json?.backlog?.deliveriesPending ?? null, 0);
714
+ assert.equal(status.json?.backlog?.deliveriesFailed ?? null, 0);
715
+ assert.equal(status.json?.backlog?.ingestRejected ?? null, 0);
716
+ assert.ok(status.json?.maintenance?.retentionCleanup?.at ?? null);
717
+
718
+ // Basic protocol headers are present on responses.
719
+ assert.equal(status.headers.get("x-settld-protocol"), PROTOCOL);
720
+
721
+ // Receiver readiness endpoint is alive.
722
+ const rdy = await httpJson({ baseUrl: RECEIVER_BASE_URL, method: "GET", path: "/health" });
723
+ assert.equal(rdy.status, 200, rdy.text);
724
+ }
725
+
726
+ main().catch((err) => {
727
+ // eslint-disable-next-line no-console
728
+ console.error("acceptance: FAILED");
729
+ // eslint-disable-next-line no-console
730
+ console.error(err);
731
+ // eslint-disable-next-line no-console
732
+ if (ART_DIR) console.error(`acceptance: artifacts in ${ART_DIR}`);
733
+ process.exit(1);
734
+ });