x402-trust-layer 5.1.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/CHANGELOG.md +55 -0
- package/DEPLOY.md +53 -0
- package/Dockerfile +30 -0
- package/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/agents/a2a-payment.d.ts +37 -0
- package/dist/agents/a2a-payment.js +105 -0
- package/dist/agents/agent-escrow.d.ts +30 -0
- package/dist/agents/agent-escrow.js +23 -0
- package/dist/agents/agent-verify.d.ts +15 -0
- package/dist/agents/agent-verify.js +112 -0
- package/dist/agents/api-router.d.ts +32 -0
- package/dist/agents/api-router.js +228 -0
- package/dist/agents/attestation-registry.d.ts +35 -0
- package/dist/agents/attestation-registry.js +76 -0
- package/dist/agents/audition-coach.d.ts +45 -0
- package/dist/agents/audition-coach.js +257 -0
- package/dist/agents/bedrock-bridge.d.ts +3 -0
- package/dist/agents/bedrock-bridge.js +60 -0
- package/dist/agents/budget-allocator.d.ts +24 -0
- package/dist/agents/budget-allocator.js +31 -0
- package/dist/agents/compliance-ledger.d.ts +66 -0
- package/dist/agents/compliance-ledger.js +80 -0
- package/dist/agents/dispute-resolver.d.ts +62 -0
- package/dist/agents/dispute-resolver.js +124 -0
- package/dist/agents/evidence-locker.d.ts +30 -0
- package/dist/agents/evidence-locker.js +47 -0
- package/dist/agents/facilitator-failover.d.ts +15 -0
- package/dist/agents/facilitator-failover.js +18 -0
- package/dist/agents/identity-gate.d.ts +20 -0
- package/dist/agents/identity-gate.js +79 -0
- package/dist/agents/mandate-compiler.d.ts +51 -0
- package/dist/agents/mandate-compiler.js +73 -0
- package/dist/agents/mandate-diff.d.ts +41 -0
- package/dist/agents/mandate-diff.js +170 -0
- package/dist/agents/market-buy-advisor.d.ts +65 -0
- package/dist/agents/market-buy-advisor.js +234 -0
- package/dist/agents/merchant-trust.d.ts +38 -0
- package/dist/agents/merchant-trust.js +171 -0
- package/dist/agents/mpp-session-broker.d.ts +27 -0
- package/dist/agents/mpp-session-broker.js +29 -0
- package/dist/agents/mpp-session-v2.d.ts +76 -0
- package/dist/agents/mpp-session-v2.js +269 -0
- package/dist/agents/payment-intent-compiler.d.ts +21 -0
- package/dist/agents/payment-intent-compiler.js +45 -0
- package/dist/agents/pipeline-execute.d.ts +40 -0
- package/dist/agents/pipeline-execute.js +100 -0
- package/dist/agents/pipeline-trust-v2.d.ts +31 -0
- package/dist/agents/pipeline-trust-v2.js +111 -0
- package/dist/agents/pre-x402-guard.d.ts +35 -0
- package/dist/agents/pre-x402-guard.js +84 -0
- package/dist/agents/quality-escrow-semantic.d.ts +88 -0
- package/dist/agents/quality-escrow-semantic.js +137 -0
- package/dist/agents/quality-escrow.d.ts +65 -0
- package/dist/agents/quality-escrow.js +104 -0
- package/dist/agents/quality-monitor.d.ts +32 -0
- package/dist/agents/quality-monitor.js +77 -0
- package/dist/agents/rail-optimizer.d.ts +33 -0
- package/dist/agents/rail-optimizer.js +133 -0
- package/dist/agents/receipt-auditor.d.ts +14 -0
- package/dist/agents/receipt-auditor.js +145 -0
- package/dist/agents/refund-arbiter.d.ts +24 -0
- package/dist/agents/refund-arbiter.js +70 -0
- package/dist/agents/research-brief.d.ts +14 -0
- package/dist/agents/research-brief.js +66 -0
- package/dist/agents/risk-gate.d.ts +11 -0
- package/dist/agents/risk-gate.js +78 -0
- package/dist/agents/settlement-graph.d.ts +16 -0
- package/dist/agents/settlement-graph.js +38 -0
- package/dist/agents/spend-governor.d.ts +2 -0
- package/dist/agents/spend-governor.js +70 -0
- package/dist/agents/trust-network.d.ts +138 -0
- package/dist/agents/trust-network.js +244 -0
- package/dist/agents/x402-proxy.d.ts +32 -0
- package/dist/agents/x402-proxy.js +90 -0
- package/dist/client/demo-alchemy-live.d.ts +1 -0
- package/dist/client/demo-alchemy-live.js +226 -0
- package/dist/client/demo-tail.d.ts +1 -0
- package/dist/client/demo-tail.js +100 -0
- package/dist/client/demo.d.ts +1 -0
- package/dist/client/demo.js +293 -0
- package/dist/config.d.ts +94 -0
- package/dist/config.js +223 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +389 -0
- package/dist/lib/agent-response.d.ts +14 -0
- package/dist/lib/agent-response.js +13 -0
- package/dist/lib/agentic-gateways.d.ts +5 -0
- package/dist/lib/agentic-gateways.js +15 -0
- package/dist/lib/agentic-probes.d.ts +10 -0
- package/dist/lib/agentic-probes.js +49 -0
- package/dist/lib/alchemy-x402-fetch.d.ts +16 -0
- package/dist/lib/alchemy-x402-fetch.js +95 -0
- package/dist/lib/apply-verifier-body.d.ts +7 -0
- package/dist/lib/apply-verifier-body.js +179 -0
- package/dist/lib/attestation.d.ts +30 -0
- package/dist/lib/attestation.js +107 -0
- package/dist/lib/bazaar-extension.d.ts +15 -0
- package/dist/lib/bazaar-extension.js +265 -0
- package/dist/lib/bazaar.d.ts +100 -0
- package/dist/lib/bazaar.js +341 -0
- package/dist/lib/certified-sellers.d.ts +41 -0
- package/dist/lib/certified-sellers.js +129 -0
- package/dist/lib/chains.d.ts +20 -0
- package/dist/lib/chains.js +78 -0
- package/dist/lib/db-persistence.d.ts +7 -0
- package/dist/lib/db-persistence.js +65 -0
- package/dist/lib/db.d.ts +5 -0
- package/dist/lib/db.js +113 -0
- package/dist/lib/discovery-page.d.ts +2 -0
- package/dist/lib/discovery-page.js +71 -0
- package/dist/lib/ecosystem-telemetry.d.ts +20 -0
- package/dist/lib/ecosystem-telemetry.js +80 -0
- package/dist/lib/erc8004/agent-card.d.ts +34 -0
- package/dist/lib/erc8004/agent-card.js +151 -0
- package/dist/lib/erc8004/cache.d.ts +3 -0
- package/dist/lib/erc8004/cache.js +17 -0
- package/dist/lib/erc8004/constants.d.ts +22 -0
- package/dist/lib/erc8004/constants.js +35 -0
- package/dist/lib/erc8004/registry.d.ts +19 -0
- package/dist/lib/erc8004/registry.js +171 -0
- package/dist/lib/erc8004/resolve-agent.d.ts +7 -0
- package/dist/lib/erc8004/resolve-agent.js +70 -0
- package/dist/lib/erc8004/trust-score.d.ts +33 -0
- package/dist/lib/erc8004/trust-score.js +136 -0
- package/dist/lib/escrow-ledger.d.ts +14 -0
- package/dist/lib/escrow-ledger.js +54 -0
- package/dist/lib/escrow-unified.d.ts +15 -0
- package/dist/lib/escrow-unified.js +28 -0
- package/dist/lib/facilitator-extra.d.ts +13 -0
- package/dist/lib/facilitator-extra.js +52 -0
- package/dist/lib/facilitators.d.ts +20 -0
- package/dist/lib/facilitators.js +89 -0
- package/dist/lib/host-policy.d.ts +4 -0
- package/dist/lib/host-policy.js +20 -0
- package/dist/lib/idempotency.d.ts +4 -0
- package/dist/lib/idempotency.js +120 -0
- package/dist/lib/ledger.d.ts +2 -0
- package/dist/lib/ledger.js +17 -0
- package/dist/lib/logger.d.ts +6 -0
- package/dist/lib/logger.js +24 -0
- package/dist/lib/mandate-vc.d.ts +20 -0
- package/dist/lib/mandate-vc.js +25 -0
- package/dist/lib/mandate.d.ts +44 -0
- package/dist/lib/mandate.js +190 -0
- package/dist/lib/marketplace.d.ts +7 -0
- package/dist/lib/marketplace.js +127 -0
- package/dist/lib/migrations.d.ts +2 -0
- package/dist/lib/migrations.js +130 -0
- package/dist/lib/nonce-store.d.ts +6 -0
- package/dist/lib/nonce-store.js +109 -0
- package/dist/lib/openapi-agentcash.d.ts +5 -0
- package/dist/lib/openapi-agentcash.js +288 -0
- package/dist/lib/openapi-meta.d.ts +5 -0
- package/dist/lib/openapi-meta.js +235 -0
- package/dist/lib/otel.d.ts +2 -0
- package/dist/lib/otel.js +25 -0
- package/dist/lib/paid-resource-url.d.ts +6 -0
- package/dist/lib/paid-resource-url.js +47 -0
- package/dist/lib/parse-with-verifier-fallback.d.ts +3 -0
- package/dist/lib/parse-with-verifier-fallback.js +13 -0
- package/dist/lib/payment-request-context.d.ts +10 -0
- package/dist/lib/payment-request-context.js +5 -0
- package/dist/lib/payment-response.d.ts +13 -0
- package/dist/lib/payment-response.js +39 -0
- package/dist/lib/payto-guard.d.ts +10 -0
- package/dist/lib/payto-guard.js +20 -0
- package/dist/lib/probe.d.ts +29 -0
- package/dist/lib/probe.js +157 -0
- package/dist/lib/problem-detail.d.ts +10 -0
- package/dist/lib/problem-detail.js +14 -0
- package/dist/lib/rate-limit.d.ts +12 -0
- package/dist/lib/rate-limit.js +126 -0
- package/dist/lib/replay-middleware.d.ts +3 -0
- package/dist/lib/replay-middleware.js +27 -0
- package/dist/lib/response-guard.d.ts +5 -0
- package/dist/lib/response-guard.js +40 -0
- package/dist/lib/safe-fetch.d.ts +5 -0
- package/dist/lib/safe-fetch.js +19 -0
- package/dist/lib/security.d.ts +13 -0
- package/dist/lib/security.js +61 -0
- package/dist/lib/semantic-judge.d.ts +14 -0
- package/dist/lib/semantic-judge.js +107 -0
- package/dist/lib/semantic-judge.test.d.ts +1 -0
- package/dist/lib/semantic-judge.test.js +11 -0
- package/dist/lib/ssrf.d.ts +10 -0
- package/dist/lib/ssrf.js +130 -0
- package/dist/lib/ssrf.test.d.ts +1 -0
- package/dist/lib/ssrf.test.js +16 -0
- package/dist/lib/suite-catalog.d.ts +83 -0
- package/dist/lib/suite-catalog.js +131 -0
- package/dist/lib/telemetry.d.ts +5 -0
- package/dist/lib/telemetry.js +37 -0
- package/dist/lib/verifier-fast-path.d.ts +10 -0
- package/dist/lib/verifier-fast-path.js +44 -0
- package/dist/lib/verifier-probe-protocol.d.ts +7 -0
- package/dist/lib/verifier-probe-protocol.js +115 -0
- package/dist/lib/verify-examples.d.ts +2 -0
- package/dist/lib/verify-examples.js +438 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.js +2 -0
- package/dist/lib/webhook-auth.d.ts +3 -0
- package/dist/lib/webhook-auth.js +34 -0
- package/dist/lib/webhook-routes.d.ts +2 -0
- package/dist/lib/webhook-routes.js +112 -0
- package/dist/lib/webhooks.d.ts +23 -0
- package/dist/lib/webhooks.js +123 -0
- package/dist/lib/webhooks.test.d.ts +1 -0
- package/dist/lib/webhooks.test.js +16 -0
- package/dist/lib/x402-client-options.d.ts +28 -0
- package/dist/lib/x402-client-options.js +138 -0
- package/dist/lib/x402-headers.d.ts +10 -0
- package/dist/lib/x402-headers.js +27 -0
- package/dist/lib/x402-paid.d.ts +5 -0
- package/dist/lib/x402-paid.js +252 -0
- package/dist/lib/x402-payment-replay.d.ts +22 -0
- package/dist/lib/x402-payment-replay.js +57 -0
- package/dist/lib/x402gle-host-verify.d.ts +3 -0
- package/dist/lib/x402gle-host-verify.js +27 -0
- package/dist/protocol/agent-passport.d.ts +34 -0
- package/dist/protocol/agent-passport.js +44 -0
- package/dist/protocol/compliance-v2.d.ts +21 -0
- package/dist/protocol/compliance-v2.js +19 -0
- package/dist/protocol/credit-bureau.d.ts +18 -0
- package/dist/protocol/credit-bureau.js +44 -0
- package/dist/protocol/crypto.d.ts +6 -0
- package/dist/protocol/crypto.js +41 -0
- package/dist/protocol/escrow-fsm.d.ts +33 -0
- package/dist/protocol/escrow-fsm.js +99 -0
- package/dist/protocol/fraud-engine.d.ts +28 -0
- package/dist/protocol/fraud-engine.js +77 -0
- package/dist/protocol/observability.d.ts +14 -0
- package/dist/protocol/observability.js +21 -0
- package/dist/protocol/pipeline-full-trust.d.ts +40 -0
- package/dist/protocol/pipeline-full-trust.js +96 -0
- package/dist/protocol/proof-of-execution.d.ts +36 -0
- package/dist/protocol/proof-of-execution.js +48 -0
- package/dist/protocol/reasoning-audit.d.ts +27 -0
- package/dist/protocol/reasoning-audit.js +51 -0
- package/dist/protocol/replay-guard.d.ts +28 -0
- package/dist/protocol/replay-guard.js +76 -0
- package/dist/protocol/replay-guard.test.d.ts +1 -0
- package/dist/protocol/replay-guard.test.js +10 -0
- package/dist/protocol/security-audit.d.ts +18 -0
- package/dist/protocol/security-audit.js +45 -0
- package/dist/protocol/store.d.ts +5 -0
- package/dist/protocol/store.js +59 -0
- package/dist/protocol/threat-catalog.d.ts +13 -0
- package/dist/protocol/threat-catalog.js +75 -0
- package/dist/protocol/trust-oracle.d.ts +23 -0
- package/dist/protocol/trust-oracle.js +30 -0
- package/dist/protocol/trust-score-v2.d.ts +33 -0
- package/dist/protocol/trust-score-v2.js +78 -0
- package/dist/protocol/zk-proofs.d.ts +24 -0
- package/dist/protocol/zk-proofs.js +32 -0
- package/dist/routes/a2a-agent-card.d.ts +3 -0
- package/dist/routes/a2a-agent-card.js +28 -0
- package/dist/routes/catalog.d.ts +5 -0
- package/dist/routes/catalog.js +47 -0
- package/dist/routes/register-all.d.ts +3 -0
- package/dist/routes/register-all.js +1240 -0
- package/dist/routes/schemas.d.ts +83 -0
- package/dist/routes/schemas.js +38 -0
- package/dist/routes/shared.d.ts +16 -0
- package/dist/routes/shared.js +27 -0
- package/dist/routes-protocol.d.ts +10 -0
- package/dist/routes-protocol.js +322 -0
- package/dist/routes.d.ts +2 -0
- package/dist/routes.js +2 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.js +1 -0
- package/openapi.json +7940 -0
- package/package.json +124 -0
- package/public/.well-known/ai-plugin.json +12 -0
- package/public/assets/aegis-logo-blue.png +0 -0
- package/public/assets/aegis-logo-gold.png +0 -0
- package/public/assets/aegis-logo-green.png +0 -0
- package/public/assets/aegis-logo-purple.png +0 -0
- package/public/assets/aegis-logo-red.png +0 -0
- package/public/assets/aegis-logo-white.png +0 -0
- package/public/assets/aegis-logo.png +0 -0
- package/public/assets/x402-trustlayer-logo.png +0 -0
- package/public/assets/x402-trustlayer-logo.svg +5 -0
- package/public/data/agents.json +1528 -0
- package/public/index.html +198 -0
- package/public/landing.css +342 -0
- package/public/landing.js +405 -0
- package/public/llms-full.txt +582 -0
- package/public/llms.txt +132 -0
- package/public/skill.md +135 -0
- package/railway.toml +9 -0
- package/scripts/docker-entrypoint.sh +7 -0
- package/scripts/patch-facilitator-timeout.mjs +61 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
2
|
+
import { assessUrlSecurity } from "../lib/security.js";
|
|
3
|
+
import { isVerifierAgentId } from "../lib/verifier-fast-path.js";
|
|
4
|
+
import { isEvmAddress } from "../lib/erc8004/constants.js";
|
|
5
|
+
import { computeTrustScore, meetsMinTier } from "../lib/erc8004/trust-score.js";
|
|
6
|
+
import { runIdentityGate } from "./identity-gate.js";
|
|
7
|
+
import { runRiskGate } from "./risk-gate.js";
|
|
8
|
+
import { runSpendGovernor } from "./spend-governor.js";
|
|
9
|
+
/** One paid call before x402_fetch — spend + identity + risk (replaces 3 separate calls). */
|
|
10
|
+
export async function runPreX402Guard(input) {
|
|
11
|
+
const spendInput = {
|
|
12
|
+
agentId: input.agentId,
|
|
13
|
+
estimatedCostUsdc: input.estimatedCostUsdc,
|
|
14
|
+
targetUrl: input.targetUrl,
|
|
15
|
+
network: input.network,
|
|
16
|
+
policy: input.policy,
|
|
17
|
+
};
|
|
18
|
+
const [spend, risk, identity] = await Promise.all([
|
|
19
|
+
runSpendGovernor(spendInput),
|
|
20
|
+
runRiskGate({
|
|
21
|
+
targetUrl: input.targetUrl,
|
|
22
|
+
estimatedCostUsdc: input.estimatedCostUsdc,
|
|
23
|
+
fastProbe: isVerifierAgentId(input.agentId, input.requestHeaders),
|
|
24
|
+
policy: {
|
|
25
|
+
perCallCapUsdc: input.policy.perCallCapUsdc,
|
|
26
|
+
blockedHosts: input.policy.blockedHosts,
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
runIdentityGate({
|
|
30
|
+
walletAddress: input.walletAddress,
|
|
31
|
+
maxTierSpendUsdc: input.maxTierSpendUsdc ?? input.policy.perCallCapUsdc * 20,
|
|
32
|
+
}),
|
|
33
|
+
]);
|
|
34
|
+
let agentTrust = null;
|
|
35
|
+
if (isEvmAddress(input.walletAddress) && (input.minAgentTier || input.minTrustScore != null)) {
|
|
36
|
+
const trust = await computeTrustScore({ walletAddress: input.walletAddress });
|
|
37
|
+
agentTrust = { tier: trust.tier, trustScore: trust.trustScore };
|
|
38
|
+
}
|
|
39
|
+
const blockers = [];
|
|
40
|
+
if (!spend.allowed)
|
|
41
|
+
blockers.push(`spend: ${spend.reason}`);
|
|
42
|
+
if (!identity.allowed)
|
|
43
|
+
blockers.push(`identity: ${identity.reasons.join("; ")}`);
|
|
44
|
+
if (!risk.safe)
|
|
45
|
+
blockers.push(`risk: ${risk.reasons.join("; ") || `score ${risk.riskScore}`}`);
|
|
46
|
+
if (agentTrust && input.minAgentTier && !meetsMinTier(agentTrust.tier, input.minAgentTier)) {
|
|
47
|
+
blockers.push(`agent_tier: ${agentTrust.tier} below min ${input.minAgentTier}`);
|
|
48
|
+
}
|
|
49
|
+
if (agentTrust &&
|
|
50
|
+
typeof input.minTrustScore === "number" &&
|
|
51
|
+
agentTrust.trustScore < input.minTrustScore) {
|
|
52
|
+
blockers.push(`trust_score: ${agentTrust.trustScore} below min ${input.minTrustScore}`);
|
|
53
|
+
}
|
|
54
|
+
const urlSec = assessUrlSecurity(input.targetUrl);
|
|
55
|
+
const allowed = blockers.length === 0 && urlSec.grade !== "F";
|
|
56
|
+
const checks = [
|
|
57
|
+
"spend_governor",
|
|
58
|
+
"identity_gate",
|
|
59
|
+
"risk_gate",
|
|
60
|
+
"url_security_grade",
|
|
61
|
+
];
|
|
62
|
+
if (agentTrust)
|
|
63
|
+
checks.push("erc8004_trust_score");
|
|
64
|
+
if (allowed)
|
|
65
|
+
checks.push("policy_pass");
|
|
66
|
+
const payload = {
|
|
67
|
+
allowed,
|
|
68
|
+
securityGrade: urlSec.grade,
|
|
69
|
+
summary: allowed
|
|
70
|
+
? "Safe to proceed with x402 payment on targetUrl"
|
|
71
|
+
: `Blocked — ${blockers.join(" | ")}`,
|
|
72
|
+
savingsVsSeparateUsdc: 0.11,
|
|
73
|
+
spend,
|
|
74
|
+
identity,
|
|
75
|
+
risk,
|
|
76
|
+
agentTrust,
|
|
77
|
+
overlapNote: "Spend, identity, and risk are also available as separate endpoints; this bundle runs them in one call.",
|
|
78
|
+
integrationHint: "Call POST /api/guard/pre-x402 once before every x402_fetch / OpenDexter paid call.",
|
|
79
|
+
};
|
|
80
|
+
return withAgentTrust(payload, agentTrustMeta(checks, {
|
|
81
|
+
confidence: allowed ? 0.86 : 0.72,
|
|
82
|
+
sources: ["spend-governor", "identity-gate", "risk-gate", "url-security", "erc-8004"],
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { type ExpectedProfile, type ActualResponse } from "./quality-escrow.js";
|
|
2
|
+
export type SemanticEscrowInput = {
|
|
3
|
+
action?: "hold" | "settle" | "refund";
|
|
4
|
+
escrowId?: string;
|
|
5
|
+
payerAgentId?: string;
|
|
6
|
+
payeeMerchant?: string;
|
|
7
|
+
amountUsdc?: number;
|
|
8
|
+
releaseThreshold?: number;
|
|
9
|
+
/** What the buyer/agent expected semantically (e.g. "ETH/USD spot price number") */
|
|
10
|
+
deliveryIntent: string;
|
|
11
|
+
expectedProfile?: ExpectedProfile;
|
|
12
|
+
actualResponse?: ActualResponse & {
|
|
13
|
+
/** Parsed JSON fields when available */
|
|
14
|
+
fields?: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Semantic Delivery Escrow — schema match + intent/rubric heuristics before release/refund.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runSemanticQualityEscrow(input: SemanticEscrowInput): Promise<({
|
|
21
|
+
action: string;
|
|
22
|
+
escrowId: string;
|
|
23
|
+
status: string;
|
|
24
|
+
payerAgentId: string | null;
|
|
25
|
+
payeeMerchant: string | null;
|
|
26
|
+
amountUsdc: number | null;
|
|
27
|
+
releaseThreshold: number;
|
|
28
|
+
note: string;
|
|
29
|
+
} & import("../lib/agent-response.js").AgentTrustMeta) | ({
|
|
30
|
+
action: string;
|
|
31
|
+
escrowId: string;
|
|
32
|
+
status: string;
|
|
33
|
+
decision: string;
|
|
34
|
+
note: string;
|
|
35
|
+
} & import("../lib/agent-response.js").AgentTrustMeta) | ({
|
|
36
|
+
status: string;
|
|
37
|
+
ok: boolean;
|
|
38
|
+
allowed: boolean;
|
|
39
|
+
summary: string;
|
|
40
|
+
action: string;
|
|
41
|
+
escrowId: string;
|
|
42
|
+
escrowStatus: string;
|
|
43
|
+
decision: string;
|
|
44
|
+
qualityScore: number;
|
|
45
|
+
releaseThreshold: number;
|
|
46
|
+
payeeMerchant: string | null;
|
|
47
|
+
payerAgentId: string | null;
|
|
48
|
+
amountUsdc: number | null;
|
|
49
|
+
reasons: string[];
|
|
50
|
+
nextStep: {
|
|
51
|
+
method: string;
|
|
52
|
+
path: string;
|
|
53
|
+
note: string;
|
|
54
|
+
} | null;
|
|
55
|
+
} & import("../lib/agent-response.js").AgentTrustMeta) | ({
|
|
56
|
+
mode: string;
|
|
57
|
+
judgeMode: "heuristic" | "llm";
|
|
58
|
+
deliveryIntent: string;
|
|
59
|
+
semanticScore: number;
|
|
60
|
+
schemaScore: number;
|
|
61
|
+
qualityScore: number;
|
|
62
|
+
combinedScore: number;
|
|
63
|
+
releaseThreshold: number;
|
|
64
|
+
escrowStatus: string;
|
|
65
|
+
decision: string;
|
|
66
|
+
allowed: boolean;
|
|
67
|
+
summary: string;
|
|
68
|
+
reasons: string[];
|
|
69
|
+
suggestedHoldFeeUsdc: number | null;
|
|
70
|
+
evidenceForDispute: {
|
|
71
|
+
deliveryIntent: string;
|
|
72
|
+
semanticScore: number;
|
|
73
|
+
schemaScore: number;
|
|
74
|
+
sample: string | null;
|
|
75
|
+
} | null;
|
|
76
|
+
bondSlash: {
|
|
77
|
+
ok: boolean;
|
|
78
|
+
host: string;
|
|
79
|
+
slashedUsdc: number;
|
|
80
|
+
bondRemainingUsdc: number;
|
|
81
|
+
reason: string;
|
|
82
|
+
} | null;
|
|
83
|
+
nextStep: {
|
|
84
|
+
method: string;
|
|
85
|
+
path: string;
|
|
86
|
+
note: string;
|
|
87
|
+
} | null;
|
|
88
|
+
} & import("../lib/agent-response.js").AgentTrustMeta)>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { runQualityEscrow } from "./quality-escrow.js";
|
|
2
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
3
|
+
import { runSemanticJudge } from "../lib/semantic-judge.js";
|
|
4
|
+
import { slashSellerBond, getCertifiedHost } from "../lib/certified-sellers.js";
|
|
5
|
+
import { hostOf } from "../lib/probe.js";
|
|
6
|
+
const PLACEHOLDER_VALUES = /^(null|undefined|n\/a|moon|test|foo|bar|xxx|-+)$/i;
|
|
7
|
+
const SUSPICIOUS_STRINGS = /lorem ipsum|click here|scam|free money/i;
|
|
8
|
+
async function computeSemanticScores(input) {
|
|
9
|
+
const fields = input.actualResponse?.fields ?? {};
|
|
10
|
+
const sample = input.actualResponse?.sample ?? JSON.stringify(fields);
|
|
11
|
+
const judge = await runSemanticJudge({
|
|
12
|
+
deliveryIntent: input.deliveryIntent,
|
|
13
|
+
sample,
|
|
14
|
+
fields,
|
|
15
|
+
});
|
|
16
|
+
let semantic = judge.score;
|
|
17
|
+
const reasons = [...judge.reasons];
|
|
18
|
+
if (input.actualResponse?.empty || input.actualResponse?.byteLength === 0) {
|
|
19
|
+
semantic = Math.min(semantic, 15);
|
|
20
|
+
reasons.push("Empty response body");
|
|
21
|
+
}
|
|
22
|
+
for (const [key, val] of Object.entries(fields)) {
|
|
23
|
+
const s = String(val);
|
|
24
|
+
if (PLACEHOLDER_VALUES.test(s)) {
|
|
25
|
+
semantic = Math.max(0, semantic - 15);
|
|
26
|
+
reasons.push(`Field ${key} looks like placeholder: ${s}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (SUSPICIOUS_STRINGS.test(sample)) {
|
|
30
|
+
semantic = Math.max(0, semantic - 20);
|
|
31
|
+
reasons.push("Suspicious phrasing detected");
|
|
32
|
+
}
|
|
33
|
+
semantic = Math.max(0, Math.min(100, semantic));
|
|
34
|
+
const schemaResult = runQualityEscrow({
|
|
35
|
+
action: "settle",
|
|
36
|
+
expectedProfile: input.expectedProfile,
|
|
37
|
+
actualResponse: input.actualResponse,
|
|
38
|
+
releaseThreshold: 0,
|
|
39
|
+
});
|
|
40
|
+
const schemaScore = typeof schemaResult === "object" && schemaResult && "qualityScore" in schemaResult
|
|
41
|
+
? Number(schemaResult.qualityScore)
|
|
42
|
+
: 0;
|
|
43
|
+
const combinedScore = Math.round(schemaScore * 0.45 + semantic * 0.55);
|
|
44
|
+
return { semanticScore: semantic, schemaScore, combinedScore, reasons, judgeMode: judge.mode };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Semantic Delivery Escrow — schema match + intent/rubric heuristics before release/refund.
|
|
48
|
+
*/
|
|
49
|
+
export async function runSemanticQualityEscrow(input) {
|
|
50
|
+
const threshold = input.releaseThreshold ?? 72;
|
|
51
|
+
const escrowId = input.escrowId ?? `qsem_${Date.now().toString(36)}`;
|
|
52
|
+
if (input.action === "hold") {
|
|
53
|
+
return withAgentTrust({
|
|
54
|
+
action: "hold",
|
|
55
|
+
escrowId,
|
|
56
|
+
status: "held",
|
|
57
|
+
mode: "semantic",
|
|
58
|
+
payerAgentId: input.payerAgentId ?? null,
|
|
59
|
+
payeeMerchant: input.payeeMerchant ?? null,
|
|
60
|
+
amountUsdc: input.amountUsdc ?? null,
|
|
61
|
+
deliveryIntent: input.deliveryIntent,
|
|
62
|
+
releaseThreshold: threshold,
|
|
63
|
+
note: "Call semantic-settle with actualResponse after downstream API returns.",
|
|
64
|
+
}, agentTrustMeta(["escrow_open", "semantic_mode"], { confidence: 0.9, sources: ["quality-escrow-semantic"] }));
|
|
65
|
+
}
|
|
66
|
+
if (input.action === "refund") {
|
|
67
|
+
return runQualityEscrow({
|
|
68
|
+
action: "refund",
|
|
69
|
+
escrowId,
|
|
70
|
+
payerAgentId: input.payerAgentId,
|
|
71
|
+
payeeMerchant: input.payeeMerchant,
|
|
72
|
+
amountUsdc: input.amountUsdc,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const { semanticScore, schemaScore, combinedScore, reasons, judgeMode } = await computeSemanticScores(input);
|
|
76
|
+
const release = combinedScore >= threshold;
|
|
77
|
+
const base = runQualityEscrow({
|
|
78
|
+
action: "settle",
|
|
79
|
+
escrowId,
|
|
80
|
+
payerAgentId: input.payerAgentId,
|
|
81
|
+
payeeMerchant: input.payeeMerchant,
|
|
82
|
+
amountUsdc: input.amountUsdc,
|
|
83
|
+
expectedProfile: input.expectedProfile,
|
|
84
|
+
actualResponse: input.actualResponse,
|
|
85
|
+
releaseThreshold: threshold,
|
|
86
|
+
});
|
|
87
|
+
const escrowStatus = release ? "released" : "refunded";
|
|
88
|
+
const holdFeePct = input.amountUsdc ? Math.round(input.amountUsdc * 0.015 * 1000) / 1000 : null;
|
|
89
|
+
let bondSlash = null;
|
|
90
|
+
if (!release && input.payeeMerchant && input.amountUsdc) {
|
|
91
|
+
const h = hostOf(input.payeeMerchant) || input.payeeMerchant.toLowerCase();
|
|
92
|
+
const cert = await getCertifiedHost(h);
|
|
93
|
+
if (cert?.bondRemainingUsdc && cert.bondRemainingUsdc > 0) {
|
|
94
|
+
const slashAmt = Math.min(cert.bondRemainingUsdc, input.amountUsdc);
|
|
95
|
+
bondSlash = await slashSellerBond(h, slashAmt, "semantic_delivery_fail");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return withAgentTrust({
|
|
99
|
+
...(typeof base === "object" && base ? base : {}),
|
|
100
|
+
mode: "semantic",
|
|
101
|
+
judgeMode,
|
|
102
|
+
deliveryIntent: input.deliveryIntent,
|
|
103
|
+
semanticScore,
|
|
104
|
+
schemaScore,
|
|
105
|
+
qualityScore: combinedScore,
|
|
106
|
+
combinedScore,
|
|
107
|
+
releaseThreshold: threshold,
|
|
108
|
+
escrowStatus,
|
|
109
|
+
decision: release ? "release-to-merchant" : "auto-refund-to-payer",
|
|
110
|
+
allowed: release,
|
|
111
|
+
summary: release
|
|
112
|
+
? `Semantic+schema score ${combinedScore} ≥ ${threshold} — release approved`
|
|
113
|
+
: `Score ${combinedScore} < ${threshold} — auto-refund (semantic delivery failed)`,
|
|
114
|
+
reasons,
|
|
115
|
+
suggestedHoldFeeUsdc: holdFeePct,
|
|
116
|
+
evidenceForDispute: !release
|
|
117
|
+
? {
|
|
118
|
+
deliveryIntent: input.deliveryIntent,
|
|
119
|
+
semanticScore,
|
|
120
|
+
schemaScore,
|
|
121
|
+
sample: input.actualResponse?.sample?.slice(0, 500) ?? null,
|
|
122
|
+
}
|
|
123
|
+
: null,
|
|
124
|
+
bondSlash,
|
|
125
|
+
nextStep: release
|
|
126
|
+
? null
|
|
127
|
+
: {
|
|
128
|
+
method: "POST",
|
|
129
|
+
path: bondSlash?.ok ? "/api/trust-network/bond/slash" : "/api/dispute/resolve",
|
|
130
|
+
note: "Escalate with evidenceForDispute or bond slash record",
|
|
131
|
+
},
|
|
132
|
+
}, agentTrustMeta(release ? ["semantic_pass", "schema_pass"] : ["semantic_fail", "auto_refund"], {
|
|
133
|
+
confidence: 0.84,
|
|
134
|
+
sources: ["quality-escrow-semantic", "good-response-profile"],
|
|
135
|
+
accuracy_note: "Semantic rubric is heuristic (no external LLM). Supply fields/sample for best accuracy; upgrade path: LLM judge hook.",
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type ExpectedProfile = {
|
|
2
|
+
requiredKeys?: string[];
|
|
3
|
+
minLengthBytes?: number;
|
|
4
|
+
mustMatchRegex?: string;
|
|
5
|
+
forbidEmpty?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type ActualResponse = {
|
|
8
|
+
bodyKeys?: string[];
|
|
9
|
+
byteLength?: number;
|
|
10
|
+
sample?: string;
|
|
11
|
+
empty?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type QualityEscrowInput = {
|
|
14
|
+
action: "hold" | "settle" | "refund";
|
|
15
|
+
escrowId?: string;
|
|
16
|
+
payerAgentId?: string;
|
|
17
|
+
payeeMerchant?: string;
|
|
18
|
+
amountUsdc?: number;
|
|
19
|
+
expectedProfile?: ExpectedProfile;
|
|
20
|
+
actualResponse?: ActualResponse;
|
|
21
|
+
releaseThreshold?: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Quality-Verified Escrow with Auto-Refund.
|
|
25
|
+
* Holds an agent's payment, then on settle verifies the merchant's actual
|
|
26
|
+
* response against its published "good response" profile. Releases to the
|
|
27
|
+
* merchant on a pass, auto-refunds the buyer agent on a fail. This closes the
|
|
28
|
+
* trust gap that final stablecoin settlements leave open.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runQualityEscrow(input: QualityEscrowInput): ({
|
|
31
|
+
action: string;
|
|
32
|
+
escrowId: string;
|
|
33
|
+
status: string;
|
|
34
|
+
payerAgentId: string | null;
|
|
35
|
+
payeeMerchant: string | null;
|
|
36
|
+
amountUsdc: number | null;
|
|
37
|
+
releaseThreshold: number;
|
|
38
|
+
note: string;
|
|
39
|
+
} & import("../lib/agent-response.js").AgentTrustMeta) | ({
|
|
40
|
+
action: string;
|
|
41
|
+
escrowId: string;
|
|
42
|
+
status: string;
|
|
43
|
+
decision: string;
|
|
44
|
+
note: string;
|
|
45
|
+
} & import("../lib/agent-response.js").AgentTrustMeta) | ({
|
|
46
|
+
status: string;
|
|
47
|
+
ok: boolean;
|
|
48
|
+
allowed: boolean;
|
|
49
|
+
summary: string;
|
|
50
|
+
action: string;
|
|
51
|
+
escrowId: string;
|
|
52
|
+
escrowStatus: string;
|
|
53
|
+
decision: string;
|
|
54
|
+
qualityScore: number;
|
|
55
|
+
releaseThreshold: number;
|
|
56
|
+
payeeMerchant: string | null;
|
|
57
|
+
payerAgentId: string | null;
|
|
58
|
+
amountUsdc: number | null;
|
|
59
|
+
reasons: string[];
|
|
60
|
+
nextStep: {
|
|
61
|
+
method: string;
|
|
62
|
+
path: string;
|
|
63
|
+
note: string;
|
|
64
|
+
} | null;
|
|
65
|
+
} & import("../lib/agent-response.js").AgentTrustMeta);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
2
|
+
function matchScore(expected, actual) {
|
|
3
|
+
const reasons = [];
|
|
4
|
+
let score = 100;
|
|
5
|
+
if (expected.forbidEmpty && (actual.empty || actual.byteLength === 0)) {
|
|
6
|
+
score -= 70;
|
|
7
|
+
reasons.push("Response empty but forbidEmpty set");
|
|
8
|
+
}
|
|
9
|
+
if (expected.requiredKeys?.length) {
|
|
10
|
+
const present = new Set(actual.bodyKeys ?? []);
|
|
11
|
+
const missing = expected.requiredKeys.filter((k) => !present.has(k));
|
|
12
|
+
if (missing.length) {
|
|
13
|
+
score -= Math.min(60, missing.length * 20);
|
|
14
|
+
reasons.push(`Missing required keys: ${missing.join(", ")}`);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
reasons.push("All required keys present");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (expected.minLengthBytes != null && actual.byteLength != null) {
|
|
21
|
+
if (actual.byteLength < expected.minLengthBytes) {
|
|
22
|
+
score -= 25;
|
|
23
|
+
reasons.push(`Body ${actual.byteLength}B below minimum ${expected.minLengthBytes}B`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (expected.mustMatchRegex && actual.sample != null) {
|
|
27
|
+
try {
|
|
28
|
+
const re = new RegExp(expected.mustMatchRegex);
|
|
29
|
+
if (!re.test(actual.sample)) {
|
|
30
|
+
score -= 30;
|
|
31
|
+
reasons.push("Sample does not match required pattern");
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
reasons.push("Sample matches required pattern");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
reasons.push("Invalid mustMatchRegex — skipped");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { score: Math.max(0, Math.min(100, score)), reasons };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Quality-Verified Escrow with Auto-Refund.
|
|
45
|
+
* Holds an agent's payment, then on settle verifies the merchant's actual
|
|
46
|
+
* response against its published "good response" profile. Releases to the
|
|
47
|
+
* merchant on a pass, auto-refunds the buyer agent on a fail. This closes the
|
|
48
|
+
* trust gap that final stablecoin settlements leave open.
|
|
49
|
+
*/
|
|
50
|
+
export function runQualityEscrow(input) {
|
|
51
|
+
const threshold = input.releaseThreshold ?? 70;
|
|
52
|
+
const escrowId = input.escrowId ?? `qesc_${Date.now().toString(36)}`;
|
|
53
|
+
if (input.action === "hold") {
|
|
54
|
+
return withAgentTrust({
|
|
55
|
+
action: "hold",
|
|
56
|
+
escrowId,
|
|
57
|
+
status: "held",
|
|
58
|
+
payerAgentId: input.payerAgentId ?? null,
|
|
59
|
+
payeeMerchant: input.payeeMerchant ?? null,
|
|
60
|
+
amountUsdc: input.amountUsdc ?? null,
|
|
61
|
+
releaseThreshold: threshold,
|
|
62
|
+
note: "Funds held. Call action=settle with expectedProfile + actualResponse to verify and release/refund.",
|
|
63
|
+
}, agentTrustMeta(["escrow_open"], { confidence: 0.9, sources: ["quality-escrow"] }));
|
|
64
|
+
}
|
|
65
|
+
if (input.action === "refund") {
|
|
66
|
+
return withAgentTrust({
|
|
67
|
+
action: "refund",
|
|
68
|
+
escrowId,
|
|
69
|
+
status: "refunded",
|
|
70
|
+
decision: "refund-to-payer",
|
|
71
|
+
note: "Manual refund executed; funds returned to payer agent.",
|
|
72
|
+
}, agentTrustMeta(["escrow_refund"], { confidence: 0.9, sources: ["quality-escrow"] }));
|
|
73
|
+
}
|
|
74
|
+
// settle: verify quality then release or refund.
|
|
75
|
+
const expected = input.expectedProfile ?? {};
|
|
76
|
+
const actual = input.actualResponse ?? {};
|
|
77
|
+
const { score, reasons } = matchScore(expected, actual);
|
|
78
|
+
const release = score >= threshold;
|
|
79
|
+
return withAgentTrust({
|
|
80
|
+
status: "ok",
|
|
81
|
+
ok: true,
|
|
82
|
+
allowed: release,
|
|
83
|
+
summary: release
|
|
84
|
+
? `Quality score ${score} ≥ ${threshold} — released $${input.amountUsdc ?? "?"} to ${input.payeeMerchant ?? "merchant"}`
|
|
85
|
+
: `Quality score ${score} < ${threshold} — auto-refund to payer`,
|
|
86
|
+
action: "settle",
|
|
87
|
+
escrowId,
|
|
88
|
+
escrowStatus: release ? "released" : "refunded",
|
|
89
|
+
decision: release ? "release-to-merchant" : "auto-refund-to-payer",
|
|
90
|
+
qualityScore: score,
|
|
91
|
+
releaseThreshold: threshold,
|
|
92
|
+
payeeMerchant: input.payeeMerchant ?? null,
|
|
93
|
+
payerAgentId: input.payerAgentId ?? null,
|
|
94
|
+
amountUsdc: input.amountUsdc ?? null,
|
|
95
|
+
reasons,
|
|
96
|
+
nextStep: release
|
|
97
|
+
? null
|
|
98
|
+
: { method: "POST", path: "/api/dispute/resolve", note: "Escalate refused settlement to dispute resolver" },
|
|
99
|
+
}, agentTrustMeta(["quality_match", release ? "release_gate_passed" : "auto_refund_triggered"], {
|
|
100
|
+
confidence: 0.86,
|
|
101
|
+
sources: ["quality-escrow", "good-response-profile"],
|
|
102
|
+
accuracy_note: "Quality match compares supplied actualResponse to expectedProfile; the integrator must capture the real response faithfully.",
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type QualityTarget = {
|
|
2
|
+
url: string;
|
|
3
|
+
expectedStatus?: number;
|
|
4
|
+
};
|
|
5
|
+
export type QualityMonitorInput = {
|
|
6
|
+
targets: QualityTarget[];
|
|
7
|
+
/** Skip outbound probes — used for marketplace verifier audits */
|
|
8
|
+
fastProbe?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type QualityEntry = {
|
|
11
|
+
url: string;
|
|
12
|
+
status: number;
|
|
13
|
+
expectedStatus: number | null;
|
|
14
|
+
matchesExpectation: boolean;
|
|
15
|
+
classification: "ok" | "expected_failure" | "unexpected_failure";
|
|
16
|
+
requiresPayment: boolean;
|
|
17
|
+
priceUsdc: number | null;
|
|
18
|
+
healthy: boolean;
|
|
19
|
+
score: number;
|
|
20
|
+
notes: string[];
|
|
21
|
+
};
|
|
22
|
+
export type QualityMonitorResult = {
|
|
23
|
+
status: "ok";
|
|
24
|
+
success: boolean;
|
|
25
|
+
healthy: boolean;
|
|
26
|
+
checkedAt: string;
|
|
27
|
+
results: QualityEntry[];
|
|
28
|
+
averageScore: number;
|
|
29
|
+
overall: "pass" | "inconclusive" | "fail";
|
|
30
|
+
summary: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function runQualityMonitor(input: QualityMonitorInput): Promise<QualityMonitorResult>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { probeEndpoint } from "../lib/probe.js";
|
|
2
|
+
export async function runQualityMonitor(input) {
|
|
3
|
+
const results = [];
|
|
4
|
+
for (const t of input.targets.slice(0, 10)) {
|
|
5
|
+
const probe = await probeEndpoint(t.url, {
|
|
6
|
+
fastSynthetic: input.fastProbe === true,
|
|
7
|
+
timeoutMs: input.fastProbe ? 1_500 : 6_000,
|
|
8
|
+
});
|
|
9
|
+
const notes = [];
|
|
10
|
+
let score = 50;
|
|
11
|
+
const expected = typeof t.expectedStatus === "number" ? t.expectedStatus : null;
|
|
12
|
+
// If caller does not provide an expected status, treat any reachable HTTP response
|
|
13
|
+
// as a successful probe execution (this endpoint audits observability, not contract tests).
|
|
14
|
+
const matchesExpectation = expected == null ? probe.status > 0 : probe.status === expected;
|
|
15
|
+
if (probe.status === 402) {
|
|
16
|
+
score += 25;
|
|
17
|
+
notes.push("Correctly returns HTTP 402 for unpaid requests");
|
|
18
|
+
}
|
|
19
|
+
else if (probe.status === 200) {
|
|
20
|
+
score += 10;
|
|
21
|
+
notes.push("Returns 200 without payment — verify this is intentional");
|
|
22
|
+
}
|
|
23
|
+
else if (probe.status === 0) {
|
|
24
|
+
score -= 40;
|
|
25
|
+
notes.push("Unreachable");
|
|
26
|
+
}
|
|
27
|
+
else if (probe.status >= 400) {
|
|
28
|
+
score -= 10;
|
|
29
|
+
notes.push(`HTTP ${probe.status} from target`);
|
|
30
|
+
}
|
|
31
|
+
if (matchesExpectation)
|
|
32
|
+
score += 10;
|
|
33
|
+
if (!matchesExpectation && expected != null)
|
|
34
|
+
notes.push(`Expected HTTP ${expected}, got ${probe.status}`);
|
|
35
|
+
if (probe.priceUsdc != null && probe.priceUsdc <= 0.25)
|
|
36
|
+
score += 10;
|
|
37
|
+
if (probe.warnings.length)
|
|
38
|
+
notes.push(...probe.warnings);
|
|
39
|
+
const classification = matchesExpectation
|
|
40
|
+
? expected != null && expected >= 400
|
|
41
|
+
? "expected_failure"
|
|
42
|
+
: "ok"
|
|
43
|
+
: "unexpected_failure";
|
|
44
|
+
results.push({
|
|
45
|
+
url: t.url,
|
|
46
|
+
status: probe.status,
|
|
47
|
+
expectedStatus: expected,
|
|
48
|
+
matchesExpectation,
|
|
49
|
+
classification,
|
|
50
|
+
requiresPayment: probe.requiresPayment,
|
|
51
|
+
priceUsdc: probe.priceUsdc,
|
|
52
|
+
healthy: matchesExpectation,
|
|
53
|
+
score: Math.max(0, Math.min(100, score)),
|
|
54
|
+
notes,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const averageScore = results.length > 0 ? results.reduce((s, r) => s + r.score, 0) / results.length : 0;
|
|
58
|
+
const healthyCount = results.filter((r) => r.healthy).length;
|
|
59
|
+
const unexpectedFailures = results.filter((r) => r.classification === "unexpected_failure").length;
|
|
60
|
+
const overall = unexpectedFailures === 0 && results.length > 0
|
|
61
|
+
? "pass"
|
|
62
|
+
: healthyCount > 0
|
|
63
|
+
? "inconclusive"
|
|
64
|
+
: "fail";
|
|
65
|
+
return {
|
|
66
|
+
status: "ok",
|
|
67
|
+
success: unexpectedFailures === 0,
|
|
68
|
+
healthy: unexpectedFailures === 0,
|
|
69
|
+
checkedAt: new Date().toISOString(),
|
|
70
|
+
results,
|
|
71
|
+
averageScore: Number(averageScore.toFixed(1)),
|
|
72
|
+
overall,
|
|
73
|
+
summary: unexpectedFailures === 0
|
|
74
|
+
? `${healthyCount}/${results.length} targets met expected status`
|
|
75
|
+
: `${unexpectedFailures} targets deviated from expected status; ${healthyCount}/${results.length} met expectation`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type RailId = "visa-cli" | "stripe-mpp" | "circle-nano" | "base-x402" | "solana-x402";
|
|
2
|
+
export type RailOptimizerInput = {
|
|
3
|
+
amountUsdc: number;
|
|
4
|
+
disputable?: boolean;
|
|
5
|
+
latencySensitive?: boolean;
|
|
6
|
+
expectedCalls?: number;
|
|
7
|
+
merchantRailsSupported?: RailId[];
|
|
8
|
+
preferProtection?: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Cross-Rail Payment Optimizer.
|
|
12
|
+
* Picks the best settlement rail per transaction across Visa CLI, Stripe MPP,
|
|
13
|
+
* Circle Nanopayments, Base x402, and Solana x402 — balancing cost, finality,
|
|
14
|
+
* and chargeback protection. Nothing in the public ecosystem unifies card rails
|
|
15
|
+
* with stablecoin x402 rails in one decision.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runRailOptimizer(input: RailOptimizerInput): {
|
|
18
|
+
amountUsdc: number;
|
|
19
|
+
recommendedRail: RailId;
|
|
20
|
+
recommendation: string;
|
|
21
|
+
ranked: {
|
|
22
|
+
rail: RailId;
|
|
23
|
+
label: string;
|
|
24
|
+
viable: boolean;
|
|
25
|
+
estimatedFeeUsdc: number;
|
|
26
|
+
chargeback: boolean;
|
|
27
|
+
finality: "reversible" | "final";
|
|
28
|
+
protectionScore: number;
|
|
29
|
+
fitScore: number;
|
|
30
|
+
notes: string;
|
|
31
|
+
reasons: string[];
|
|
32
|
+
}[];
|
|
33
|
+
} & import("../lib/agent-response.js").AgentTrustMeta;
|