From fe396eee7be723166369b848a64f7b656ccf9b2a Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Mon, 17 Aug 2026 12:25:41 +0200 Subject: [PATCH 1/2] fix(router): qualify BCK.ROUTER.0006 in the windsurf rules, and correct how the asset symbol is resolved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two independent corrections, both true against nvm-monorepo main today — deliberately carrying no reference to any unreleased error code, so this can land on its own. 1. `.windsurf/rules/nevermined-router.md` wrote the retryable pair as bare `0006`/`0007` where its four sibling IDE rule files write `BCK.ROUTER.0006`. nvm-monorepo's `check-skill-error-drift` guard matches on the qualified form, so it has been reporting the code as undocumented — the ONLY drift between the published skill and `api-errors.ts` today, and it turns that check red on every nvm PR touching the error catalogue. 2. `products/router/rails-x402.mdx` said the asset symbol "is read from the entry's `extra.name` field". That is the pre-#2768 behaviour and has been false since nevermined-io/nvm-monorepo#2775: the symbol comes from the `asset` ADDRESS, matched against the canonical token addresses. The old text sends a reader debugging in exactly the wrong direction. Adds a short section on what `extra.name` actually is — the token's own EIP-712 domain, "USD Coin" on Base mainnet and "USDC" on Base Sepolia — since mistaking it for a ticker is what produced that bug. Split out of nevermined-io/docs#304, which documents two error codes that do not exist until nvm-monorepo#2959 merges and therefore has to wait for it. Co-Authored-By: Claude Opus 5 (1M context) --- .windsurf/rules/nevermined-router.md | 4 ++-- products/router/rails-x402.mdx | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) 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/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 From 309438f66e7d773a9b41ec7f7a31c7ec0be9ebfb Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Tue, 18 Aug 2026 13:36:57 +0200 Subject: [PATCH 2/2] docs: correct the windsurf headroom figure to 5,991 (review fold) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR's edit to `.windsurf/rules/nevermined-router.md` grew it by 11 characters, so the figure CLAUDE.md pins was wrong the moment it landed. Re-measured with the exact command CLAUDE.md prescribes (characters, not bytes — `wc -c` reads 6,063 here because the file is full of `—` and `⚠️`): base 237a9b5 = 5,980, head = 5,991. The payments sibling is unchanged at 3,759, verified the same way. The number is maintained precisely because the failure is silent: Windsurf drops the END of the file, where the guardrails live. Nine characters of headroom now remain, so the next edit to this file has to displace something rather than absorb it. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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