diff --git a/.windsurf/rules/nevermined-router.md b/.windsurf/rules/nevermined-router.md index cbd14d72..a791595b 100644 --- a/.windsurf/rules/nevermined-router.md +++ b/.windsurf/rules/nevermined-router.md @@ -78,8 +78,8 @@ back. For spend to date read `GET /api/v1/delegation/{id}` → `amountSpentCents written, so `requestId` won't suppress it. - `BCK.ROUTER.0011` (402) — card rail: needs 3-D Secure, which an agent can't complete. Nothing charged; each retry strands a single-use credential. **Don't auto-retry.** -- Only `0006` (500) and `0007` (429, too many concurrent) are **retryable**; everything else is a - decision, and retrying it unchanged gives the same answer. +- Only `BCK.ROUTER.0006` (500) and `0007` (429, too many concurrent) are **retryable**; everything + else is a decision, and retrying it unchanged gives the same answer. **Never widen a Delegation, and never create a second one, to get past a refusal.** The cap is the user's decision; a fresh one to escape an exhausted Delegation defeats it. diff --git a/CLAUDE.md b/CLAUDE.md index d7b063a0..2b18af90 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,7 +49,7 @@ They give AI coding assistants (Claude Code, Cursor, Copilot, Codex, Windsurf, C ⚠️ **Windsurf's 6,000-character cap is a hard truncation, and `nevermined-router.md` is at its ceiling.** Windsurf silently drops everything past 6,000 characters — it does not error, and what it drops is the **end** of the file, which is where the guardrails and accounting sections live. As of -2026-08-17 `.windsurf/rules/nevermined-router.md` is **5,980 of 6,000** characters (its payments +2026-08-17 `.windsurf/rules/nevermined-router.md` is **5,991 of 6,000** characters (its payments sibling is 3,759; the 12,000 all-files cap is not the binding one). The other three IDE rule files share a fuller body; **Windsurf's copy is deliberately terser and is diff --git a/products/router/rails-x402.mdx b/products/router/rails-x402.mdx index 109ed2f4..a18c1d0e 100644 --- a/products/router/rails-x402.mdx +++ b/products/router/rails-x402.mdx @@ -56,7 +56,13 @@ A **mixed-chain 402 still works** as long as one option is fundable. If a servic ### How an option gets chosen -Given several fundable entries, the Router filters to `scheme: "exact"` on a funded network with a funded asset, then prefers **USDC**. The asset symbol is read from the entry's **`extra.name`** field — a service that omits it won't match the symbol filter even if its `asset` address is USDC. +Given several fundable entries, the Router filters to `scheme: "exact"` on a funded network with a funded asset, then prefers **USDC**. The asset symbol is resolved from the entry's **`asset` address**, matched against the canonical token addresses for that chain — never from `extra.name`, which is something else entirely (see below). A token the Router doesn't recognise on that chain isn't fundable, however the entry labels it. + +### `extra.name` is the EIP-712 domain, not a ticker + +`extra.name` and `extra.version` are the settlement token's **EIP-712 domain** — the `name()` and `version()` the token contract itself signs under, and what the payment authorization is signed against. They are frequently *not* the ticker: canonical Base-mainnet USDC signs under `"USD Coin"`, while the Base Sepolia deployment signs under `"USDC"`. + +Both fields are **required**. If you are the seller, copy them from the token contract's `name()` and `version()` exactly — an authorization signed under the wrong domain produces a signature the token cannot recover, so guessing the ticker yields a payment that simply cannot settle. ## Money and budget