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
@@ -40,6 +40,13 @@ function computeBackoffMs({ attempts, baseMs = 1000, maxMs = 60_000, random = Ma
40
40
  return Math.max(baseMs, Math.floor(raw * jitter));
41
41
  }
42
42
 
43
+ function headerSafeValue(value) {
44
+ // Prevent fetch/undici from throwing on invalid header values (CTL chars, newlines).
45
+ // `orderKey` is allowed to include newlines internally; for transport we normalize it.
46
+ const s = String(value ?? "");
47
+ return s.replaceAll(/[\u0000-\u001F\u007F]/g, " ").trim();
48
+ }
49
+
43
50
  async function fetchWithTimeout(fetchFn, url, options, timeoutMs) {
44
51
  if (typeof fetchFn !== "function") throw new TypeError("fetchFn must be a function");
45
52
  const ms = Number(timeoutMs);
@@ -105,6 +112,30 @@ export function createDeliveryWorker({
105
112
  return list.find((d) => d.destinationId === destinationId) ?? null;
106
113
  }
107
114
 
115
+ async function recordWebhookEndpointDeliveryResult({
116
+ tenantId,
117
+ destinationId,
118
+ deliveredAt = nowIso(),
119
+ success,
120
+ failureReason = null,
121
+ statusCode = null
122
+ } = {}) {
123
+ if (typeof store.recordX402WebhookEndpointDeliveryResult !== "function") return;
124
+ if (typeof destinationId !== "string" || destinationId.trim() === "") return;
125
+ try {
126
+ await store.recordX402WebhookEndpointDeliveryResult({
127
+ tenantId,
128
+ destinationId,
129
+ deliveredAt,
130
+ success,
131
+ failureReason,
132
+ statusCode
133
+ });
134
+ } catch {
135
+ // best effort; delivery processing should not fail because health tracking failed
136
+ }
137
+ }
138
+
108
139
  function safeKeySegment(value) {
109
140
  return String(value ?? "")
110
141
  .trim()
@@ -236,9 +267,14 @@ export function createDeliveryWorker({
236
267
  failureReason: failureReasonForSecretError(err)
237
268
  };
238
269
  }
270
+ const previousSecrets = Array.isArray(dest.previousSecrets)
271
+ ? dest.previousSecrets.filter((value) => typeof value === "string" && value.trim() !== "")
272
+ : [];
239
273
 
240
274
  const timestamp = nowIso();
241
- const signature = hmacSignArtifact({ secret, timestamp, bodyJson: artifact });
275
+ const allSecrets = [secret, ...previousSecrets.filter((candidate) => candidate !== secret)];
276
+ const signatures = allSecrets.map((activeSecret) => hmacSignArtifact({ secret: activeSecret, timestamp, bodyJson: artifact }));
277
+ const signatureHeader = signatures.length > 1 ? signatures.map((value) => `v1=${value}`).join(",") : signatures[0];
242
278
  const body = canonicalJsonStringify(artifact);
243
279
 
244
280
  let res;
@@ -255,9 +291,11 @@ export function createDeliveryWorker({
255
291
  "x-proxy-artifact-type": String(delivery.artifactType ?? ""),
256
292
  "x-proxy-artifact-id": String(delivery.artifactId ?? ""),
257
293
  "x-proxy-artifact-hash": String(delivery.artifactHash ?? ""),
258
- "x-proxy-order-key": String(delivery.orderKey ?? ""),
294
+ "x-proxy-order-key": headerSafeValue(delivery.orderKey ?? ""),
259
295
  "x-proxy-timestamp": timestamp,
260
- "x-proxy-signature": signature
296
+ "x-proxy-signature": signatureHeader,
297
+ "x-settld-timestamp": timestamp,
298
+ "x-settld-signature": signatureHeader
261
299
  },
262
300
  body
263
301
  },
@@ -265,7 +303,16 @@ export function createDeliveryWorker({
265
303
  );
266
304
  } catch (err) {
267
305
  const isTimeout = err?.name === "AbortError" || String(err?.message ?? "").toLowerCase().includes("timeout");
268
- return { ok: false, status: null, error: isTimeout ? "timeout" : "network error", destinationType: "webhook", failureReason: isTimeout ? "timeout" : "network_error" };
306
+ const code = typeof err?.cause?.code === "string" ? err.cause.code : typeof err?.code === "string" ? err.code : null;
307
+ const msg = typeof err?.message === "string" && err.message.trim() ? err.message.trim() : String(err ?? "");
308
+ const detail = code ? `${code}: ${msg || "fetch failed"}` : msg || "fetch failed";
309
+ return {
310
+ ok: false,
311
+ status: null,
312
+ error: isTimeout ? "timeout" : `network error: ${detail}`,
313
+ destinationType: "webhook",
314
+ failureReason: isTimeout ? "timeout" : "network_error"
315
+ };
269
316
  }
270
317
 
271
318
  const ok = res.status >= 200 && res.status < 300;
@@ -325,6 +372,14 @@ export function createDeliveryWorker({
325
372
  attempts
326
373
  });
327
374
  if (result.ok) {
375
+ await recordWebhookEndpointDeliveryResult({
376
+ tenantId: t,
377
+ destinationId: String(delivery.destinationId ?? ""),
378
+ deliveredAt: nowIso(),
379
+ success: true,
380
+ failureReason: null,
381
+ statusCode: result.status ?? null
382
+ });
328
383
  const expiresAt = expiresAtForState({ tenantId: t, state: "delivered", at: nowIso() });
329
384
  await store.updateDeliveryAttempt({
330
385
  tenantId: t,
@@ -350,6 +405,14 @@ export function createDeliveryWorker({
350
405
  continue;
351
406
  }
352
407
 
408
+ await recordWebhookEndpointDeliveryResult({
409
+ tenantId: t,
410
+ destinationId: String(delivery.destinationId ?? ""),
411
+ deliveredAt: nowIso(),
412
+ success: false,
413
+ failureReason: result.failureReason ?? result.error ?? "failed",
414
+ statusCode: result.status ?? null
415
+ });
353
416
  if (attempts >= maxAttempts) {
354
417
  const expiresAt = expiresAtForState({ tenantId: t, state: "failed", at: nowIso() });
355
418
  await store.updateDeliveryAttempt({
@@ -413,6 +476,14 @@ export function createDeliveryWorker({
413
476
  processed.push({ id: delivery.id, status: "retrying", nextAttemptAt });
414
477
  } catch (err) {
415
478
  const lastError = typeof err?.message === "string" && err.message.trim() ? err.message : String(err ?? "delivery failed");
479
+ await recordWebhookEndpointDeliveryResult({
480
+ tenantId: t,
481
+ destinationId: String(delivery.destinationId ?? ""),
482
+ deliveredAt: nowIso(),
483
+ success: false,
484
+ failureReason: "exception",
485
+ statusCode: null
486
+ });
416
487
  try {
417
488
  store.metrics?.incCounter?.("delivery_attempt_total", { destinationType: "unknown" }, 1);
418
489
  } catch {}
@@ -521,6 +592,14 @@ export function createDeliveryWorker({
521
592
  attempts
522
593
  });
523
594
  if (result.ok) {
595
+ await recordWebhookEndpointDeliveryResult({
596
+ tenantId: t,
597
+ destinationId: String(d.destinationId ?? ""),
598
+ deliveredAt: nowIso(),
599
+ success: true,
600
+ failureReason: null,
601
+ statusCode: result.status ?? null
602
+ });
524
603
  d.state = "delivered";
525
604
  d.deliveredAt = nowIso();
526
605
  d.expiresAt = expiresAtForState({ tenantId: t, state: "delivered", at: d.deliveredAt });
@@ -541,6 +620,14 @@ export function createDeliveryWorker({
541
620
  continue;
542
621
  }
543
622
 
623
+ await recordWebhookEndpointDeliveryResult({
624
+ tenantId: t,
625
+ destinationId: String(d.destinationId ?? ""),
626
+ deliveredAt: nowIso(),
627
+ success: false,
628
+ failureReason: result.failureReason ?? result.error ?? "failed",
629
+ statusCode: result.status ?? null
630
+ });
544
631
  d.lastStatus = result.status;
545
632
  d.lastError = result.error;
546
633
  if (attempts >= maxAttempts) {
@@ -592,6 +679,14 @@ export function createDeliveryWorker({
592
679
  store.deliveries.set(key, d);
593
680
  } catch (err) {
594
681
  d.lastError = typeof err?.message === "string" ? err.message : String(err);
682
+ await recordWebhookEndpointDeliveryResult({
683
+ tenantId: t,
684
+ destinationId: String(d.destinationId ?? ""),
685
+ deliveredAt: nowIso(),
686
+ success: false,
687
+ failureReason: "exception",
688
+ statusCode: null
689
+ });
595
690
  try {
596
691
  store.metrics?.incCounter?.("delivery_attempt_total", { destinationType: "unknown" }, 1);
597
692
  } catch {}
@@ -0,0 +1,159 @@
1
+ import { DEFAULT_TENANT_ID, normalizeTenantId } from "../../core/tenancy.js";
2
+
3
+ function assertPositiveSafeInt(value, fieldName) {
4
+ if (!Number.isSafeInteger(value) || value <= 0) {
5
+ throw new TypeError(`${fieldName} must be a positive safe integer`);
6
+ }
7
+ }
8
+
9
+ function normalizeTenantIds(input) {
10
+ if (!Array.isArray(input)) return [];
11
+ const out = [];
12
+ const seen = new Set();
13
+ for (const raw of input) {
14
+ const tenantId = normalizeTenantId(raw ?? DEFAULT_TENANT_ID);
15
+ if (seen.has(tenantId)) continue;
16
+ seen.add(tenantId);
17
+ out.push(tenantId);
18
+ }
19
+ out.sort((left, right) => String(left).localeCompare(String(right)));
20
+ return out;
21
+ }
22
+
23
+ async function collectActiveAgentsForTenant({
24
+ tenantId,
25
+ listActiveAgents,
26
+ batchSize,
27
+ maxAgents
28
+ }) {
29
+ const agents = [];
30
+ let offset = 0;
31
+ while (agents.length < maxAgents) {
32
+ const remaining = maxAgents - agents.length;
33
+ const pageLimit = Math.max(1, Math.min(batchSize, remaining));
34
+ const page = await listActiveAgents({
35
+ tenantId,
36
+ status: "active",
37
+ limit: pageLimit,
38
+ offset
39
+ });
40
+ const rows = Array.isArray(page) ? page : [];
41
+ if (rows.length === 0) break;
42
+ agents.push(...rows);
43
+ if (rows.length < pageLimit) break;
44
+ offset += rows.length;
45
+ }
46
+ return agents;
47
+ }
48
+
49
+ export function createInsolvencySweepWorker({
50
+ nowIso,
51
+ listTenantIds,
52
+ listActiveAgents,
53
+ evaluateAgent,
54
+ freezeAgent
55
+ } = {}) {
56
+ if (typeof nowIso !== "function") throw new TypeError("nowIso is required");
57
+ if (typeof listTenantIds !== "function") throw new TypeError("listTenantIds is required");
58
+ if (typeof listActiveAgents !== "function") throw new TypeError("listActiveAgents is required");
59
+ if (typeof evaluateAgent !== "function") throw new TypeError("evaluateAgent is required");
60
+ if (typeof freezeAgent !== "function") throw new TypeError("freezeAgent is required");
61
+
62
+ async function tickInsolvencySweep({
63
+ tenantId = null,
64
+ maxTenants = 50,
65
+ maxMessages = 100,
66
+ batchSize = 100
67
+ } = {}) {
68
+ assertPositiveSafeInt(maxTenants, "maxTenants");
69
+ assertPositiveSafeInt(maxMessages, "maxMessages");
70
+ assertPositiveSafeInt(batchSize, "batchSize");
71
+
72
+ const tenantIds = normalizeTenantIds(await listTenantIds({ tenantId, maxTenants }));
73
+ const startedAt = nowIso();
74
+ let scanned = 0;
75
+ let processed = 0;
76
+ let frozen = 0;
77
+ let skipped = 0;
78
+ let failures = 0;
79
+ const outcomes = [];
80
+
81
+ for (const currentTenantId of tenantIds) {
82
+ if (processed >= maxMessages) break;
83
+ const remaining = maxMessages - processed;
84
+ const activeAgents = await collectActiveAgentsForTenant({
85
+ tenantId: currentTenantId,
86
+ listActiveAgents,
87
+ batchSize,
88
+ maxAgents: remaining
89
+ });
90
+
91
+ for (const identity of activeAgents) {
92
+ if (processed >= maxMessages) break;
93
+ const agentId = typeof identity?.agentId === "string" ? identity.agentId.trim() : "";
94
+ if (!agentId) continue;
95
+ scanned += 1;
96
+ processed += 1;
97
+
98
+ try {
99
+ const evaluation = await evaluateAgent({
100
+ tenantId: currentTenantId,
101
+ identity,
102
+ nowAt: startedAt
103
+ });
104
+ if (!(evaluation?.insolvent === true)) {
105
+ skipped += 1;
106
+ outcomes.push({
107
+ tenantId: currentTenantId,
108
+ agentId,
109
+ action: "skipped",
110
+ reasonCode: evaluation?.reasonCode ?? null
111
+ });
112
+ continue;
113
+ }
114
+
115
+ const freezeResult = await freezeAgent({
116
+ tenantId: currentTenantId,
117
+ identity,
118
+ evaluation,
119
+ nowAt: startedAt
120
+ });
121
+ if (freezeResult?.changed === true) frozen += 1;
122
+ else skipped += 1;
123
+ outcomes.push({
124
+ tenantId: currentTenantId,
125
+ agentId,
126
+ action: freezeResult?.changed === true ? "frozen" : "noop",
127
+ reasonCode: evaluation?.reasonCode ?? null,
128
+ lifecycleStatus: freezeResult?.lifecycle?.status ?? null
129
+ });
130
+ } catch (err) {
131
+ failures += 1;
132
+ outcomes.push({
133
+ tenantId: currentTenantId,
134
+ agentId,
135
+ action: "error",
136
+ code: err?.code ?? null,
137
+ message: err?.message ?? String(err ?? "")
138
+ });
139
+ }
140
+ }
141
+ }
142
+
143
+ return {
144
+ ok: true,
145
+ startedAt,
146
+ tenantCount: tenantIds.length,
147
+ scanned,
148
+ processed,
149
+ frozen,
150
+ skipped,
151
+ failures,
152
+ outcomes
153
+ };
154
+ }
155
+
156
+ return {
157
+ tickInsolvencySweep
158
+ };
159
+ }
@@ -0,0 +1,69 @@
1
+ import { normalizeForCanonicalJson } from "./canonical-json.js";
2
+
3
+ function assertNonEmptyString(value, name) {
4
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
5
+ }
6
+
7
+ function normalizeBaseUrl(value) {
8
+ assertNonEmptyString(value, "baseUrl");
9
+ let parsed;
10
+ try {
11
+ parsed = new URL(String(value));
12
+ } catch {
13
+ throw new TypeError("baseUrl must be an absolute URL");
14
+ }
15
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
16
+ throw new TypeError("baseUrl must use http or https");
17
+ }
18
+ return parsed.toString().replace(/\/+$/, "");
19
+ }
20
+
21
+ export function buildSettldAgentCard({
22
+ baseUrl,
23
+ version = null,
24
+ protocols = ["SettlementKernel.v1"],
25
+ bundleTypes = ["InvoiceBundle.v1", "ClosePack.v1", "JobProofBundle.v1", "MonthProofBundle.v1", "FinancePackBundle.v1"],
26
+ paymentRails = ["internal_escrow", "circle_usdc"],
27
+ disputeSupport = true,
28
+ reputationQueries = true
29
+ } = {}) {
30
+ const url = normalizeBaseUrl(baseUrl);
31
+ const resolvedVersion = version === null || version === undefined || String(version).trim() === "" ? null : String(version).trim();
32
+ const resolvedProtocols = Array.isArray(protocols) ? protocols.map((p) => String(p)).filter(Boolean) : [];
33
+ const resolvedBundles = Array.isArray(bundleTypes) ? bundleTypes.map((b) => String(b)).filter(Boolean) : [];
34
+ const resolvedRails = Array.isArray(paymentRails) ? paymentRails.map((r) => String(r)).filter(Boolean) : [];
35
+
36
+ const card = {
37
+ name: "settld-settlement-agent",
38
+ description: "Settlement kernel for autonomous economic agreements (agreement -> evidence -> decision -> receipt -> dispute).",
39
+ url,
40
+ version: resolvedVersion,
41
+ capabilities: {
42
+ settlement: {
43
+ protocols: resolvedProtocols,
44
+ bundleTypes: resolvedBundles,
45
+ paymentRails: resolvedRails,
46
+ disputeSupport: disputeSupport === true,
47
+ reputationQueries: reputationQueries === true
48
+ }
49
+ },
50
+ skills: [
51
+ { id: "create_agreement", description: "Create an agreement/run for a payable capability call." },
52
+ { id: "submit_evidence", description: "Append evidence to a run event chain." },
53
+ { id: "settle_run", description: "Mark a run completed/failed (triggers settlement evaluation)." },
54
+ { id: "resolve_settlement", description: "Manually resolve a settlement (released/refunded)." },
55
+ { id: "open_dispute", description: "Open a dispute within the dispute window." },
56
+ { id: "query_reputation", description: "Query append-only reputation facts for a counterparty." }
57
+ ],
58
+ authentication: {
59
+ schemes: [
60
+ { type: "api_key", in: "header", name: "x-api-key" },
61
+ { type: "ops_token", in: "header", name: "x-proxy-ops-token" }
62
+ ]
63
+ }
64
+ };
65
+
66
+ // Omit null version for cleaner discovery payloads.
67
+ if (card.version === null) delete card.version;
68
+ return normalizeForCanonicalJson(card, { path: "$" });
69
+ }
@@ -188,6 +188,37 @@ function normalizeDisputeResolution(disputeResolution, { name = "settlement.disp
188
188
  const closedAtRaw = disputeResolution.closedAt ?? defaultClosedAt ?? null;
189
189
  const closedAt = closedAtRaw === null || closedAtRaw === undefined ? null : String(closedAtRaw).trim();
190
190
  if (closedAt !== null) assertIsoDate(closedAt, `${name}.closedAt`);
191
+ const releaseRatePctRaw = disputeResolution.releaseRatePct;
192
+ const releaseRatePct =
193
+ releaseRatePctRaw === null || releaseRatePctRaw === undefined || releaseRatePctRaw === ""
194
+ ? null
195
+ : Number.isSafeInteger(Number(releaseRatePctRaw))
196
+ ? Number(releaseRatePctRaw)
197
+ : Number.NaN;
198
+ if (releaseRatePct !== null && (!Number.isSafeInteger(releaseRatePct) || releaseRatePct < 0 || releaseRatePct > 100)) {
199
+ throw new TypeError(`${name}.releaseRatePct must be an integer within 0..100`);
200
+ }
201
+ if (outcome === AGENT_RUN_SETTLEMENT_DISPUTE_RESOLUTION_OUTCOME.ACCEPTED && releaseRatePct !== null && releaseRatePct !== 100) {
202
+ throw new TypeError(`${name}.releaseRatePct must be 100 when outcome=accepted`);
203
+ }
204
+ if (outcome === AGENT_RUN_SETTLEMENT_DISPUTE_RESOLUTION_OUTCOME.REJECTED && releaseRatePct !== null && releaseRatePct !== 0) {
205
+ throw new TypeError(`${name}.releaseRatePct must be 0 when outcome=rejected`);
206
+ }
207
+ if (outcome === AGENT_RUN_SETTLEMENT_DISPUTE_RESOLUTION_OUTCOME.PARTIAL) {
208
+ if (releaseRatePct === null) {
209
+ throw new TypeError(`${name}.releaseRatePct is required when outcome=partial`);
210
+ }
211
+ if (releaseRatePct <= 0 || releaseRatePct >= 100) {
212
+ throw new TypeError(`${name}.releaseRatePct must be within 1..99 when outcome=partial`);
213
+ }
214
+ }
215
+ if (
216
+ (outcome === AGENT_RUN_SETTLEMENT_DISPUTE_RESOLUTION_OUTCOME.WITHDRAWN ||
217
+ outcome === AGENT_RUN_SETTLEMENT_DISPUTE_RESOLUTION_OUTCOME.UNRESOLVED) &&
218
+ releaseRatePct !== null
219
+ ) {
220
+ throw new TypeError(`${name}.releaseRatePct is only allowed for accepted|rejected|partial outcomes`);
221
+ }
191
222
  const evidenceRefs = normalizeDisputeEvidenceRefs(disputeResolution.evidenceRefs, `${name}.evidenceRefs`);
192
223
  return {
193
224
  outcome,
@@ -195,6 +226,7 @@ function normalizeDisputeResolution(disputeResolution, { name = "settlement.disp
195
226
  closedByAgentId,
196
227
  summary,
197
228
  closedAt,
229
+ ...(releaseRatePct !== null ? { releaseRatePct } : {}),
198
230
  evidenceRefs
199
231
  };
200
232
  }
@@ -368,6 +400,39 @@ export function refundAgentWalletEscrow({ wallet, amountCents, at = new Date().t
368
400
  );
369
401
  }
370
402
 
403
+ export function transferAgentWalletAvailable({ fromWallet, toWallet, amountCents, at = new Date().toISOString() }) {
404
+ assertIsoDate(at, "at");
405
+ assertAmountCents(amountCents, "amountCents");
406
+ const from = normalizeWalletRecord(fromWallet);
407
+ const to = normalizeWalletRecord(toWallet);
408
+ if (from.currency !== to.currency) throw new TypeError("wallet currencies must match");
409
+ if (from.tenantId !== to.tenantId) throw new TypeError("wallet tenants must match");
410
+ const debited = withWalletUpdate(
411
+ from,
412
+ (base) => {
413
+ if (base.availableCents < amountCents) {
414
+ const err = new Error("insufficient wallet balance");
415
+ err.code = "INSUFFICIENT_WALLET_BALANCE";
416
+ throw err;
417
+ }
418
+ return {
419
+ availableCents: base.availableCents - amountCents,
420
+ totalDebitedCents: base.totalDebitedCents + amountCents
421
+ };
422
+ },
423
+ { at }
424
+ );
425
+ const credited = withWalletUpdate(
426
+ to,
427
+ (base) => ({
428
+ availableCents: base.availableCents + amountCents,
429
+ totalCreditedCents: base.totalCreditedCents + amountCents
430
+ }),
431
+ { at }
432
+ );
433
+ return { fromWallet: debited, toWallet: credited };
434
+ }
435
+
371
436
  export function validateAgentRunSettlementRequest(payload) {
372
437
  assertPlainObject(payload, "settlement");
373
438
  assertNonEmptyString(payload.payerAgentId, "settlement.payerAgentId");
@@ -704,6 +769,172 @@ export function resolveAgentRunSettlement({
704
769
  });
705
770
  }
706
771
 
772
+ export function refundReleasedAgentRunSettlement({
773
+ settlement,
774
+ runStatus = "refunded",
775
+ decisionStatus = AGENT_RUN_SETTLEMENT_DECISION_STATUS.MANUAL_RESOLVED,
776
+ decisionMode = AGENT_RUN_SETTLEMENT_DECISION_MODE.MANUAL_REVIEW,
777
+ decisionPolicyHash = null,
778
+ decisionReason = "x402_refund_resolved",
779
+ decisionTrace = null,
780
+ resolutionEventId = null,
781
+ at = new Date().toISOString()
782
+ }) {
783
+ const current = normalizeSettlementRecord(settlement);
784
+ if (current.status !== AGENT_RUN_SETTLEMENT_STATUS.RELEASED) {
785
+ throw new TypeError("refundReleasedAgentRunSettlement requires status=released");
786
+ }
787
+ assertNonEmptyString(runStatus, "runStatus");
788
+ assertIsoDate(at, "at");
789
+ if (resolutionEventId !== null && resolutionEventId !== undefined) assertNonEmptyString(resolutionEventId, "resolutionEventId");
790
+ const normalizedDecisionStatus = String(decisionStatus ?? AGENT_RUN_SETTLEMENT_DECISION_STATUS.MANUAL_RESOLVED).toLowerCase();
791
+ if (!Object.values(AGENT_RUN_SETTLEMENT_DECISION_STATUS).includes(normalizedDecisionStatus)) {
792
+ throw new TypeError("decisionStatus must be pending|auto_resolved|manual_review_required|manual_resolved");
793
+ }
794
+ const normalizedDecisionMode = String(decisionMode ?? AGENT_RUN_SETTLEMENT_DECISION_MODE.MANUAL_REVIEW).toLowerCase();
795
+ if (!Object.values(AGENT_RUN_SETTLEMENT_DECISION_MODE).includes(normalizedDecisionMode)) {
796
+ throw new TypeError("decisionMode must be automatic|manual-review");
797
+ }
798
+ const normalizedDecisionPolicyHash =
799
+ decisionPolicyHash === null || decisionPolicyHash === undefined ? null : String(decisionPolicyHash).trim();
800
+ if (normalizedDecisionPolicyHash !== null && normalizedDecisionPolicyHash === "") {
801
+ throw new TypeError("decisionPolicyHash must be a non-empty string when provided");
802
+ }
803
+ const normalizedDecisionReason = decisionReason === null || decisionReason === undefined ? null : String(decisionReason).trim();
804
+ if (normalizedDecisionReason !== null && normalizedDecisionReason === "") {
805
+ throw new TypeError("decisionReason must be a non-empty string when provided");
806
+ }
807
+ if (decisionTrace !== null && decisionTrace !== undefined) {
808
+ assertPlainObject(decisionTrace, "decisionTrace");
809
+ }
810
+ return normalizeSettlementRecord({
811
+ ...current,
812
+ status: AGENT_RUN_SETTLEMENT_STATUS.REFUNDED,
813
+ runStatus: String(runStatus),
814
+ releasedAmountCents: 0,
815
+ refundedAmountCents: current.amountCents,
816
+ releaseRatePct: 0,
817
+ disputeStatus: AGENT_RUN_SETTLEMENT_DISPUTE_STATUS.NONE,
818
+ disputeId: null,
819
+ disputeOpenedAt: null,
820
+ disputeClosedAt: null,
821
+ disputeContext: null,
822
+ disputeResolution: null,
823
+ decisionStatus: normalizedDecisionStatus,
824
+ decisionMode: normalizedDecisionMode,
825
+ decisionPolicyHash: normalizedDecisionPolicyHash,
826
+ decisionReason: normalizedDecisionReason,
827
+ decisionTrace: decisionTrace ?? current.decisionTrace ?? null,
828
+ decisionUpdatedAt: at,
829
+ resolvedAt: at,
830
+ resolutionEventId: resolutionEventId ?? current.resolutionEventId ?? null,
831
+ revision: current.revision + 1,
832
+ updatedAt: at
833
+ });
834
+ }
835
+
836
+ export function reconcileResolvedAgentRunSettlement({
837
+ settlement,
838
+ status,
839
+ runStatus = null,
840
+ releasedAmountCents = null,
841
+ refundedAmountCents = null,
842
+ releaseRatePct = null,
843
+ decisionStatus = AGENT_RUN_SETTLEMENT_DECISION_STATUS.MANUAL_RESOLVED,
844
+ decisionMode = AGENT_RUN_SETTLEMENT_DECISION_MODE.MANUAL_REVIEW,
845
+ decisionPolicyHash = null,
846
+ decisionReason = null,
847
+ decisionTrace = null,
848
+ resolutionEventId = null,
849
+ at = new Date().toISOString()
850
+ }) {
851
+ const current = normalizeSettlementRecord(settlement);
852
+ if (current.status === AGENT_RUN_SETTLEMENT_STATUS.LOCKED) {
853
+ throw new TypeError("reconcileResolvedAgentRunSettlement requires a resolved settlement");
854
+ }
855
+ const nextStatus = String(status ?? "").toLowerCase();
856
+ if (nextStatus !== AGENT_RUN_SETTLEMENT_STATUS.RELEASED && nextStatus !== AGENT_RUN_SETTLEMENT_STATUS.REFUNDED) {
857
+ throw new TypeError("status must be released|refunded");
858
+ }
859
+ const nextRunStatusRaw = runStatus === null || runStatus === undefined ? current.runStatus : runStatus;
860
+ assertNonEmptyString(nextRunStatusRaw, "runStatus");
861
+ assertIsoDate(at, "at");
862
+ if (resolutionEventId !== null && resolutionEventId !== undefined) {
863
+ assertNonEmptyString(resolutionEventId, "resolutionEventId");
864
+ }
865
+
866
+ let nextReleasedAmountCents = releasedAmountCents === null || releasedAmountCents === undefined ? null : Number(releasedAmountCents);
867
+ let nextRefundedAmountCents = refundedAmountCents === null || refundedAmountCents === undefined ? null : Number(refundedAmountCents);
868
+ if (nextStatus === AGENT_RUN_SETTLEMENT_STATUS.RELEASED) {
869
+ if (nextReleasedAmountCents === null) nextReleasedAmountCents = current.amountCents;
870
+ if (nextRefundedAmountCents === null) nextRefundedAmountCents = current.amountCents - nextReleasedAmountCents;
871
+ } else {
872
+ if (nextReleasedAmountCents === null) nextReleasedAmountCents = 0;
873
+ if (nextRefundedAmountCents === null) nextRefundedAmountCents = current.amountCents;
874
+ }
875
+ assertAmountCents(nextReleasedAmountCents, "releasedAmountCents", { allowZero: true });
876
+ assertAmountCents(nextRefundedAmountCents, "refundedAmountCents", { allowZero: true });
877
+ if (nextReleasedAmountCents + nextRefundedAmountCents !== current.amountCents) {
878
+ throw new TypeError("releasedAmountCents + refundedAmountCents must equal settlement.amountCents");
879
+ }
880
+
881
+ const nextReleaseRatePct =
882
+ releaseRatePct === null || releaseRatePct === undefined
883
+ ? current.amountCents > 0
884
+ ? Math.round((nextReleasedAmountCents * 100) / current.amountCents)
885
+ : 0
886
+ : Number(releaseRatePct);
887
+ if (!Number.isSafeInteger(nextReleaseRatePct) || nextReleaseRatePct < 0 || nextReleaseRatePct > 100) {
888
+ throw new TypeError("releaseRatePct must be an integer within 0..100");
889
+ }
890
+
891
+ const normalizedDecisionStatus = String(decisionStatus ?? AGENT_RUN_SETTLEMENT_DECISION_STATUS.MANUAL_RESOLVED).toLowerCase();
892
+ if (!Object.values(AGENT_RUN_SETTLEMENT_DECISION_STATUS).includes(normalizedDecisionStatus)) {
893
+ throw new TypeError("decisionStatus must be pending|auto_resolved|manual_review_required|manual_resolved");
894
+ }
895
+ const normalizedDecisionMode = String(decisionMode ?? AGENT_RUN_SETTLEMENT_DECISION_MODE.MANUAL_REVIEW).toLowerCase();
896
+ if (!Object.values(AGENT_RUN_SETTLEMENT_DECISION_MODE).includes(normalizedDecisionMode)) {
897
+ throw new TypeError("decisionMode must be automatic|manual-review");
898
+ }
899
+ const normalizedDecisionPolicyHash =
900
+ decisionPolicyHash === null || decisionPolicyHash === undefined ? null : String(decisionPolicyHash).trim();
901
+ if (normalizedDecisionPolicyHash !== null && normalizedDecisionPolicyHash === "") {
902
+ throw new TypeError("decisionPolicyHash must be a non-empty string when provided");
903
+ }
904
+ const normalizedDecisionReason = decisionReason === null || decisionReason === undefined ? null : String(decisionReason).trim();
905
+ if (normalizedDecisionReason !== null && normalizedDecisionReason === "") {
906
+ throw new TypeError("decisionReason must be a non-empty string when provided");
907
+ }
908
+ if (decisionTrace !== null && decisionTrace !== undefined) {
909
+ assertPlainObject(decisionTrace, "decisionTrace");
910
+ }
911
+
912
+ return normalizeSettlementRecord({
913
+ ...current,
914
+ status: nextStatus,
915
+ runStatus: String(nextRunStatusRaw),
916
+ releasedAmountCents: nextReleasedAmountCents,
917
+ refundedAmountCents: nextRefundedAmountCents,
918
+ releaseRatePct: nextReleaseRatePct,
919
+ disputeStatus: AGENT_RUN_SETTLEMENT_DISPUTE_STATUS.NONE,
920
+ disputeId: null,
921
+ disputeOpenedAt: null,
922
+ disputeClosedAt: null,
923
+ disputeContext: null,
924
+ disputeResolution: null,
925
+ decisionStatus: normalizedDecisionStatus,
926
+ decisionMode: normalizedDecisionMode,
927
+ decisionPolicyHash: normalizedDecisionPolicyHash,
928
+ decisionReason: normalizedDecisionReason,
929
+ decisionTrace: decisionTrace ?? current.decisionTrace ?? null,
930
+ decisionUpdatedAt: at,
931
+ resolvedAt: at,
932
+ resolutionEventId: resolutionEventId ?? current.resolutionEventId ?? null,
933
+ revision: current.revision + 1,
934
+ updatedAt: at
935
+ });
936
+ }
937
+
707
938
  export function updateAgentRunSettlementDecision({
708
939
  settlement,
709
940
  decisionStatus = null,