Skip to content

fix(router): qualify BCK.ROUTER.0006 in the windsurf rules, and correct how the asset symbol is resolved - #305

Merged
r-marques merged 2 commits into
mainfrom
docs/router-0006-and-symbol-source
Aug 18, 2026
Merged

fix(router): qualify BCK.ROUTER.0006 in the windsurf rules, and correct how the asset symbol is resolved#305
r-marques merged 2 commits into
mainfrom
docs/router-0006-and-symbol-source

Conversation

@r-marques

Copy link
Copy Markdown
Member

Split out of #304 so it can land immediately: this PR references no unreleased error code, so it is independent of nevermined-io/nvm-monorepo#2959 and unblocks nvm-monorepo#2956 now.

Why now

check-skill-error-drift in nvm-monorepo compares this repo's skill against api-errors.ts and runs on every nvm PR touching the error catalogue. Against nvm main today it reports exactly one drift, and it is fix (1) below:

✗ 1 drift(s) between api-errors.ts and the published skill:
  [undocumented] BCK.ROUTER.0006 — .windsurf/rules/nevermined-router.md

With this branch:

✓ published skill matches api-errors.ts — 11 BCK.ROUTER codes across 2 table(s)
  exit: 0

nvm-monorepo#2956 is otherwise ready and blocked only on that check being red.

The two changes

1. .windsurf/rules/nevermined-router.md — qualify BCK.ROUTER.0006. It wrote the retryable pair as bare `0006`/`0007` where its four sibling IDE rule files write the qualified form. The guard matches BCK\.ROUTER\.\d{4}, so it could not see the code there and reported it as undocumented. One token; no wording change.

2. products/router/rails-x402.mdx — the asset symbol does not come from extra.name. The page said:

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.

That is the pre-#2768 behaviour and has been false since nvm-monorepo#2775. The symbol is resolved from the asset address, matched against the canonical token addresses for the chain. As written the page tells a seller the opposite of what is true and sends a reader debugging in exactly the wrong direction.

Corrected, plus a short section on what extra.name actually is — the settlement token's own EIP-712 domain, "USD Coin" on Base mainnet and "USDC" on Base Sepolia — since mistaking it for a ticker is precisely what produced that bug. Both facts hold against nvm main today.

Scope discipline

Deliberately not included, because they document behaviour that does not exist until nvm-monorepo#2959 merges: the byte-for-byte domain check, BCK.ROUTER.0012, and BCK.ROUTER.0013. Those stay in #304.

That ordering is not a preference — the drift guard is bidirectional. diffErrorTable (scripts/lib/skill-error-table.ts:232) flags a code this skill documents that api-errors.ts lacks, verified by running the docs-first scenario: 4 stale drifts, exit 1. So #304 must land after #2959; this PR must not.

Verification

  • Drift check against nvm main: green, exit 0 (output above).
  • mintlify broken-links: no broken links found, whole site.
  • No skill version bump: SKILL.md is untouched here.

🤖 Generated with Claude Code

…ct how the asset symbol is resolved

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 #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) <noreply@anthropic.com>
@r-marques
r-marques requested a review from a team as a code owner August 17, 2026 10:26
@mintlify

mintlify Bot commented Aug 17, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Nevermined 🟢 Ready View Preview Aug 17, 2026, 10:26 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

r-marques added a commit that referenced this pull request Aug 17, 2026
The two EIP-712 signing-domain refusals introduced by nevermined-io/nvm-monorepo#2959.
Two codes rather than one because the same check fails for opposite owners: 0012 (400) is
the seller advertising a domain its own settlement token does not sign under; 0013 (500) is
a gap in Nevermined's canonical token table. Coding ours as the seller's told an agent to
report OUR defect to an innocent counterparty, and buried the only signal that the table
has drifted.

Added to all 10 surfaces the drift guard holds to api-errors.ts, plus the rails-x402 page.
Skill 0.1.2 -> 0.1.3.

⚠️ MERGE AFTER nvm-monorepo#2959. The drift guard is bidirectional — diffErrorTable
(scripts/lib/skill-error-table.ts:232) flags a code documented here that api-errors.ts does
not define. Landing this first produces 4 stale drifts on nvm main, and publishes a skill
telling autonomous buyers to branch on codes the API cannot return.

Stacked on #305, which carries the two corrections that are independent of #2959.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@eruizgar91

Copy link
Copy Markdown
Member

👀 Reviewing

@eruizgar91 eruizgar91 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review

Both corrections were verified against nevermined-io/nvm-monorepo at main, not taken from the PR description. One low-severity note is posted inline; nothing else survived.

Verified true

  • BCK.ROUTER.0006 / 0007 facts. api-errors.ts has 0006 = 500, retryable: true ("Error getting router payments summary") and 0007 = 429 Too many concurrent routed requests, retryable: true. The bullet's claim that these are the only two retryable codes matches the registry.
  • The drift check actually goes green. Ran pnpm exec tsx scripts/check-skill-error-drift.ts against a detached worktree at fe396ee: ✓ published skill matches api-errors.ts — 11 BCK.ROUTER codes across 2 table(s), exit 0. Reproduces the PR body's claim exactly.
  • Leaving 0007 bare is correct, not a half-finished edit. .windsurf/rules/nevermined-router.md is a PROSE_SURFACES entry whose omit list is CONDENSED_IDE_RULES = [0004, 0005, 0007] (scripts/check-skill-error-drift.ts:63-72), and the presence rule is a literal text.includes(code) (:190-202). Only 0006 was required and missing. The three sibling IDE rule files write the same asymmetric form at base — .cursor/rules/nevermined-router.mdc:129, .clinerules/nevermined-router.md:133, .amazonq/rules/nevermined-router.md:124 — so this restores parity rather than creating divergence. Blame confirms the bare form was a regression introduced by #299 (this PR's own base), not the original wording.
  • The extra.name correction. assetSymbol() resolves the symbol from entry.asset against KNOWN_ASSETS_BY_CHAINID and returns undefined for anything unrecognised, which is then treated as not fundable (apps/api/src/router/x402/x402-exact.ts:52-110). extra.name/extra.version are consumed only as the EIP-712 signing domain and are hard-required (:210-211, :233-234). The "USD Coin" (Base mainnet) vs "USDC" (Base Sepolia) split is stated in that file's own comment block. Every sentence added on lines 59-65 holds.
  • Merge order. The diff contains no reference to BCK.ROUTER.0012 or 0013; neither code exists in api-errors.ts today, so nothing here depends on nvm-monorepo#2959 and the bidirectional guard cannot go stale on this branch.
  • Completeness of the fix. extra.name appears exactly once in the whole docs tree — the line this PR corrects. No sibling surface (skills/nevermined-router/, the four IDE rule files, AGENTS.md, .github/copilot-instructions.md) ever carried the wrong claim, so no companion edit is missing.

Considered and discarded

  • "a signature the token cannot recover" (line 65) — loose phrasing; ecrecover yields a different signer rather than failing to recover. The operative claim (the payment cannot settle) is right, and the precision is not worth a reader's attention.
  • The new section omits the security half of the rationalex402-exact.ts:66-69 also notes extra.name is merchant-controlled and therefore untrustworthy for "is this USDC?". Absent, but not contradicted, and the page is seller-facing.
  • No docs.json entry for the new ### heading — it is an in-page subheading under the existing ##, not a route; nav is unaffected.
  • No SKILL.md version bump — history shows the version tracks edits to SKILL.md's own content; neither touched file is mirrored there.
  • Commit title uses fix(router): rather than the docs: prefix CLAUDE.md lists — the repo's own merged history (#269, #289, #291, #299) consistently does the same.

Coverage note. Four of the five analysis lenses completed: repo-convention compliance, git history/blame, prior-PR review feedback, and in-file/consumer guidance. The shallow-bug lens and the automated PR-summary pass did not complete (infrastructure interruption); their scope — factual accuracy of every added sentence, MDX structure, and the 0012/0013 forward-reference check — was covered directly against the monorepo source and the rendered file at fe396ee, as itemised above.

🤖 Generated with Claude Code

Comment thread .windsurf/rules/nevermined-router.md

@eruizgar91 eruizgar91 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Approved with comments — no blockers; 0 should-fix, 1 nit(s) left inline.

Inline review: #305 (review)

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) <noreply@anthropic.com>
@r-marques
r-marques merged commit 9f7d0e8 into main Aug 18, 2026
2 checks passed
@r-marques
r-marques deleted the docs/router-0006-and-symbol-source branch August 18, 2026 11:37
r-marques added a commit that referenced this pull request Aug 18, 2026
The two EIP-712 signing-domain refusals introduced by nevermined-io/nvm-monorepo#2959.
Two codes rather than one because the same check fails for opposite owners: 0012 (400) is
the seller advertising a domain its own settlement token does not sign under; 0013 (500) is
a gap in Nevermined's canonical token table. Coding ours as the seller's told an agent to
report OUR defect to an innocent counterparty, and buried the only signal that the table
has drifted.

Added to all 10 surfaces the drift guard holds to api-errors.ts, plus the rails-x402 page.
Skill 0.1.2 -> 0.1.3.

⚠️ MERGE AFTER nvm-monorepo#2959. The drift guard is bidirectional — diffErrorTable
(scripts/lib/skill-error-table.ts:232) flags a code documented here that api-errors.ts does
not define. Landing this first produces 4 stale drifts on nvm main, and publishes a skill
telling autonomous buyers to branch on codes the API cannot return.

Stacked on #305, which carries the two corrections that are independent of #2959.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
r-marques added a commit that referenced this pull request Aug 18, 2026
* docs(router): document BCK.ROUTER.0012 and 0013

The two EIP-712 signing-domain refusals introduced by nevermined-io/nvm-monorepo#2959.
Two codes rather than one because the same check fails for opposite owners: 0012 (400) is
the seller advertising a domain its own settlement token does not sign under; 0013 (500) is
a gap in Nevermined's canonical token table. Coding ours as the seller's told an agent to
report OUR defect to an innocent counterparty, and buried the only signal that the table
has drifted.

Added to all 10 surfaces the drift guard holds to api-errors.ts, plus the rails-x402 page.
Skill 0.1.2 -> 0.1.3.

⚠️ MERGE AFTER nvm-monorepo#2959. The drift guard is bidirectional — diffErrorTable
(scripts/lib/skill-error-table.ts:232) flags a code documented here that api-errors.ts does
not define. Landing this first produces 4 stale drifts on nvm main, and publishes a skill
telling autonomous buyers to branch on codes the API cannot return.

Stacked on #305, which carries the two corrections that are independent of #2959.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(router): fit the windsurf copy under its cap by omitting 0012 there

Documenting BCK.ROUTER.0012 and 0013 pushed
`.windsurf/rules/nevermined-router.md` to 6,469 characters — 469 over
Windsurf's 6,000 cap, which truncates silently and drops the END of the
file, exactly where the guardrails live. The overflow would have shipped
unnoticed: nothing errors, the rules just stop.

The file could not absorb both codes. Measured, not estimated: at the
tersest honest wording, and after displacing every pure example the file
still had, two codes came to 6,054 — still over. So one had to go.

`0012` is the one omitted, and only from Windsurf:

- It is a **400**, and the file already states the rule that decides it —
  "only 0006 and 0007 are retryable". Nothing is lost that the reader
  cannot act on.
- `0013` is a **500**, the one shape an agent retries by default. That is
  the same reason this copy keeps `0010` while omitting `0007`.
- Cursor, Cline, Amazon Q, Copilot, AGENTS.md and both table surfaces all
  carry BOTH codes. Only the capped file diverges.

Displaced to make room, all presentation rather than rules, per CLAUDE.md
("what it trades away is presentation, never a rule"): the `category`
enum example, the spelled-out `payment.fee` column list, and the gloss on
`0007` — itself a declared omission on this surface.

Also updates the headroom figure to 5,994 (6 characters left) and records
the omission on the install page, so the promise the page makes to
readers stays true.

Needs the matching nvm-monorepo change to PROSE_SURFACES before the drift
check accepts it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants