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.
- package/README.md +93 -3
- package/SETTLD_VERSION +1 -1
- package/bin/settld-mcp +2 -0
- package/bin/settld.js +71 -0
- package/conformance/kernel-v0/README.md +7 -0
- package/conformance/kernel-v0/run.mjs +292 -4
- package/docs/ACCESS.md +57 -0
- package/docs/ADOPTION_CHECKLIST.md +44 -0
- package/docs/ALERTS.md +198 -0
- package/docs/ARCHITECTURE.md +69 -0
- package/docs/ARCHITECTURE_FOUNDER_GUIDE.md +284 -0
- package/docs/ARTIFACTS.md +60 -0
- package/docs/CERTIFICATION_CHECKLIST.md +33 -0
- package/docs/CIRCLE_SANDBOX_E2E.md +152 -0
- package/docs/CONFIG.md +297 -0
- package/docs/CONTRACTS_APIS.md +23 -0
- package/docs/DEPRECATION.md +31 -0
- package/docs/DOMAIN_MODEL.md +92 -0
- package/docs/EVENT_ENVELOPE.md +53 -0
- package/docs/FINANCE_PACK_FORMAT.md +53 -0
- package/docs/INCIDENT_TAXONOMY.md +30 -0
- package/docs/JOB_STATE_MACHINE.md +66 -0
- package/docs/KERNEL_COMPATIBLE.md +60 -0
- package/docs/KERNEL_V0.md +40 -0
- package/docs/KEY_ROTATION.md +80 -0
- package/docs/LEDGER.md +82 -0
- package/docs/LIVENESS.md +76 -0
- package/docs/MVP_BUILD_ORDER.md +36 -0
- package/docs/ONCALL_PLAYBOOK.md +39 -0
- package/docs/OPERATIONS_SIGNING.md +20 -0
- package/docs/OVERVIEW.md +190 -0
- package/docs/PERF_BASELINE.md +85 -0
- package/docs/PRD.md +77 -0
- package/docs/QUICKSTART_KERNEL_V0.md +96 -0
- package/docs/QUICKSTART_MCP.md +377 -0
- package/docs/QUICKSTART_MCP_HOSTS.md +210 -0
- package/docs/QUICKSTART_POLICY_PACKS.md +65 -0
- package/docs/QUICKSTART_PRODUCE.md +61 -0
- package/docs/QUICKSTART_PROFILES.md +198 -0
- package/docs/QUICKSTART_RELEASE_VERIFY.md +39 -0
- package/docs/QUICKSTART_SDK.md +125 -0
- package/docs/QUICKSTART_SDK_PYTHON.md +111 -0
- package/docs/QUICKSTART_VERIFY.md +54 -0
- package/docs/QUICKSTART_X402_GATEWAY.md +317 -0
- package/docs/README.md +33 -0
- package/docs/RELEASE_CHECKLIST.md +182 -0
- package/docs/RELEASING.md +82 -0
- package/docs/REPO_SETTINGS.md +37 -0
- package/docs/RUNBOOK.md +86 -0
- package/docs/SKILLS.md +42 -0
- package/docs/SKILL_BUNDLE_FORMAT.md +48 -0
- package/docs/SLO.md +131 -0
- package/docs/SUMMARY.md +17 -0
- package/docs/SUPPORT.md +31 -0
- package/docs/THREAT_MODEL.md +36 -0
- package/docs/TRUST.md +59 -0
- package/docs/WORKFLOW.md +35 -0
- package/docs/X402_BATCH_SETTLEMENT.md +126 -0
- package/docs/blog/2026-02-14-your-ai-agent-just-spent-500-where-is-the-receipt.md +73 -0
- package/docs/examples/x402-provider-payout-registry.example.json +14 -0
- package/docs/gitbook/README.md +64 -0
- package/docs/gitbook/SETUP.md +25 -0
- package/docs/gitbook/SUMMARY.md +15 -0
- package/docs/gitbook/api-reference.md +73 -0
- package/docs/gitbook/closepacks.md +55 -0
- package/docs/gitbook/conformance.md +59 -0
- package/docs/gitbook/core-primitives.md +85 -0
- package/docs/gitbook/dispute-lifecycle.md +33 -0
- package/docs/gitbook/faq.md +21 -0
- package/docs/gitbook/guides.md +49 -0
- package/docs/gitbook/operations-runbook.md +36 -0
- package/docs/gitbook/quickstart.md +103 -0
- package/docs/gitbook/replay-and-audit.md +30 -0
- package/docs/gitbook/sdk-reference.md +35 -0
- package/docs/gitbook/security-model.md +58 -0
- package/docs/integrations/README.md +15 -0
- package/docs/integrations/github-actions-verify.yml +31 -0
- package/docs/integrations/github-actions.md +34 -0
- package/docs/integrations/openclaw/CLAWHUB_PUBLISH_CHECKLIST.md +65 -0
- package/docs/integrations/openclaw/PUBLIC_QUICKSTART.md +95 -0
- package/docs/integrations/openclaw/settld-mcp-skill/SKILL.md +69 -0
- package/docs/integrations/openclaw/settld-mcp-skill/mcp-server.example.json +12 -0
- package/docs/kernel-compatible/capabilities.json +36 -0
- package/docs/marketing/agent-commerce-substrate.md +78 -0
- package/docs/marketing/hn-repost-2026-02-17.md +102 -0
- package/docs/marketing/show-hn-post.md +45 -0
- package/docs/ops/ARTIFACT_VERIFICATION_STATUS.md +43 -0
- package/docs/ops/BILLING_WEBHOOK_REPLAY.md +105 -0
- package/docs/ops/CI_FLAKE_BUDGET.md +31 -0
- package/docs/ops/DISPUTE_FINANCE_RECONCILIATION_PACKET.md +56 -0
- package/docs/ops/GO_LIVE_GATE_S13.md +27 -0
- package/docs/ops/HOSTED_BASELINE_R2.md +129 -0
- package/docs/ops/KERNEL_V0_SHIP_GATE.md +69 -0
- package/docs/ops/LIGHTHOUSE_PRODUCTION_CLOSE.md +51 -0
- package/docs/ops/MCP_COMPATIBILITY_MATRIX.md +30 -0
- package/docs/ops/MINIMUM_PRODUCTION_TOPOLOGY.md +89 -0
- package/docs/ops/P0_BACKEND_PROGRESS.md +150 -0
- package/docs/ops/PAYMENTS_ALPHA_R5.md +105 -0
- package/docs/ops/PILOT_ONBOARDING_RUNBOOK.md +112 -0
- package/docs/ops/PRODUCTION_DEPLOYMENT_CHECKLIST.md +140 -0
- package/docs/ops/R1_SLOS.md +66 -0
- package/docs/ops/RELEASE_SIGNING_INCIDENT.md +58 -0
- package/docs/ops/SELF_SERVE_LAUNCH_AUTOMATION.md +89 -0
- package/docs/ops/THROUGHPUT_DRILL_10X.md +48 -0
- package/docs/ops/TRUST_CONFIG_WIZARD.md +60 -0
- package/docs/ops/X402_PILOT_WEEKLY_METRICS.md +76 -0
- package/docs/ops/tool-call-disputes-holdback.md +52 -0
- package/docs/pilot-kit/PILOT_PACKAGE_SCORECARD_X402.md +46 -0
- package/docs/pilot-kit/README.md +29 -0
- package/docs/pilot-kit/architecture-one-pager.md +48 -0
- package/docs/pilot-kit/buyer-email.txt +19 -0
- package/docs/pilot-kit/buyer-one-pager.md +31 -0
- package/docs/pilot-kit/gtm-pilot-playbook.md +182 -0
- package/docs/pilot-kit/offline-verify.md +33 -0
- package/docs/pilot-kit/procurement-one-pager.md +50 -0
- package/docs/pilot-kit/rfp-clause.md +46 -0
- package/docs/pilot-kit/roi-calculator-template.csv +2 -0
- package/docs/pilot-kit/security-qa.md +153 -0
- package/docs/pilot-kit/security-summary.md +35 -0
- package/docs/plans/2026-02-13-mcp-spike-design.md +113 -0
- package/docs/plans/2026-02-20-trust-os-v1-jira-backlog.md +348 -0
- package/docs/plans/2026-02-21-agent-economic-actor-operating-model.md +169 -0
- package/docs/plans/2026-02-21-trust-os-v1-strategy.md +241 -0
- package/docs/research/2026-02-21-agent-spend-host-landscape.md +57 -0
- package/docs/spec/AcceptanceCriteria.v1.md +17 -0
- package/docs/spec/AcceptanceEvaluation.v1.md +10 -0
- package/docs/spec/AgentEvent.v1.md +47 -0
- package/docs/spec/AgentIdentity.v1.md +62 -0
- package/docs/spec/AgentPassport.v1.md +95 -0
- package/docs/spec/AgentReputation.v1.md +59 -0
- package/docs/spec/AgentReputation.v2.md +52 -0
- package/docs/spec/AgentRun.v1.md +47 -0
- package/docs/spec/AgentRunSettlement.v1.md +52 -0
- package/docs/spec/AgentWallet.v1.md +43 -0
- package/docs/spec/AgreementDelegation.v1.md +109 -0
- package/docs/spec/ArbitrationCase.v1.md +67 -0
- package/docs/spec/ArbitrationOutcomeMapping.v1.md +62 -0
- package/docs/spec/ArbitrationVerdict.v1.md +60 -0
- package/docs/spec/BundleHeadAttestation.v1.md +32 -0
- package/docs/spec/CANONICAL_JSON.md +31 -0
- package/docs/spec/CRYPTOGRAPHY.md +61 -0
- package/docs/spec/ClosePack.v1.md +49 -0
- package/docs/spec/ClosePackManifest.v1.md +24 -0
- package/docs/spec/DelegationGrant.v1.md +90 -0
- package/docs/spec/DisputeCaseLifecycle.v1.md +51 -0
- package/docs/spec/DisputeOpenEnvelope.v1.md +43 -0
- package/docs/spec/ERRORS.md +76 -0
- package/docs/spec/ESCROW_NETTING_INVARIANTS.md +71 -0
- package/docs/spec/EvidenceIndex.v1.md +20 -0
- package/docs/spec/ExecutionIntent.v1.md +90 -0
- package/docs/spec/FinancePackBundleManifest.v1.md +24 -0
- package/docs/spec/FundingHold.v1.md +60 -0
- package/docs/spec/GovernancePolicy.v1.md +34 -0
- package/docs/spec/GovernancePolicy.v2.md +30 -0
- package/docs/spec/INVARIANTS.md +389 -0
- package/docs/spec/InteractionDirectionMatrix.v1.md +30 -0
- package/docs/spec/InvoiceBundleManifest.v1.md +24 -0
- package/docs/spec/InvoiceClaim.v1.md +11 -0
- package/docs/spec/MONEY_RAIL_STATE_MACHINE.md +58 -0
- package/docs/spec/MarketplaceAcceptance.v2.md +46 -0
- package/docs/spec/MarketplaceOffer.v2.md +54 -0
- package/docs/spec/MeteringReport.v1.md +18 -0
- package/docs/spec/OperatorAction.v1.md +90 -0
- package/docs/spec/PRODUCER_ERRORS.md +42 -0
- package/docs/spec/PolicyDecision.v1.md +83 -0
- package/docs/spec/PricingMatrix.v1.md +20 -0
- package/docs/spec/PricingMatrixSignatures.v1.md +30 -0
- package/docs/spec/PricingMatrixSignatures.v2.md +29 -0
- package/docs/spec/ProduceCliOutput.v1.md +46 -0
- package/docs/spec/ProofBundleManifest.v1.md +24 -0
- package/docs/spec/README.md +109 -0
- package/docs/spec/REFERENCE_IMPLEMENTATIONS.md +29 -0
- package/docs/spec/REFERENCE_VERIFIER_BEHAVIOR.md +68 -0
- package/docs/spec/REMOTE_SIGNER.md +66 -0
- package/docs/spec/ReleaseIndex.v1.md +32 -0
- package/docs/spec/ReleaseIndexSignatures.v1.md +17 -0
- package/docs/spec/ReleaseTrust.v1.md +13 -0
- package/docs/spec/ReleaseTrust.v2.md +26 -0
- package/docs/spec/RemoteSignerRequest.v1.md +21 -0
- package/docs/spec/RemoteSignerResponse.v1.md +16 -0
- package/docs/spec/ReputationEvent.v1.md +63 -0
- package/docs/spec/RevocationList.v1.md +28 -0
- package/docs/spec/SIGNER_PROVIDER_PLUGIN.md +32 -0
- package/docs/spec/STRICTNESS.md +68 -0
- package/docs/spec/SUPPLY_CHAIN.md +33 -0
- package/docs/spec/SettlementAdjustment.v1.md +45 -0
- package/docs/spec/SettlementDecisionRecord.v1.md +48 -0
- package/docs/spec/SettlementDecisionRecord.v2.md +53 -0
- package/docs/spec/SettlementDecisionReport.v1.md +44 -0
- package/docs/spec/SettlementKernel.v1.md +59 -0
- package/docs/spec/SettlementReceipt.v1.md +63 -0
- package/docs/spec/SlaDefinition.v1.md +24 -0
- package/docs/spec/SlaEvaluation.v1.md +12 -0
- package/docs/spec/THREAT_MODEL.md +113 -0
- package/docs/spec/TOOL_PROVENANCE.md +30 -0
- package/docs/spec/TRUST_ANCHORS.md +84 -0
- package/docs/spec/TenantSettings.v1.md +90 -0
- package/docs/spec/TenantSettings.v2.md +99 -0
- package/docs/spec/TimestampProof.v1.md +25 -0
- package/docs/spec/ToolCallAgreement.v1.md +34 -0
- package/docs/spec/ToolCallEvidence.v1.md +47 -0
- package/docs/spec/ToolManifest.v1.md +47 -0
- package/docs/spec/VERIFIER_ENVIRONMENT.md +38 -0
- package/docs/spec/VERSIONING.md +107 -0
- package/docs/spec/VerificationReport.v1.md +50 -0
- package/docs/spec/VerifyAboutOutput.v1.md +10 -0
- package/docs/spec/VerifyCliOutput.v1.md +28 -0
- package/docs/spec/WARNINGS.md +83 -0
- package/docs/spec/error-codes.v1.txt +285 -0
- package/docs/spec/examples/agreement_delegation_v1.example.json +21 -0
- package/docs/spec/examples/arbitration_case_v1.example.json +26 -0
- package/docs/spec/examples/arbitration_verdict_v1.example.json +32 -0
- package/docs/spec/examples/dispute_open_envelope_v1.example.json +18 -0
- package/docs/spec/examples/produce_cli_output_v1.example.json +32 -0
- package/docs/spec/examples/release_index_signature_v1.example.json +9 -0
- package/docs/spec/examples/release_index_signatures_v1.example.json +14 -0
- package/docs/spec/examples/release_index_v1.example.json +15 -0
- package/docs/spec/examples/release_trust_v1.example.json +7 -0
- package/docs/spec/examples/release_trust_v2.example.json +22 -0
- package/docs/spec/examples/remote_signer_request_v1.example.json +18 -0
- package/docs/spec/examples/remote_signer_response_v1.example.json +8 -0
- package/docs/spec/examples/reputation_event_v1.example.json +29 -0
- package/docs/spec/examples/verification_report_v1.example.json +24 -0
- package/docs/spec/examples/verify_about_output_v1.example.json +29 -0
- package/docs/spec/examples/verify_cli_output_v1.example.json +13 -0
- package/docs/spec/legacy/MarketplaceAcceptance.v1.md +48 -0
- package/docs/spec/legacy/MarketplaceOffer.v1.md +56 -0
- package/docs/spec/legacy/schemas/MarketplaceAcceptance.v1.schema.json +53 -0
- package/docs/spec/legacy/schemas/MarketplaceOffer.v1.schema.json +61 -0
- package/docs/spec/producer-error-codes.v1.txt +14 -0
- package/docs/spec/schemas/AcceptanceCriteria.v1.schema.json +24 -0
- package/docs/spec/schemas/AcceptanceEvaluation.v1.schema.json +26 -0
- package/docs/spec/schemas/AgentEvent.v1.schema.json +49 -0
- package/docs/spec/schemas/AgentIdentity.v1.schema.json +129 -0
- package/docs/spec/schemas/AgentPassport.v1.schema.json +112 -0
- package/docs/spec/schemas/AgentReputation.v1.schema.json +151 -0
- package/docs/spec/schemas/AgentReputation.v2.schema.json +120 -0
- package/docs/spec/schemas/AgentRun.v1.schema.json +71 -0
- package/docs/spec/schemas/AgentRunSettlement.v1.schema.json +75 -0
- package/docs/spec/schemas/AgentWallet.v1.schema.json +54 -0
- package/docs/spec/schemas/AgreementDelegation.v1.schema.json +50 -0
- package/docs/spec/schemas/ArbitrationCase.v1.schema.json +133 -0
- package/docs/spec/schemas/ArbitrationVerdict.v1.schema.json +149 -0
- package/docs/spec/schemas/BundleHeadAttestation.v1.schema.json +21 -0
- package/docs/spec/schemas/ClosePackManifest.v1.schema.json +38 -0
- package/docs/spec/schemas/DelegationGrant.v1.schema.json +102 -0
- package/docs/spec/schemas/DisputeOpenEnvelope.v1.schema.json +78 -0
- package/docs/spec/schemas/EvidenceIndex.v1.schema.json +41 -0
- package/docs/spec/schemas/ExecutionIntent.v1.schema.json +85 -0
- package/docs/spec/schemas/FinancePackBundleManifest.v1.schema.json +38 -0
- package/docs/spec/schemas/FundingHold.v1.schema.json +46 -0
- package/docs/spec/schemas/GovernancePolicy.v1.schema.json +45 -0
- package/docs/spec/schemas/GovernancePolicy.v2.schema.json +70 -0
- package/docs/spec/schemas/InteractionDirectionMatrix.v1.schema.json +43 -0
- package/docs/spec/schemas/InvoiceBundleManifest.v1.schema.json +38 -0
- package/docs/spec/schemas/InvoiceClaim.v1.schema.json +39 -0
- package/docs/spec/schemas/MarketplaceAcceptance.v2.schema.json +53 -0
- package/docs/spec/schemas/MarketplaceOffer.v2.schema.json +61 -0
- package/docs/spec/schemas/MeteringReport.v1.schema.json +45 -0
- package/docs/spec/schemas/OperatorAction.v1.schema.json +113 -0
- package/docs/spec/schemas/PolicyDecision.v1.schema.json +74 -0
- package/docs/spec/schemas/PricingMatrix.v1.schema.json +24 -0
- package/docs/spec/schemas/PricingMatrixSignatures.v1.schema.json +24 -0
- package/docs/spec/schemas/PricingMatrixSignatures.v2.schema.json +24 -0
- package/docs/spec/schemas/ProduceCliOutput.v1.schema.json +107 -0
- package/docs/spec/schemas/ProofBundleManifest.v1.schema.json +37 -0
- package/docs/spec/schemas/PublicKeys.v1.schema.json +33 -0
- package/docs/spec/schemas/ReleaseIndex.v1.schema.json +45 -0
- package/docs/spec/schemas/ReleaseIndexSignature.v1.schema.json +16 -0
- package/docs/spec/schemas/ReleaseIndexSignatures.v1.schema.json +16 -0
- package/docs/spec/schemas/ReleaseTrust.v1.schema.json +15 -0
- package/docs/spec/schemas/ReleaseTrust.v2.schema.json +37 -0
- package/docs/spec/schemas/RemoteSignerPublicKeyResponse.v1.schema.json +14 -0
- package/docs/spec/schemas/RemoteSignerRequest.v1.schema.json +24 -0
- package/docs/spec/schemas/RemoteSignerResponse.v1.schema.json +10 -0
- package/docs/spec/schemas/RemoteSignerSignRequest.v1.schema.json +27 -0
- package/docs/spec/schemas/RemoteSignerSignResponse.v1.schema.json +16 -0
- package/docs/spec/schemas/ReputationEvent.v1.schema.json +164 -0
- package/docs/spec/schemas/RevocationList.v1.schema.json +51 -0
- package/docs/spec/schemas/SettlementAdjustment.v1.schema.json +44 -0
- package/docs/spec/schemas/SettlementDecisionRecord.v1.schema.json +66 -0
- package/docs/spec/schemas/SettlementDecisionRecord.v2.schema.json +149 -0
- package/docs/spec/schemas/SettlementDecisionReport.v1.schema.json +61 -0
- package/docs/spec/schemas/SettlementReceipt.v1.schema.json +135 -0
- package/docs/spec/schemas/SlaDefinition.v1.schema.json +33 -0
- package/docs/spec/schemas/SlaEvaluation.v1.schema.json +26 -0
- package/docs/spec/schemas/TenantSettings.v1.schema.json +90 -0
- package/docs/spec/schemas/TenantSettings.v2.schema.json +161 -0
- package/docs/spec/schemas/TimestampProof.v1.schema.json +17 -0
- package/docs/spec/schemas/ToolCallAgreement.v1.schema.json +34 -0
- package/docs/spec/schemas/ToolCallEvidence.v1.schema.json +45 -0
- package/docs/spec/schemas/ToolManifest.v1.schema.json +54 -0
- package/docs/spec/schemas/VerificationReport.v1.schema.json +83 -0
- package/docs/spec/schemas/VerifyAboutOutput.v1.schema.json +54 -0
- package/docs/spec/schemas/VerifyCliOutput.v1.schema.json +75 -0
- package/docs/spec/schemas/VerifyReleaseOutput.v1.schema.json +47 -0
- package/docs/spec/x402-error-codes.v1.txt +35 -0
- package/docs/templates/buyer-email.txt +18 -0
- package/docs/templates/buyer-one-pager.md +24 -0
- package/package.json +53 -6
- package/scripts/acceptance/full-stack.mjs +734 -0
- package/scripts/acceptance/full-stack.sh +99 -0
- package/scripts/audit/build-audit-packet.mjs +242 -0
- package/scripts/backup-pg.sh +45 -0
- package/scripts/backup-restore/README.md +18 -0
- package/scripts/backup-restore/capture-state.mjs +130 -0
- package/scripts/backup-restore/client.mjs +97 -0
- package/scripts/backup-restore/seed-workload.mjs +235 -0
- package/scripts/backup-restore/verify-state.mjs +139 -0
- package/scripts/backup-restore-test.sh +217 -0
- package/scripts/chaos.js +221 -0
- package/scripts/ci/build-launch-cutover-packet.mjs +304 -0
- package/scripts/ci/build-self-serve-benchmark-report.mjs +122 -0
- package/scripts/ci/changelog-guard.mjs +145 -0
- package/scripts/ci/check-kernel-v0-launch-gate.mjs +233 -0
- package/scripts/ci/check-secret-hygiene.mjs +78 -0
- package/scripts/ci/check-version-consistency.mjs +42 -0
- package/scripts/ci/cli-pack-smoke.mjs +160 -0
- package/scripts/ci/flake-budget-guard.mjs +68 -0
- package/scripts/ci/generate-error-codes.mjs +54 -0
- package/scripts/ci/lib/lighthouse-tracker.mjs +90 -0
- package/scripts/ci/lib/self-serve-launch-gate.mjs +89 -0
- package/scripts/ci/npm-pack-smoke.mjs +454 -0
- package/scripts/ci/run-10x-throughput-drill.mjs +318 -0
- package/scripts/ci/run-10x-throughput-incident-rehearsal.mjs +368 -0
- package/scripts/ci/run-arbitration-workspace-browser-e2e.sh +22 -0
- package/scripts/ci/run-circle-sandbox-smoke.mjs +237 -0
- package/scripts/ci/run-go-live-gate.mjs +150 -0
- package/scripts/ci/run-kernel-v0-ship-gate.mjs +97 -0
- package/scripts/ci/run-mcp-host-cert-matrix.mjs +201 -0
- package/scripts/ci/run-mcp-host-smoke.mjs +473 -0
- package/scripts/ci/run-offline-verification-parity-gate.mjs +762 -0
- package/scripts/ci/run-onboarding-host-success-gate.mjs +516 -0
- package/scripts/ci/run-onboarding-policy-slo-gate.mjs +537 -0
- package/scripts/ci/run-production-cutover-gate.mjs +540 -0
- package/scripts/ci/run-public-openclaw-npx-smoke.mjs +148 -0
- package/scripts/ci/run-release-promotion-guard.mjs +756 -0
- package/scripts/ci/run-self-serve-launch-gate.mjs +56 -0
- package/scripts/ci/runtime-import-smoke.mjs +58 -0
- package/scripts/ci/update-lighthouse-tracker.mjs +112 -0
- package/scripts/closepack/lib.mjs +286 -0
- package/scripts/collect-debug.sh +263 -0
- package/scripts/demo/compositional-settlement-3hop.mjs +237 -0
- package/scripts/demo/delivery-robot/export-ui-fixture.mjs +188 -0
- package/scripts/demo/delivery-robot/generate.mjs +377 -0
- package/scripts/demo/kernel-agent-goes-shopping.mjs +202 -0
- package/scripts/demo/magic-link-first-green.mjs +118 -0
- package/scripts/demo/magic-link-kind-smoke.mjs +577 -0
- package/scripts/demo/mcp-paid-exa.mjs +1110 -0
- package/scripts/dev/billing-doctor.sh +145 -0
- package/scripts/dev/billing-smoke-prod.sh +219 -0
- package/scripts/dev/billing-webhook-replay.sh +161 -0
- package/scripts/dev/env.dev.example +29 -0
- package/scripts/dev/env.sh +37 -0
- package/scripts/dev/new-sdk-key.sh +81 -0
- package/scripts/dev/sdk-first-run.sh +21 -0
- package/scripts/dev/smoke-x402-gateway.sh +115 -0
- package/scripts/dev/start-api.sh +24 -0
- package/scripts/doctor/mcp-host.mjs +120 -0
- package/scripts/examples/produce-and-verify-jobproof.mjs +191 -0
- package/scripts/examples/sdk-first-paid-rfq.py +105 -0
- package/scripts/examples/sdk-first-verified-run.mjs +85 -0
- package/scripts/examples/sdk-first-verified-run.py +99 -0
- package/scripts/examples/sdk-tenant-analytics.mjs +103 -0
- package/scripts/examples/sdk-tenant-analytics.py +118 -0
- package/scripts/finance-pack/bundle.mjs +284 -0
- package/scripts/fixtures/generate-bundle-fixtures.mjs +877 -0
- package/scripts/governance/export.mjs +169 -0
- package/scripts/load/delivery-stress.k6.js +183 -0
- package/scripts/load/ingest-burst.k6.js +236 -0
- package/scripts/load/run-delivery-load.js +66 -0
- package/scripts/load/webhook-receiver.js +131 -0
- package/scripts/magic-link/migrate-run-records-to-db.mjs +35 -0
- package/scripts/mcp/probe.mjs +238 -0
- package/scripts/mcp/settld-mcp-http-gateway.mjs +178 -0
- package/scripts/mcp/settld-mcp-server.mjs +1511 -0
- package/scripts/openapi/write.mjs +13 -0
- package/scripts/ops/bootstrap-tenant-conformance.mjs +185 -0
- package/scripts/ops/build-x402-pilot-reliability-report.mjs +489 -0
- package/scripts/ops/check-x402-receipt-sample.mjs +181 -0
- package/scripts/ops/design-partner-run-packet.mjs +466 -0
- package/scripts/ops/dispute-finance-reconciliation-packet.mjs +313 -0
- package/scripts/ops/hosted-baseline-evidence.mjs +890 -0
- package/scripts/ops/money-rails-chargeback-evidence.mjs +509 -0
- package/scripts/ops/money-rails-reconcile-evidence.mjs +180 -0
- package/scripts/ops/p0-seed-money-rail-operation.mjs +432 -0
- package/scripts/ops/run-x402-hitl-smoke.mjs +607 -0
- package/scripts/pilot/finance-pack.mjs +495 -0
- package/scripts/pilot/fixtures/robot-keypair.json +4 -0
- package/scripts/pilot/fixtures/server-signer.json +4 -0
- package/scripts/policy/cli.mjs +600 -0
- package/scripts/profile/cli.mjs +1324 -0
- package/scripts/proof-bundle/job.mjs +109 -0
- package/scripts/proof-bundle/lib.mjs +92 -0
- package/scripts/proof-bundle/month.mjs +103 -0
- package/scripts/provider/conformance-run.mjs +159 -0
- package/scripts/provider/keys-generate.mjs +135 -0
- package/scripts/provider/publish.mjs +420 -0
- package/scripts/quickstart/x402.mjs +334 -0
- package/scripts/register-entity-secret.mjs +102 -0
- package/scripts/release/build-artifacts.mjs +181 -0
- package/scripts/release/generate-release-index.mjs +112 -0
- package/scripts/release/release-index-lib.mjs +232 -0
- package/scripts/release/sign-release-index.mjs +85 -0
- package/scripts/release/validate-release-assets.mjs +170 -0
- package/scripts/release/verify-release.mjs +261 -0
- package/scripts/restore-pg.sh +34 -0
- package/scripts/scaffold/create-settld-paid-tool.mjs +19 -0
- package/scripts/sdk/smoke-python.py +30 -0
- package/scripts/sdk/smoke.mjs +16 -0
- package/scripts/settlement/x402-batch-worker.mjs +1091 -0
- package/scripts/setup/circle-bootstrap.mjs +310 -0
- package/scripts/setup/host-config.mjs +617 -0
- package/scripts/setup/onboard.mjs +1337 -0
- package/scripts/setup/openclaw-onboard.mjs +423 -0
- package/scripts/setup/wizard.mjs +986 -0
- package/scripts/slo/check.mjs +239 -0
- package/scripts/smoke/k8s-smoke.mjs +214 -0
- package/scripts/spec/generate-protocol-vectors.mjs +1019 -0
- package/scripts/test/check-no-generated-artifacts.sh +12 -0
- package/scripts/test/run.sh +59 -0
- package/scripts/trust/validate-trust-file.mjs +57 -0
- package/scripts/trust-config/rotate-settld-pay.mjs +277 -0
- package/scripts/trust-config/wizard.mjs +161 -0
- package/scripts/vendor-contract-test-lib.mjs +182 -0
- package/scripts/vendor-contract-test.mjs +55 -0
- package/scripts/vercel/build-mkdocs.sh +9 -0
- package/scripts/vercel/ignore-mkdocs.sh +25 -0
- package/scripts/vercel/install-mkdocs.sh +6 -0
- package/scripts/verify-pg.js +217 -0
- package/scripts/x402/receipt-verify.mjs +289 -0
- package/services/finance-sink/src/dedupe-store.js +29 -6
- package/services/receiver/src/dedupe-store.js +29 -5
- package/services/x402-gateway/Dockerfile +13 -0
- package/services/x402-gateway/README.md +58 -0
- package/services/x402-gateway/examples/upstream-mock.js +337 -0
- package/services/x402-gateway/src/server.js +1058 -0
- package/src/api/app.js +34658 -16940
- package/src/api/maintenance.js +70 -0
- package/src/api/middleware/trust-kernel.js +114 -0
- package/src/api/openapi.js +1778 -70
- package/src/api/persistence.js +456 -0
- package/src/api/server.js +81 -5
- package/src/api/store.js +1581 -62
- package/src/api/workers/deliveries.js +99 -4
- package/src/api/workers/insolvency-sweep.js +159 -0
- package/src/core/agent-card.js +69 -0
- package/src/core/agent-wallets.js +231 -0
- package/src/core/agreement-delegation.js +549 -0
- package/src/core/billing-plans.js +40 -6
- package/src/core/circle-reserve-adapter.js +845 -0
- package/src/core/event-policy.js +21 -2
- package/src/core/maintenance-locks.js +1 -0
- package/src/core/operator-action.js +303 -0
- package/src/core/paid-tool-manifest.js +318 -0
- package/src/core/policy-decision.js +322 -0
- package/src/core/policy-packs.js +207 -0
- package/src/core/profile-fingerprint.js +27 -0
- package/src/core/profile-simulation-reasons.js +84 -0
- package/src/core/profile-templates.js +242 -0
- package/src/core/provider-publish-conformance.js +525 -0
- package/src/core/provider-publish-proof.js +396 -0
- package/src/core/provider-quote-signature.js +170 -0
- package/src/core/settld-keys.js +112 -0
- package/src/core/settld-pay-token.js +344 -0
- package/src/core/settlement-kernel.js +239 -2
- package/src/core/settlement-verifier.js +335 -0
- package/src/core/tool-call-agreement.js +112 -0
- package/src/core/tool-call-evidence.js +144 -0
- package/src/core/tool-provider-signature.js +98 -0
- package/src/core/wallet-assignment-resolver.js +129 -0
- package/src/core/wallet-provider-bootstrap.js +365 -0
- package/src/core/x402-escalation-override.js +258 -0
- package/src/core/x402-gate.js +118 -0
- package/src/core/x402-provider-refund-decision.js +220 -0
- package/src/core/x402-receipt-verifier.js +708 -0
- package/src/core/x402-reversal-command.js +251 -0
- package/src/core/x402-wallet-issuer-decision.js +252 -0
- package/src/core/zk-verifier.js +300 -0
- package/src/db/migrations/029_reputation_event_index.sql +54 -0
- package/src/db/migrations/030_artifacts_source_event_unique_job_only.sql +15 -0
- package/src/db/pg.js +18 -7
- 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
|
|
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":
|
|
294
|
+
"x-proxy-order-key": headerSafeValue(delivery.orderKey ?? ""),
|
|
259
295
|
"x-proxy-timestamp": timestamp,
|
|
260
|
-
"x-proxy-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
|
-
|
|
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,
|