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
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
import { canonicalJsonStringify, normalizeForCanonicalJson } from "./canonical-json.js";
|
|
2
|
+
import { sha256Hex } from "./crypto.js";
|
|
3
|
+
|
|
4
|
+
export const AGREEMENT_DELEGATION_SCHEMA_VERSION = "AgreementDelegation.v1";
|
|
5
|
+
|
|
6
|
+
export const AGREEMENT_DELEGATION_STATUS = Object.freeze({
|
|
7
|
+
ACTIVE: "active",
|
|
8
|
+
SETTLED: "settled",
|
|
9
|
+
REVOKED: "revoked"
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
function assertPlainObject(value, name) {
|
|
13
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${name} must be an object`);
|
|
14
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
15
|
+
throw new TypeError(`${name} must be a plain object`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function assertNonEmptyString(value, name) {
|
|
20
|
+
if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function assertIsoDate(value, name, { allowNull = false } = {}) {
|
|
24
|
+
if (allowNull && (value === null || value === undefined)) return;
|
|
25
|
+
assertNonEmptyString(value, name);
|
|
26
|
+
if (!Number.isFinite(Date.parse(value))) throw new TypeError(`${name} must be an ISO date string`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function normalizeId(value, name, { min = 1, max = 200 } = {}) {
|
|
30
|
+
assertNonEmptyString(value, name);
|
|
31
|
+
const out = String(value).trim();
|
|
32
|
+
if (out.length < min || out.length > max) throw new TypeError(`${name} must be length ${min}..${max}`);
|
|
33
|
+
if (!/^[A-Za-z0-9:_-]+$/.test(out)) throw new TypeError(`${name} must match ^[A-Za-z0-9:_-]+$`);
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeHexHash(value, name) {
|
|
38
|
+
assertNonEmptyString(value, name);
|
|
39
|
+
const out = String(value).trim().toLowerCase();
|
|
40
|
+
if (!/^[0-9a-f]{64}$/.test(out)) throw new TypeError(`${name} must be a 64-hex sha256`);
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeCurrency(value, name) {
|
|
45
|
+
const raw = typeof value === "string" && value.trim() !== "" ? value : "USD";
|
|
46
|
+
const out = raw.trim().toUpperCase();
|
|
47
|
+
if (!/^[A-Z][A-Z0-9_]{2,11}$/.test(out)) throw new TypeError(`${name} must match ^[A-Z][A-Z0-9_]{2,11}$`);
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function assertPositiveSafeInt(value, name) {
|
|
52
|
+
const n = Number(value);
|
|
53
|
+
if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer`);
|
|
54
|
+
return n;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function assertNonNegativeSafeInt(value, name) {
|
|
58
|
+
const n = Number(value);
|
|
59
|
+
if (!Number.isSafeInteger(n) || n < 0) throw new TypeError(`${name} must be a non-negative safe integer`);
|
|
60
|
+
return n;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function normalizeStatus(value, name) {
|
|
64
|
+
const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
65
|
+
if (!Object.values(AGREEMENT_DELEGATION_STATUS).includes(normalized)) {
|
|
66
|
+
throw new TypeError(`${name} must be one of: ${Object.values(AGREEMENT_DELEGATION_STATUS).join("|")}`);
|
|
67
|
+
}
|
|
68
|
+
return normalized;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizeAncestorChain(value, { name = "ancestorChain", requiredDepth = null, expectedParentHash = null } = {}) {
|
|
72
|
+
if (value === null || value === undefined) return undefined;
|
|
73
|
+
if (!Array.isArray(value)) throw new TypeError(`${name} must be an array`);
|
|
74
|
+
const out = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
77
|
+
const h = normalizeHexHash(value[i], `${name}[${i}]`);
|
|
78
|
+
if (seen.has(h)) throw new TypeError(`${name} must not contain duplicates`);
|
|
79
|
+
seen.add(h);
|
|
80
|
+
out.push(h);
|
|
81
|
+
}
|
|
82
|
+
if (requiredDepth !== null && out.length !== requiredDepth) {
|
|
83
|
+
throw new TypeError(`${name} length must equal delegationDepth`);
|
|
84
|
+
}
|
|
85
|
+
if (expectedParentHash && out.length && out[out.length - 1] !== expectedParentHash) {
|
|
86
|
+
throw new TypeError(`${name} last element must equal parentAgreementHash`);
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function computeAgreementDelegationHashV1(delegationCore) {
|
|
92
|
+
assertPlainObject(delegationCore, "delegationCore");
|
|
93
|
+
const copy = { ...delegationCore };
|
|
94
|
+
delete copy.delegationHash;
|
|
95
|
+
delete copy.status;
|
|
96
|
+
delete copy.resolvedAt;
|
|
97
|
+
delete copy.updatedAt;
|
|
98
|
+
delete copy.revision;
|
|
99
|
+
delete copy.metadata;
|
|
100
|
+
const normalized = normalizeForCanonicalJson(copy, { path: "$" });
|
|
101
|
+
return sha256Hex(canonicalJsonStringify(normalized));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function buildAgreementDelegationV1({
|
|
105
|
+
delegationId,
|
|
106
|
+
tenantId,
|
|
107
|
+
parentAgreementHash,
|
|
108
|
+
childAgreementHash,
|
|
109
|
+
delegatorAgentId,
|
|
110
|
+
delegateeAgentId,
|
|
111
|
+
budgetCapCents,
|
|
112
|
+
currency,
|
|
113
|
+
delegationDepth,
|
|
114
|
+
maxDelegationDepth,
|
|
115
|
+
ancestorChain,
|
|
116
|
+
createdAt
|
|
117
|
+
} = {}) {
|
|
118
|
+
const at = createdAt ?? new Date().toISOString();
|
|
119
|
+
assertIsoDate(at, "createdAt");
|
|
120
|
+
|
|
121
|
+
const parentHash = normalizeHexHash(parentAgreementHash, "parentAgreementHash");
|
|
122
|
+
const depth = assertNonNegativeSafeInt(delegationDepth, "delegationDepth");
|
|
123
|
+
const normalizedAncestorChain = normalizeAncestorChain(ancestorChain, {
|
|
124
|
+
name: "ancestorChain",
|
|
125
|
+
requiredDepth: ancestorChain === undefined || ancestorChain === null ? null : depth,
|
|
126
|
+
expectedParentHash: parentHash
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const normalized = normalizeForCanonicalJson(
|
|
130
|
+
{
|
|
131
|
+
schemaVersion: AGREEMENT_DELEGATION_SCHEMA_VERSION,
|
|
132
|
+
delegationId: normalizeId(delegationId, "delegationId", { min: 3, max: 240 }),
|
|
133
|
+
tenantId: normalizeId(tenantId, "tenantId", { min: 1, max: 128 }),
|
|
134
|
+
parentAgreementHash: parentHash,
|
|
135
|
+
childAgreementHash: normalizeHexHash(childAgreementHash, "childAgreementHash"),
|
|
136
|
+
delegatorAgentId: normalizeId(delegatorAgentId, "delegatorAgentId", { min: 3, max: 128 }),
|
|
137
|
+
delegateeAgentId: normalizeId(delegateeAgentId, "delegateeAgentId", { min: 3, max: 128 }),
|
|
138
|
+
budgetCapCents: assertPositiveSafeInt(budgetCapCents, "budgetCapCents"),
|
|
139
|
+
currency: normalizeCurrency(currency, "currency"),
|
|
140
|
+
delegationDepth: depth,
|
|
141
|
+
maxDelegationDepth: assertNonNegativeSafeInt(maxDelegationDepth, "maxDelegationDepth"),
|
|
142
|
+
createdAt: at,
|
|
143
|
+
...(normalizedAncestorChain ? { ancestorChain: normalizedAncestorChain } : {})
|
|
144
|
+
},
|
|
145
|
+
{ path: "$" }
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
if (normalized.delegationDepth > normalized.maxDelegationDepth) {
|
|
149
|
+
throw new TypeError("delegationDepth must be <= maxDelegationDepth");
|
|
150
|
+
}
|
|
151
|
+
if (normalized.parentAgreementHash === normalized.childAgreementHash) {
|
|
152
|
+
throw new TypeError("parentAgreementHash must differ from childAgreementHash");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const delegationHash = computeAgreementDelegationHashV1(normalized);
|
|
156
|
+
return normalizeForCanonicalJson(
|
|
157
|
+
{
|
|
158
|
+
...normalized,
|
|
159
|
+
delegationHash,
|
|
160
|
+
status: AGREEMENT_DELEGATION_STATUS.ACTIVE,
|
|
161
|
+
revision: 0,
|
|
162
|
+
updatedAt: at
|
|
163
|
+
},
|
|
164
|
+
{ path: "$" }
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function validateAgreementDelegationV1(delegation) {
|
|
169
|
+
assertPlainObject(delegation, "delegation");
|
|
170
|
+
if (delegation.schemaVersion !== AGREEMENT_DELEGATION_SCHEMA_VERSION) {
|
|
171
|
+
throw new TypeError(`delegation.schemaVersion must be ${AGREEMENT_DELEGATION_SCHEMA_VERSION}`);
|
|
172
|
+
}
|
|
173
|
+
normalizeId(delegation.delegationId, "delegation.delegationId", { min: 3, max: 240 });
|
|
174
|
+
normalizeId(delegation.tenantId, "delegation.tenantId", { min: 1, max: 128 });
|
|
175
|
+
const parentHash = normalizeHexHash(delegation.parentAgreementHash, "delegation.parentAgreementHash");
|
|
176
|
+
const childHash = normalizeHexHash(delegation.childAgreementHash, "delegation.childAgreementHash");
|
|
177
|
+
if (parentHash === childHash) throw new TypeError("delegation.parentAgreementHash must differ from delegation.childAgreementHash");
|
|
178
|
+
normalizeId(delegation.delegatorAgentId, "delegation.delegatorAgentId", { min: 3, max: 128 });
|
|
179
|
+
normalizeId(delegation.delegateeAgentId, "delegation.delegateeAgentId", { min: 3, max: 128 });
|
|
180
|
+
assertPositiveSafeInt(delegation.budgetCapCents, "delegation.budgetCapCents");
|
|
181
|
+
normalizeCurrency(delegation.currency, "delegation.currency");
|
|
182
|
+
const depth = assertNonNegativeSafeInt(delegation.delegationDepth, "delegation.delegationDepth");
|
|
183
|
+
const maxDepth = assertNonNegativeSafeInt(delegation.maxDelegationDepth, "delegation.maxDelegationDepth");
|
|
184
|
+
if (depth > maxDepth) throw new TypeError("delegation.delegationDepth must be <= delegation.maxDelegationDepth");
|
|
185
|
+
assertIsoDate(delegation.createdAt, "delegation.createdAt");
|
|
186
|
+
if (Object.prototype.hasOwnProperty.call(delegation, "ancestorChain")) {
|
|
187
|
+
normalizeAncestorChain(delegation.ancestorChain ?? null, {
|
|
188
|
+
name: "delegation.ancestorChain",
|
|
189
|
+
requiredDepth: delegation.ancestorChain === null ? null : depth,
|
|
190
|
+
expectedParentHash: parentHash
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
normalizeHexHash(delegation.delegationHash, "delegation.delegationHash");
|
|
194
|
+
normalizeStatus(delegation.status, "delegation.status");
|
|
195
|
+
const revision = Number(delegation.revision ?? 0);
|
|
196
|
+
if (!Number.isSafeInteger(revision) || revision < 0) throw new TypeError("delegation.revision must be a non-negative safe integer");
|
|
197
|
+
assertIsoDate(delegation.updatedAt, "delegation.updatedAt");
|
|
198
|
+
if (Object.prototype.hasOwnProperty.call(delegation, "resolvedAt")) {
|
|
199
|
+
assertIsoDate(delegation.resolvedAt ?? null, "delegation.resolvedAt", { allowNull: true });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const computed = computeAgreementDelegationHashV1(delegation);
|
|
203
|
+
if (computed !== String(delegation.delegationHash).toLowerCase()) throw new TypeError("delegationHash mismatch");
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function resolveAgreementDelegationV1({ delegation, status, resolvedAt = null, metadata = null } = {}) {
|
|
208
|
+
validateAgreementDelegationV1(delegation);
|
|
209
|
+
const nextStatus = normalizeStatus(status, "status");
|
|
210
|
+
const at = resolvedAt ?? new Date().toISOString();
|
|
211
|
+
assertIsoDate(at, "resolvedAt");
|
|
212
|
+
if (nextStatus === AGREEMENT_DELEGATION_STATUS.ACTIVE) throw new TypeError("cannot resolve delegation to active");
|
|
213
|
+
const currentStatus = String(delegation.status ?? "").toLowerCase();
|
|
214
|
+
if (currentStatus !== AGREEMENT_DELEGATION_STATUS.ACTIVE) return delegation;
|
|
215
|
+
|
|
216
|
+
const meta = metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : null;
|
|
217
|
+
const next = {
|
|
218
|
+
...delegation,
|
|
219
|
+
status: nextStatus,
|
|
220
|
+
resolvedAt: at,
|
|
221
|
+
revision: Number(delegation.revision ?? 0) + 1,
|
|
222
|
+
updatedAt: at
|
|
223
|
+
};
|
|
224
|
+
if (meta) next.metadata = normalizeForCanonicalJson(meta, { path: "$.metadata" });
|
|
225
|
+
return normalizeForCanonicalJson(next, { path: "$" });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function indexDelegations(delegations) {
|
|
229
|
+
const byChild = new Map();
|
|
230
|
+
const childrenByParent = new Map();
|
|
231
|
+
for (const d of Array.isArray(delegations) ? delegations : []) {
|
|
232
|
+
if (!d || typeof d !== "object" || Array.isArray(d)) continue;
|
|
233
|
+
const status = String(d.status ?? "").toLowerCase();
|
|
234
|
+
if (status === AGREEMENT_DELEGATION_STATUS.REVOKED) continue;
|
|
235
|
+
const parent = typeof d.parentAgreementHash === "string" ? d.parentAgreementHash.toLowerCase() : null;
|
|
236
|
+
const child = typeof d.childAgreementHash === "string" ? d.childAgreementHash.toLowerCase() : null;
|
|
237
|
+
if (!parent || !child) continue;
|
|
238
|
+
|
|
239
|
+
if (byChild.has(child) && byChild.get(child)?.parentAgreementHash !== parent) {
|
|
240
|
+
const err = new Error("multiple parents found for childAgreementHash");
|
|
241
|
+
err.code = "AGREEMENT_DELEGATION_MULTIPLE_PARENTS";
|
|
242
|
+
err.childAgreementHash = child;
|
|
243
|
+
throw err;
|
|
244
|
+
}
|
|
245
|
+
byChild.set(child, { delegationId: d.delegationId ?? null, parentAgreementHash: parent, childAgreementHash: child });
|
|
246
|
+
|
|
247
|
+
const list = childrenByParent.get(parent) ?? [];
|
|
248
|
+
list.push({ delegationId: d.delegationId ?? null, parentAgreementHash: parent, childAgreementHash: child });
|
|
249
|
+
childrenByParent.set(parent, list);
|
|
250
|
+
}
|
|
251
|
+
for (const [p, list] of childrenByParent.entries()) {
|
|
252
|
+
list.sort((a, b) => String(a.childAgreementHash).localeCompare(String(b.childAgreementHash)));
|
|
253
|
+
childrenByParent.set(p, list);
|
|
254
|
+
}
|
|
255
|
+
return { byChild, childrenByParent };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function indexDelegationsById(delegations) {
|
|
259
|
+
const byId = new Map();
|
|
260
|
+
for (const delegation of Array.isArray(delegations) ? delegations : []) {
|
|
261
|
+
if (!delegation || typeof delegation !== "object" || Array.isArray(delegation)) continue;
|
|
262
|
+
const delegationId = typeof delegation.delegationId === "string" ? delegation.delegationId.trim() : "";
|
|
263
|
+
if (!delegationId) continue;
|
|
264
|
+
if (byId.has(delegationId)) {
|
|
265
|
+
const err = new Error("duplicate delegationId in input set");
|
|
266
|
+
err.code = "AGREEMENT_DELEGATION_DUPLICATE_ID";
|
|
267
|
+
err.delegationId = delegationId;
|
|
268
|
+
throw err;
|
|
269
|
+
}
|
|
270
|
+
byId.set(delegationId, delegation);
|
|
271
|
+
}
|
|
272
|
+
return byId;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function summarizeAgreementDelegationLedgerV1({ delegations } = {}) {
|
|
276
|
+
const summary = {
|
|
277
|
+
schemaVersion: "AgreementDelegationLedger.v1",
|
|
278
|
+
totalDelegations: 0,
|
|
279
|
+
activeCount: 0,
|
|
280
|
+
settledCount: 0,
|
|
281
|
+
revokedCount: 0,
|
|
282
|
+
terminalCount: 0,
|
|
283
|
+
unresolvedCount: 0,
|
|
284
|
+
countsByStatus: {
|
|
285
|
+
[AGREEMENT_DELEGATION_STATUS.ACTIVE]: 0,
|
|
286
|
+
[AGREEMENT_DELEGATION_STATUS.SETTLED]: 0,
|
|
287
|
+
[AGREEMENT_DELEGATION_STATUS.REVOKED]: 0
|
|
288
|
+
},
|
|
289
|
+
invariant: {
|
|
290
|
+
ok: true,
|
|
291
|
+
code: "AGREEMENT_DELEGATION_LEDGER_INVARIANT_OK",
|
|
292
|
+
message: "active+settled+revoked equals total"
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
for (const delegation of Array.isArray(delegations) ? delegations : []) {
|
|
296
|
+
if (!delegation || typeof delegation !== "object" || Array.isArray(delegation)) continue;
|
|
297
|
+
summary.totalDelegations += 1;
|
|
298
|
+
const status = String(delegation.status ?? "").trim().toLowerCase();
|
|
299
|
+
if (status === AGREEMENT_DELEGATION_STATUS.ACTIVE) {
|
|
300
|
+
summary.activeCount += 1;
|
|
301
|
+
summary.unresolvedCount += 1;
|
|
302
|
+
summary.countsByStatus[AGREEMENT_DELEGATION_STATUS.ACTIVE] += 1;
|
|
303
|
+
} else if (status === AGREEMENT_DELEGATION_STATUS.SETTLED) {
|
|
304
|
+
summary.settledCount += 1;
|
|
305
|
+
summary.terminalCount += 1;
|
|
306
|
+
summary.countsByStatus[AGREEMENT_DELEGATION_STATUS.SETTLED] += 1;
|
|
307
|
+
} else if (status === AGREEMENT_DELEGATION_STATUS.REVOKED) {
|
|
308
|
+
summary.revokedCount += 1;
|
|
309
|
+
summary.terminalCount += 1;
|
|
310
|
+
summary.countsByStatus[AGREEMENT_DELEGATION_STATUS.REVOKED] += 1;
|
|
311
|
+
} else {
|
|
312
|
+
summary.invariant = {
|
|
313
|
+
ok: false,
|
|
314
|
+
code: "AGREEMENT_DELEGATION_STATUS_UNKNOWN",
|
|
315
|
+
message: "delegation has unsupported status"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (summary.totalDelegations !== summary.activeCount + summary.settledCount + summary.revokedCount) {
|
|
320
|
+
summary.invariant = {
|
|
321
|
+
ok: false,
|
|
322
|
+
code: "AGREEMENT_DELEGATION_LEDGER_IMBALANCED",
|
|
323
|
+
message: "active+settled+revoked must equal totalDelegations"
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
return normalizeForCanonicalJson(summary, { path: "$" });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function applyDelegationResolutionPlan({
|
|
330
|
+
delegations,
|
|
331
|
+
edges,
|
|
332
|
+
targetStatus,
|
|
333
|
+
resolvedAt = null,
|
|
334
|
+
metadata = null,
|
|
335
|
+
resultKind
|
|
336
|
+
} = {}) {
|
|
337
|
+
const nextStatus = normalizeStatus(targetStatus, "targetStatus");
|
|
338
|
+
if (nextStatus === AGREEMENT_DELEGATION_STATUS.ACTIVE) {
|
|
339
|
+
throw new TypeError("targetStatus must be settled|revoked");
|
|
340
|
+
}
|
|
341
|
+
const byId = indexDelegationsById(delegations);
|
|
342
|
+
const updates = new Map();
|
|
343
|
+
const operations = [];
|
|
344
|
+
const at = resolvedAt ?? new Date().toISOString();
|
|
345
|
+
assertIsoDate(at, "resolvedAt");
|
|
346
|
+
|
|
347
|
+
for (const edge of Array.isArray(edges) ? edges : []) {
|
|
348
|
+
const delegationId = typeof edge?.delegationId === "string" ? edge.delegationId.trim() : "";
|
|
349
|
+
if (!delegationId) {
|
|
350
|
+
const err = new Error("delegationId is required on plan edge");
|
|
351
|
+
err.code = "AGREEMENT_DELEGATION_PLAN_EDGE_ID_REQUIRED";
|
|
352
|
+
throw err;
|
|
353
|
+
}
|
|
354
|
+
const current = updates.get(delegationId) ?? byId.get(delegationId) ?? null;
|
|
355
|
+
if (!current) {
|
|
356
|
+
const err = new Error("plan references unknown delegationId");
|
|
357
|
+
err.code = "AGREEMENT_DELEGATION_PLAN_EDGE_NOT_FOUND";
|
|
358
|
+
err.delegationId = delegationId;
|
|
359
|
+
throw err;
|
|
360
|
+
}
|
|
361
|
+
const currentStatus = String(current.status ?? "").trim().toLowerCase();
|
|
362
|
+
if (currentStatus !== AGREEMENT_DELEGATION_STATUS.ACTIVE && currentStatus !== nextStatus) {
|
|
363
|
+
const err = new Error("delegation already resolved with conflicting terminal status");
|
|
364
|
+
err.code = "AGREEMENT_DELEGATION_TERMINAL_CONFLICT";
|
|
365
|
+
err.delegationId = delegationId;
|
|
366
|
+
err.currentStatus = currentStatus;
|
|
367
|
+
err.targetStatus = nextStatus;
|
|
368
|
+
throw err;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (currentStatus === nextStatus) {
|
|
372
|
+
operations.push({
|
|
373
|
+
delegationId,
|
|
374
|
+
result: "noop",
|
|
375
|
+
fromStatus: currentStatus,
|
|
376
|
+
toStatus: nextStatus
|
|
377
|
+
});
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const nextDelegation = resolveAgreementDelegationV1({
|
|
382
|
+
delegation: current,
|
|
383
|
+
status: nextStatus,
|
|
384
|
+
resolvedAt: at,
|
|
385
|
+
metadata
|
|
386
|
+
});
|
|
387
|
+
updates.set(delegationId, nextDelegation);
|
|
388
|
+
operations.push({
|
|
389
|
+
delegationId,
|
|
390
|
+
result: "applied",
|
|
391
|
+
fromStatus: currentStatus,
|
|
392
|
+
toStatus: nextStatus
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const nextDelegations = [];
|
|
397
|
+
for (const delegation of Array.isArray(delegations) ? delegations : []) {
|
|
398
|
+
if (!delegation || typeof delegation !== "object" || Array.isArray(delegation)) continue;
|
|
399
|
+
const delegationId = typeof delegation.delegationId === "string" ? delegation.delegationId.trim() : "";
|
|
400
|
+
if (!delegationId) continue;
|
|
401
|
+
nextDelegations.push(updates.get(delegationId) ?? delegation);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const applied = operations.filter((row) => row.result === "applied").length;
|
|
405
|
+
const noop = operations.filter((row) => row.result === "noop").length;
|
|
406
|
+
const ledger = summarizeAgreementDelegationLedgerV1({ delegations: nextDelegations });
|
|
407
|
+
|
|
408
|
+
return normalizeForCanonicalJson(
|
|
409
|
+
{
|
|
410
|
+
ok: true,
|
|
411
|
+
kind: resultKind,
|
|
412
|
+
targetStatus: nextStatus,
|
|
413
|
+
resolvedAt: at,
|
|
414
|
+
operations,
|
|
415
|
+
stats: {
|
|
416
|
+
attempted: operations.length,
|
|
417
|
+
applied,
|
|
418
|
+
noop
|
|
419
|
+
},
|
|
420
|
+
ledger,
|
|
421
|
+
delegations: nextDelegations
|
|
422
|
+
},
|
|
423
|
+
{ path: "$" }
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Read-only: returns a deterministic "plan" for the caller to execute.
|
|
428
|
+
export function cascadeSettlementCheck({ delegations, fromChildHash } = {}) {
|
|
429
|
+
const start = normalizeHexHash(fromChildHash, "fromChildHash");
|
|
430
|
+
const { byChild } = indexDelegations(delegations);
|
|
431
|
+
const parents = [];
|
|
432
|
+
const edges = [];
|
|
433
|
+
const seen = new Set([start]);
|
|
434
|
+
let cursor = start;
|
|
435
|
+
while (true) {
|
|
436
|
+
const link = byChild.get(cursor) ?? null;
|
|
437
|
+
if (!link) break;
|
|
438
|
+
const parent = link.parentAgreementHash;
|
|
439
|
+
if (seen.has(parent)) {
|
|
440
|
+
const err = new Error("cycle detected in delegation graph");
|
|
441
|
+
err.code = "AGREEMENT_DELEGATION_CYCLE";
|
|
442
|
+
err.agreementHash = parent;
|
|
443
|
+
throw err;
|
|
444
|
+
}
|
|
445
|
+
seen.add(parent);
|
|
446
|
+
edges.push({ delegationId: link.delegationId ?? null, childAgreementHash: cursor, parentAgreementHash: parent });
|
|
447
|
+
parents.push(parent);
|
|
448
|
+
cursor = parent;
|
|
449
|
+
}
|
|
450
|
+
return normalizeForCanonicalJson(
|
|
451
|
+
{
|
|
452
|
+
ok: true,
|
|
453
|
+
kind: "cascade_settlement_check_v1",
|
|
454
|
+
fromChildHash: start,
|
|
455
|
+
parentAgreementHashes: parents,
|
|
456
|
+
edges
|
|
457
|
+
},
|
|
458
|
+
{ path: "$" }
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Read-only: returns a deterministic "plan" for the caller to execute.
|
|
463
|
+
export function refundUnwindCheck({ delegations, fromParentHash } = {}) {
|
|
464
|
+
const start = normalizeHexHash(fromParentHash, "fromParentHash");
|
|
465
|
+
const { childrenByParent } = indexDelegations(delegations);
|
|
466
|
+
const orderedChildren = [];
|
|
467
|
+
const edges = [];
|
|
468
|
+
const seen = new Set([start]);
|
|
469
|
+
const queue = [start];
|
|
470
|
+
while (queue.length) {
|
|
471
|
+
const parent = queue.shift();
|
|
472
|
+
const children = childrenByParent.get(parent) ?? [];
|
|
473
|
+
for (const link of children) {
|
|
474
|
+
const child = link.childAgreementHash;
|
|
475
|
+
edges.push({ delegationId: link.delegationId ?? null, parentAgreementHash: parent, childAgreementHash: child });
|
|
476
|
+
if (seen.has(child)) continue;
|
|
477
|
+
seen.add(child);
|
|
478
|
+
orderedChildren.push(child);
|
|
479
|
+
queue.push(child);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return normalizeForCanonicalJson(
|
|
483
|
+
{
|
|
484
|
+
ok: true,
|
|
485
|
+
kind: "refund_unwind_check_v1",
|
|
486
|
+
fromParentHash: start,
|
|
487
|
+
childAgreementHashes: orderedChildren,
|
|
488
|
+
edges
|
|
489
|
+
},
|
|
490
|
+
{ path: "$" }
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function cascadeSettlementExecute({ delegations, fromChildHash, resolvedAt = null, metadata = null } = {}) {
|
|
495
|
+
const plan = cascadeSettlementCheck({ delegations, fromChildHash });
|
|
496
|
+
const result = applyDelegationResolutionPlan({
|
|
497
|
+
delegations,
|
|
498
|
+
edges: plan.edges,
|
|
499
|
+
targetStatus: AGREEMENT_DELEGATION_STATUS.SETTLED,
|
|
500
|
+
resolvedAt,
|
|
501
|
+
metadata,
|
|
502
|
+
resultKind: "cascade_settlement_execute_v1"
|
|
503
|
+
});
|
|
504
|
+
return normalizeForCanonicalJson(
|
|
505
|
+
{
|
|
506
|
+
...result,
|
|
507
|
+
plan
|
|
508
|
+
},
|
|
509
|
+
{ path: "$" }
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export function cascadeUnwindExecute({ delegations, fromChildHash, resolvedAt = null, metadata = null } = {}) {
|
|
514
|
+
const plan = cascadeSettlementCheck({ delegations, fromChildHash });
|
|
515
|
+
const result = applyDelegationResolutionPlan({
|
|
516
|
+
delegations,
|
|
517
|
+
edges: plan.edges,
|
|
518
|
+
targetStatus: AGREEMENT_DELEGATION_STATUS.REVOKED,
|
|
519
|
+
resolvedAt,
|
|
520
|
+
metadata,
|
|
521
|
+
resultKind: "cascade_unwind_execute_v1"
|
|
522
|
+
});
|
|
523
|
+
return normalizeForCanonicalJson(
|
|
524
|
+
{
|
|
525
|
+
...result,
|
|
526
|
+
plan
|
|
527
|
+
},
|
|
528
|
+
{ path: "$" }
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export function refundUnwindExecute({ delegations, fromParentHash, resolvedAt = null, metadata = null } = {}) {
|
|
533
|
+
const plan = refundUnwindCheck({ delegations, fromParentHash });
|
|
534
|
+
const result = applyDelegationResolutionPlan({
|
|
535
|
+
delegations,
|
|
536
|
+
edges: plan.edges,
|
|
537
|
+
targetStatus: AGREEMENT_DELEGATION_STATUS.REVOKED,
|
|
538
|
+
resolvedAt,
|
|
539
|
+
metadata,
|
|
540
|
+
resultKind: "refund_unwind_execute_v1"
|
|
541
|
+
});
|
|
542
|
+
return normalizeForCanonicalJson(
|
|
543
|
+
{
|
|
544
|
+
...result,
|
|
545
|
+
plan
|
|
546
|
+
},
|
|
547
|
+
{ path: "$" }
|
|
548
|
+
);
|
|
549
|
+
}
|
|
@@ -12,6 +12,7 @@ const BILLING_PLAN_CATALOG = Object.freeze({
|
|
|
12
12
|
subscriptionCents: 0,
|
|
13
13
|
includedVerifiedRunsPerMonth: 1000,
|
|
14
14
|
verifiedRunOverageCents: 0,
|
|
15
|
+
verifiedRunOverageMilliCents: 0,
|
|
15
16
|
settledVolumeFeeBps: 0,
|
|
16
17
|
arbitrationCaseFeeCents: 0,
|
|
17
18
|
hardLimitVerifiedRunsPerMonth: 1000
|
|
@@ -22,6 +23,7 @@ const BILLING_PLAN_CATALOG = Object.freeze({
|
|
|
22
23
|
subscriptionCents: 9900,
|
|
23
24
|
includedVerifiedRunsPerMonth: 10_000,
|
|
24
25
|
verifiedRunOverageCents: 1,
|
|
26
|
+
verifiedRunOverageMilliCents: 1000,
|
|
25
27
|
settledVolumeFeeBps: 75,
|
|
26
28
|
arbitrationCaseFeeCents: 200,
|
|
27
29
|
hardLimitVerifiedRunsPerMonth: 0
|
|
@@ -31,7 +33,8 @@ const BILLING_PLAN_CATALOG = Object.freeze({
|
|
|
31
33
|
displayName: "Growth",
|
|
32
34
|
subscriptionCents: 59_900,
|
|
33
35
|
includedVerifiedRunsPerMonth: 100_000,
|
|
34
|
-
verifiedRunOverageCents:
|
|
36
|
+
verifiedRunOverageCents: 0.7,
|
|
37
|
+
verifiedRunOverageMilliCents: 700,
|
|
35
38
|
settledVolumeFeeBps: 45,
|
|
36
39
|
arbitrationCaseFeeCents: 100,
|
|
37
40
|
hardLimitVerifiedRunsPerMonth: 0
|
|
@@ -42,6 +45,7 @@ const BILLING_PLAN_CATALOG = Object.freeze({
|
|
|
42
45
|
subscriptionCents: 0,
|
|
43
46
|
includedVerifiedRunsPerMonth: 0,
|
|
44
47
|
verifiedRunOverageCents: 0,
|
|
48
|
+
verifiedRunOverageMilliCents: 0,
|
|
45
49
|
settledVolumeFeeBps: 35,
|
|
46
50
|
arbitrationCaseFeeCents: 0,
|
|
47
51
|
hardLimitVerifiedRunsPerMonth: 0
|
|
@@ -56,6 +60,22 @@ function assertNonNegativeSafeInt(value, fieldName) {
|
|
|
56
60
|
return n;
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
function assertNonNegativeCentsRate(value, fieldName) {
|
|
64
|
+
const n = Number(value);
|
|
65
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
66
|
+
throw new TypeError(`${fieldName} must be a non-negative finite number`);
|
|
67
|
+
}
|
|
68
|
+
const rounded = Math.round(n * 1000) / 1000;
|
|
69
|
+
if (Math.abs(rounded - n) > 1e-9) {
|
|
70
|
+
throw new TypeError(`${fieldName} must use at most 3 decimal places`);
|
|
71
|
+
}
|
|
72
|
+
return rounded;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function toMilliCentsFromCentsRate(centsRate) {
|
|
76
|
+
return Math.round(assertNonNegativeCentsRate(centsRate, "plan.verifiedRunOverageCents") * 1000);
|
|
77
|
+
}
|
|
78
|
+
|
|
59
79
|
export function normalizeBillingPlanId(value, { allowNull = false, defaultPlan = BILLING_PLAN_ID.FREE } = {}) {
|
|
60
80
|
if (value === null || value === undefined || String(value).trim() === "") {
|
|
61
81
|
if (allowNull) return null;
|
|
@@ -96,11 +116,17 @@ export function normalizeBillingPlanOverrides(input, { allowNull = true } = {})
|
|
|
96
116
|
);
|
|
97
117
|
}
|
|
98
118
|
if (Object.prototype.hasOwnProperty.call(input, "verifiedRunOverageCents")) {
|
|
99
|
-
out.verifiedRunOverageCents =
|
|
119
|
+
out.verifiedRunOverageCents = assertNonNegativeCentsRate(
|
|
100
120
|
input.verifiedRunOverageCents,
|
|
101
121
|
"billing.overrides.verifiedRunOverageCents"
|
|
102
122
|
);
|
|
103
123
|
}
|
|
124
|
+
if (Object.prototype.hasOwnProperty.call(input, "verifiedRunOverageMilliCents")) {
|
|
125
|
+
out.verifiedRunOverageMilliCents = assertNonNegativeSafeInt(
|
|
126
|
+
input.verifiedRunOverageMilliCents,
|
|
127
|
+
"billing.overrides.verifiedRunOverageMilliCents"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
104
130
|
if (Object.prototype.hasOwnProperty.call(input, "settledVolumeFeeBps")) {
|
|
105
131
|
const bps = assertNonNegativeSafeInt(input.settledVolumeFeeBps, "billing.overrides.settledVolumeFeeBps");
|
|
106
132
|
if (bps > 10_000) throw new TypeError("billing.overrides.settledVolumeFeeBps must be within 0..10000");
|
|
@@ -144,10 +170,16 @@ export function computeBillingEstimate({
|
|
|
144
170
|
plan?.includedVerifiedRunsPerMonth ?? normalizedPlan.includedVerifiedRunsPerMonth ?? 0,
|
|
145
171
|
"plan.includedVerifiedRunsPerMonth"
|
|
146
172
|
);
|
|
147
|
-
const verifiedRunOverageCentsPerUnit =
|
|
173
|
+
const verifiedRunOverageCentsPerUnit = assertNonNegativeCentsRate(
|
|
148
174
|
plan?.verifiedRunOverageCents ?? normalizedPlan.verifiedRunOverageCents ?? 0,
|
|
149
175
|
"plan.verifiedRunOverageCents"
|
|
150
176
|
);
|
|
177
|
+
const verifiedRunOverageMilliCentsPerUnit = assertNonNegativeSafeInt(
|
|
178
|
+
plan?.verifiedRunOverageMilliCents ??
|
|
179
|
+
normalizedPlan.verifiedRunOverageMilliCents ??
|
|
180
|
+
toMilliCentsFromCentsRate(verifiedRunOverageCentsPerUnit),
|
|
181
|
+
"plan.verifiedRunOverageMilliCents"
|
|
182
|
+
);
|
|
151
183
|
const settledVolumeFeeBps = assertNonNegativeSafeInt(
|
|
152
184
|
plan?.settledVolumeFeeBps ?? normalizedPlan.settledVolumeFeeBps ?? 0,
|
|
153
185
|
"plan.settledVolumeFeeBps"
|
|
@@ -165,9 +197,9 @@ export function computeBillingEstimate({
|
|
|
165
197
|
const settledVolumeCents = assertNonNegativeSafeInt(usage?.settledVolumeCents ?? 0, "usage.settledVolumeCents");
|
|
166
198
|
const arbitrationCases = assertNonNegativeSafeInt(usage?.arbitrationCases ?? 0, "usage.arbitrationCases");
|
|
167
199
|
|
|
168
|
-
const verifiedRunOverageUnits =
|
|
169
|
-
|
|
170
|
-
const verifiedRunOverageCents =
|
|
200
|
+
const verifiedRunOverageUnits = Math.max(0, verifiedRuns - includedVerifiedRunsPerMonth);
|
|
201
|
+
const verifiedRunOverageMilliCents = verifiedRunOverageUnits * verifiedRunOverageMilliCentsPerUnit;
|
|
202
|
+
const verifiedRunOverageCents = Math.round(verifiedRunOverageMilliCents / 1000);
|
|
171
203
|
const settledVolumeFeeCents = Math.floor((settledVolumeCents * settledVolumeFeeBps) / 10_000);
|
|
172
204
|
const arbitrationFeeCents = arbitrationCases * arbitrationCaseFeeCents;
|
|
173
205
|
const totalEstimatedCents = subscriptionCents + verifiedRunOverageCents + settledVolumeFeeCents + arbitrationFeeCents;
|
|
@@ -177,7 +209,9 @@ export function computeBillingEstimate({
|
|
|
177
209
|
includedVerifiedRunsPerMonth,
|
|
178
210
|
verifiedRunOverageUnits,
|
|
179
211
|
verifiedRunOverageCents,
|
|
212
|
+
verifiedRunOverageMilliCents,
|
|
180
213
|
verifiedRunOverageCentsPerUnit,
|
|
214
|
+
verifiedRunOverageMilliCentsPerUnit,
|
|
181
215
|
settledVolumeFeeBps,
|
|
182
216
|
settledVolumeFeeCents,
|
|
183
217
|
arbitrationCaseFeeCents,
|