# x402 defect classes, v22

Stable names for the ways an x402 endpoint can be broken, each with what it asserts, what a finding of it would be falsified by, and whether an unpaid probe can see it at all. Published so that two independent instruments observing the same door can tell whether they agree.

**What this is not.** Not a ranking, and not a list of anybody. Every class describes an observable property of ONE endpoint at ONE moment; nothing here accumulates across weeks into a judgment on an operator.

**Where readings diverge.** A cross-instrument mapping below is a dated read of somebody else's surface. Where their reading and ours diverge on a door, a term, or a claim, both stand with their derivations at https://scvd.store/disagreements — neither authoritative over the other.

**The method line.** unpaid = visible from a GET nobody paid for. paid = only a settled payment reveals it. A door clean to an unpaid probe and defective to a paid walk is not a contradiction; it is two instruments measuring different things, and this field is how a reader tells the difference.

Cross-instrument mappings read on 2026-08-23. Mappings to another instrument's names are our reading of their published definitions on the date above, not their endorsement. Each carries the path to check it and what would show it wrong. If they change a definition, this file is stale until corrected — say so rather than trusting it.

Launch Check v4 compares complete response bytes. Transaction references alone do not establish redelivery; changed bytes alone do not establish fresh fulfillment. Historical v3 served_again and redelivered mappings were heuristics, and a fresh challenge alone proves no second charge. Read the report's battery, response evidence and payment_attempt.verification separately. The September 13 correction at /corrections withdraws the stronger interpretation; saved signed records retain their bytes.

---

### `no-402` — Listed, but serves no payment challenge

**Asserts:** The URL a directory lists answers 402 Payment Required to an unpaid request using a method the resource accepts — the method its catalog, challenge or specification declares, or, where none is declared, a method the endpoint does not refuse as a method.

**Costs:** Every buyer routed here finds no challenge at all. The listing is an advertisement for a door that does not open.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The same URL answering 402 with a parseable challenge to an unauthenticated request, by ANY HTTP method, at the stated moment. A 405 or 501 to the probing instrument's method falsifies a finding of this class outright: a method refusal is an observation about the request, not about the challenge, and an instrument that reports this class without having tried a method the door accepts has published a claim it has no evidence for. A 402 that appears only for some callers is a different finding, not this one.

**How an operator clears it:** Serve 402 with a PAYMENT-REQUIRED challenge at the exact URL your listing names. The commonest causes are a listing that points at a marketing page instead of the paid resource, and a proxy or CDN answering before your x402 middleware does. If the door moved, update the listing. If your door takes POST rather than GET, both halves of RFC 9110 §15.5.6 are worth serving on the refusal — the 405 AND an Allow header naming the method — because an indexer or preflight that reads Allow finds your door on the first try, and one that does not will keep asking the wrong question.

**What a buyer does:** Do not pay, and do not retry with money: there is no challenge to sign against. Treat the listing as pointing somewhere other than the paid resource; if you hold a different URL for the same service, preflight that one instead.

**Our signal:** `status-402`

### `unparseable-challenge` — Challenge cannot be read by a client

**Asserts:** The PAYMENT-REQUIRED header is present and is base64-encoded JSON a v2 client can parse.

**Costs:** Surfaces to the buyer as 'invalid payment header format' or a silent parse failure. The seller sees nothing.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The header decoding to valid JSON by any conforming base64 + JSON reader at the stated moment.

**How an operator clears it:** Emit PAYMENT-REQUIRED as base64 over UTF-8 JSON, unwrapped and untruncated — check for a proxy that rewrites or size-caps headers, and for double encoding. Decode your own header with an independent client before relisting; the free preflight does exactly that.

**What a buyer does:** Do not guess the terms. A challenge you could not decode is a door you cannot sign for; report the parse failure by name and move on, or hand the operator the free preflight's reading so they can see what your client saw.

**Our signal:** `payment-required-header`

### `unsignable-offer` — Offer a buyer cannot sign against

**Asserts:** Every accepts entry carries the fields a client needs to construct a payment, as strings.

**Costs:** A buyer reaches the signing step and has nothing to sign. Indistinguishable, from the seller's logs, from nobody wanting the goods.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** Every accepts entry carrying the published required fields at the stated moment.

**How an operator clears it:** Fill every accepts entry with the v2-required fields, as strings, and regenerate the offer from your server's own config rather than hand-editing JSON. The free preflight names the missing field.

**What a buyer does:** Do not sign: a missing required field means your client has nothing to construct, and any library that proceeds anyway is filling the gap with a default you did not choose. Read the preflight's named missing field and wait for a challenge that carries it.

**Our signal:** `accepts`

### `transfer-method-unrecognized` — Asks for a signature nobody can build

**Asserts:** Where an accepts entry names extra.assetTransferMethod, the value is an authorization standard a published x402 client can produce — eip3009 (TransferWithAuthorization), permit2, or erc7710.

**Costs:** A buyer who reads the field has nothing to construct from it and a buyer who ignores it signs blind. The refusal lands before any payment reaches the seller, whose logs record it as nobody wanting the goods. Absence of the field is not this class: it is optional, most doors omit it, and eip3009 is the settled default.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The same entry naming one of the published methods at the stated moment, or a client implementation that builds an authorization from the named method — the second retires the finding by making the method recognized, and the register is the thing that should move.

**How an operator clears it:** Name the method your facilitator actually verifies — for USDC on an EVM rail that is almost always eip3009 — or omit the field, which reads as eip3009 by default. If the value names a standard your own stack defines, publishing what a client must build for it turns a door only your clients can walk into one anybody can.

**What a buyer does:** Do not sign blind. If the named method is one your client can build, build it; if not, refuse, because a signature over the wrong authorization standard is money sent under terms neither side agreed to. Absence of the field is not this class and reads as eip3009.

**Our signal:** `transfer-method-signable`

### `unpayable-payto` — payTo is not the bytes a payment signs over

**Asserts:** payTo is a 20-byte 0x address on an EVM rail, or a base58 pubkey on Solana — not a name, and not a wallet pasted into the wrong rail's entry.

**Costs:** Most clients throw inside their signing library. The seller never learns a buyer came.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The payTo parsing as a valid address for the rail its own entry names.

**How an operator clears it:** Give each accepts entry its own rail's address format: a 20-byte 0x address on EVM entries, a base58 pubkey on Solana entries. The commonest cause is one wallet string pasted across every rail's entry.

**What a buyer does:** Never resolve a name in payTo yourself and pay the result: your signature would bind to whatever the resolver said that second. Refuse until payTo is a concrete address in the format of its own entry's rail.

**Our signal:** `accepts`

### `rail-cannot-receive` — The address cannot be credited in the mint it asked for

**Asserts:** On Solana, the payTo owns an associated token account for the offered mint, so a transfer has somewhere to land.

**Costs:** The payment fails in simulation before it can broadcast. Every structural check passes and nobody can pay.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** getTokenAccountsByOwner returning at least one account for that owner and mint. Anyone can repeat the read; it is public and unpaid.

**How an operator clears it:** Create the associated token account for the offered mint on the payTo address — one transaction from any wallet tooling — or point payTo at an address that already holds one. Re-run getTokenAccountsByOwner yourself to confirm before relisting.

**What a buyer does:** Do not broadcast on Solana against this payTo: the transfer has no token account to land in and will fail in simulation, or worse. Pay on another rail the door offers, or wait until getTokenAccountsByOwner shows an account for that mint.

**Our signal:** `solana-rail-receivable`

**Also known as:** `rail-cannot-receive` (Cairn (cairnwake.com)). Check: cairnwake.com/scoreboard.json, read 2026-08-23: a public machine-readable rollup of its published reports. Wrong if: Their published definition describing a different observable property than the one asserted here.

### `wrong-network` — Offered on a network the buyer is not on

**Asserts:** The accepts entries name the mainnet rail a buyer is expected to pay from.

**Costs:** A client attaches payment and keeps getting 402. The commonest cause is a testnet left in the offer.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The entry naming a mainnet chain id the buyer's client supports.

**How an operator clears it:** Replace the testnet chain id in accepts with the mainnet rail you settle on, and keep test offers behind a separate listing. If you meant mainnet, look for a deploy-time environment default leaking into production.

**What a buyer does:** Do not let a mainnet wallet sign a testnet offer: the payment settles nowhere real and the goods never come. Check the CAIP-2 network id against the chains you actually hold funds on before signing anything, and prefer a door whose offer names one of them.

**Our signal:** `testnet-network`

### `amount-not-atomic` — Price written in dollars where atomic units are required

**Asserts:** accepts amounts are integer atomic units (USDC has six decimals).

**Costs:** A decimal point usually means the price is off by a factor of a million, in one direction or the other.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The amount parsing as an integer string.

**How an operator clears it:** Write amount as an integer string of atomic units — for USDC, dollars times ten to the sixth — and derive it from one constant so the menu and the challenge cannot disagree.

**What a buyer does:** Do not pay a decimal amount: the true price is off by a factor of a million in a direction you cannot know. Refuse, and if you must proceed, get the atomic integer from the operator in writing first.

**Our signal:** `amount-not-atomic`

### `inputs-undeclared` — Required parameters a buyer discovers only by being refused

**Asserts:** A resource needing parameters declares them in the challenge, before payment.

**Costs:** The buyer is refused AFTER signing, and their ledger records that as this endpoint failing. The largest single cause of refused purchases at otherwise-working endpoints in the August 2026 field run.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** A declared input contract in the challenge, or the resource succeeding with no parameters.

**How an operator clears it:** Declare required parameters in the challenge itself, before payment, so a buyer learns them by reading rather than by being refused after signing. If the resource can serve a sensible default, accept a bare call too.

**What a buyer does:** Expect a refusal after payment if you call bare. Read the resource's documentation for its required parameters before paying, send them on the first call, and keep the settlement reference so a refused call can be retried as a paid retry rather than a second purchase.

**Our signal:** `no-input-contract`

### `replay-accepted` — Serves the goods twice for one settled payment

**Asserts:** A byte-identical, already-settled payment presented a second time is not served as a new sale: it is refused, or answered with the original purchase's own outcome naming the settlement that paid for it.

**Costs:** The seller gives its product away. The authorization's nonce is spent, so nothing reaches them on the second pass — and from their side both requests look like successful sales.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** The endpoint answering the identical presented payment on the second attempt with a refusal, or with the original purchase naming its settlement transaction, at the stated moment.

**How an operator clears it:** Record each settled authorization nonce at settle time and, BEFORE fulfillment runs, either refuse a byte-identical presentation or answer it with the original purchase and its settlement reference, charged nothing — one keyed read at the till. Naming the original settlement either way keeps you clear of the nonce-unbound class below.

**What a buyer does:** This costs the seller, not you, but it tells you the till keeps no settlement ledger: keep your own record of what you paid and the response you got, because the door cannot help you reconstruct it later.

**Our signal:** `launch_check stage: replay (outcome served_again)`

**Also known as:** `replay-accepted / check replay_rejected` (Cairn (cairnwake.com)). Check: cairnwake.com/scoreboard.json, read 2026-08-23: a public machine-readable rollup of its published reports. Wrong if: Their check asserting something other than the refusal of an identical already-settled payment.

### `nonce-unbound-from-settlement` — Marks the nonce spent without naming what spent it

**Asserts:** A till that refuses an already-settled payment can name the settlement transaction that spent the authorization's nonce.

**Costs:** A buyer who paid and lost the response cannot be told apart from one who never paid. The seller can say 'spent' but not prove WHAT spent it, so honest recovery and fraud look identical — and any paid-retry lane (deliver again for the SAME settlement, charge nothing) has nothing to stand on. The money moved once; the proof of which movement is gone.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** The door's replay refusal, or an equivalent receipt surface, producing the settlement transaction hash for the spent nonce at the stated moment.

**How an operator clears it:** Store the settlement transaction hash beside the nonce when you mark it spent, and return it on the replay refusal — one extra column, and a buyer's honest recovery becomes distinguishable from fraud.

**What a buyer does:** Keep the settlement transaction hash yourself, from your wallet or the facilitator's response, before you need it: this door cannot tell you what spent your nonce, so your honest recovery of a lost response rests on your own record.

**Our signal:** `this store's own replay refusals return the original settlement transaction (HTTP door since the paid-retry lane; MCP door since 2026-08-27 — it exhibited this class until that day's fix, found live by an outside reproduction, and that is recorded here rather than smoothed over).`

### `re-challenges-spent-authorization` — Asks for new money when a settled payment is presented again

**Asserts:** A byte-identical, already-settled payment presented a second time is answered with the original outcome or a refusal, never with a fresh payment challenge.

**Costs:** A buyer who paid and lost the response re-presents the same authorization and is told to pay. Its nonce is spent, so the only way through the new challenge is a second signature — and the second signature is a second charge for goods the first one already bought. From the buyer's side it is one purchase attempted twice; from the seller's, two sales. This is the receiver-side defect the x402 specification thread measured in seven of ten money paths in September 2026.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** The endpoint answering the identical presented payment on the second attempt with anything other than a new payment challenge — a refusal, or the original purchase — at the stated moment.

**How an operator clears it:** When a presented authorization's nonce is already spent, look it up before you build a challenge: answer with the original purchase's outcome and its settlement reference (a paid retry, charged nothing), or refuse naming that settlement. Never let the spent-nonce path fall through to the code that issues a fresh 402.

**What a buyer does:** If a door answers your re-presented payment with a new challenge, do not sign it: your first authorization may have settled, and a second one is a second charge. Keep the settlement reference from your first response, read the chain for it, and use the door's recovery path or ask for delivery against that settlement before paying again.

**Our signal:** `launch_check stage: replay (outcome rechallenged)`

### `advertised-version-unpayable` — Refuses payment in the protocol version it advertises

**Asserts:** A correctly signed payment, presented in the protocol version the door's own challenge advertises, reaches that door's verifier: it is accepted, or refused on something about the payment, never answered with the door's own terms re-served as though nothing had been presented.

**Costs:** The buyer that followed the instructions is the one that cannot pay. It read the advertised version, signed against those terms, presented them in that version's envelope, and got back the offer it started with — from outside, identical to never having paid at all. No money moves, so there is nothing to refund and nothing to chase; what is lost is the sale, silently, and the door has no failed payment to look at either. Seen in the field on 2026-09-12 during a protocol migration, on a door whose operator then found the same version-keyed read on three more of his own surfaces.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** The door answering a correctly signed payment, presented in the version its challenge advertises, with anything other than its own terms re-served — the goods, a refusal naming something about the payment, or an offer whose material terms (scheme, network, payTo, asset, amount) have changed — at the stated moment. A door that advertises one version and refuses a DIFFERENT one is not this defect: the class is about the version the door itself names. Nor is a door that re-serves terms which differ only in a nonce, an expiry or a timeout being cleared by that variation; those rotate legitimately and this class reads the material terms alone.

**How an operator clears it:** Count every place your code names a payment header; this is a version-keyed read and it is rarely in one place. Route every paid front-end through one translation that accepts each version you advertise and hands the inner payload to a single verifier unchanged — for exact/eip3009 the signed EIP-712 domain carries chainId rather than a network label, so translating the envelope cannot disturb the signature. Then check what your request log and payment ledger key on: a surface that accepts the newer version while its ledger keys on the older one is a separate fault this class cannot see, and it makes your own attempt counts a floor rather than a number.

**What a buyer does:** If a door answers your signed payment with the offer you already read, do not sign again — nothing settled, and a second signature buys nothing the first did not. Read the refusal for a header name different from the one you sent; if it names another version's header, the door is unpayable as advertised rather than refusing you. Keep your raw request and response: the door's own records may hold no row for the attempt, so yours may be the only account of it.

**Our signal:** `launch_check stage: settle (advertised-version-unpayable PRESENT); also walkabout ledger: advertised_version_unpayable (checked, present)`

### `settlement-error` — A correct payment is answered with a server error

**Asserts:** A valid, sufficient payment is answered with a 2xx and the goods.

**Costs:** Money may move with nothing delivered. The failure is invisible to the free preflight, which never pays.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** A correctly-formed payment settling and returning a 2xx at the stated moment.

**How an operator clears it:** Read your settle-path logs: the failure sits after payment verification, most often a facilitator timeout, an unhandled fulfillment exception, or a dead upstream. Fail BEFORE money moves or deliver after it — never answer a settled payment with a 500.

**What a buyer does:** Do not retry with a fresh nonce: money may already have moved once. Check the chain for your settlement first; if it settled, present the same payment again or ask for a paid retry against that settlement, and if it did not, only then pay again.

**Our signal:** `launch_check stage: settle`

**Also known as:** `settlement-server-error` (Cairn (cairnwake.com)). Check: cairnwake.com/scoreboard.json, read 2026-08-23: a public machine-readable rollup of its published reports. Wrong if: Their class covering refusals of INVALID payments, which is conformant behaviour and not this defect.

### `delivered-nothing` — Settled, and the buyer is left holding nothing

**Asserts:** A settled payment returns a non-empty body.

**Costs:** Money moved for zero bytes. Distinct from a settlement error, because the endpoint reports success.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** A non-empty response body accompanying the 2xx.

**How an operator clears it:** Produce the goods before presenting the settlement, and treat an empty body as a failed delivery that aborts the charge — deliver-first ordering makes this class impossible by construction.

**What a buyer does:** Treat an empty 2xx after settlement as a failed delivery and keep the settlement reference: it is the only evidence that you paid. Ask for a paid retry against that settlement before paying a second time.

**Our signal:** `launch_check stage: delivery`

### `receipt-absent-on-paid-response` — Serves the goods with no settlement receipt

**Asserts:** A paid 2xx carries a PAYMENT-RESPONSE header — or the settlement receipt its protocol version names in its place — identifying the settlement that paid for it.

**Costs:** The buyer holds goods and no proof of what bought them. A lost response cannot be re-presented against a settlement the door never named, a dispute has the buyer's wallet history on one side and nothing on the other, and a paid-retry lane has no reference to honour. The money moved once and the door kept the only record of what it was for.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** The paid 2xx carrying a PAYMENT-RESPONSE header, or its version's named equivalent, at the stated moment.

**How an operator clears it:** Return the facilitator's settlement response on the paid reply as PAYMENT-RESPONSE (base64 JSON: success, transaction, network, payer); the reference x402 middleware sets it by default, and a proxy, CDN or framework layer stripping headers it does not know is the usual cause. Check the header survives to the client, not only that the middleware emits it.

**What a buyer does:** Record the settlement transaction hash from your own wallet or the facilitator's response before you need it, and keep the response bytes and their hash beside it: this door will not give you a reference, so your record is the only one. If you lose the response, look up the settlement on chain first rather than paying again.

**Our signal:** `bounty board: what_the_walks_show.reports.receipt_absent on /api/bounties, and crowd_walks[].defect_classes on /corpus/host/{host}.json — a walker's report at the crowd-walked tier, recorded as their claim and never verified by this store, which saw neither request nor response. No paid instrument of ours reports it yet; the launch check's settle stage is where it would go.`

### `payto-moved` — The recipient changed under a door that otherwise stayed the same

**Asserts:** The payTo a door presents for a given network is the one it presented the last time it was observed, or the change was announced where the door's buyers read before the door presented it.

**Costs:** A buyer whose client trusts the door on its history pays a wallet that history never covered. Every structural check still passes — the challenge is well-formed, the amount atomic, the address payable — so a one-off preflight reads the door as ready at the exact moment it is most worth not paying. Visible only to something that looked twice.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** Two signed rows from the same watch, bracketing the claimed change, whose challenge_bytes decode to the same (network, payTo) set; or a dated notice of the rotation, published where the door's buyers read, that predates the first row showing it.

**How an operator clears it:** Rotate deliberately: publish the new payTo and its date where your buyers read — your llms.txt, your directory listings, a signed offer under a key they already hold — BEFORE the door presents it, and keep the old address listed as retired. A silent move is indistinguishable from a hijack to anyone watching, because from outside it is the same observation.

**What a buyer does:** Before paying a door you have paid before, compare the payTo against the one you last saw for that network; if it moved and no dated notice explains it where the door's buyers read, treat the door as unverified today, whatever the preflight says about its shape.

**Our signal:** `standing_watch summary: payto_changes, derived at read time from the signed rows' challenge_bytes`

### `discovery-info-invalid` — The discovery block fails the schema served beside it

**Asserts:** Where a challenge carries extensions.bazaar, its info block satisfies its schema block on every keyword a catalog's validator applies before listing.

**Costs:** A catalog that validates this contract may reject the entry. This probe observes the schema contradiction, not whether any directory ingested or rejected it. Earlier batteries leave this advisory; v3 counts it against readiness.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The info block validating against the schema block under a standard JSON Schema validator; or the endpoint appearing in an ingestion-built catalog with a complete listing despite the block failing.

**How an operator clears it:** Generate info and schema from one declaration rather than typing them twice (the reference helpers do this), and run a JSON Schema validator over the pair in your own tests, which is how this store found the same shape in its own listings.

**What a buyer does:** The door may still be payable, but its discovery info contradicts its schema and blocks v3 readiness. A catalog may reject the entry; this probe does not observe ingestion. Retain the URL and ask the operator to reconcile the discovery contract.

**Our signal:** `discovery-info-fails-schema (advisory)`

### `offer-contradicts-challenge` — A signed offer promises terms the challenge does not carry

**Asserts:** Every signed offer a door serves commits to a network, asset, payTo and amount that appear together on one entry of the same response's accepts.

**Costs:** A buyer holding the offer as a pre-payment commitment and the challenge as the terms to sign has two prices from one door in one breath, and whichever it pays, the other document says it paid wrong. In a dispute the door's own signature argues against its own challenge.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The offer's decoded payload matching an accepts entry of the same response on network, asset, payTo and amount; the spec tells verifiers to match on those fields, never on array position.

**How an operator clears it:** Sign offers from the accepts entries themselves at the moment the challenge is built, one offer per entry, so the two cannot drift; never sign a cached offer beside a freshly priced challenge.

**What a buyer does:** Sign against the challenge's accepts, which is what your client will actually pay, and keep the signed offer beside it: two prices from one door in one breath is a dispute waiting to happen, and the copy you hold is your evidence of which terms you were shown.

**Our signal:** `offer-contradicts-challenge (advisory)`

### `surface-contradicts-challenge` — A same-origin surface names different payment terms than the 402

**Asserts:** Every machine-readable surface on the door's own origin that names a price for the probed path — llms.txt by the code-span convention, the OpenAPI document's payment fields, the challenge's own resource URL — names the 402's minimum on its first rail. For MPP, an observed challenge matches at least one advertised alternative on the exact GET operation's named method, intent, amount and currency fields, with the compared terms stable at both bookends; dynamic amount and omitted currency make no assertion.

**Costs:** A buyer who budgets from the surface it happened to read first — an installed skill, a fetched llms.txt, a client generated from the OpenAPI document — arrives at the till with the wrong number, refuses or overpays, and reports the door as something it is not. This store did exactly that to its own doors in an installed bundle for weeks before a check looked at a number beside a name.

**Detectable:** paid — only a settled payment reveals it

**Falsified by:** For MPP, any advertised alternative matching all named fields, or an unreadable or moving bookend. For x402, the surface, re-read, naming the 402's minimum on the same rail; or the 402 read again on either side of the surface read carrying a different price, which makes the reading moving rather than contradicting; or the surface's number sitting only in prose, which the convention does not read.

**How an operator clears it:** Derive every surface from the one place the price lives, the way this store derives its llms.txt lines from its shelf, and never type a number into a document that a buyer may install and never refresh. Where a surface must be static, put the endpoint path and the dollar amount in one code span so the convention reads it, and publish the date it was last derived.

**What a buyer does:** Budget from the 402, not from the surface you read first: an installed skill, a fetched llms.txt or a generated client can carry a stale number. Before paying, read the challenge's amount and refuse if it is not what you were told, rather than reporting the door as broken.

**Our signal:** `surfaces (the paid single-door audit's section; rows with state read and agrees false, when the bookend did not move; MPP: surfaces.mpp.rows with state differ under its cited reading rule)`

### `mpp-core-observable-invalid` — An observable MPP core requirement fails

**Asserts:** The named observable core check passes under mpp-core-v1 and its cited draft-01 source. The field, response condition and failed challenge indexes determine the assertion; unmeasured registry, binding and payment behavior make no assertion.

**Costs:** A buyer can receive an ambiguous or malformed challenge, select an unsupported credential header, or reuse cacheable or expired payment terms. The observation identifies the failing condition without claiming a payment was attempted.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The captured response satisfying the named check under the same battery at the observation time, or evidence that the required field was not captured and the check should have remained unmeasured.

**How an operator clears it:** Correct the named auth parameter, encoding, expiry or response header in the challenge producer, then obtain a fresh read. A passing core subset does not establish method validity or payment delivery.

**What a buyer does:** Keep the cited check and observation time. Resolve the reported condition before constructing a credential, and independently validate the chosen method and payment terms; this finding comes from an unpaid read, never a payment.

**Our signal:** `mpp_core.checks with state fail, under the core block's cited battery and source digest`

### `mpp-challenge-id` — MPP challenge with no id

**Asserts:** Every WWW-Authenticate: Payment challenge carries a non-empty id.

**Costs:** Clients and parsers MUST reject a challenge whose id is missing or empty, so a stock MPP client refuses before any payment; the seller sees a request for a price followed by silence.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The same challenge carrying a non-empty id at the stated moment.

**How an operator clears it:** Mint an id per challenge — any non-empty opaque string your server can recognise on the credential's return — and never leave the parameter out to save bytes.

**What a buyer does:** Do not construct a credential against a challenge with no id: the door cannot bind your payment to its own request, and a client that proceeds pays into a challenge the server may not recognise. Refuse, and say which parameter was missing.

**Our signal:** `mpp-challenge-id`

### `mpp-challenge-realm` — MPP challenge with no realm

**Asserts:** Every Payment challenge names its realm, the RFC 9110 protection space.

**Costs:** A client cannot scope a credential to the door that asked for it; some clients refuse, others send credentials where they were not asked for.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The same challenge carrying a realm at the stated moment.

**How an operator clears it:** Set realm to your door's protection space — usually your host — on every challenge; the auth-scheme grammar requires it.

**What a buyer does:** Treat a challenge with no realm as unscoped: do not reuse a credential across doors, and prefer a door whose challenge names where the credential belongs.

**Our signal:** `mpp-challenge-realm`

### `mpp-method-unregistered` — MPP challenge naming a method no client can build

**Asserts:** The method parameter names a payment method the specification repository holds a draft for (card, evm, hedera, lightning, nearintents, solana, stellar, stripe, tempo, usdc).

**Costs:** A buyer holding the registry has no credential shape to construct; the refusal lands on the buyer's machine and the seller never learns a buyer came.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The method appearing as a draft under specs/methods at the stated read date, or a published client building a credential for it.

**How an operator clears it:** Name a method the drafts define, spelled lowercase exactly; if your method is your own, publish its credential shape where clients read and expect the registry to move before buyers do.

**What a buyer does:** Do not guess a credential shape for a method you do not recognise: a signature over the wrong payload is money sent under terms neither side agreed to. Refuse, and name the method you could not build.

**Our signal:** `mpp-method-registered`

### `mpp-intent-unregistered-or-missing` — MPP challenge with no usable intent

**Asserts:** The intent parameter is present and is either a drafted intent (charge, subscription) or one implementers advertise (session).

**Costs:** Without an intent a client cannot tell a one-off charge from a recurring commitment; a client that guesses charge on a subscription challenge signs for more than it meant to.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The challenge naming a drafted or widely advertised intent at the stated moment.

**How an operator clears it:** Name the intent on every challenge; charge for a one-off, subscription for recurring; if you advertise session, know that it has no draft and a registry-only client cannot pay it.

**What a buyer does:** Do not sign against a challenge whose intent you do not recognise: you cannot know whether you are committing once or repeatedly. Refuse, and say which intent you could not read.

**Our signal:** `mpp-intent-registered`

### `mpp-request-undecodable` — MPP request that does not decode

**Asserts:** The request parameter is base64url of a JSON object.

**Costs:** The price, currency and recipient are inside the request; a client that cannot decode it has nothing to sign and nothing to show its human. The seller sees nothing.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The request decoding, by any conforming base64url and JSON reader, to a JSON object at the stated moment.

**How an operator clears it:** Encode the request as base64url (no padding, URL-safe alphabet) of UTF-8 JSON, and decode your own header with an independent client before shipping; a proxy that rewrites or size-caps headers is the usual cause.

**What a buyer does:** Do not guess the terms: a request you could not decode is a door you cannot sign for. Report the decode failure by name and move on.

**Our signal:** `mpp-request-decodes`

### `mpp-request-not-canonical` — MPP request whose bytes are not their canonical form

**Asserts:** Re-canonicalizing the decoded request by RFC 8785 (JCS) reproduces the served bytes exactly.

**Costs:** A client that hashes the request for challenge binding gets a different hash from the one the server computed, so a correct payment is refused as mismatched, or a careless server accepts a rebound one.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The served request bytes equalling the RFC 8785 canonicalization of their own decoded JSON at the stated moment.

**How an operator clears it:** Serialise the request with a JCS canonicalizer — sorted keys, no whitespace, ECMAScript number and string forms — rather than a pretty-printer or a hand-written template; the draft says MUST.

**What a buyer does:** Bind your credential to the bytes you were served, never to a re-serialisation of them, and expect a mismatch refusal from a server that hashes its own canonical form; if the door's own bytes are not canonical, tell the operator rather than retrying.

**Our signal:** `mpp-request-canonical`

### `mpp-amount-not-integer` — MPP amount not an integer string in the smallest unit

**Asserts:** The request's amount is a base-10 integer string with no sign, point or exponent.

**Costs:** A decimal or a number usually means the price is off by a factor of the unit's decimals in one direction or the other — the amount-not-atomic mistake on the second wire.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The amount parsing as a digit string at the stated moment.

**How an operator clears it:** Write amount as an integer string of the smallest unit — cents for fiat, the token's smallest unit for chains — derived from one constant so the discovery document and the challenge cannot disagree.

**What a buyer does:** Do not pay a decimal amount: the true price is unknowable from it. Refuse, and if you must proceed, get the integer amount and its unit from the operator in writing first.

**Our signal:** `mpp-amount-shape`

### `mpp-currency-unnamed` — MPP request with no currency

**Asserts:** The request names its currency: ISO 4217 lowercase for fiat, a token contract address for chains, or the method's own convention.

**Costs:** A client cannot resolve what the amount is denominated in; a wallet that assumes settles in the wrong asset or refuses.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The request carrying a non-empty currency at the stated moment.

**How an operator clears it:** Name the currency on every request in the form the method draft specifies, and keep it beside the amount in one object so they cannot drift.

**What a buyer does:** Do not sign for an amount with no currency: you cannot know what you are paying in. Refuse, and say which field was missing.

**Our signal:** `mpp-currency-named`

### `mpp-recipient-missing` — MPP request with no recipient on a chain method

**Asserts:** On the evm, tempo and solana methods the request names a recipient the credential's to MUST match.

**Costs:** There is nowhere for the payment to land; a client that fills in a recipient from elsewhere pays a wallet the challenge never named.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The request carrying a recipient in the method's native format at the stated moment.

**How an operator clears it:** Put the receiving address on every chain-method request in that chain's native format, and generate it from your server's config rather than a template.

**What a buyer does:** Never supply a recipient the challenge did not: the credential's to must match the challenge, and a payment to any other address is unrecoverable. Refuse until the door names one.

**Our signal:** `mpp-recipient-present`

### `mpp-challenge-expired-at-issue` — MPP challenge already expired, or with an unreadable expires

**Asserts:** Where the challenge carries expires, it is RFC 3339 and later than the moment the challenge was served.

**Costs:** A challenge expired at issue cannot be paid: the server refuses the credential as payment-expired and the buyer's ledger records a failed purchase at a door that never offered a live one.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The same door serving a challenge whose expires parses and lies in the future at the stated moment.

**How an operator clears it:** Set expires from the server's clock at issue time plus a window a client can act in, in RFC 3339 with a timezone, or omit it; a fixed or stale timestamp is the usual cause.

**What a buyer does:** Do not pay a challenge that is already expired: the credential will be refused and the attempt may still be logged against you. Re-request the door for a fresh challenge, and if it is expired again, tell the operator.

**Our signal:** `mpp-expires-rfc3339`

### `mpp-challenge-over-http` — MPP challenge issued over unencrypted HTTP

**Asserts:** Payment challenges are issued only over TLS.

**Costs:** Servers MUST NOT issue Payment challenges over unencrypted HTTP; a credential sent in reply travels in the clear, and a client that honours the MUST refuses the door outright.

**Detectable:** unpaid — a free probe can see it

**Falsified by:** The same door serving its challenge over https at the stated moment.

**How an operator clears it:** Serve the door over https only and redirect or refuse plain http before the 402 is built; a challenge over http is a challenge no conforming client will answer.

**What a buyer does:** Never send a Payment credential over plain http, whatever the door asks: the credential travels in the clear. Refuse, and use the door's https address if it has one.

**Our signal:** `mpp-tls-only`

## Evidence labels — a separate register

Labels for how a claim was come by, not for what is wrong with a service. They attach to the claimant, never to the operator: listed-not-walked says the instrument did not look, and says nothing whatever about the door.

### `listed-not-walked` — Listed, not walked

**Asserts:** A claim about a service whose provenance is an index, directory, census row, or register entry, made by an instrument that has not itself completed the act the entry implies — no probe sent, no payment made, no settlement observed by the claiming instrument. The label marks the gap between appearing in a register and having been walked: it says the evidence is the listing, not the walk.

**Does NOT assert:** Nothing about the service. A listed-not-walked claim is a statement about the CLAIMANT'S coverage, never about the operator's endpoint — it is not 'unverified because suspect', it is 'unverified because we did not look'. Reading it as a mark against the service inverts its whole purpose.

**Falsified by:** A published, instrument-signed record of the walk itself — for a paid battery, a signed report carrying the settlement transaction; for this store's census, a v2 walk row — dated at or before the claim it would falsify.

**Authored by:** Cairn (cairnwake.com), verbatim on 2026-08-24 but for the schema-name substitution in falsified_by, confirmed back to them. Registered 2026-08-24.

### `cleared-not-examined` — Cleared, not examined

**Asserts:** A claim carrying a check's passing status about a subject that was never in the set that check examined. The status is true OF THE CHECK — it ran, it loaded its sources, it reported — and says nothing whatever about the subject, because the subject was never compared to anything. It arises wherever the set a check assembles is derived from the shape of a transaction rather than from the subject a reader cares about. In the case that named it: a settlement where the SUBMITTER IS NOT THE PAYER, so a payee never enters a set built from movements originating with the transaction sender — the ordinary facilitator-relayed case, and the whole shape of x402.

**Does NOT assert:** Nothing about the subject, in either direction. The subject is unscreened, not suspect: it was not found clean and it was not found dirty, and reading the label as a negative finding inverts it exactly as far as reading the status as a clearance did. Nor does it assert that the instrument is broken in general — on shapes where the subject does enter the examined set, the same status means precisely what it says. This is a statement about one claim's coverage, never about the instrument's competence or its operator.

**Falsified by:** Deriving the check's examined set from its own published output and finding the subject present in it. In the instrument that named the class that set is NOT `checks.assessed_for`: that field is the check's SUBJECT — the principals whose exposure the statuses describe, which on a relayer-submitted transfer is the payer and not the sender. The examined set is derived from it, per the line that computes it: `for (const m of movements) if (principals.has(m.from)) exposed.add(m.to)`, where `principals` is what gets published as `assessed_for`. So the examined set is the `assets_moved[].to` whose `.from` appears in `assessed_for`, and a subject absent from THAT set is unscreened whatever the status beside it says. Both fields ride in the same response, so the derivation needs no further transaction lookup. IT HOLDS ON RELAYED SETTLEMENTS ONLY. Where the transaction is not relayed the examined set also contains the transaction target, and on any transaction carrying an approval it contains the spender or operator; neither is recoverable from the published fields this way, and a subject of those shapes will read as unscreened when it was screened. Where an instrument publishes no such output at all, this label cannot be retired by reading it — the absence is the condition the label describes.

**Authored by:** 0200project (github.com/0200project), who found the class in their own product, disclosed it unprompted to a party that had not bought it, and then withdrew three of their own published falsifiers before the one above stood — the third after this register had already shipped it, corrected by them on 2026-09-07 against the line in their own source. Registered as source at their agreement on 2026-09-06; wording is this store's at their explicit invitation, and the falsifier is theirs. THE WITHDRAWN VERSIONS ARE DELIBERATELY NOT RECORDED HERE — they asked that the version that stands carry their name rather than the first one, which is the whole discipline this register is for. This store has not run the falsifier: we do not consume that instrument, and registering a class is not a claim to have tested it.. Registered 2026-09-06.

## Changelog

- **v1** (2026-08-23, at the instigation of this store) — First publication. Eleven defect classes, each carrying what it asserts, what would falsify a finding of it, and whether an unpaid probe can detect it. Cross-instrument mappings to Cairn (cairnwake.com) read on 2026-08-23.
- **v2** (2026-08-24, at the instigation of Cairn (cairnwake.com), who supplied the definition and the falsifier) — Added EVIDENCE_LABELS, a second and separate register. A defect class describes a property of an ENDPOINT; an evidence label describes the PROVENANCE OF A CLAIM about one. Conflating the two was the gap: both instruments had been making listing-backed claims with no name for what made them weaker than walk-backed ones. First entry: listed-not-walked.
- **v3** (2026-08-27, at the instigation of SolomonisBlack (github.com/SolomonisBlack), who named the class; this store registers it as source, not author, at his request) — Added nonce-unbound-from-settlement: a till that marks an authorization's nonce spent without recording which settlement spent it, leaving a buyer who paid and lost the response indistinguishable from one who never paid. Registered the same day this store fixed the instance of it on its OWN MCP lane (the HTTP lane bound the transaction already) — found live by an outside reproduction on 2026-08-26, and stated here because a register that lists a class its registrar quietly exhibited would be worth nothing. DefectClass entries gained optional sourced_by/registered fields, the registrar-not-author discipline the evidence labels already carried.
- **v4** (2026-08-27, at the instigation of an outside strategic review of the evidence layer, accepted the same day) — Every defect class gains repair_hint: what the operator does, in their own systems, to clear the class. Additive only — no id, assertion, or falsified_by changed; a hint is advice about a door, never a judgment about its operator, and falsified_by remains the only authority on presence.
- **v5** (2026-08-29, at the instigation of this store, from a public thread (@danbuildss, 2026-08-28) chased to the actual observable) — Added transfer-method-unrecognized: an accepts entry naming an authorization standard in extra.assetTransferMethod that no published client can build, leaving a buyer with a field they can read and nothing they can sign. Registered with the reading that produced it — this store had been reading extra.name and extra.version out of that object and stepping over the field that decides whether a signature is acceptable at all. ONE CLASS ONLY, DELIBERATELY: a door asking for permit2 or erc7710 gets no class, because naming a recognized method in the place the spec provides is not a defect. That case ships as an advisory (nonstandard-transfer-method), where a fact a buyer should read before signing belongs, and a register that called it a defect would be charging an operator for telling the truth about themselves.
- **v6** (2026-08-30, at the instigation of the keeper, ruling on a question this register raised) — transfer-method-unrecognized keeps its assertion, its falsifier and its repair hint unchanged; what moved is our_signal, from the advisory `unrecognized-transfer-method` to the check `transfer-method-signable`, because the v2 battery now FOLDS that reading into its verdict rather than carrying it beside one. A reader joining our findings to another instrument's needs the pointer to name the signal that actually decides, and after 2026-08-30 that signal is a check. Nothing about when the class is present changed: falsified_by remains the only authority on that.
- **v7** (2026-09-01, at the instigation of the keeper, on reading a competitor's pitch (x402 Trust, x402.fuchss.app) and asking why the failure it described had no name here) — Added payto-moved: the payTo a door presents for a network is not the one it presented the last time it was observed. Unpaid-detectable, and detectable ONLY ACROSS TIME — a single probe cannot carry it, which is why no battery folds it and no verdict moved: it is a property of a series, and the standing watch derives it at read time from the challenge_bytes every row already carried inside its signature, so no preimage changed and no old row means anything new. The pitch that named the shape is credited in sourced_by under the registrar-not-author rule: the observation was theirs to name first, and a vocabulary is worth less the moment it pretends otherwise. What the class does NOT say: why the recipient changed. A rotation and a hijack are the same observation from outside; the class asserts the change and never the motive, and the readout that reports it points at where the new wallet's own history can be read rather than reading it for you.
- **v8** (2026-09-02, at the instigation of this store, roadmap S8 (cross-surface consistency), after being caught by the same shape in its own published bundle on 2026-08-31) — Added two classes for a door disagreeing with itself inside one response — the first tier of cross-surface consistency, where the truth costs no second request. discovery-info-invalid: the bazaar discovery block does not satisfy the schema served beside it, which is the catalog's own listing rule and so a door absent from the catalog without knowing. offer-contradicts-challenge: a signed offer commits to a network, asset, payTo or amount the challenge's accepts do not carry, a signed promise of one price beside a challenge for another. Both unpaid-detectable from the bytes every probe already holds; both ship as advisories first (discovery-info-fails-schema, offer-contradicts-challenge) and fold into a verdict only under a later battery, by the keeper's hand. The catalog's copy differing from the live door and a same-origin surface differing from the 402 are the next tiers and are not classes yet: no signal reports them, and a class with no signal is a word with nothing behind it.
- **v9** (2026-09-02, at the instigation of this store, roadmap S8 Tier B, on the keeper's ruling that the paid audit reads the door's other surfaces always) — Added surface-contradicts-challenge: a machine-readable surface on the same origin — the llms.txt read by the published code-span convention, or the OpenAPI document's payment fields — names a different price for the probed path than the 402's minimum on its first rail; or the challenge's own resource URL serves a 402 whose accepts differ from the probed door's. Paid-detectable only: the reads cost two to four requests the free preflight and the census have promised not to make, so the signal is the surfaces section of the paid single-door audit and nothing else. The class is never present when the 402 moved between the audit's first read and its bookend, when a surface is absent or silent, or when the surface's number sits in prose — silence is not disagreement and prose is not read. The catalog's copy differing from the door is a fact about the catalog and stays out of the vocabulary.
- **v10** (2026-09-03, at the instigation of this store, roadmap C1 (the runtime workflow), on the keeper's word to take the channels in order) — Every defect class gains buyer_hint: what the buyer does when a door shows the class — refuse, keep the settlement reference, pay on another rail, wait — the other half of the remediation repair_hint has carried since v4. Additive only: no id, assertion, detectable line or falsified_by changed. The same rows now ride the free preflight report and the paid audit as remediation, derived from each failed check or raised advisory through our_signal, so an agent that has just read a named defect gets both halves without a second fetch. A hint is advice about a door, never a judgment about its operator.
- **v11** (2026-09-04, at the instigation of this store, roadmap V3 PR 1 (the second wire, read only), on the keeper's rulings of 2026-09-04: the x402 verdict keeps its meaning permanently, protocols_spoken carries the union, and implementation gets bolder) — Added the Machine Payments Protocol's challenge classes, one per Tier 0 check of the MPP battery that can fail (mpp-challenge-id through mpp-challenge-over-http), each unpaid-detectable and each sourced to the specification's own MUSTs in github.com/tempoxyz/mpp-specs at draft-00 — this store is the registrar, not the author. mpp-challenge-present is a check and not a class: a door with no Payment challenge is not defective, it speaks another wire. The MPP advisories (testnet default, unregistered intent, body not problem+json, x402-and-mpp) are advisories, not classes: none is a defect. Additive only; no x402 class moved.
- **v12** (2026-09-06, at the instigation of 0200project (github.com/0200project), who named the class by finding it in their own product and disclosing it unprompted; this store registers it as source, not author, at their agreement) — Added cleared-not-examined to EVIDENCE_LABELS, the second such label and the first since Cairn's. It goes there rather than among the defect classes on the register's own distinction: a defect class is a property of an ENDPOINT, an evidence label is the PROVENANCE OF A CLAIM about one, and this is a claim whose backing check never looked at the subject. Registered the same week this store found two instances of the same shape in its own instrument — a guard asserting `expect(true).toBe(true)` and a `payto-payable` naming its unjudged entries only in prose (both fixed, PR 527) — and stated here because a register carrying a class its registrar was exhibiting would be worth nothing. It also cost this store a house rule: 52 covered only the wrongful "no" until 2026-09-06, and the "ok" half is theirs.
- **v13** (2026-09-07, at the instigation of 0200project (github.com/0200project), correcting the falsifier they had supplied for v12, against the line in their own source rather than a description of it) — cleared-not-examined keeps its assertion and loses its falsifier. v12 read `checks.assessed_for` as the check's published COVERAGE SET; it is the check's SUBJECT — the principals whose exposure the statuses describe, the payer on a relayed transfer. The examined set is derived from that field, not equal to it: the `assets_moved[].to` whose `.from` appears in `assessed_for`. The v12 rule therefore MISFIRED ON THE COMMONEST SHAPE THERE IS — on a plain transfer `assessed_for` is [sender], the recipient was screened and is absent from the field, so the rule reported unscreened about an address the check had examined. A false reading, inside a label whose entire subject is the provenance of readings. Its author found it by RUNNING it rather than reasoning about it (a blocklisted recipient absent from `assessed_for` still raises the instrument's own drainer flag, which is only possible if it was screened) and disclosed it four hours after this register shipped the wrong version, unprompted and again unpaid. THE V12 TEXT, SO IT STAYS READABLE: 'Reading the check's own published coverage set — `checks.assessed_for` in the instrument that named the class — and finding the subject present in it. Any subject absent from that set is unscreened whatever the status beside it says. Exact on the three settlement shapes its author tested (plain, relayed, batched); it OVER-FIRES ON APPROVALS, where a spender is screened without any movement being involved, and that boundary is part of the finding rather than a caveat on it.' Two things this store owes the record. The v12 entry disclosed that WE HAD NOT RUN THE FALSIFIER, and that disclosure is the only reason this is a correction to a definition rather than an instance of cleared-not-examined in the register that named it — a passing claim about a subject its registrar never examined. And the approvals boundary is no longer an over-fire noted beside the rule but a shape the derivation does not reach at all, stated as such above.
- **v14** (2026-09-12, at the instigation of the x402 specification thread (x402-foundation/x402#3325 and #3437): aurumflux20's field read of ten money paths and the receiver obligation drafted from it; this store registers the class as source, not author) — Added re-challenges-spent-authorization: a door that answers a byte-identical, already-settled payment with a fresh payment challenge, so a buyer who lost the response is asked to sign — and pay — again. The thread's finding was that the double-charge defect lives on the RECEIVING side of a settlement response, and this store's launch check had been reading every non-2xx on its replay stage as a correct refusal, a 402 carrying new terms included; from this version the stage reads the answer four ways (served again, re-challenged, refused, unknown) and says whether it named the original settlement. replay-accepted is AMENDED in the same breath, and the amendment is self-implicating: its assertion since v1 read 'is refused', and this store's own till does not refuse — it answers the replay with the original purchase, charged nothing, naming its settlement (the paid-retry lane). By the letter of v1 the registrar exhibited the class. The assertion now reads 'is not served as a new sale: refused, or answered with the original purchase naming the settlement that paid for it', which is what the receiver obligation asks of a door and what a walk can observe from outside. Costs, detectability and the Cairn mapping are unchanged; Cairn's replay_rejected may count a re-delivery as accepted, and that divergence is stated here rather than hidden in the mapping. Beside the vocabulary, the scvd-defects package from 0.14.0 ships settlement-response fixtures and a reader (settlement-response-v1) for the other side of the same seam: what a SettleResponse lets a reader conclude, with the pending shapes as the negative control a naive reader fails.
- **v15** (2026-09-13, at the instigation of this store's own walk of a door on 2026-09-12, and StillOS Notary (stillosdigitalholdings.com), who confirmed the finding, generalized it on his own surfaces, and then corrected the class before it shipped) — Added advertised-version-unpayable: a door that answers a correctly signed payment, presented in the protocol version its own challenge advertises, with that same offer re-served — so the buyer that followed the instructions is the one that cannot pay, no money moves, and the door has no failed payment to look at. Found by paying: the walk presented an EIP-3009 authorization for the door's exact v2 terms and was answered 402 naming the v1 payment header. THE CLASS IS NARROWER THAN THE FINDING, and the narrowing came from the operator we found it on. The corrections are his and both are taken. First, the detector originally compared accepts[] whole, which would have scored clean on any door carrying a per-request nonce, expiry or rotating timeout — the more careful half of the ecosystem — so the comparator reads the five material terms (scheme, network, payTo, asset, amount) and lets everything else vary the way it already let the error prose vary. Second, the assertion does not reach the variant we cared most about and said so: a door that ACCEPTS the newer version, settles it, delivers, and logs nothing because its request log keys on the older header. Nothing buyer-side can observe that, so detectable: paid cannot reach it and this class does not claim it; the repair hint names it as a separate fault and buyer_hint tells a buyer their record may be the only one. The instrument ships with the controls he asked for before its first green was trusted — a positive case read off our own 2026-09-12 ledger rather than hand-built, a rotating-nonce case that must still fire, honest-refusal and re-quote cases that must not, and the rule that it never returns a quiet clean: `checked: false` is a different answer from `present: false`, because an instrument that reads nothing and reports fine gets believed. That rule is his too, from a chain instrument of his own that read zero revenue at 27 of 27 doors on a mistyped field name, failing closed and silent.
- **v16** (2026-09-15, at the instigation of this store, roadmap V3 PR 3, on the keeper's instruction to continue the paid MPP discovery comparison) — surface-contradicts-challenge gains a separately versioned MPP reader in surfaces.mpp. It compares the exact GET operation's advertised alternatives with each observed Payment challenge. All alternatives must conflict on at least one named field, and the compared terms must match at both bookends, before a difference counts. Dynamic amount, omitted currency, unresolved operations, failed reads and changing terms cannot create a contradiction. The x402 assertion and verdict are unchanged. The former assertion remains here: Every machine-readable surface on the door's own origin that names a price for the probed path — llms.txt by the code-span convention, the OpenAPI document's payment fields, the challenge's own resource URL — names the 402's minimum on its first rail. The MPP discovery reading is advisory and does not claim general conformance or that this store's till speaks MPP.
- **v17** (2026-09-15, at the instigation of the keeper, closing the half of v15 that was left open: a class marked detectable: "paid" whose our_signal named only a research ledger) — advertised-version-unpayable becomes obtainable. Its assertion, falsifier, costs and boundary are UNCHANGED; what moved is our_signal, which named `walkabout ledger: advertised_version_unpayable` — a file in this store's research directory. A class is marked detectable: "paid" to tell a buyer the finding exists on the other side of money, and pointing that buyer at our field notes tells them we saw it once. The launch check now reads every refusal on its settle stage rather than only recording the status: it compares the offer the door serves AFTER refusing a correctly signed payment against the offer it served unpaid, on the five material terms alone, and reports advertised-version-unpayable present, not present, or not checked. So the signal a reader joins on is now a stage of a paid instrument they can commission, with the ledger kept beside it because the research reading is still real and still reproducible. The comparator is the corrected one from v15 — scheme, network, payTo, asset, amount, with nonces, expiries and timeouts free to rotate — and it keeps the v15 rule that it never returns a quiet clean: a refusal carrying no readable challenge reads `not checked`, which is a different fact from `not present` and says so in the stage line a buyer reads.
- **v18** (2026-09-16, at the instigation of the keeper, completing separately versioned draft-01 core support) — Added an unpaid MPP observable-core finding under mpp-core-v1 and core draft-01. It identifies failed named checks, with unmeasured binding, registry and payment behavior separate. The historical mpp-v1 battery and its assertions remain unchanged.
- **v19** (2026-09-16, at the instigation of the operator of a POST-only endpoint this store had published not_ready, who asked for the exact method, URL, headers and timestamp our probe used) — `no-402`'s ASSERTION AND FALSIFIER CHANGE — the first time this vocabulary has narrowed a class because it authorised a wrong finding of ours. Both texts named GET: the class asserted a 402 "to an unpaid GET" and was falsified only by a 402 "to an unauthenticated GET". Every probe this store runs sent GET and nothing else, so a door that declares POST in its own OpenAPI, answers 405 to GET and serves a valid x402 v2 challenge to POST satisfied the class as written. It was published not_ready on its passport page, entered the corpus, and an automated note went to the operator's security contact naming the failed check. The class now asserts a 402 to a method THE RESOURCE ACCEPTS, and a 405 or 501 to the probing instrument's method now FALSIFIES a finding of this class outright. The old text stays readable above, per the append rule. Nothing already signed is re-scored: rows sealed under v17 were rendered under the criteria as they stood and stand as history. The repair hint gains the Allow header, because the door that caught us sends none and an indexer that reads Allow would have found it. Cross-instrument consequence, stated plainly: any instrument mapping to this class that probes with a single hard-coded method is making a claim v19 does not support.
- **v20** (2026-09-18, at the instigation of this store, the wording audit docs/MPP_OPENAPI_DISCOVERY_2026-09-17.md left open, on the day the native till opened on every HTTP door, the MCP door and the WebMCP bridge) — mpp-core-observable-invalid's buyer_hint no longer says this store's till does not speak MPP; it says the finding comes from an unpaid read, never a payment. No assertion, falsifier, cost, boundary, signal or source changes. The same sentence was reconciled on every MPP reading surface (battery, census, core, surface reads, passport rule, corpus, datasets) to one spelled-once note: no reading rests on a payment, and the till speaking MPP says nothing about the door read.
- **v21** (2026-09-28, at the instigation of the keeper, asking what the store does with the bounty board's reports beyond listing them: 'it feels I'm paying people to check doors I'm already checking and doing nothing with the feedback') — Added receipt-absent-on-paid-response: a door that settles the payment and serves the goods with no PAYMENT-RESPONSE header, so the buyer holds bytes and no proof of what bought them. Seven walker reports on four doors had said exactly this on the bounty board since 2026-09-08 — the one observation on the board that a free probe structurally cannot make — and the register had no word for it, so the reports were counted on one page and named nowhere. THE PROVENANCE IS STATED ON THE CLASS AND IT IS THE WEAKEST THIS REGISTER CARRIES: the signal is the walker's own report at the crowd-walked tier, recorded verbatim as their claim and never verified by this store, which saw neither the request nor the response. It is registered anyway because a class with a stated weak signal can be compared and strengthened, and a report with no class cannot; the launch check's settle stage is the paid instrument of ours that could carry it next, and the entry says so rather than claiming it. Detectable: paid. No operator, host or wallet is named. The host history now prints each crowd walk with this class beside a report that says the receipt was absent, and the board's findings name the class beside the count.
- **v22** (2026-10-05, at the instigation of the keeper's S8 v3 release verification) — Discovery/schema and offer/challenge classes now also map their v3 verdict checks through verdict_signal, retaining the advisory mappings and the same assertions. Repair guidance therefore labels a failed v3 check as a check. The discovery buyer hint previously said the door would not be found in an ingestion-built catalog; it now states possible rejection and explicitly unobserved ingestion. No historical signed report is changed.

Definitions are appended and never edited in place. A changed assertion is a new version with the old text still readable in the changelog, and every version records at whose instigation it moved. Outside instruments may author entries; where one did, the entry names them as author and this store only as registrar.

Machine-readable: https://scvd.store/defects.json — CC BY 4.0. Take the names; that is the point of publishing them.
