---
title: "Corrections"
description: "Things this store said that were not true, dated, with what found each one and the mechanism that changed so it cannot recur quietly."
canonical: "https://scvd.store/corrections"
url: "https://scvd.store/corrections"
---

# Corrections

Things this store said that were not true, dated, with what found each one and the mechanism that changed so it cannot recur quietly.

## Title

Corrections

## Summary

Things this store said that were not true, what found them, and what changed so each one cannot happen again quietly. Dated, in the open, and not summarised anywhere kinder.

## How to read

HOW TO READ THIS RECORD: each entry is one thing this store said that was not true, dated the day it was found, with how long it stood, who found it, and the mechanism that changed so it cannot recur quietly. What qualifies is a published claim that was false or overstated, not a bug nobody could have read; a bug that never reached a claim is a commit, not an entry. Entries are never edited after publication; a correction to a correction is a new entry under a new date, and the old one stands. Outside reports are credited as outside reports. Nothing here is summarised anywhere kinder, and the count going up is the system working.

## How things get caught

HOW THINGS GET CAUGHT HERE, which matters more than the list below: every claim this store makes about itself is walked by a test, and the build fails when a promise outruns the code. That machinery exists because of the first entry below rather than in spite of it — each correction added the check that would have caught it. So the honest way to read a growing list is not "they keep breaking things" but "the loop is short and it is running." A store this young claiming a clean record would be making the less plausible claim.

## What we cannot do ourselves

AND THE PART WE CANNOT DO OURSELVES, which the sixth entry below proved rather than suggested: a store cannot audit its own signatures on its own authority. That entry was invisible to four hundred and forty-six passing tests, and not by carelessness — every one of them checked a signature by calling the same code that made it, so a flaw in that code cancelled itself on both sides of the check and no quantity of the same kind of test could ever have surfaced it. It took somebody outside, holding nothing but a public URL and using their own cryptography library, to see that our certificates could not actually be verified. That is structural to self-verification anywhere, not a habit of ours, which is why the outside read is listed here as machinery and not as gratitude: it is the only vantage point that reaches this class of defect. Tests in CI now re-derive the signed bytes from the SERVED response and check them with the raw library, which is the closest an inside test can get to standing outside — and it is still not the same thing. If you hold something we signed and it does not check out, the mailbox is free.

## Scope

WHAT THIS IS NOT: a bug log. Ordinary defects get fixed and forgotten like anywhere else. This page is narrower and more uncomfortable — it is only for things the store SAID, on a surface somebody could read, that turned out not to be so. Every entry names what changed structurally; an admission without a mechanism behind it would read as an apology, and this store does not trade in those.

## What this record cannot show you

WHAT THIS RECORD CANNOT SHOW YOU: the entries below are written by hand. Detection is largely automatic — a delivery audit looks for settlements with no artifact behind them, an hourly walk compares our books against Base itself, and the build fails when a claim outruns the code — but every one of those raises an ALERT to a person, and a person then writes the entry. Nothing on this page is machine-generated, on purpose: a store that could auto-publish its own corrections could auto-phrase them. So read a quiet stretch carefully. It means nobody wrote anything down, which is usually because nothing happened and is not the same statement. The gap between the two is a human being, and if you want to check that human rather than trust him, the artifacts are signed and the chain is public: our books can be walked against Base by anyone, without asking us.

## Corrections

### 2026-10-22

#### What was wrong

Credit cash-out instructions called the signature the payment and said an unredeemed authorization could expire with nothing lost and be requested again. The artifact description also said nothing was owed after expiry. A signature permits a transfer; it does not prove receipt, and expiry alone does not resolve an underlying obligation. A lost response did not have a dedicated saved-authorization recovery path.

#### How long

Present in the source before this correction on 2026-10-22. The start of the affected period and any production loss have not been established.

#### Found by

Review of the earning and cash-out path while adding recovery for a lost authorization response.

#### What changed

The instructions and artifact description now distinguish authorization, expiry and received payment. Newly saved credit authorizations can be retrieved after a fresh recovery-only signature from the earning wallet, with their original bytes, nonce and expiry. Recovery creates no replacement and spends no newly accrued credit. Tests cover lost save replies, signer rotation, expiry, recipient binding and challenge-mode substitution. Older or unsaved authorizations remain unavailable through this path; an interrupted save is not treated as payment or permission to sign again.

### 2026-10-19

#### What was wrong

A confirmed batch_spot_check purchase recovered its certificate after an interrupted request, but its per-settlement record was missing. The recovery alarm completed accounting for MPP, not x402, and could retire after delivering the goods. The hourly raise could not restore evidence that had never been recorded. The sale's revenue and counter remained short until its certificate was backfilled and the next raise ran.

#### How long

Observed on October 19: the request hit a CPU limit at 10:09 UTC, the certificate was retained at 10:10, and the missing-record alarm first fired at 10:31. The authorized backfill ran around 13:29 and the hourly raise restored the sale's counters at 13:30. The precise interruption point and the omission's introduction date were not reconstructed.

#### Found by

The store's books-invariant alarm identified cert_9xdgjs3j6r. The keeper requested the repair and root-cause investigation. The retained purchase and chain receipt agreed on the payment; a regression reproduced a recovered batch certificate with no settlement record.

#### What changed

Confirmed x402 purchase recovery now retains its settlement record, including after delivery or when the goods require manual delivery. A failed write leaves a retry armed; successful recovery preserves the request's house classification and does not replay counter increments. Eligible counter floors still come from the hourly raise. The regression fails against the original recovery code. Public count provenance, the README and admin reconciliation explain this two-stage repair. The all-time one-count residue also documented on October 12 remains unresolved after subtracting the separate founding allowance; no counter was decremented to hide it. Historical journals without the request's house classification retain that evidence gap.

### 2026-10-13

#### What was wrong

The bounty picker treated exact USDC offers on the same chain as interchangeable and selected the cheapest before checking the payment mechanism. Bounty bty_af4ww9tx captured QuickNode's 100-unit Gateway/batched offer on Base, while our claim verifier requires an individual USDC Transfer from the payer to the captured recipient. The ordinary Base per-request offer quoted 1,000 units when rechecked. Our refusal guidance also incorrectly described price drift as the only possible cause of a transfer mismatch.

#### How long

The affected listing opened on 2026-10-12 at 20:54:19.529Z and remained open at the independent unpaid check on 2026-10-13 at 14:09Z. The wider number and history of affected listings have not been established.

#### Found by

A walker's private clarification before spending, followed by an independent read of the public bounty, the live unpaid challenge and the claim verifier. No paid QuickNode purchase was performed in that check.

#### What changed

Posting filters ordinary EVM USDC payment modes and token identity before choosing a price, refusing unsupported-only offers without opening a bounty. The affected listing is withdrawn on public reads and automated claims; its original terms and any already-paid history remain intact. The withdrawal directs anyone who already spent money to keeper review, without promising payment. Public instructions rule out a manual-transfer workaround and explain the supported chain evidence. Regression tests reproduce the cheaper Gateway selection and verify withdrawal, preserved history and fresh-term replacement. A replacement bounty requires a separate posting against a fresh compatible quote; this correction does not claim a successful merchant purchase.

### 2026-10-10

#### What was wrong

The store's shared buying copy and several guides said a delivery that fails takes no money at all, leaving nothing to refund. That widened a pre-settlement guarantee into an end-to-end delivery guarantee. Signing, storage and response delivery still happen after money can move. The delivery audit made the opposite unsupported leap: a leftover marker was described as proof that a buyer received nothing, even though its clearing write can fail after goods were retained.

#### How long

The ordering promise dates from the August 10 deliver-first amendment. Its pre-settlement protection did not remove the later failure window. The October 10 revenue review found the contradictory marker reading; the exact lifetime of each copied sentence was not reconstructed.

#### Found by

The keeper asked for a revenue and agent-readability review. Comparing the admin delivery report with retained purchase evidence exposed the marker inference. Reproducing an existing signing-outage test showed a settled purchase whose delivery journal still lacked goods, disproving the broader no-charge promise.

#### What changed

The shared ordering sentence now distinguishes failures before settlement from failures afterward and directs buyers to retain their original payment and recovery handle. Buying guides, item outcome contracts, the practice page, answer copy, OpenAPI and the installed skill use the corrected scope. The delivery audit separately reports markers explained by matching retained deliveries and keeps unavailable or mismatched evidence unresolved. The signing-outage regression test in test/purchase-reconciliation.spec.ts checks the public guidance while the purchase is settled with no retained delivery, then verifies recovery without another charge. MCP tool descriptions name the enabled MPP lane, and recovery guidance names handle locations and explains that not_established_by_this_record is not proof of non-delivery. Existing signed artifacts and transaction histories are unchanged.

### 2026-10-07

#### What was wrong

The monthly corpus page called the latest available signed week a reading at month end even while the month was open. The growth desk compared a running month's totals with the previous complete month and could declare the growth hypothesis failed, or label instruments as falling, before the month ended.

#### How long

The monthly corpus wording dated from its September 3 introduction. The growth desk's month comparisons were present before the keeper identified the unfinished October comparison on October 6.

#### Found by

The keeper questioned a failure verdict six days into October. Checking adjacent comparisons found the same period mismatch in instrument deltas and demand movements, and premature month-end wording on the public corpus page.

#### What changed

The growth desk labels the open month as month to date and withholds hypothesis verdicts, instrument deltas and rise/fall lists until the UTC month closes. Counts remain visible. The corpus page describes the latest available week, labels an open month, and returns month_complete in JSON and markdown, calculated outside the corpus cache. Signed snapshots and their counts are unchanged. Tests cover the open month, its final day and the UTC closing boundary.

### 2026-10-01

#### What was wrong

The welcome note called an unpaid challenge a payable 402 without stating the request method or separating challenge checks from paid settlement and successful delivery. The September 5 date repair stamped new probes correctly but still substituted the round or snapshot date for an older row's missing request timestamp. Agreement between derived dates did not make that substitution an observation. A passport with no cited modules could also publish an empty not_observed list despite the unpaid probe's limits.

#### How long

The welcome wording remained after the September 5 correction. Legacy timestamp fallbacks remained in outreach, host history, the tier index and routing exports. Original archived rows retain their bytes; a snapshot timestamp alone does not establish when an endpoint was requested.

#### Found by

David Batista asked for the timestamped method, raw challenge, freshness policy, and separate scopes for DELX Commerce, DELX Protocol, paid settlement and image delivery. Reading the retained image-endpoint row exposed the missing request timestamp; its snapshot date cannot substantiate the September 5 probe date in the email.

#### What changed

Outreach states the recorded method and full request timestamp, or explicitly says they are unknown, and limits the finding to unpaid challenge checks at the exact endpoint. Derived history, host citations and routing rows no longer substitute publication dates for missing observation dates. An undated latest reading cannot issue a usable passport. The passport summary and its HTML carry the exact request, recorded method, original snapshot and available raw-challenge link, with paid settlement and successful delivery explicitly untested by the unpaid request even when no evidence modules are cited. Refreshes retain their recorded method and do not inherit an older census capture. The eight/sixteen-day freshness thresholds are unchanged. Archived signed snapshots are not rewritten.

### 2026-09-30

#### What was wrong

Some reports described different populations as the same sales count. Monthly admin totals and the pulse omitted native MPP; the monthly rail series was x402-only without saying so; the stats method described per-item rows as uniformly raw even though native MPP house corrections were applied. A valid MPP reading could also cause stats to publish a network split after contradictory x402 counters had made that split unavailable. The rails chart included other recorded networks in its totals without drawing them. The pulse's percentage used recorded offers while its adjacent '1 in' explanation could use corrected offers. The store-month page linked dated JSON paths that returned 404.

#### How long

Present in the source reviewed September 29–30. The mixed-protocol scope errors matter once native MPP sales are recorded; the rate and dated-link defects predate this review. Their first deployed occurrences were not established by this pass.

#### Found by

The keeper's request to review admin and public reporting; local fixtures reproduced the discrepancies, including a dated report whose advertised JSON link returned 404.

#### What changed

The September 29–30 source repairs add separate combined and native monthly totals while retaining the x402 funnel, preserve the network refusal on contradictory counters, draw the other-network bucket, use one denominator for both rate expressions, and repair the dated JSON route. New monthly signatures carry the additional totals. Older signed records remain byte-for-byte unchanged and are labelled as not retaining combined monthly sales. Monthly rail history stays explicitly x402-only and before later house reclassification. The public-reporting regressions in test/public-reporting-review.spec.ts witnessed the failures before their fixes. This entry records the source repair; deployment and live readback are tracked separately in ROADMAP.md.

### 2026-09-30

#### What was wrong

Developer and authentication guides still described paid access as x402-only after native MPP checkout was implemented. Authentication metadata hand-listed networks rather than reading enabled checkout rails. A host corpus Dataset title said x402 even for MPP observations. Developer conventions denied reader-based Markdown negotiation and limits outside preflight, although both existed.

#### How long

Present in the September 30 source review. The exact first deployed occurrence of each stale description was not established.

#### Found by

The keeper's ordered reporting and discovery review, with local enabled/disabled checkout fixtures and rendered-page checks.

#### What changed

Guides, MCP discovery aliases and authentication metadata now derive native availability and networks from existing checkout declarations. Homepage inspection copy and schema share the observed-protocol scope and its limits; host Dataset titles follow the visible protocol title. Developer conventions describe actual negotiation and endpoint-specific limits. Regression failures were witnessed before the source repairs. This records local source changes; release, public readback and external indexing are separate gates in ROADMAP.md.

### 2026-09-30

#### What was wrong

The decline desk printed OURS beside eight missing-input codes — host, url, tx_hash, tx_hashes, mandate, tag, digest, confession — on the word of one client. `Mozilla/5.0 (research)` swept every input-taking door on the shelf six times between the evening of 2026-09-27 and noon on 2026-09-28, refused at each for its one required input with a payment header attached, and on the last sweep signed four payments of one unit against offers of 10000, 5000, 990000 and 500000. It named no job, so the machinery table could not catch it; it carried a signature, so the walk rule's own line — 'a settle or a decline is a wallet opened at the door' — said it was a buyer. It was therefore the one intent-bearing client the shared-reason escalation needs beside x402lint, vet402, StillOS or TrustprobeBot, and the fault column moved to OURS on that basis. On this desk OURS means money the store turned away, and a signature carried down the whole shelf in thirty seconds, then a probe of the amount gate, is not money. Same finding as 2026-09-16 (two crawlers is not a lost sale) with a client that does not admit what it is. Two smaller blindnesses sat beside it. A missing-input row kept the code and nothing about what DID arrive, so `node`, refused three times in ten seconds at spot_check on 2026-09-30 — the one buyer-shaped client on the page after the template fixes — could not be told apart as a stock client retrying the bare door or a caller that had learned ?url= on twelve doors and carried it to the one that says ?host=. And spot_check was that one door: the 2026-09-28 alias table covered urls, wallet and tx_hashes and left host, the only input-taking name with no sibling, to be refused for a hostname the buyer had brought inside its URL.

#### How long

The OURS verdicts ran from the first sweep on 2026-09-27 21:49 UTC to this correction, about three days on the live desk; the rule that let a signed walk count as a buyer is as old as the walk rule itself (2026-09-04), and whether an earlier walker with a signature moved a verdict before the sweeper is not recoverable past the index's 2026-09-06 floor. The arrived-input blindness is as old as the missing-input booking (2026-09-04). The host gap is two days old, from the 2026-09-28 alias table that did not include it.

#### Found by

The keeper, pasting the desk back and asking whether any of it was ours to fix. The 2026-09-28 desk entry had already put the question — is this string machinery? — and had framed the answer as a word to promote or not; the keeper's reply reframed it as the rule: should the desk read behaviour, and what if walkers are being handed wallets.

#### What changed

Three mechanisms, one for the rule and two for the smaller blindnesses. (1) THE WALK RULE IS AMENDED, not the table. lib/walkers.ts now reads the same rule off DECLINE rows — declineWalkersAmong: a client refused at WALK_MIN_ITEMS or more distinct doors inside WALK_WINDOW_MS is machinery by behaviour on the decline desk — and its doctrine line now says a payment that SETTLES is a customer's, and a client REFUSED at that many doors is walking with a signature. The desk's counts moved out of the per-row scan into a pass with the whole window in hand (tallyDeclines), the walk is taken over every decline the scan touched so a desk filtered to one door cannot lose it, and isNoiseFloor honours a row's walk width so every reader of the desk — the page, the buyers instrument, the open-for-business draft — draws the same line without a second test. The walker's rows stay on the page, still count toward whether an input is discoverable, and each says on its face how wide the walk was; they leave the column that means money turned away, so the shared-reason escalation reads them as machinery and needs a client refused at fewer doors to print OURS. The keeper's harder question — what if walkers are being handed wallets — is answered in the rule's own comment in three parts: a walker that pays and settles is a customer, unchanged; a walker whose wallet is refused at four doors inside a minute is a walker with a wallet; a walker with a wallet refused at ONE door is read as a buyer, deliberately, because that mistake costs one OURS and the opposite one costs a buyer the store learned to ignore. No user-agent string was promoted: 'research' is a shelf here and a word the Coinbase buyer used, and a bare word promoted is misclassified forever. test/decline-walkers.spec.ts pins both directions — eight refusals in a minute is a walk and three is not, an hour apart is not, the house never is, a walker beside a crawler reads discoverability only, and `node` refused once beside the same walker still turns the code OURS. (2) THE BOOKS KEEP WHAT ARRIVED. A missing-input decline now carries inputs_present — the NAMES of the query parameters or tool arguments the refused request brought, never their values, bounded to eight names of forty characters, with the house secret, the attribution markers and the MCP shelf selector left out — on both doors, and the desk prints them in an arrived-with column and in the row's reading; an older row reads not recorded rather than nothing. test/what-arrived-is-booked.spec.ts asserts the buyer's value is nowhere in the books. (3) spot_check READS A HOSTNAME OUT OF url. The alias table became a list of directed edges, and the one edge that derives rather than crosses verbatim is host from url, taking the URL's hostname; url is never read from host, so the twelve url doors are unchanged, and a url that is not a URL crosses verbatim and is refused under host's own rule, labelled as read from url. The 402 body names it under input_aliases and the listing's constraint says so; test/input-aliases.spec.ts and test/spot-check.spec.ts pin the derivation, the direction, that host wins when both are sent, and a paid spot check bought at ?url=.

### 2026-09-28

#### What was wrong

Open for Business, the weekly issue for sellers, read every counter under the month's key and printed the month to date as 'this month' beside a week's title. Two issues went on the shelf that way (2026-W38 and 2026-W39), so a buyer of the second paid for numbers that mostly repeated the first. Worse than the window, three sentences claimed what the counters could not see. The section on who reads the record counted any host with two or more reads as a repeat reader and printed 6,774 of 6,775 hosts as read more than once, with none of the 96,089 reads referred from a host itself and about fourteen reads a host: an unnamed fetcher walking every page, classed as an agent because the machinery table did not know it. The concentration histogram had been built on 2026-09-21 to tell exactly that walk from a return, names the weekly as a consumer in its own comment, and the weekly never read it. The number of the week and the went-well lead said a re-check over a week old came 'from someone other than the buyer'; the gap line under the same section says age says when, not who. And the lead on refusals named three reasons and left the largest bucket, 235 of 501 filed as 'other', unmentioned, most of it 400s keyed by a code and about no field at all.

#### How long

From the shelf opening on 2026-09-18 until this correction, across two published issues and every draft on the desk.

#### Found by

The keeper, pasting the desk's draft of 2026-W40 back and asking what could be honed. The 6,774 of 6,775 was the shape that gave it away, as the 287 on one field had on the refusal desk a week earlier.

#### What changed

Every writer the issue reads now bumps a week twin beside the month (lib/kv-keys.ts: a period is a month or an ISO week, and a week key gets its own prefix so the whole-prefix scans never see it), and the issue reads its own week and prints the days it counted, from the day the twins went live. A week the twins never saw is laid as not read and is never pressed onto the shelf. The reader section reads the histogram, publishes hosts at five and ten reads and the mean, and calls a walk a walk when nine in ten hosts sit at two or more reads; the operator clause appears only when a read was referred from the host itself. The number of the week stops at the age. The refusal lead names the 'other' bucket and the code that led it, and its disclosure line is derived from the census rather than asserted. The MCP handshake census goes through the machinery table the way refusals do. The settles are put against the 402s issued, per channel, as a floor and never a rate. Tests in test/week-twins.spec.ts prove each writer lands its twin, and test/open-for-business.spec.ts seeds a fixed week and witnesses each sentence red without the fix. The two issues already on the shelf are left as published, under the keeper's take-down lever; nothing on them is restated here as the week's figure, because a month to date is not a week and the twins did not exist to count one.

### 2026-09-28

#### What was wrong

The 2026-09-21 correction said every discovery document now carried buy_url_template, and the reading printed beside every missing-input decline since then has said a row dated after that fix 'is a client that had a buyable URL in every document it read'. Six documents did not carry it, and they are the ones a buyer is standing on when it decides to pay: the ladder rungs a free preflight or look hands back (launch_check, service_audit, conformance_watch, standing_watch, passport_refresh — every one of them wants ?url=), the paid examples on /how-it-works and the deeper reads on /doors (spot_check, the_case_file, provenance_check and the watches, all input-taking), the agent line in every room footer that sells a deeper read, the markdown twin of every item page, whose line marked buy printed the bare door and left the input to the house-rules prose four lines down, and the answer-engine copy at /what. Each of those handed an agent the bare door — a signable 402 followed by a refusal before the gate — while the desk's reading told the keeper the buyer had been given the right URL everywhere.

#### How long

The rungs, the room footers, the markdown twin and /what have named the bare door since each surface opened; the gap in the 2026-09-21 claim is seven days old. The keeper's second reading of the decline desk on 2026-09-28 found no real payment turned away — the missing-input volume was one full-catalog sweeper on a fifteen-to-forty-five-minute loop plus the conformance walkers the machinery table already names — so no money is known to have been lost to this, and the finding is the claim, not a sale.

#### Found by

Reading the desk's own instruction to its end again: it says to check what the buyer was actually handed before reading any row as a careless buyer, and the 2026-09-21 check had fetched the challenge and the catalog and stopped there. Fetching the rest of what a buyer reads between a free probe and a paid retry found the six.

#### What changed

The rung helper every ladder rides (ladderRung) emits buy_url_template beside buy_url, so the preflight, the look and the operator's statement carry it at once; /how-it-works, /doors and the room rungs emit the same key from the same function, and the room footer's agent line quotes the template rather than the bare door. The markdown twin's buy line IS the template now, with a required-inputs line naming each slot and the bare door as the thing that quotes and refuses; an input-less item's twin is byte-identical to before. /what's long-tail answers name the template. buy_url stays bare everywhere, for the probe rule. THE MECHANISM: test/buy-url-you-can-buy-at.spec.ts walks all six — the rungs by name, both JSON documents, every room that sells a deeper read, the markdown twin of every input-taking item and the answer copy — and asserts each carries the identical string the catalog and the 402's retry_url_template already carry, so the next document that names a buy door without its slots is the next red test rather than the next decline.

### 2026-09-21

#### What was wrong

Every discovery document this store publishes handed an agent a `buy_url` that, on the twelve input-taking doors, refuses the purchase it advertises. The requirement sat in `required_params` directly beside it — a SIBLING field the reader has to notice, cross-reference, and then act on by rewriting the URL itself. An agent that does the obvious thing with a field called buy_url gets a signable 402 and then a refusal before the gate. The bounded price-discovery row at /api/catalog/v1 was worse: it carries buy_url and has no required_params at all, so nothing on that document said the door needed anything. Four places already named the rule — the resource description, two extensions, the 400's repair block — and the reading on the decline desk still had to end 'the requirement is not discoverable where they are looking', because the one field an agent ACTS on was still the wrong URL.

#### How long

As old as the input-taking doors. The catalog has published a bare buy_url beside required_params since those items opened; the 2026-09-06 pass added required_params to the catalog precisely because seventeen listings named a price and a buy_url and never the input, and it added the sentence rather than fixing the URL.

#### Found by

Following the decline desk's own instruction to its end. The PAYMENT-REQUIRED header was fetched live from all twelve doors and carried the requirement every way x402 allows, so the publishing was ruled out — and x402 v2 has nowhere left to put it: ResourceInfo is {url, description, mimeType, serviceName, tags, iconUrl} and PaymentRequirements carries no input schema, both read off the installed @x402/core types. A simulated stock client then showed the whole shape in two runs: probe `?host=example.com`, sign, retry, 200 and delivered; probe the bare door, sign, retry, 400 and no money moved. The buyer path works. What fails is the URL the store hands out.

#### What changed

A URL that does not need the rule read. `buy_url_template` is the same door with its required inputs already in place as `<name>` slots, in the identical form the 402's required-inputs extension already uses for retry_url_template — a test pins the two to the same string, so no document teaches a different URL. It is emitted on every item in the full catalog and the compact input contract, equal to buy_url where nothing is required, for the reason routes/catalog.ts gives for required_params: one key, one type, never telling 'absent' from 'needs nothing'. On the bounded /api/catalog/v1 row, which has a size ceiling and no required_params, it is emitted ONLY where it differs, so its presence is itself the signal that the bare door will not serve. The refusal carries it too: a query-door 400 now hands back the URL to retry instead of only the field names, and its next_action says to buy that URL. The checkout steps say to buy the template, not the bare door. BUY_URL ITSELF IS UNTOUCHED AND STAYS BARE: a bare probe of it must keep answering 402 or every indexer and directory checker reads the door as dead, which is the regression of 2026-07-26 and again of 2026-09-11 — a test asserts both halves, that the template differs and that the bare probe still quotes.

### 2026-09-21

#### What was wrong

The avoidable-400s desk counted machinery as buyers, and /open-for-business published the total as a sentence about agents: 'N agents were refused before paying this month.' recordInputRefusal asked nothing about who was refused — no house check, no reader class, nothing — while every other recorder in the same file skips the house, and the settle signal beside it says why in its own comment: 'the family's own wallets would be the loudest voice in a signal this quiet.' In refusals the loudest voice is louder still. The month's figure was 1,053, of which 287 malformed ONE field at one door and 178 and 167 did the same at two others; a buyer does not malform the same field 287 times, and a census walking every door on a loop does. StillOS-payability-census/1.0 writes 'measurement, no payment attached' into its own user-agent and was counted in that number, because the machinery table held 'census-probe' and this client calls itself a census without the probe. The same lesson had already been learned twice on the decline desk next door, in the corrections of 2026-09-15 and 2026-09-16, one of which states the principle in the words that fit here exactly: no money was ever going to come from a conformance walker. It did not cross the gap between two desks in one file.

#### How long

From the day the desk opened until this correction. The published sentence carried the mixed figure for the whole of that period, and the keeper read it off the live page as a usability crisis, which is what surfaced it.

#### Found by

The keeper, pasting the live desk back — the avoidable-400s table and the decline desk one above the other. The decline desk below it named the very clients the table above had swallowed, which is what made the odd shape legible: 287 refusals on a single field beside a bot that announces it will never pay.

#### What changed

recordInputRefusal now classes every refusal with readerClass, the same classifier the receipt desk already used, and writes to one of two maps: refusal_organic for agents and browsers, refusal_machinery for self-identified machinery. Machinery is KEPT and published rather than dropped — whether a linter can satisfy an input contract is evidence about the challenge, and this store does not hide a denominator it has — but it is stated as its own number and excluded from the sentence about agents. 'census' is in the machinery table as a whole-word job name now, widened in place from the 'census-probe' entry that nearly matched and therefore matched nothing — but that widening is NOT this correction's doing and is not claimed as it. The decline desk found the same client on its own books the same day, took 'census-probe' to the bare word, and added 'no payment' beside it; that is the correction of 2026-09-21 on the sixteen declines, and this one inherits the table fix rather than making it. The mechanism here is the classifier split alone, which is what would still have been missing had the table been right all along: a desk can hold a correct machinery table and still publish machinery as buyers if it never asks the table who knocked. The old `refusal` map is retired rather than migrated: it mixed the two irreversibly, so every figure it produced is withdrawn rather than restated, and the desk reads the new pair from the day of this correction. Two tests in test/buyer-signals.spec.ts pin both directions and fail the build if either slips: one asserts a census and a linter refused at the same door land on the machinery map while a python-httpx client lands on the buyers', and one asserts readerClass calls a self-named census machinery, which is the near-miss that let this through. What this still cannot say is how many DISTINCT clients sent the rest; the rows keep no client string, where the decline desk does, and that remains unfixed and named here rather than implied.

### 2026-09-21

#### What was wrong

The decline desk's headline read '25 of 54 outside declines look like ours — money the store turned away', and told the keeper to fix the published requirements before anything else. Both halves were wrong by this date. SIXTEEN of those twenty-five rows were one client, StillOS-payability-census/1.0, which writes 'measurement, no payment attached' into its own user-agent, walked the same three doors twice in eleven minutes at two seconds a request, and, on the six of its rows that recorded a payer at all, signs from 0x…0001 — the ecrecover precompile, an address no buyer holds a key to. It sat in the intent-bearing column because the machinery table matched only `census-probe` and never the bare word `census`, and had no hint for a client that declares no payment in English rather than as `no-pay`. On a desk where OURS means money the store turned away, the largest single contributor to that number was a census that said in advance it would never spend any. The prescription was stale on top of it: the requirement HAD been put in the challenge on 2026-09-15, and the reading beneath every row still said it was not discoverable and that putting it there was the fix.

#### How long

The classification gap is at least as old as the window the desk can see: StillOS's rows run to 2026-09-20 and the decline index only began 2026-09-06, so how long it had been walking the doors as a counted buyer is not recoverable. The stale prescription is precisely six days old — the fix it asks for shipped in commit 893de95 on 2026-09-15 19:46 UTC and the reading was never updated to say so.

#### Found by

Reading the desk's own instruction literally. It said to check what the PAYMENT-REQUIRED header actually carries before reading any row as a careless buyer; the header was fetched live from all twelve input-taking doors and every one of them carried the parameter in the resource description AND a retry_url_template in the required-inputs extension. With the published requirement ruled out, the remaining question was who was still hitting the wall, and the biggest answer was wearing its own answer in its user-agent. Splitting the twenty-five rows on the hour that fix shipped says the same thing from the other side: six before it, nineteen after — but sixteen of those nineteen are the census, and python-httpx, which had hit this wall on five consecutive days up to 2026-09-15, hit it once more the next day and then never again in the remaining five days of the window. The fix worked. One client's double sweep was hiding that it had.

#### What changed

Two things, one for the count and one for the instruction. (1) The machinery table takes a sixth pass: `census-probe` is widened to the bare word `census` it always meant — the 2026-07-23 entry that added it already said 'trust indexes and censuses probing settled routes on a loop' — and `no payment` joins `no-pay` and `dry-only` as a declaration of intent written out in English. Both are bare words a machine chose for itself, per this table's standing rule, and the generic strings beside them (node, curl, python-httpx, axios, Deno) stay deliberately off, as every pass above says. StillOS's refusals stay on the page and stay in the shared-reason count, because the escalation deliberately counts the noise floor toward discoverability — what leaves is only the word OURS, which on that desk means money. Same correction as 2026-09-16 made for x402lint and vet402, applied to a client that declares itself more plainly than either. THE MECHANISM: test/census-says-no-payment-attached.spec.ts pins both directions — that this census and a bare 'no payment attached' read as machinery, and that node, curl, python-httpx, axios, Deno and a bare browser string still do not — so a later widening of this table cannot quietly swallow a buyer's SDK. The table still cannot move at all without a dated row in src/store/exclusions.ts, whose newest row pins its size and whose guard test fails the build otherwise. (2) The missing-input reading and the escalation note no longer prescribe a fix that shipped. They now state where the requirement rides — the resource description, the required-inputs extension, and the 400's own repair block — say that publishing it a fifth time buys nothing, and name what is actually left: a door payable only at a URL the buyer must BUILD, while the stock x402 loop probes the bare door, signs the challenge it got back and retries the same URL. The fault still moves to OURS on two distinct clients including a buyer, and for a better-stated reason: the shape of the door is the store's, not the client's.

### 2026-09-20

#### What was wrong

Host-history pages called their unsigned JSON summary the signed rows. The summary links signed corpus originals, but its tier, gap counts and combined timeline are derived context. A valid signature on one retained snapshot does not authenticate that whole view or the other weeks it cites.

#### How long

The wording is confirmed in the September 20 source read of the host page and its Markdown twin. The separate September 19 buyer cohort retained two handoffs that attributed unsigned history to signed evidence; this establishes the interpretation failure, not a causal link to one sentence.

#### Found by

Review of the retained buyer handoffs followed by a read of the host-history route and the focused verification guide.

#### What changed

Host JSON, HTML and Markdown now explicitly label the summary unsigned and point to the originals for verification; OpenAPI describes that scope. The buyer guide supplies the existing exact-subject command and explains dates, omitted rows and unsigned context. Tests execute the guide's command against signed and tampered fixtures and check every history view while preserving the original snapshot bytes. Native usability requires a separate qualified cohort.

### 2026-09-19

#### What was wrong

Host-row citations labeled a snapshot's publication time as the observation time, even when the row held an earlier observation date. The September 19 buyer capture named September 7 in the host history but September 18 in cite_json.observed_at. The comparison projection also omitted the row's separate observation date.

#### How long

The citation helper used publication time from its September 4 introduction; the mismatch is confirmed in the September 19 retained host response. The signed originals retain their dates and bytes.

#### Found by

Independent review of the September 19 directed buyer capture, comparing the retained host history with its structured citation and the shared citation helper.

#### What changed

Host citations now use the row's observation timestamp when present, and comparison results preserve it beside publication time. Snapshot citations and legacy rows without separate observation dates keep their existing publication-date behavior. Regression tests distinguish both dates across host JSON, Markdown, HTML and comparison output. No signed artifact is rewritten and no freshness window is extended.

### 2026-09-18

#### What was wrong

Two days after the 2026-09-16 correction that moved the probe's verb out of four door probes and into one file, this store's operator posted a list of five doors on the x402 specification thread (x402-foundation/x402#3249) as serving no payment challenge, and two of the five — stableenrich.dev/api/fullenrich/people-search and stableupload.dev/api/upload — serve a flawless x402 v2 challenge to POST and a 405 to GET. Both were probed with GET. Both also carry a valid MPP challenge (WWW-Authenticate: Payment) and an agent-identity challenge on the same 402, so a reader of the x402 channel alone would have called them 'no payment metadata' one layer up as well. This is the exact defect the 2026-09-16 entry corrected — a GET-only probe false-negativing a POST-only, spec-compliant door — except this time it was published on the spec's own thread rather than mailed to one operator, and a stranger caught it in seven minutes.

#### How long

The deployed free preflight, the census and the standing watch were already resolving the verb when the list was posted: re-run today, both doors come back ready, probe_method POST by fallback, protocols_spoken x402 and mpp. So the list was not produced by the corrected instruments as deployed, and this ledger does not claim to know which instrument or hand produced it — the keeper's note is the record of that. What IS established: a fifth GET-only reader of strangers' 402s survived the four-probe fix. The paid single-door audit's surface reads (services/surface-reads.ts) re-read the probed door's 402 as a bookend and read the resource URL the challenge names, and both sent GET and only GET since they shipped on 2026-09-02, so on a POST-only door the battery found the challenge with POST and the section beneath it filed the bookend as 'answered 405 with no parseable challenge' on the signed artifact. Sixteen days for that reader; two days between a correction that said 'the law lives in one file that all four door probes call' and the discovery that there were five. Rows and artifacts sealed before today stand as history; nothing is re-signed.

#### Found by

minia2auk, replying on x402-foundation/x402#3249 seven minutes after the list went up, with both doors re-curled: GET 405, POST 402 with resource.method POST in the payload. They also proposed the distinction this store had been missing in its own vector — that a wrong verb deserves its own state, NOT_EXERCISED, rather than a seat in the same bucket as a broken door — and named the second layer, the MPP challenge on the same response, that a single-channel census would have missed. The operator re-verified both doors independently before accepting either finding. The 2026-09-16 entry's found_by was an operator writing in privately; this one is a reader of the public thread, which is the direction rule 52 predicts these will keep coming from until the instrument stops making the claim.

#### What changed

FOUR THINGS, each a mechanism. (1) The fifth reader goes through the shared method law: services/surface-reads.ts now takes the battery's own ProbeMethodReading from the paid audit, the 402 bookend re-asks the SAME question the battery asked (same URL, same method, no fallback — a bookend that asks a different question cannot say whether the price moved), the resource URL read starts from the battery's method with the one bounded second look, and a method refusal on either is marked method_refused and rendered 'unreadable' with the gap named as ours — never 'silent', which is the state that means 'found, names no price' and was the false accusation in row form. The two document reads (llms.txt, OpenAPI) go through the same function with the fallback off, the shape discovery/host-probe.ts already uses, so the file carries no hard-coded verb at all. (2) The guard stops trusting its own list. test/bounded-read-honesty.spec.ts adds surface-reads.ts to the enumerated probes AND adds a sweep over every source file under src/: any file that reads a PAYMENT-REQUIRED header off a response it fetched with a hard-coded GET, without the shared law, fails the build. The enumeration was wrong twice (three, then four, then five); the sweep is the half that does not depend on anybody remembering. (3) The vector gets the state minia2auk proposed. checks_vector rows on a method_unresolved report are now not_exercised with refused_methods, instead of not_reached blocked_by status-402 — which was the prior output for an EMPTY check list and named, as the blocker, a check that had never run either. A reader dumping vectors into buckets had every reason to file that beside a real status-402 failure; now the row says 'this check was never asked, the door named the verb it wants, the gap is ours.' The OpenAPI schema carries the fourth state. (4) The offline census script (scripts/x402-census.mjs) stops excluding declared non-GET rows and stops saying 'one GET per host': it probes every row through the public preflight, which resolves the verb, tallies probe_method from each report, keeps method_unresolved out of the graded denominator, and prints a methodology line that says what was actually sent. Guarded by test: a POST-only door's bookend is read with POST and only POST; a refused bookend renders unreadable and never silent; a method_unresolved vector is all not_exercised with no blocked_by; and a POST-only door carrying both PAYMENT-REQUIRED and WWW-Authenticate: Payment reports both wires off the one response the method law resolved.

### 2026-09-17

#### What was wrong

Preflight's evidence ladder named The Night Watch as the instrument for L4-L6: whether paying a door produces the goods. The Night Watch makes unpaid structural probes. It does not buy from the observed door and cannot establish paid delivery. A cold buyer repeated the recommendation in its report.

#### How long

The ladder was introduced on 2026-09-16. The incorrect recommendation was still served during the frozen buyer run on the evening of 2026-09-17. That run spent no money; it does not establish that anyone bought the wrong instrument.

#### Found by

The directed cold-buyer acceptance run, followed by a review of the returned preflight and the recommended instrument's actual read class.

#### What changed

The L4-L6 recommendation now names The Launch Check, which attempts a purchase under its screening, authorization and spend limits. The reading states that an attempt can stop short and does not promise delivery or completion of every rung. The regression test in test/preflight-evidence-handoff.spec.ts checks both preflight batteries against the recommended item's purchase read class and its actual contract and unpaid quote. The original buyer evidence remains unchanged.

### 2026-09-16

#### What was wrong

The shared-reason escalation shipped the same morning moved a decline's fault to OURS whenever two DISTINCT clients hit the same missing-input code, and it counted the noise floor toward that two. So `local:input_missing:confession` read OURS on the strength of x402lint/0.1 and vet402-observatory-l1/1.0 — both already on the store's own machinery table, neither of which was ever going to pay. Beside it on the same page sat `local:input_missing:tx_hash`, escalated on python-httpx AND a crawler, which is a different claim entirely: there a client the store counts as a buyer was turned away. The page presented the two identically. On this desk OURS means, in its own words, 'money the store turned away', and no money was ever going to come from a conformance walker. The headline count was not inflated — noise-floor rows are excluded from it — but the verdict beside each row was, and a reader cannot be expected to re-derive that exclusion from the fault column.

#### How long

About six hours, from the merge of the escalation on 2026-09-16 until this correction. It was visible on the live desk for at least one reading.

#### Found by

The keeper, reading the live desk and pasting it back. The escalated rows were printed side by side, which is what made the odd one out legible: the rest named a client the store counts as a buyer among those refused, and this one named only machinery.

#### What changed

The report now carries outside_clients_by_reason beside clients_by_reason — the same map with the noise floor left out — and SharedReason gained outside_clients and machinery_only. The fault moves only when at least one intent-bearing client is among those refused. Where every client is machinery the row reads 'discoverability only', keeps the fault it had, and says in the reading that the finding is real but that none of these was going to pay, so calling it ours would borrow the word for money nobody was going to spend; the moment a buyer joins them it becomes ours in the same breath, and a test pins both directions. The machinery clause is scoped to the missing-input family alone, so the rail and v1-envelope readings — which annotate and never escalate — keep their own words. The discoverability count still includes the noise floor, because whether a crawler can find a required input is evidence about the CHALLENGE and always was; what changed is that it stops being counted as a lost sale.

### 2026-09-16

#### What was wrong

Every probe this store points at a stranger's x402 door sent GET and only GET. A door that takes POST answers 405, and the battery scored that 405 as a FAILED status-402 check — the published defect no-402, "listed, but serves no payment challenge" — against doors serving a flawless challenge one verb over. On 2026-09-08, round 2026-W37, the weekly census walked https://agents.suedeai.ai/api/gateway/topup, discovered through a public x402 directory listing, and published not_ready on its passport page and into the corpus. On 2026-09-14 the automated outreach step read that row, drafted a note naming the failed check, and sent it to the operator's security contact. The endpoint declares the operation as POST in its own published OpenAPI, and re-probed from here on 2026-09-16 it answers GET with 405 (no Allow header) and POST with 402 carrying a valid x402Version 2 challenge: scheme exact, eip155:8453, 1000000 atomic USDC, a canonical Base USDC asset, and a bazaar extension whose info.input.method reads POST. The verdict was a fact about our instrument wearing a finding about his door. The defect vocabulary did not catch it because the vocabulary said the same thing: no-402 asserted a 402 "to an unpaid GET" and was falsified only by a 402 "to an unauthenticated GET", so the class as published AUTHORISED the wrong finding.

#### How long

The GET-only probe is as old as the probe. The count that matters is not that: the same failure mode — a GET-only probe false-negativing a POST-only but otherwise compliant door — was flagged internally on 2026-09-11 against a different host and not acted on. Three days later a note went out to an operator on the strength of it. One published round carries the named host (2026-W37, walked 2026-09-08); how many earlier rounds and how many other hosts carry it is NOT known yet and is not estimated here — every not_ready whose only failed check is status-402 is a candidate, and auditSentNotes is being run over the hosts a note already went to so the next entry can state a denominator instead of an impression. Rows sealed before today were scored under the battery as it stood and stand as history; nothing is re-signed. W37 stays in the chain as walked and the corrected instrument publishes fresh rows beside it on the next walk.

#### Found by

The operator, Jason, who runs the endpoint. He rechecked it himself after our note, reported GET 405 and POST 402 with the challenge, pointed at his own OpenAPI declaring the operation as POST, and asked for the exact method, URL, headers, body, timestamp and discovery source our probe used — the question that made the answer unavoidable. Our own corpus row confirmed a bare unauthenticated GET with no retry. Outside eyes, on a defect our own house rule 52 has forbidden since 2026-08-25 and which our own 2026-09-14 note on scheme drift had already named in the exact words that fit here: "a verdict on our reader wearing a finding about their door."

#### What changed

The verb is resolved instead of assumed, and the law lives in ONE file (lib/probe-method.ts) that all four door probes call. FOUR, because the premise that one shared function backed every probing surface was wrong and checking it was the load-bearing step: preflight.probeOnce backs the free preflight, service_audit, conformance_watch and good_buyer, but ward-round.probeHost — the census, outreach, passport refresh, the long walk and the bounty board — carried its own hard-coded GET, and standing-watch carried a third. probeHost is the one that published Jason's verdict, so a fix proven only through probeOnce would have changed nothing that reached him. The fourth was found while fixing the other three and was in none of the scoping that opened this work: the PAID launch check omitted the method field entirely, which defaults to GET, so a POST-only door was not merely reported as serving no challenge — it was reported as unpayable by an instrument that never asked it to sell anything. Its verb is now resolved on the unpaid approach stage and reused verbatim by the paid presentation and the replay, because a payment presented by a different method than the one the challenge answered is not the same request and the whole artifact is the claim that it is. Grepping for the hard-coded string would not have found it; the structural guard now walks all four files. The resolution order: a method the feed or challenge DECLARED (declaredMethod, read off the discovery row the census already holds, costing no extra request); else GET; and on a 405 or 501 ONLY, exactly one more request — the method named in Allow when the door sends one, POST otherwise. Allow is read and is never required, because the door that caught us sends none. The published ceiling of "exactly one outbound request per call, ever" is now two, stated in preflight.ts, in single_probe_note, in the OpenAPI and in a new probe_method block on every report naming the method used, every method attempted, and where the choice came from. When every method is refused the battery emits NO checks at all and a new verdict, method_unresolved, says so: not ready, not not_ready, not unreachable — nothing was observed, and the gap is ours. Structurally, runChecks returns method_unresolved beside an EMPTY check list precisely so the `failed.length === 0 ? "ready" : "not_ready"` idiom every caller writes cannot quietly render it as a clean bill, which is rule 52's flattering answer in one ternary; every call site branches on it first. ward-round gained carriesVerdict(), asked once instead of `verdict !== "not_probed"` spelled out in eight readers, because a second non-verdict would otherwise have joined every public ready DENOMINATOR while never joining a numerator. The outreach desk will not draft a note from a method_unresolved row at all — not a softer note, no note. The standing watch freezes the resolved verb on the record so a seven-day series is 168 looks at one question, since canonicalizeProbe's field order is frozen and a signed row has nowhere to say the method changed; its unresolved ticks are counted under probes_method_unresolved and stay out of the ready/not_ready tally and the conformance drift set. The paid audit throws before its surface, rail and blacklist reads rather than binding an empty battery into a certificate. discovery/host-probe.ts explicitly passes fallback:false — a 405 on a fixed /.well-known path is an answer about the document, and the default is ON so the next x402 door somebody adds inherits the fix rather than the defect. The defect vocabulary goes to v19 (v18 was taken the same day by the separately versioned MPP core draft-01 work, which landed on main while this was in flight): no-402 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 the class outright, with a note to every consumer that an instrument probing with a single hard-coded method is making a claim v19 does not support. Enforcement extends test/bounded-read-honesty.spec.ts rather than starting a new file, exactly as the 2026-09-04 chain-reading correction did, because rule 52 already forbade this and only its enforcement was too narrow: the guard holds a POST-only door being found, a method refusal producing no check rather than a failing one, the naive ready idiom being caught, a document read NOT growing a fallback, and — structurally, per rule 46 — that none of the four door probes fixes its own verb again.

### 2026-09-16

#### What was wrong

Two facts the store computed and then threw away on every decline. (1) THE PAYER. A settle has written a payer row since the till opened; a decline never carried one, because gateSignals reads headers and query while the signer lives inside the base64 payload. So isHouseTraffic met every decline with no wallet to match — the third time this file has recorded that exact blindness, after CV's field run and the cold read — and the desk could not say WHO had been turned away. The store learned a buyer's address only if they got through. Worse: the store's own RECEIVING address is not in house-wallets.json (that file registers wallets that SPEND here), so a payment signed from the till's own payTo booked as OUTSIDE DEMAND, and the facilitator refusing it `self_send_not_allowed` was the only way the keeper ever heard. (2) THE DISAGREEMENT. describeMismatch has always built the whole report — which offer came closest, which field differs, and BOTH VALUES — and the 402 carried it to the buyer. The books kept a reason code with a field NAME in it and nothing else, so fifteen `local:requirement_mismatch:amount` rows from one client inside 48 seconds could not be told from a client that was one unit conversion away. AND a reading shipped the day before, on 2026-09-15, told the keeper to 'read the payer off the row before anything else' — advice for a field that did not exist.

#### How long

Since the decline instrument began. The payer has been absent from every decline row ever booked; the mismatch detail since describeMismatch was written. The bad advice in the self_send_not_allowed reading was live for one day.

#### Found by

The keeper, asking where in /admin to find three specific declines. The answer was that two of the three questions could not be answered from the desk at all, and that the reading pointing at the payer was pointing at nothing.

#### What changed

Both doors now book both facts. payerFromPaymentHeader runs at the decline site on the HTTP gate and the MCP door, so the payer rides EventSignals into isHouseTraffic and onto the row; mismatchSignal flattens the first FieldMismatch to three bounded strings (field, we_offered, you_sent) and books that beside it. isHouseTraffic gained a second wallet test: a payer equal to any of the store's payTo addresses on any rail is house, read off the secrets rather than through lib/payments so the metrics writer takes no import cycle. The direction of that error is the argument, the same way round as the HOUSE_AGENTS test: counting a self-send as house REMOVES it from the organic figures and understates the store, where counting it as a stranger inflates them. The desk grows a payer column and a disagreement column, and both read 'not recorded' rather than 'none' on rows older than this change, because the books cannot support the stronger claim. The self_send_not_allowed reading is corrected to name the classification rule and what genuinely remains to check, and its test now pins the new wording so the old advice cannot come back.

### 2026-09-15

#### What was wrong

Wallet Claims could locate a paid certificate after client state was lost, but could not return its original Spot Check observation. A buyer needed the old payment or private recovery handle despite having proved ownership of the paying wallet. OpenAPI also required a wallet response field that the route never returned; the actual field is address. Existing private-status and original-payment recovery could say completed while retaining the old instruction to give the keeper a week.

#### How long

Observed in the September 15 live buyer acceptance run. The first affected deployment was not established.

#### Found by

The keeper-requested buyer recovery audit after a cancelled response and a local test-journal overwrite. Expert reconstruction of an already-used payment recovered the observation without another charge; that was not a normal buyer recovery pass.

#### What changed

After wallet proof, POST /api/claims accepts an optional cert_id and reads the original retained transaction response. It checks payer, network, transaction, certificate and original signature, returns current evidence for the same human order, and honors recorded resolutions before old goods. Reads neither settle nor mint. Unknown and other-wallet certificates have the same refusal. Missing historical goods remain explicit gaps with keeper-contact guidance; unavailable storage tells the buyer to repeat a fresh wallet claim without paying. All three recovery paths now derive human-order status, message, completion time and evidence from the same response as the order page, so completed goods no longer carry the queued message. The list, OpenAPI, skill and guide explain the two-step recovery. Local signed-fixture tests cover configured EVM and Solana rails, HTTP and both MCP payment profiles, privacy, damaged records and original bytes. These checks do not establish live recovery on every rail or restore records never retained; release and live acceptance are separate.

### 2026-09-15

#### What was wrong

The OpenAPI contract declared the IETF RateLimit headers on EVERY response of the five metered doors — /api/preflight/v1, /v2 and /batch, /api/before-you-pay/v1 and /api/look/v1 — including their 400, 404 and 500. Those responses have never carried them: preflightUrl() returns its validation refusals before either probe bucket is touched, deliberately, because a malformed request never spent a probe. The prose said it twice more, on /developers and in the spec's own rate-limit note: "EVERY answer from it carries the IETF RateLimit fields". A client generated from the contract could reasonably read RateLimit-Remaining off a 400 and find nothing there, and a client that paced on it would have been pacing on absence.

#### How long

From the day withRateLimitHeaders() shipped, which hung the header refs on every status an operation could give, until 2026-09-15. The wrapper's own commit is the start; no earlier bound is claimed.

#### Found by

An outside agent-readiness scan, from the other end. It reported the rate-limit headers "documented in OpenAPI spec, but not observed on a live response" and gave a reason of its own — that the API requires authentication — which is not true of any door here: the preflight is free and anonymous, and it emits all five fields on a 200. What the scan had actually done was probe paths that refuse. Its conclusion was wrong and its observation was right, and the observation was the half worth keeping.

#### What changed

The contract now declares the RateLimit fields only on the statuses the limiter metered — the 200 and the 429 — and the two prose claims say so, naming the 400 as the case that carries none and why. The fix is the spec rather than the limiter on purpose: emitting a budget reading on a refusal would mean a KV read per malformed body, bought to decorate an error with a number the caller's own next successful call already carries. A contract states what the store does; the store does not grow work to match a contract nobody checked. The mechanism is a test, not a constant: test/openapi-rate-limit-headers.spec.ts walks every operation in the SERVED contract and fails the build if any response outside the metered statuses declares a RateLimit field, fails if none declares them at all (a guard that passes by finding nothing is not a guard), asserts a live 400 carries none of the five, and asserts both prose claims say what the headers do. METERED_STATUSES in routes/openapi.ts is the one set the wrapper reads, so a future metered door cannot be documented one way and served another without that test going red.

### 2026-09-15

#### What was wrong

The card rack on the front page, shipped 2026-09-14, offered "Ring the bell — free" as an ordinary link to /api/bell. That door is POST-only. A link is a GET, so the one free thing on the storefront answered a visitor with the store's own method refusal — {"error":"This door exists and takes POST, not GET."} — and on a phone browser it arrived as a download prompt for a 217-byte bell.json. Nothing was broken underneath: the refusal was accurate, the bell worked, and every agent using POST /api/bell or the ring_bell tool was unaffected. The only people it failed were the ones the rack was built for.

#### How long

From the card rack's deploy on 2026-09-14 to 2026-09-15, under a day. No count of visitors who hit it can be given; the store does not log who tapped what.

#### Found by

The keeper, on his phone, doing the first thing the front page invites a person to do, on 2026-09-15.

#### What changed

The bell is a room now: GET /bell renders it with a form, POST /bell rings it and renders the card you got with its face, its share button and its PNG — the same shape as the pack page, because a free card and a bought one deserve the same moment. POST /api/bell is untouched, so agents keep the door they have. The mechanism against recurrence is a guard that reads the app's OWN route table rather than a list somebody types: test/storefront-card-rack.spec.ts collects every path registered for POST and not for GET, then fails if any anchor on the storefront points at one. A typed list of known-bad paths would have repeated the original mistake one layer up. The guard was verified by reverting the href and watching it name /api/bell, then restored. The case that had asserted the broken href — which is how a full green suite shipped this — now asserts the room.

### 2026-09-15

#### What was wrong

A facilitator refusal arrives in two parts: a short reason CODE and a free-text message. The 402 got both — payment-gate's firstSuspect reads `${reason} ${message}` and can tell a buyer their wallet is probably short — but recordPaymentDecline was handed the code alone, and event.note kept only that. So the buyer got the diagnosis and the books got a stub. CDP's `invalid_payload` is overloaded across at least three different failures (a malformed payload, an already-settled nonce, and a verify-time revert from an underfunded wallet), and every reading in readReason written to tell them apart — revert, insufficient, expired, valid_after, replay — keys on words that existed only in the message. Those readings were unreachable from any booked row. The visible cost: a payment offered at /api/buy/hello and declined `invalid_payload` paged the keeper as 'UNCLEAR, needs a read — the signature did not verify', which is the catch-all at the bottom of readReason, while the 402 that same buyer received may already have named their balance. The $21 revert of 2026-09-01 got a reading written for it that could never fire.

#### How long

Since the decline instrument began booking a reason string. The revert reading added 2026-09-01 and the balance and replay readings older than it were all written against text the books never carried, so the gap is at least as old as those rules and probably as old as the desk.

#### Found by

The keeper, forwarding a live 'UNCLEAR, needs a read' alert and asking what to make of it. The alert was the evidence: its own wording is the catch-all reading, and the store had already sent the buyer better words than it kept for itself.

#### What changed

The message is now read down to ONE of a closed set of classes (revert, replay, insufficient, expired, valid_after) and rides the booked reason as a bounded suffix in the existing `+payload:` style — `invalid_payload+verdict:revert`. It is never booked verbatim: vendor English rewords without notice, and slugging it would put an unbounded string family into by_reason, which is the mistake local:sdk_threw exists to avoid. The class names are deliberately the words readReason's existing rules already match on, so a suffixed row routes to the reading written for it and no rule changed; a test pins each class to its reading, so renaming one without the other fails the build. Where the facilitator's message earns a class it OUTRANKS our own field note, because readReason checks `+payload:` before it checks revert and an advisory ERC-1271 signature note riding on an underfunded payload would otherwise bury the balance behind a signature fault. Both doors and both stages were changed together — the HTTP gate and the MCP door, verify and settle — because one door getting the good instrument is the failure this file has already recorded once.

### 2026-09-15

#### What was wrong

The decline desk published a fault verdict its own rule said was wrong, and published the rule directly beneath it. Every reading of a missing-input refusal ended 'the same thing from DIFFERENT clients means the requirement is not discoverable from the header alone, and that would be ours to fix in the challenge' — and readReason, which takes one reason string and cannot see a second client, had already hardcoded fault: buyer on the line above. The escalation could not fire however many clients hit the same wall. On 2026-09-15 the desk read 27 outside declines, all of them 'theirs', 0 house, while local:input_missing:tx_hash had been refusing three separate implementations at settlement_attestation for five consecutive days and local:input_missing:host had done the same at spot_check. The underlying cause was ours the whole time: required_params went out in the 402's JSON body and in a nonstandard bazaar discovery extension, and a stock x402 client reads neither — it decodes PAYMENT-REQUIRED, signs an accepts entry and retries. A buyer who did exactly what the protocol says was refused before the gate and then counted on our own page as careless.

#### How long

The missing-input readings and their unappliable rule shipped 2026-09-04. The discoverability gap is older: required_params has lived in the unpaid response body since the input-taking doors opened. The visible five-day run of one client (python-httpx/0.28.1, 2026-09-11 through 2026-09-15) is a floor and not a count — the decline index began 2026-09-06 and the raw scan is capped at 3000 rows, so how long it had been walking into this wall before that is not recoverable.

#### Found by

The keeper, reading the desk and asking what was worth double-clicking. No outside party reported it, which is the uncomfortable half: the clients this turned away had no way to tell us, and the page they would have shown us said it was their fault.

#### What changed

Two mechanisms, one for the cause and one for the blindness. (1) The requirement now rides the challenge every client already decodes: buyRouteDescription puts 'REQUIRES ?tx_hash= on the paid request' ahead of the pitch, in the description field, which in x402 v2 belongs to top-level ResourceInfo rather than to the PaymentRequirements entries a client echoes back — so it cannot widen the deep-equal that mints requirement_mismatch, and a test walks every menu item asserting each required parameter appears inside ROUTE_DESCRIPTION_CAP. The body, the extension and the probe rule are untouched; this is a fourth place to find it, in the first place anyone looks. (2) The desk now takes the count it kept asking for: readDeclines builds clients_by_reason and escalateSharedReasons rewrites the fault to 'ours' when two or more distinct clients hit the same missing-input code, naming them on the page so the reader can check the verdict rather than trust it. That count deliberately includes the noise floor — a conformance crawler that read our challenge and could not find a required input is evidence about the challenge whatever it intended to spend — while the demand columns beside it stay clean, and the house is excluded because family reading our own challenge proves nothing. readReason itself is unchanged and still stateless, because metrics.ts writes the keeper's page off it with one event in hand; the escalation runs where the whole window is. The rail and v1-envelope readings, which say 'DIFFERENT clients' for reasons that are not faults we own, are annotated with the count and keep their verdict.

### 2026-09-15

#### What was wrong

The 2026-09-02 rule is that a crawler this store names in robots.txt gets the PAGE when it states no preference, so an answer engine sending a bare wildcard receives the title, the description and the JSON-LD rather than a JSON body with none of them. That rule held in every negotiated room except one. /scorers called wantsHtml() with the Accept header and without the User-Agent, so every named indexer — OAI-SearchBot, PerplexityBot, Google-Extended, ora-agent and the rest — asking with `*/*` was handed JSON. The room it was wrong in is the worst one available: /scorers is the page addressed TO scorers and marketplaces, about how to pull, verify and cite this store's evidence, and the engines that would do the citing were the exact callers being served the one representation with nothing to cite in it.

#### How long

From 2026-09-02, when the named-crawler negotiation shipped and this call site was not updated with the others, until 2026-09-15. Thirteen days.

#### Found by

Not the scan that prompted the surrounding work, which never reported it. The nine landing pages that gained a markdown twin were added to test/crawler-negotiation.spec.ts to prove the twin had not cost the answer engines their JSON-LD — the position this store had just decided to hold. That assertion went red on /scorers, for a reason older than the change it was written to guard.

#### What changed

The call passes the User-Agent, as every other negotiated room already did. The mechanism is the test that caught it: crawler-negotiation.spec.ts now walks all eleven rooms with a real markdown representation and asserts, per room, that a named READER gets markdown and a named INDEXER gets HTML that still contains application/ld+json. A room that quietly stops handing an answer engine its structured data now fails the build, which is what the single-room version of this test could not do.

### 2026-09-15

#### What was wrong

This store published, in research/treaty-exchange-2026-09-11/README.md, that the claim binding on StillOS Notary receipt e851b71a…0329d799 was 'unreproducible by anyone, permanently'. That was not our observation to make. We had established only that we could not reproduce it from the claim text, and that the issuer told us the preimage was not stored and a field inside it had since changed. We turned an issuer's account of their own records into a permanent fact about the world, and put the word 'anyone' in it. On 2026-09-15 the issuer supplied the preimage: 827 bytes whose SHA-256 is 84310abb469fe44cbafe0710fafad24e204f94e262e48cb1df97bf961f4b60a6, exactly the claim_sha256 the receipt carries. It reproduces, by anyone, from bytes now published.

#### How long

Live from 2026-09-13, when the sentence merged in PR #666, to 2026-09-15. Two days on a public research record. No signed artifact carried the claim: it appeared in a research README and in the issue thread, not in any certificate, verdict or defect class.

#### Found by

StillOS Notary (stillosdigitalholdings.com), by producing the preimage we had said could not exist. The reproduction was then checked here with Node's own crypto against the published claim_sha256.

#### What changed

scripts/others-artifacts-guard.mjs is new and runs in `npm run gates`, so CI fails the build on this shape rather than waiting for the subject of the claim to disprove it. It reads every markdown file under research/ and docs/ and rejects prose that asserts a universal or permanent impossibility about reproducing or verifying something — 'unreproducible by anyone', 'permanently unreproducible', 'impossible to reproduce', 'nobody can verify'. Restoring the sentence exactly as it went out makes it fail; it also caught a second passage already in the tree. The only exit is to quote the phrase inside a passage that calls it wrong, which costs a retraction to use. What it deliberately does NOT flag is 'we could not reproduce it', because that is an observation and is precisely what we are allowed to say. The record itself now states only what we observed: that we could not reproduce the binding from the claim text, that the issuer reported the preimage unstored, and that it was later supplied and reproduces. verify.mjs was never wrong — it refused to pass a binding it could not check, and it hashed the supplied bytes without change. The defect was in prose, which is the one surface every derived-value guard in this repo was built to ignore.

### 2026-09-14

#### What was wrong

The shop window sold a buyer their own card, observed 2026-09-14. The window is the last five pressings pulled store-wide, so a wallet that had just opened a pack WAS the window: all five rows were theirs, and a pick minutes later was guaranteed to move one of their own five cards out of their binder and back into it for $0.49. Nothing was mispriced, nothing failed and the certificate was honest — the buyer simply paid half a pack for a transfer with no counterparty. On a store this young that was not an edge case but the default path: the first organic buyer who tried the window after their own pack hit it every time, and the copy invited exactly that sequence by putting the pack and the window next to each other on the shelf.

#### How long

From the window's first pressing to 2026-09-14. One purchase is known to have hit it, the walk that found it; whether any earlier buyer did cannot be established, because the store's books record a pick and its holder change and never recorded that both were the same wallet.

#### Found by

An agent walking the entire buy loop on 2026-09-14 on the keeper's own wallet — pack over hand-rolled HTTP, window pick over MCP, bell free — and reading its own receipts afterwards: "the window pick handed me my own Blue Door ... $0.49 to move my own card from my binder to my binder ... no first organic buyer re-fetches the window after their own pack, they'd feel burned."

#### What changed

Two guards, both above the settle line where the empty-window and twelve-hour-lock refusals already sat. assertWindowOpenFor refuses with charged:false and a reason by name when every pickable pressing on show is held by the picking wallet, and windowPick draws only from rows that wallet does not already hold — so a partial window sells the part that is somebody else's instead of refusing the whole purchase, and a buyer can never receive a card they already had. The free window door now returns each row's holder with a note saying to compare it against your own wallet, so the check is doable before paying rather than only enforced at the door; the shelf listing, the room copy and the published refusal guidance all say it. test/cards.spec.ts holds both halves: a wallet whose own pack fills the window is refused and left unlocked, and a mixed window sells the other wallet's pressing.

### 2026-09-14

#### What was wrong

Settlement Attestation independently matched a USDC transfer and a nonce anywhere in the receipt. It discarded the authorization's payer when deciding correspondence. A batch could therefore produce a signed SETTLED observation for a transfer belonging to a different authorization. Battery v2's binding could also claim authorization_nonce when the requested payer, recipient or amount failed to match. With only a nonce supplied, the report could select the first unrelated transfer or silently choose between multiple authorizers using the same nonce.

#### How long

Reproduced locally from the September 13 source. Battery v2's explicit binding field dates from September 11; the independent nonce/status check predates that field. The first affected deployment and production artifact count were not established.

#### Found by

The keeper-requested buyer audit: signed observations over adversarial batch receipts, wrong-authorizer and wrong-term cases, ambiguous nonces, malformed events and a signature-tampering check. These local tests spent no live money.

#### What changed

Battery v3 uses one shared canonical-USDC AuthorizationUsed/Transfer pairing reader for both the general observation's status and binding, also used by Launch Check. The nonce must identify one authorizer event immediately followed by its Transfer from that authorizer, with every supplied transfer field matching that pair. Unknown ordering, duplicate candidates and mismatches establish no binding. A payer distinguishes different authorizers' reuse of the same nonce. Signed binding.evidence records the reason and readable pair, including atomic amount and receipt positions. Discovery inputs, the practice guide and /attestation describe these limits and the older battery's caveat. The existing binding fixture was corrected from transfer-before-authorization and abbreviated event data to Circle's event order and ABI shape. test/attestation-authorization-pairing.spec.ts reproduces the failures and checks signatures against tampering. Historical signed bytes remain unchanged. This is a trusted-RPC interpretation of canonical USDC events, not a consensus proof, deployed-proxy audit, delivery claim, or repair of the separate purchase and settlement reconciliation readers. Live acceptance remains separate.

### 2026-09-14

#### What was wrong

Purchase recovery matched the original authorization and a transfer independently, so a different transfer in the same batch could establish paid status. Settlement Reconciliation could label a selected transfer no_discretion because the same payer used an authorization elsewhere in the receipt. General EVM Settlement Attestation also lacked receipt transaction, reported-chain and block/head validation; malformed provider answers could become signed settlement conclusions. The bundle reader treated a missing result as not found and let duplicate response IDs overwrite evidence.

#### How long

Reproduced locally against the September 14 source before this repair. The first affected deployment, affected production artifacts and live buyer impact were not established.

#### Found by

The keeper-requested follow-through: the actual purchase-recovery alarm, signed reconciliation outputs, malformed RPC observations, source-reversion controls, and HTTP/MCP purchase tests with local settlement fixtures. No live money was spent.

#### What changed

Both reconciliation readers now use the shared canonical-USDC AuthorizationUsed/Transfer pair. Recovery requires the original payer, nonce, recipient and atomic amount on that pair; signed reconciliation additionally checks the selected transfer's receipt position. General Settlement Attestation battery v4 validates EVM transaction identity, reported chain, recognized receipt status and safe block/head data; each bundle member is validated and missing or duplicate batch answers are refused. Explicit null remains a dated not-found observation, while invalid provider evidence cannot become a claim about money. New receipt refusals tell HTTP and both MCP payment dialects that this request submitted no payment, explain same-payment retry, leave temporariness unknown and do not invent a verification URL. Previously settled purchase failures retain their separate recovery handling. Current artifact descriptions point to this correction; historical signed bytes remain unchanged. The canonical-USDC interpretation remains dependent on the observed RPC evidence and recognized token event ordering, not a consensus proof or a guarantee about delivery. Separate Approval cap attribution and the Settlement Reconciliation reader's own RPC context are not repaired by these changes. Deployment and live acceptance remain separate from this local evidence.

### 2026-09-14

#### What was wrong

Settlement Reconciliation treated the largest same-owner Approval in a receipt as the selected transfer's observed ceiling, without establishing its spender or spending mechanism. It could override a correctly paired EIP-3009 fixed-value authorization, or invent an observed limit from a later approval. Its own receipt reader also lacked reported-chain, transaction identity, status and block/head checks. Wrong or incomplete provider evidence could become signed conclusions. The public report repeated the approval claim and described a missing ceiling as caller-supplied. A zero-match observation also contradicted its numeric count by saying exactly one transfer matched.

#### How long

Reproduced locally against the September 14 source after the separate authorization-pairing repair. First affected deployment and affected production artifacts are not established. This is synthetic evidence, not a claim that a live provider returned these faults.

#### Found by

The keeper-requested buyer audit: signed synthetic receipts, unrelated approvals before and after transfers, malformed provider context, HTTP and both MCP payment dialects, and unauthenticated recipient reads. Tests were run against the unfixed implementation first. No live money was spent.

#### What changed

Current reconciliation only reports an observed limit for the selected canonically paired EIP-3009 transfer. Approval co-occurrence establishes no spending cap; declared caps remain declared. It uses the shared chain and receipt-context validators before signing. Invalid evidence is refused before settlement with actionable same-payment retry guidance; explicit null remains a dated not-found observation on an established chain and head. Public product and verification copy now explains those limits. Zero-match prose now agrees with the signed count, with missing, empty and reverted receipts tested separately. Historical chain_same_tx_approval records receive a correction warning outside the signed object; their original signed bytes are not rewritten. Recipient guidance supplies exact primary signature bytes and historical-key lookup, and separates a valid signature from truth of a claim. These are local repairs; deployment and live acceptance remain separate. Neither the RPC checks nor the signature establish consensus, finality or delivery.

### 2026-09-14

#### What was wrong

Every link to this store posted anywhere social unfurled with no picture and no preview, and had since the day each page shipped. The cause was content negotiation: wantsHtml() served HTML to a browser and to a named search or AI indexer, and the JSON twin to everything else. A link-preview bot is neither. Twitterbot, facebookexternalhit (which is also Instagram and WhatsApp), Slackbot-LinkExpanding, Discordbot, LinkedInBot, Telegram, Reddit, Mastodon and Bluesky all send Accept: */* with a bot User-Agent, so all of them received a signed record with no Open Graph tags in it and drew the only preview they could, which was none. The store meanwhile promised the opposite in writing: the menu description, the buy_pack MCP tool and SPEC_RETURNS all said each card has "a page that unfurls wherever it is posted", the share sheet has been rendered at 1200x675 for precisely this purpose since the card table opened, and every card page carries correct og:image and twitter:card tags that no unfurler was ever shown. Nothing errored, so nothing reported it.

#### How long

From each page's own ship date to 2026-09-14. For the card pages, the share sheets and the share buttons, that is the whole life of the Paywall; for /design and the older rooms it is longer. No count of affected posts can be given — the store cannot see a preview that was never drawn.

#### Found by

The keeper, buying a pack with his own wallet and pressing the store's own Share on X button: "also no image included in the share on twitter part." The meta tags, the image and its content-type all checked out on inspection; the fault only appeared when the page was requested with a Twitterbot User-Agent, which returned 1,509 bytes of JSON.

#### What changed

SOCIAL_UNFURLERS is a new list in lib/crawlers.ts, kept separate from the indexers and the readers because the three want different representations for different reasons: an indexer wants JSON-LD, a reader wants prose, an unfurler wants meta tags. wantsHtml() now returns HTML for any of them on any Accept header. The guard is test/pack-page-and-unfurls.spec.ts, which asserts every name on the list gets HTML on */*, on a missing Accept and on an explicit application/json, and separately fetches a live card page as Twitterbot and requires og:image, twitter:card and twitter:image in the bytes plus a real PNG behind the URL they name. The pack page and the binder are checked the same way, since those are the two links a person actually posts. Ordinary agents still get the record: the negotiation was narrowed, not removed.

### 2026-09-13

#### What was wrong

The preamble of /llms.txt — the store's own front door for agents — told every reader that /llms-full.txt "serves this SAME document, byte for byte", that ours "has always been complete", that the alias existed only to spare a blind crawler a 404, and that it "is not a fuller copy and this file will not pretend otherwise". All of that was true when it was written and none of it was true when it was read. The index/full split shipped afterwards: /llms.txt became a 30,000-character map and /llms-full.txt the 159,000-character guide it maps. A reader who believed the sentence had no reason to fetch the full document, which is the only place most of this store is described — so the false claim cost exactly the readers it was written to help.

#### How long

From the day the index and the full guide became different documents until 2026-09-13. The split's own commit is the start; no earlier bound is claimed.

#### Found by

The keeper's ask to put the Paywall on the storefront and name the release wheel across the client-facing surfaces. Naming one more door pushed the index six characters past the convention's budget, and the paragraph read while hunting for characters to trim was this one.

#### What changed

The sentence now says what is true: /llms-full.txt is the complete prose this file maps, and this file is the index. The mechanism is a guard, not care — test/llms-modular.spec.ts asserts the served index does not contain "SAME document" or "byte for byte" and does contain the true sentence, in the same file as the older byte-equality test that had been silently contradicting the prose for a fortnight. The two guards now disagree loudly instead of quietly: one reads the bytes, the other reads the sentence about the bytes. Nothing else in the guide changed meaning, and the correction bought 85 characters, which is what paid for the new door.

### 2026-09-13

#### What was wrong

Launch Check battery v3 classified a 2xx replay naming the original transaction as redelivery without comparing the goods, and a 2xx without that reference as fresh fulfillment without establishing new work. It credited server errors as correct refusals and described the first authorization as already settled before independently establishing that fact. The delivery note repeated those conclusions, including claims of money taken twice or product given away. The separate seller-named transfer read did not correlate this walk's exact authorization and amount; payment_attempt.settlement remained unknown even when stronger evidence was available.

#### How long

Reproduced locally from the September 13 source. Battery v3 dates from September 12; the transfer-only reading predates it. No production recipient count, affected signed-report inventory or first affected deployment was established.

#### Found by

The keeper-requested buyer audit, using local seller responses, actual throwaway signatures, fixture RPC receipts with multiple authorizations, invalid UTF-8, capped streams and failure responses. These tests spent no live money.

#### What changed

Battery v4 binds a candidate receipt to the expected chain, transaction, canonical USDC contract, payer, nonce, recipient and exact atomic amount using the paired AuthorizationUsed and Transfer events. It reports confirmed, pending_finality or unresolved settlement separately from the broad transfer observation. Invalid chain/receipt identity or block evidence also prevents a confirmed broad-transfer label; unresolved reads do not earn a successful verification stage. Replay compares complete raw response bytes and publishes their digests and read limits: identical bytes establish byte recovery, changed bytes do not establish fresh fulfillment, and missing, empty, truncated or temporary-failure responses remain unresolved. A repeated transaction reference alone proves neither payment nor delivery. A fresh challenge establishes no second charge; the walk signs no new authorization and either presentation may have been the first settlement. The guide, note and specimen now state these limits. Current instrument caveats accompany the versioned defect vocabulary without rewriting its definitions or claiming its historical mappings establish these defects. test/launch-payment-binding.spec.ts and test/launch-replay-evidence.spec.ts reproduce the boundaries, serve and verify the signed evidence, and reject tampering. Historical signed records retain their bytes. This repair does not change the general Settlement Attestation product's older nonce-only classifier, verify a linked artifact's truth or usefulness, or establish live-chain behavior.

### 2026-09-12

#### What was wrong

The shelf quoted the same receiving wallet two ways. The doors Worker, which answers every unpaid knock on /api/buy/*, had its Polygon, Arbitrum and World pay-to secrets typed in lowercase; the store Worker had the same wallet checksummed. Nothing showed until 2026-09-11, when launch_check and opening_day began answering from the store: from then on thirty doors quoted 0xdd35… on Polygon and World and two doors quoted 0xDD35…, and the two store-answered doors offered no Arbitrum rail at all, because ARBITRUM_PAY_TO was never set on the store. x402-list diffs the whole accepts[] on every probe: at 02:38 UTC on 2026-09-12 its change feed recorded a payTo rotation and an Arbitrum removal for this store, it re-captured the envelope at 04:30 UTC, and its EIP-712 signability check — which had read pass on the 2026-09-08 capture — has read unknown since. Unknown is excluded from its ?signable=true results. Every EVM entry on the wire carried extra.name and extra.version the whole time; the credit was lost to a shelf that answered one question two ways.

#### How long

The two spellings existed from the day the secrets were entered (Polygon 2026-08-20, Arbitrum and World 2026-09-06) and reached the wire from the 2026-09-11 handover until this correction deployed. The Arbitrum gap on the store Worker persists until the keeper sets ARBITRUM_PAY_TO there; the store's own /rails page and its two 402s name what it accepts, so the gap is visible rather than hidden.

#### Found by

The keeper, reading x402-list's assessment on 2026-09-12: the EIP-712 row had gone from pass to unknown with no change to the domain fields. The store's own npm run doors:live read 31 of 33 doors as differing from discovery the same afternoon; x402-list's change feed supplied the timestamps.

#### What changed

Every EVM pay-to now passes through one function that checksums it (EIP-55) before it reaches a 402, the discovery accepts, or a bank walk, so two Workers with the same wallet typed in two cases quote one string. A test hands the helpers every spelling a keeper could type and fails the build unless the wire carries exactly one, on every EVM rail, in the terms and in the manifest. What code cannot fix is named for the keeper: ARBITRUM_PAY_TO must be entered on the store Worker as it is on the doors Worker, and the live parity instrument (npm run doors:live) is the check that both were.

### 2026-09-12

#### What was wrong

The public Launch Check verification guide named tx_hash_status confirmed, which the instrument does not emit, and described it as verified settlement. The actual confirmed_on_chain reading establishes a transfer between the named accounts, without correlating this walk's exact authorization nonce and amount. The guide omitted contradicted and unverifiable_shape, and pointed only at the current signing key without explaining historical keys. The delivery note also tested for the nonexistent confirmed value, so actual confirmed_on_chain reports fell through to a note saying the chain read had not confirmed a transfer.

#### How long

Reproduced from the served local report during the September 12 buyer repair follow-through. No production recipient count or first affected deployment was established.

#### Found by

The keeper-requested buyer audit: signed local reports with receipt, missing-receipt, malformed-identifier and unpaid fixtures, read through the public route.

#### What changed

The delivery note now accepts the instrument's status type and recognizes confirmed_on_chain without claiming exact purchase settlement. The guide derives every status name from a map checked against the instrument's type, explains finality and unresolved payment separately, and gives the exact signature-byte construction and key-history lookup. A valid signature authenticates bytes under a key; it does not establish the underlying claim's truth. Served-report regressions exercise the outcomes and a raw ed25519 check rejects a changed subject. Existing signed records keep their bytes. Exact authorization-to-settlement correlation and stronger replay interpretation remain open repairs; this change supplies accurate instructions, not those missing observations.

### 2026-09-11

#### What was wrong

For seven hours the HTTP purchase door answered a bare unsigned request to any input-taking item with a 400 field refusal instead of the 402 payment challenge. 25 of the 32 doors stopped answering the probe every stock x402 client, indexer and directory checker sends first. x402-list's checker counted 7 endpoints alive from 17:34 UTC and marked the store degraded; the store's own free preflight would have failed the same 25 doors on its status-402 check. The store was, for those hours, the inputs-undeclared defect its own vocabulary names.

#### How long

From the merge of PR #636 at 17:28 UTC on 2026-09-11 until this correction deployed. x402-list's per-check history is the outside witness: 32 endpoints found at 17:18, 7 at 17:34 and every check after.

#### Found by

An outside agent's standing watch on the store tripped at 17:42 UTC and traced the drop to the deploy; x402-list's public history confirmed the timing. The BUY-002 audit that motivated the change had itself recorded that a quote alone is not evidence of money loss and that changing bare probes to strict purchases needed a coordinated discovery/client transition, which had not happened.

#### What changed

The probe rule is back and narrowed to one predicate: an unsigned request missing a required input is a probe and answers 402, with required_params, required_params_note and input_contract_url in the body beside the signable terms. Every other request — signed, or unsigned with every required input supplied — is validated in full before terms, so BUY-002's protection for a buyer who composed a purchase is kept, and an invalid supplied input still receives a field refusal with no offer. A regression now walks every menu item through both Workers and fails the build if a bare probe answers anything but 402; a second walk fails it if a supplied invalid input ever produces payment terms. The published checkout contract declares bare_probe_answers_402 so a client can read the policy rather than infer it.

### 2026-09-11

#### What was wrong

Concurrent buyers could each pass the same human-queue or weekly-inventory count before either order appeared. Both payments could settle for the last available slot.

#### How long

Reproduced in the September buyer audit and local simultaneous-buyer tests. Those tests establish the race, not a production oversale count.

#### Found by

The keeper-requested BUY-035 repair, with signed fixture purchases across all checkout rails, both MCP profiles, HTTP and the Commission Desk.

#### What changed

New human purchases reserve a slot atomically before settlement. The original purchase identity and admission time survive fulfillment retries and week boundaries. Unknown settlement keeps its hold without a timeout; confirmed non-payment or completed work releases the open slot, and a completed sale still counts against its original week. Incomplete legacy inventory refuses new reservations. Old paid obligations remain owed. The migration depends on the existing ledger projection and does not prove the absence of undiscoverable historical obligations. Regression tests force simultaneous buyers through the old count, remove the reservation path to prove failures, and exercise payment uncertainty, recovery and week boundaries. No live payment or buyer callback was sent.

### 2026-09-11

#### What was wrong

The HTTP purchase door returned usable payment terms for missing or malformed required inputs under an older price-probe policy. A payment client could sign those terms and only then learn that the purchase could not be fulfilled.

#### How long

The bare-probe policy dated to July and was reproduced in the September buyer audit. Fixture tests establish the route behavior, not a production buyer count.

#### Found by

The keeper-requested BUY-002 audit and matching local requests through the store and doors Workers.

#### What changed

All HTTP purchase requests validate their inputs before usable payment terms. Price-only discovery stays free in the compact item contract and catalog, and field refusals point there. Valid buyer inputs receive the normal x402 quote; authenticated retained purchases still recover original goods. Client guidance now distinguishes free discovery from a purchase quote. Regression tests cover missing, whitespace-only and malformed inputs, signed-header aliases, free discovery and valid quotes through both Workers. No live payment or buyer message was sent.

### 2026-09-11

#### What was wrong

A malformed human-order callback could disappear after payment; a syntactically valid callback could name a private address, insecure scheme or the store itself. Completion POSTs followed redirects. Their outcomes were recorded on orders but omitted from buyer polling responses. Probe purchases also compared the store hostname without normalizing a DNS root dot, and HTTP catalogue/commission capacity refusals omitted machine-readable no-charge fields.

#### How long

Reproduced by the keeper-requested buyer audit on September 6. The earlier probe-target validator and callback outcome ledger already existed; their presence did not protect these purchase and polling paths. These local fixtures do not establish a production customer count.

#### Found by

The buyer audit, followed by signed local payment fixtures through HTTP and both MCP payment profiles and independent callback transport controls.

#### What changed

Supplied human-order callbacks are validated before payment and rechecked at dispatch using the public https URL policy. Completion POSTs do not follow redirects or retry automatically; callback.result and its policy are visible through the order URL and check_order, alongside the completed goods. Probe purchases compare canonical own hostnames. HTTP catalogue and commission capacity refusals now return capacity_unavailable and charged:false with their counts. The URL policy does not resolve DNS or claim DNS-rebinding protection. This repair does not reserve concurrent capacity or change the broader HTTP quote policy; those remain separate audit findings. No live payment or buyer callback was sent.

### 2026-09-11

#### What was wrong

Some accepted buyer text was stripped or shortened, including split Unicode characters. Price guidance disagreed with the shelf. Blessing and fortune words were outside the purchase signature, and human completions did not bind the accepted brief to the delivered work. Invalid optional observation constraints could be dropped, partially parsed or treated as a default declaration after payment.

#### How long

Reproduced by the keeper-requested September 6 buyer audit. Local fixture purchases establish these code paths, not a production customer count.

#### Found by

The buyer audit and signed local fixture purchases through HTTP and both MCP payment profiles, with independent signature and tampering checks.

#### What changed

Accepted buyer text is preserved with Unicode code-point limits and grapheme-safe badge clipping. Budget and receipt guidance derive prices from the shelf. New blessing/fortune purchases include a separate signed text envelope. New human orders sign the accepted commission; completions sign the exact deliverable digest and accepted-input commitment, with proof and body published together. Older orders disclose missing acceptance proof. Supplied observation constraints are validated before payment, while authenticated older purchases remain retrievable. These signatures prove correspondence, not the quality of human work; the broader HTTP quote policy and concurrent capacity reservation remain separate repairs. No live payment or human order was made.

### 2026-09-10

#### What was wrong

Ordinary purchase retries could fail checkout verification after the original payment expired or was spent, before reaching retained goods. HTTP and legacy MCP refusal instructions could replace a buyer's original key with the current minute's suggestion. Refusal copy also described this verification attempt as proof that no earlier payment had moved.

#### How long

The buyer audit reproduced these paths with local signed fixtures on September 6. Private purchase-status and wallet Claims recovery already existed; the defect was the ordinary purchase retry and its advice, not the absence of every recovery mechanism. No live customer count is established by these tests.

#### Found by

The keeper-requested buyer audit and a matrix that replays original signed payments after a verifier-policy refusal, without their original keys.

#### What changed

A recovery reader authenticates retained original purchases independently of current spendability and never submits payment or creates replacement goods. EVM and Solana signatures are checked locally; new verified payments also retain a one-way fingerprint for exact contract-signature recovery. Original goods, commission terms and signed resolutions remain retrievable; missing evidence remains owed. Refusals preserve a supplied key and distinguish this attempt from earlier outcomes. Historical records lacking both a usable signature proof and a retained fingerprint still need a private status handle, Claims where supported, or keeper resolution. Regression tests reject tampered signatures, recover original goods after verifier failures, and preserve unresolved obligations when storage is unavailable. The repair stores no executable payment bytes and makes no live purchases or refunds.

### 2026-09-10

#### What was wrong

The same-key retry promise did not cover concurrent fresh payment authorizations. Two requests could both miss the response cache and settle separately. Some purchase instructions also said idempotency could never refuse a purchase, although uncertainty must stop another settlement.

#### How long

The cache-only safeguard was introduced August 1; the buyer audit reproduced the race with local signed fixtures on September 6. This is a verified implementation defect, not a count of affected live buyers.

#### Found by

The keeper-requested buyer audit, followed by a controlled test that pauses one settlement while a second authorization arrives with the same purchase key.

#### What changed

New keyed purchases atomically retain one payment identity before settlement. Concurrent duplicates return the original purchase or its status; unavailable admission stops settlement. The claim persists beyond the response cache and survives object eviction. Tests cover every catalogue product, every configured fixture rail, both MCP profiles, HTTP, commissions and paid publications, plus lost storage replies and unavailable records. Historical purchases without a retained key association cannot acquire that missing history from this change. Expired authorization verification and lost recovery handles remain separate repairs.

### 2026-09-09

#### What was wrong

The ward's own-door check treated one ranked CDP search response as a complete inventory. Search returns at most twenty resources and declares partialResults when truncated; the check ignored that flag and called every other menu door missing. The admin ward, office and weekly alert then recommended another purchase to restore indexing. Presence was also tested against the whole response text, so a URL in another listing's description could count as found. The W37 reading's missing list did not establish absence.

#### How long

The one-query check stood through the W37 reading reported by the keeper on 2026-09-09. On that day's independent read, five of its thirteen supposedly missing doors were returned by individual URL searches. Eight individual queries still returned no resource. That later read does not reconstruct which doors the index held when the weekly round was sealed.

#### Found by

The keeper, asking why doors he had deliberately purchased twice were still reported missing; followed by a read of the current Coinbase search contract and public index.

#### What changed

Unreturned menu URLs receive individual urlSubstring lookups. Only a complete, parseable lookup can record a miss; failed, malformed and partial replies remain unchecked. Presence uses resource URL fields with exact matching. The admin pages withdraw legacy missing claims without changing signed bytes and provide a free current index check. Alerts and the office no longer prescribe repeat purchases. Price discrepancies carry both observed amounts and the index update date, while older records explicitly lack that detail. Regression tests reproduce truncated search, false presence from descriptions, unreadable targeted lookups and the old purchase instruction. Existing receipts and discovery metadata still need reconciliation for doors not returned; another payment is not the diagnosis.

### 2026-09-09

#### What was wrong

The hand-rolling notes called their payment envelope complete while omitting the quoted resource and extensions. The browser checkout omitted them too. Those fields carry discovery metadata: a payment can settle without them and leave the search listing absent or stale. Separately, the attestation bundle's published schema used a nested counted regex that JavaScript accepted but Coinbase's discovery validator rejected.

#### How long

The browser omission was present from its first implementation on 2026-08-26 until this correction. The notes and bundle schema were found on 2026-09-09. Retained bundle settlement responses from August 19 and 26 reported invalid discovery configuration; those generic historical responses do not establish which field was rejected then.

#### Found by

The keeper's report of repeat purchases still absent from search, followed by free endpoint validation, retained discovery-response and sale-record reads, and reproduction with Go's regex engine.

#### What changed

The browser echoes the quoted resource and extensions unchanged, and the hand-built-client example shows both fields. The bundle uses a compatible pattern with separate length bounds preserving its two-to-twenty hash limit. CI compiles the published schema patterns with Go, and a browser regression checks the submitted envelope. The free validation script now uses the documented request and distinguishes rejection from an unreadable or failed probe. These repairs do not establish that earlier payments carried metadata or restore existing index entries. The affected recent sale records name custom clients; their retained discovery responses generally contain no Bazaar status, and their submitted envelopes were not retained. No repeat purchase was made during this diagnosis.

### 2026-09-09

#### What was wrong

The corpus feed and several descriptions called snapshots Bitcoin-anchored without checking completion; the feed did so whenever a timestamp submission record existed, including pending and failed submissions. The corpus submitted its digests but had no follow-up pass to collect completed proofs. All six published entries still said pending in the September 9 read, although completed proofs were available from their calendars.

#### How long

The feed wording shipped September 3. The corpus upgrade gap was present from its first published snapshot, August 9, through the September 9 investigation. The captured snapshots retain their original signatures and digests.

#### Found by

A keeper-requested verification follow-through read every published corpus snapshot and queried its timestamp calendar. The saved inputs and independent Bitcoin-header checks are in research/verification-2026-09-09; the method is in docs/VERIFICATION_OBSERVATIONS_2026-09-08.md.

#### What changed

An hourly, bounded corpus pass retrieves completed proofs and retries failed submissions without changing signed snapshots. It counts unreadable and invalid records and reports deferred work. The feed states the stored timestamp status; the other descriptions distinguish submission from independent Bitcoin verification. The attestation specification also uses the shared package instructions and names the PQ experiment as outside production. test/corpus-anchors.spec.ts checks pending responses, failed submissions, tampering, bounded work and agreement between R2 records and KV pointers; the pending-feed assertion failed before the wording changed.

### 2026-09-06

#### What was wrong

The correction dated 2026-09-05, describing the machinery built after two operators corrected two of this desk's notes in one afternoon, said of the re-read: 'one press knocks again on every door a note went to and lays the current instrument's reading beside the row the note was drafted from.' It did not lay it beside that row. It laid it beside whatever row the LATEST weekly census held for that host, which is the same row only until the next census runs and then is a different fact entirely — after a walk, the comparison was this week's census against a live probe, a staleness check on the census rather than a check on the note. Worse, the disagreement rule compared one bit: ready against not-ready. A note that named `payto-payable` at a door now failing `amount-atomic` read AGREE, because both readings are not-ready — so the exact failure mode the re-read was built to catch, a note whose named finding no longer holds, was the one it was blind to. Both flaws shipped in the same commit as the sentence describing them, and the page repeated the sentence on the keeper's own screen.

#### How long

One day, 2026-09-05 to 2026-09-06, in the ledger entry, in the section heading and prose on /admin/outreach, and in the code itself. No wrong note was sent because of it; what it cost is a day in which the desk's own audit could have called a wrong note quiet and nobody would have known. The re-read had been pressed by hand a small number of times in that window, all against the census round that produced the notes, where the two comparisons happen to coincide.

#### Found by

The keeper, asking where the press was and then what happens when it disagrees — which made the desk read its own comparison aloud and find that it did not do what its own correction said. Not found by any test: the specs asserted the rule as written, and a test that pins the wrong rule passes forever.

#### What changed

The claim a note makes is now frozen on the ledger the moment the note goes out (OutreachEntry.claimed — the reading it was drafted from, its week, and the rails the door offered then), by the wire at send and by the stamp routes for hand delivery, and it is never overwritten. The re-read is held against THAT, and a note stamped before the field existed says on its own row that it is falling back to the census. The comparison is on the checks the note named, not on the readiness bit. The call is three ways: `agree`; `ours`, DERIVED from the retraction ledger when every check the note named has since been retracted, which needs no judgement and drafts the correction email itself; and `look`, everything else, which stays the keeper's because healed-since and ours are the same shape from outside a door. And it no longer waits for a press: auditSweep rides the half-hourly tick, five doors a pass, each door at most once a day, and pages the keeper with the drafted correction attached. It still sends nothing — rule 30 does not relax because a cron is in front of it. test/outreach-audit.spec.ts pins all three calls, the daily floor, and the drafted correction; test/outreach-desk-hygiene.spec.ts pins the freezing.

### 2026-09-06

#### What was wrong

Checkout gained Arbitrum and World, but secondary copy still described Base alone or Base, Polygon and Solana. The browser wallet indicator omitted the new EVM networks and its signature advice assumed one USDC domain name. The practice counter also called half a cent the cheapest price beside a cheaper shelf; the standards and dependency pages retained obsolete settlement-order claims.

#### How long

The remaining network-copy gaps were confirmed on 2026-09-06 after activation. The price and settlement-order wording predated this check; their exact introduction dates were not established. The payment offers and certificate signatures were not changed by this correction.

#### Found by

The keeper reported a successful browser-till purchase, cert_et6zuesrrn, and pasted the surrounding practice-counter copy. A repository and live-response sweep found the same drift in receipt identity, discovery descriptions and dependency disclosures.

#### What changed

Browser network hints now derive from enabled checkout configuration, and signature advice compares with the selected quote. Static checkout descriptions point to current quotes; statement copy refers to its own network input contract. README, practice-counter pricing, receipt identity, discovery descriptions, trust, stack, standards and skill bundles were corrected together. The reported browser test and its limits are recorded in docs/BROWSER_CHECKOUT_2026-09-06.md; secondary-payment-copy.spec.ts checks the connected surfaces.

### 2026-09-05

#### What was wrong

After the rail double-count was reversed, the storefront's ledger line read '2 from before we logged the rail' — two organic settles the books held with no chain against them. They were not new and they were not unknowable: two settles counted at the till between the Solana door opening (2026-08-04) and the till learning to write rails down (2026-08-07T21:16Z), with no certificate to carry a rail, exactly the closed set /stats had described since August. The reversal did not create them; it stopped two double-counted Solana entries from silently standing in for them. The store's own rule for that set was a chain read against the transaction hash, and nobody had done the read.

#### How long

The two settles have been unplaced in the books since 2026-08-07. The line was visible on the storefront for about an hour on 2026-09-05, between the rail-seam press and this placement; before that the double count hid it.

#### Found by

The keeper, reading the front of the store and refusing the wording for the second time: 'we have already been through this.' The first time (2026-08-13) the unplaced sale was a July penny page, placed by the fact that Base was the only door then. This time both doors were open, so only the chain could place them.

#### What changed

The read was done. Every USDC transfer into the Base receiving wallet from 2026-08-01 to the rail meter's first tick was listed from the chain and matched against the certificate drawer. Exactly three outside payments in the window carry no certificate, all from one wallet, 0x42b3…029f, inside one minute on 2026-08-07: two of $0.005 (small_blessing's price, an item that mints a certificate — so two deliveries died after the money moved, the failure rule 9's settle-last ordering later closed) and one of $0.01 (a penny page's price, which mints none by design). The till counted two settles there; the books cannot say which two, and do not pretend to. Both placements are entered in RAILS_ENTERED_BY_HAND on Base with their transaction hashes as the evidence — the second entry cites both candidate hashes and says so — and the shape now allows exactly that: an entry is one placed sale carrying the hash or hashes that prove its chain, never a bare count. The storefront reads 25 on Base, 3 on Solana, and the remainder is zero. Not read: the Solana receiving wallet over the same window, because this session's network could not reach a Solana RPC; a certificate-less Solana payment in that window would mean one of these two placements is wrong, and the net statement's Solana inflow line is where it would show.

### 2026-09-05

#### What was wrong

The storefront, /stats and /rails read 5 organic sales settled on Solana and 0 from before the till logged the rail, when the books hold 3 on Solana and 2 unplaced. The same afternoon's repair, which books a settle the till never ran from its certificate, rebooked two Solana settles from 2026-08-05 and bumped the till's August Solana rail counter for both — but both certificates predate the rail-meter seam, so the certificate walk had already placed them. Two sales, four Solana entries. The organic total (28) was right throughout: the paid counter is the only organic count and it took each settle once. The rail split was wrong, and the identity check that guards it (base + solana + unplaced = organic) never fired, because two rail-less penny settles from the same August window were silently absorbing the surplus.

#### How long

From the press of POST /admin/repair/payer-settles on 2026-09-05, around 15:00 UTC, until the rail-seam repair is pressed after this ships — the front of the store keeps reading 5 on Solana until that press. Every surface that prints the rail split: the storefront's ledger line, /stats, /rails, the skill's track-record sentence.

#### Found by

The keeper, reading the front of the store against his own ledger: 28 organic with 5 on Solana on the page, 2 organic settles on the day in the office, and no idea where three Solana sales had come from. Not found by the books sweep, whose rail identity held by arithmetic accident.

#### What changed

The rebook stops at the seam: rebookSettleFromCertificate bumps the till's rail COUNT only for a certificate dated at or after KV_KEYS.railMeterStart, where the till is the rail record; before it, the walk is, and the repair reports the rail as left to the certificates (rail_left_to_certificates on the response). The money per rail is booked either way, since the net statement reads booked revenue against chain inflow and the walk carries no money. The two bumps already on the books are reversed by POST /admin/repair/rail-seam, which takes the transactions from the repair's own counters_rebooked list and checks each against the certificate on the shelf before moving a counter — a payer, a rail, a date before the seam, a settle record the backfill wrote — and writes a marker per transaction so a second press is a no-op. test/reconciliation.spec.ts holds both: a pre-seam rebook books the settle and not the rail, and the reversal moves one counter once and refuses a till-booked settle, a post-seam certificate, and a transaction no certificate names.

### 2026-09-05

#### What was wrong

The service-window check on /api/verify, shipped 2026-08-24 as 'layer 3' and described as closing the stolen-retired-key gap, answered `in_service` on the strength of the date the artifact carries — and that date is the one field a holder of a stolen retired key chooses. A receipt minted today, dated inside a retired key's window, citing a real settlement from that window and signed with that key, read `in_service` with prose that placed it inside the window as if the placement had been checked. The check caught the careless forgery (dated after retirement) and passed the careful one. The store's key log, which the /attestation page offered as the Bitcoin-anchored half of the answer, bounds when a handover was ANNOUNCED and says nothing about when any artifact the retired key signed came to exist; the settlement transaction inside each receipt gives a not-before and nothing gave a not-after.

#### How long

From 2026-08-24, when the window check shipped with that description, to 2026-09-05: twelve days on every certificate verify response, and on the /attestation page's framing of the key log for the whole time it has been anchored.

#### Found by

navigatorbuilds, an outside reader on the x402 settlement-attestation-receipt thread (coinbase/x402 PR 46), replying to CV's description of the anchor log: the log's existed-by bounds the announcement, not the artifact, so 'a key that appears having already issued artifacts is a compromise' is only decidable if the artifact's own existence is bounded, and the honest verdict without that is 'signed by a key that was once current'. Not found by any test here: test/key-window.spec.ts forged the shape the check catches and never the shape it does not.

#### What changed

Every certificate's signed bytes are now digested and submitted to OpenTimestamps by the hourly sweep (services/certificate-anchors.ts), upgraded to a Bitcoin attestation, and the block height is read off the completed proof. /api/verify serves it as `existence`, with the digest compared against artifact_hash on the same response and a five-state verdict that never collapses: a bound on or before the key's retirement is 'signed while the key was current'; a bound after it is 'issue time unproven' — the shape of every receipt anchored on backfill AND of a stolen retired key, which the artifact alone cannot tell apart, and the verdict says so instead of guessing; no bound yet is 'unproven', never a pass. The artifact's own date is not an input to that verdict. Receipts minted before 2026-09-05 were anchored on backfill and carry the weaker verdict permanently. The /attestation page's line on chains now says what the per-receipt bound does and does not add. test/certificate-anchors.spec.ts holds the walk, the proof parse, the block lookup, and the verdict on each key state, including the careful forgery.

### 2026-09-05

#### What was wrong

The passport chip — the one artifact this store asks operators to paste into their README — drew its own text on top of itself. Two runs shared the top baseline with no width budget between them, so on any host with a tier the label ran through the freshness and date: `SCVD PASSPORT · INDETERMINATE` overprinted `FRESH • 2026-09-01`, illegibly, and the two words a reader could pick out of the wreck contradicted each other. On the line below, the hostname ran through a verify URL printed at the right edge. The share card that a pasted passport link unfurls into had the matching problem of kind rather than of overlap: a 5x7 hand set enormous on a blank field, which reads as a terminal dump rather than as a document. The keeper, looking at a live chip: "why would anyone post this on their readme."

#### How long

The chip has rendered at /badges/passport/{host}.svg since 2026-08-21 and gained the tier on its face on 2026-09-02; from that date any host with a tier — which is every census-observed host — drew the overlap. Three days, on every chip anyone had pasted, plus the passport page's own To Share block. The share card has looked as it did since 2026-09-02. No verdict was wrong: this is a defect in what we published, not in what we observed, and it is in this ledger because the ledger is where things this store put in front of people that were not fit to be there get dated.

#### Found by

The keeper, opening a live chip for bykaranteli.com and the share card on the same passport page.

#### What changed

SVG text does not wrap and a Worker cannot measure a glyph, so every label in badge-svg.ts had been placed at hand-picked coordinates and hoped. A character count could not have caught it either — the old fit was host.slice(0, 34), and WWW.EXAMPLE.COM is nowhere near the width of illinois.io. So there is now a width estimate by glyph class (textWidth) that errs WIDE on purpose, a fitter that truncates to a stated budget (fitToWidth), and the chip's geometry lives in CHIP_LAYOUT with every budget DERIVED from it rather than typed twice. test/chip-geometry.spec.ts walks every drawn run against its budget for the inputs that actually break a layout — the longest registrable hostname, the widest possible caps, every freshness word, every tier — so an edit that moves the seal without moving the budget fails in the suite instead of on somebody's front page. The chip was then redrawn as a letterpress label: one hairline frame with squared corners, a struck seal, tracked small caps over the host over one record line, and printer's inks rather than a dashboard's greens. The tier's word no longer rides on the face when it is `indeterminate` — that is a statement about how many rounds we hold, not about the door, and it had been the loudest thing on a chip whose own decision was READY. The share card was rebuilt on a coverage buffer with a 6x9 engraved alphabet, proportional metrics, and a certificate's frame, rules and seal; it encodes as a sixteen-step indexed PNG so the type is inked rather than tiled. A third pass then gave the chip a SPINE inked in the freshness colour — a cream label is quiet on a light page and invisible in a row of shields, and the chip now carries its own contrast onto any background while an expired reading goes visibly dead rather than announcing it in six-point type. A long hostname is no longer cut: fitHost walks a size ramp and sets the whole name smaller, mutes everything before the registrable domain so the eye lands on the name a reader knows, and only past the ramp cuts — from the FRONT, where the subdomains are. The seal is struck at a small angle derived from the hostname, so a chip renders identically every time and neighbouring hosts never sit at the same angle. A fourth pass, on the keeper's read that the result was still "second tier of five", made it a CARD at 400x110 rather than a 300px strip — the store's own copy calls it a colophon to paste beside your door, and a colophon is not a shield — and gave it the one visual language the artifact's own name implies: an engraved ground under the type, a seal with its legend set around the top arc, and the freshness STRUCK across the corner as an entry stamp carrying the observation date. The aspect changed with it, which an already-pasted embed cannot follow; every generator here emits the new dimensions from CHIP_LAYOUT rather than repeating them, and the keeper's desk carries the note. A contrast audit of that pass then found the design had walked into a WCAG failure while nobody was measuring: the secondary tone, #8a7b64, sat at 3.69:1 against the paper and was carrying BOTH small runs — the eyebrow and the record line — on an artifact we ask other people to embed, where their own accessibility audit would have failed them for our defect. It is #6f6250 now, at 5.31:1; the expired stamp's date was at 4.36:1 purely because it was set at 0.9 opacity, so no run of text on the chip carries a fill-opacity at all any more; the two runs a reader is meant to read went from 7px and 8px to 8px and 9.5px; and the seal's ornament is a drawn path rather than a ◆ set in a font, which some platforms give an emoji face. test/chip-contrast.spec.ts walks every ink against the paper at 4.5:1 and fails the build under it, because contrast is arithmetic and arithmetic belongs in a test rather than in a review note. A fifth pass answered the last of the keeper's read — "I don't like the off white paper texture, I want premium... I see it on the page and I don't click, I scroll right past" — by naming the fault, which is not a taste one: a pale label sits at the same VALUE as the README around it, and equal value is exactly what an eye skips. The ground is now the forest-black the store's own favicon badge is cut from, under a gradient, with a lit rim and a shadowed one for the bevel; the frame and the seal are struck in foil; the eyebrow, the host and the stamp's date are set bold; and the seal holds the STORE'S DINOSAUR rather than the letters SCVD, drawn from the same path data the favicon draws, since a mark kept in two files is a mark that drifts. The share card follows onto the same dark ground with the same mark, which needed a scanline polygon filler and a path flattener in a renderer that until then knew only rectangles. Every ink was re-checked against the lit end of the new gradient before it shipped.

### 2026-09-05

#### What was wrong

Two notes went out by hand on 2026-09-05 and both operators wrote back the same afternoon with a fact of ours that did not hold. To 402signal.com: "got a response that no x402 buyer can pay: payto-payable" — drafted from the week's stored row, a payTo on an Algorand rail misread as unpayable by the instrument this store had corrected the day BEFORE (the 2026-09-04 entry below). The operator ran our free preflight and got ready on both batteries, three payable accepts. And "no x402 buyer can pay" is not what one failed check on one of three rails means even when the check is right. To tensorfeed.ai, a welcome: "On 2026-09-05 our weekly pass ... fetched" a door whose passport, linked in the same note, said observed 2026-09-01. Both notes dated the observation to the day the round was sealed, not the moment the row was read — the walk knocks in hourly batches across the week and Sunday only assembles, and no row carried its own time.

#### How long

The wire has re-probed every door live at press time since 2026-08-20 (rule 30's condition), so a note it sent was never a stored reading. The wire has been paused since 2026-08-26, and hand delivery — copying the card's draft, then the mailto: link of 2026-09-04 and the Gmail link of 2026-09-05 — drafted from the stored row for as long as the desk has existed. The seal-time date is older: every note and every welcome since the desk opened on 2026-08-19 carried the round's `at`, and every passport carried the corpus snapshot's `taken_at`, and neither was the knock. Two hosts are known to have received a note that was wrong in one of these ways; the outreach ledger holds which others were hand-delivered from rows of round 2026-W36.

#### Found by

Ross McIntyre of 402Signal, replying with the live preflight verdict, the live challenge, and the passport's stale state side by side; and TensorFeed.ai's operator, replying that the note's date and the passport's should be the same date "for a shop whose whole pitch is dated observations".

#### What changed

Three mechanisms. (1) The hand road walks the wire's law: a broken-door card has no note until the keeper presses verify live — one probe by the instrument as deployed at that moment (verifyProspect); a door that answers ready is stamped fixed and gets no note; a door that still reads broken has its reading written on the ledger, dated, with the battery that spoke, and handDraftFor drafts from that and nothing else. The Gmail and mail-app links render only while a reading under LIVE_READING_FRESH_HOURS old exists; past it the button is back. A batch button verifies the next ten and sends nothing. (2) The probe stamps every row with the moment it knocked (WardHostResult.observed_at, on the answered and the unanswered branch alike); the queue, the welcome, the subject history and the fresh set date a row by that stamp and fall back to the seal only for rows walked before it existed — so the note, the corpus row, the fresh set and the passport now carry one date by derivation, not by agreement. (The fresh set's own comment had said "per-row where the row knows it" for two weeks while reading the seal.) (3) The note's finding says what the check saw — "got an answer that did not pass our readiness check. What failed, by name: …" with the check definitions linked — and its subject names a failed check; "turning buyers away" is kept for doors that gave no answer at all. The re-check line carries the re-check's own timestamp. test/outreach-verify.spec.ts, test/outreach.spec.ts, test/ward-round-evidence.spec.ts, test/subject-history.spec.ts and test/fresh-set.spec.ts hold all three. Two more mechanisms exist because the keeper asked how the desk finds the NEXT wrong note before its operator does. THE RE-READ: one press knocks again on every door a note went to (auditSentNotes, ten a press, oldest first, sends nothing) and lays the current instrument's reading beside the row the note was drafted from; a disagreement is named at the top of the desk and never resolved by arithmetic, because 'healed since' and 'ours' look identical from here and only the keeper can tell them apart. AND THE STRUCTURAL GUARD (rule 46): test/one-date-per-observation.spec.ts asserts that neither the outreach page nor its routes can reach the raw drafter at all — the only road to a note runs through the live-reading gate — and that the note and the passport it links derive their date from the same field, so a surface that grows its own clock again fails in the suite rather than in somebody's inbox.

### 2026-09-05

#### What was wrong

The correction dated 2026-09-04, one line below this one, said that an EIP-3009 authorization nonce is a value 'no node will ever answer' — and 0200project, reasonably, drew the consequence in public: any ledger row keyed on the nonce can never be verified against the chain by anyone. Both were too strong. As a TRANSACTION identifier the nonce is unaddressable and the null lookups stand. But a nonce is indexed on chain: the settlement emits AuthorizationUsed(authorizer, nonce) on the USDC contract with the nonce as an indexed topic, and eth_getLogs on that topic answers it with the settlement transaction. Run on 2026-09-05, that lookup recovered settlement hashes for six of the seven rows this store had published, one day earlier, as unrecoverable. Each receipt has status 0x1, was mined within two seconds of observed_at, and carries one USDC transfer from the declared house wallet to the row's payTo for exactly amount_usd. The seventh — row 1, the very settlement we handed the other instrument for the cross-check — has no AuthorizationUsed on any contract in ±25 hours and no transfer into its payTo at all: on Base mainnet its $0.10 did not move. Its 'settled' was the door's word.

#### How long

The overstatement stood one day, 2026-09-04 to 2026-09-05, in the ledger's basis fields, its README, and two public comments on issue #188. The six unrecorded settlement hashes had been recoverable from public chain data since the moment each settled on 2026-09-02; nothing about them was ever lost, only unlooked-for. Row 1's unconfirmed settlement has stood since 2026-09-02 and stands still, stated now.

#### Found by

The keeper, reading 0200project's reply and calling its consequence 'a little extreme' — which sent us to check the consequence before agreeing with it, and the check found the lookup that both instruments had missed. Not found by any test: the guard shipped on 2026-09-04 held the schema, and the schema was right; what was wrong was a sentence about what the chain could do, and a sentence is what a schema guard cannot see.

#### What changed

Rows 2–7 carry settlement_tx_hash with a settlement_tx_hash_basis naming the RPC, the event, the block, the mined time against observed_at, and the transfer matched to payTo and amount. Row 1 carries settlement_confirmation: not_found_on_base_mainnet, a basis naming both negative searches and the chains not searched, and terminal_state_basis saying plainly that 'settled' is the door's report. scripts/walk-ledger-verify.mjs now reads every row two ways — as a transaction and as an authorization — and exits non-zero when a settlement hash did not spend the row's nonce, or when the chain shows a nonce spent that the row carries no settlement for: the chain knowing more than the row now fails the build, not a comment on a thread; test/walk-ledger-identifiers.spec.ts still holds the schema beside it. The README retracts the sentence by name.

### 2026-09-04

#### What was wrong

cert_a7qcdbh98v and cert_6fbvtpdwgu, a pair this store signed and sold on 2026-09-04, attest to nothing: their `attests` field is the sha256 of the empty string, a signed attestation over zero observations. Both signatures are genuine, and /api/verify answered valid: true for both, correctly and unhelpfully. WHY THEY EXISTED, since the entry beside this one says what the defect was: the store's two doors had grown apart. The HTTP door ran twenty-three pre-payment checks and mapped every query parameter into the till; the MCP door read a handful of arguments by name and dropped every other one its own published schema advertised. So the buyer sent two transaction hashes for a sheaf, the tool's schema accepted them, the till received none, observed nothing, hashed the empty sheaf, settled the $0.05, and signed. The buyer's money was real; the artifacts were void. Under house rule 56 both are withdrawn as evidence.

#### How long

Minted 2026-09-04, both inside one afternoon, on the deployed store while the fix sat unmerged on a branch. They stay on the wall as the record; they are withdrawn as evidence, and /api/verify says so on each.

#### Found by

CV, an outside agent testing the store on 2026-09-04, who bought the same sheaf twice, once over MCP and once over HTTP, and compared the two artifacts: the HTTP twin carried a real content hash and both settlements; the MCP one attested to the empty string, recognisable on sight.

#### What changed

The till refuses a sheaf of zero hashes before settlement, whatever door it came through, so no future door can buy a signature over nothing (test/round-two-integrity.spec.ts). /api/verify says, beside valid: true, when an attestation is the hash of the empty string, with the digest derived rather than typed, so an automated check no longer passes a void artifact in silence. And a knock never made is no longer signed as "unreachable": a target that is not a URL is a refused target on every probing door, and the deliverable says we did not knock.

### 2026-09-04

#### What was wrong

The x402 walk ledger carried one key, `authorization_or_tx_id`, whose own documentation read "the authorization nonce or settlement tx". Nothing in a row said which of the two a value was, and the two are opposite in what they permit: an EIP-3009 nonce is client-generated random bytes no node will ever answer to, a settlement hash is addressable by anyone with an RPC endpoint. Same shape on the page. On 2026-09-03 the store then published row 1's value into a public cross-check on issue #188 as "Transaction: 0x3e366c96…f794090 on Base mainnet" — a sentence the ledger's own schema never supported. It is the authorization nonce; `buildAuthorization` in scripts/lib/walkabout.mjs mints it as 0x + randomBytes(32) before the payment is signed, and the walker keeps the settlement hash in a separate field it reads off the PAYMENT-RESPONSE receipt. The ledger collapsed two distinct captured fields into one key and prose resolved the ambiguity in the wrong direction, in public, in the exact artifact whose selling point is that a reader can check it. The class was already ours: `nonce-unbound-from-settlement` has been in this store's public defect vocabulary since 2026-08-27 — marks the nonce spent without naming what spent it, sourced by SolomonisBlack — with the repair hint 'store the settlement transaction hash beside the nonce'. We wrote it, aimed it at other people's tills, and failed it on our own record.

#### How long

The union key from the ledger's publication on 2026-09-02 to 2026-09-04, across all seven rows. The mislabel built on it was live for one day, 2026-09-03 to 2026-09-04, on a public issue thread, and was the first thing an outside instrument tried to use.

#### Found by

0200project (base-tx-explain), from outside, inside 24 hours of being handed the identifier — in the cross-check this store proposed, doing exactly what a cross-check is for. They ran eth_getTransactionByHash and eth_getTransactionReceipt on Base mainnet and Base Sepolia, got null from all four, and ran a control hash from the head block through the same endpoint to prove the null was about our identifier and not their reach. Then asked whether it was a transaction hash at all rather than asserting it was not. No test here could have caught it: every guard on that ledger checked that fields were present, none asked whether a field's name could be read.

#### What changed

The rows carry `authorization_nonce`, `settlement_tx_hash` (null on all seven, so the absence is in the bytes instead of behind a union) and `identifier_kind` + `identifier_kind_basis`, which names the kind and what it rests on. Shape decides nothing — the two kinds are the same 32 bytes — so the basis is a chain read: both lookups returned null for all seven values on Base mainnet at head block 50879438 on 2026-09-04, with a control hash from that block resolving through the same endpoint, replicating the read 0200project made independently and first. It names its falsifier too: any node, on any chain, answering one of these values. scripts/walk-ledger-verify.mjs (npm run walk-ledger:verify) is that read, kept — it refuses to claim anything if its control does not resolve, and exits non-zero on a nonce that resolves or a settlement hash that does not. test/walk-ledger-identifiers.spec.ts fails the build if any row reintroduces a union identifier key, drops the kind or its basis, omits settlement_tx_hash, publishes one value as both, or names a settlement hash without a settlement_tx_hash_basis carrying a dated read; it was run red against the pre-fix ledger first and reproduced all four failures. The ledger README states the hole in the verify-it-yourself section rather than leaving a reader to hit it, and records the correction with the outside instrument named.

### 2026-09-04

#### What was wrong

The weekly walk published not_ready verdicts against doors that were payable, because two of its checks read every chain as if it were Ethereum or Solana. payto-payable resolved any unrecognised CAIP-2 namespace to the EVM branch: an XRPL classic address is base58 in a band that sits inside the Solana window, so a correct XRPL payTo was reported as "a base58 Solana address ... no buyer on this rail can pay this offer", and Stellar and Algorand addresses, being base32, matched nothing and were reported as neither an address nor a name service. amount-atomic applied the USDC atomic-units rule to XRPL issued currencies, which the ledger itself denominates in decimals, and told those doors that "0.01" underprices by a factor of a million. In round 2026-W36, 63 of 1,089 hosts walked failed payto-payable and 56 failed amount-atomic; every one of those 56 also offered a chain the desk could not read. The verdicts were signed and published against named hosts.

#### How long

One published round. The three checks were promoted from advisories into the v2 verdict on 2026-08-30. Round 2026-W35, walked 2026-08-24, carried zero such failures; round 2026-W36, walked 2026-09-01, carried 65, of which 61 hosts had read ready the week before. Before the promotion the same misreads existed but rode as advisories, visible and not verdict-changing. For the week the verdicts stood, the affected hosts’ passport pages showed not_ready and their README chips refused to render, since the chip publishes names only on the ready side. Round W36 stays in the chain as walked; the corrected instrument publishes fresh rows on the next walk beside it.

#### Found by

The keeper asked how to double-check an operator who had replied "I forsure know mine works". Running our own preflight against his door returned 7 of 8 checks passing and one failure, and the failure was ours: his XRPL address read as a Solana one. Reading the round for the same signature found 63 hosts, 3 of them on our own outreach list — we had written to operators about doors our instrument had misjudged.

#### What changed

familyOf now names xrpl, stellar and algorand and returns "unknown" instead of defaulting to evm, and readPayTo gained a fourth verdict kind, unknown-network, whose payable is null: not judged, never failed. l3bChecks threads that null through, keeps unjudged entries out of the verdict, and prints them beside the pass so the reading names what it did not judge. amount-atomic now judges amounts only on the rails this store settles on and has tested, EVM and Solana, and names every other rail's amount beside the pass rather than ruling on it — a first draft exempted only XRPL issued currencies and kept judging Stellar and Algorand on the same assumption that had just been wrong, and the rule-52 guard below caught it before it shipped. transfer-method-signable no longer calls a non-EVM method unbuildable, since the methods it knows are EVM signature standards. Rule 52 already forbade all of this; its enforcement walked only KV reads, so test/bounded-read-honesty.spec.ts now also walks the readers that judge strangers, asserting that no unrecognised chain can ever produce a "no". test/value-checks.spec.ts holds the three real doors that were misjudged, by their actual addresses, and holds a genuinely broken EVM door still failing both checks.

### 2026-09-04

#### What was wrong

The source register at /sources, and the ward page beside it, said the CDP discovery feed had never answered this store: status never_answered, roster_disagrees true, and on the keeper's page the line "Not answering: discovery." The feed had answered every one of the five rounds the register read. In W32 through W34 its paging served page one to every offset and the round kept 100 rows; in W35 and W36 it answered all sixty pages the read asked for, 6,000 rows, and declared more. The census rightly refused both as short lists, since a listing cut short cannot tell a delisting from a next page, and wrote null. The register, built the same day, had two words for a null, stale and never_answered, and neither means answered short. So a feed that had outgrown our read was published as a feed that was down, and the keeper read it as one.

#### How long

The register opened on 2026-09-04 and carried the word for part of that day. The read it described had been short for five rounds: page one only from W32, and capped at 6,000 rows of a larger listing from W35. Every round said coverage_suspect and its row count, so the shortfall was on the record the whole time; the word for it was not.

#### Found by

The keeper, pressing /admin/ward after the sweep shipped, pasted the line and asked whether everything else was done. Reading the five rounds back showed listed_resources at exactly 100 and exactly 6,000, the two shapes of a read that stopped, under a status that said nothing had ever come back.

#### What changed

The census writes WHY beside every null (per_source[].why: unreadable, capped or pagination), and the register gained a fifth status the same day, partial, for a feed that answered and whose short list the census refused; /sources and /admin/ward say it in words. The read itself no longer caps: the long walk's start firing was given a 300-page cap the same day, and past that the walk reads the feed across hourly firings on a stored cursor until the feed's own declared total is reached, so a listing of any size is read whole a few hours into the week. The walk's roster is capped at 2,000 feed doors, where the KV value that holds a week's evidence would otherwise fail near 3,900, and the round says when that binds; the census still counts every host the feed named. test/long-walk.spec.ts reads a feed larger than one pass over two firings and holds the cap announced; test/population.spec.ts holds that the reason rides beside the null and never beside an answer.

### 2026-09-04

#### What was wrong

The MCP door took a buyer's arguments, validated the arguments of a handful of items, and carried a short list of fields into fulfillment. Every other field an item needs to know what it is being asked about — `url`, `address`, `tx_hash`, `tx_hashes`, `wallet`, `digest`, `mandate` and the rest — was read off the wire and dropped before the goods were made. Three shapes came out of that one defect. good_buyer and launch_check each produced and SETTLED a signed artifact about the empty string: at $0.99 and $5.00 respectively, both on 2026-09-04: each probed "", folded the unreachable result into a signed reading exactly as they are built to do, and took the money — so the buyer holds two real, correctly signed observations about no endpoint on earth. attestation_bundle minted a certificate over an empty sheaf, settled, and then threw on its way out, leaving money moved, a certificate issued and a 500 in the buyer's hand, recoverable only via /trust if they knew to look. passport_refresh and provenance_check threw before the settle, so those cost nothing — the deliver-first rule holding — but answered a paying customer with an error page roughly half the time. The HTTP door was never affected: it had the whole map and the whole set of refusals.

#### How long

From the day the MCP buy shelves opened until 2026-09-04. No purchase over MCP of any affected item was ever correct, and the store cannot say how many there were beyond the first buyer's, because the argument that would have identified the subject is the argument that was dropped. Making the buyer whole for the two settled artifacts is the keeper's hand, not this fix's.

#### Found by

The first outside agent to shop the MCP shelf with a real wallet, reporting all three shapes with the amounts and the item ids, on the day they happened. Nothing in here found it: the store's own MCP tests bought the items whose arguments the door DID carry, and the one spec that came near it wrote the reason down — "service_audit takes its url later, so it reaches the challenge instead" — and treated that as a fact about the test rather than as the defect it was.

#### What changed

Both doors now read one argument map and one set of pre-payment refusals out of src/lib/purchase-args.ts; the MCP door's forked copies of both are deleted, so an item that grows a field gets it on both doors or on neither. test/mcp-carries-the-buyers-arguments.spec.ts derives its guard from the published input schema rather than from a list: for every item on every MCP shelf, removing a required argument must change what fulfillment is handed, and both doors must build byte-identical input from the same values. A second derived guard buys nothing and asserts that no shelf issues payment terms for a call missing a required argument. Dropping one item out of the shared map fails all of them.

### 2026-09-04

#### What was wrong

Every conversion figure on /pulse and /stats was computed against an organic ask count that subtracted only the machines that named themselves. The census had computed the other kind since July — clients that touch four or more doors inside a minute are walking the catalog whatever their user-agent says — and published them on the office wall as undeclared_walkers, a report and not a correction. So September's standing correction removed 2 rows of 7,017; August's per-door visits sat between 70 and 101 for a half-cent blessing and a $25 collaboration alike; and 48,566 all-time asks stood against 97 wallets ever opened, a ratio that held at a quarter of a percent across months whose volumes differed sevenfold. The published corrected figures were ceilings and said so, but they were far higher ceilings than the store already knew how to draw.

#### How long

From the day the standing correction shipped (2026-09-02) until today, and in spirit from the day the census first listed undeclared walkers (2026-07-26) — the rule existed, the books did not use it.

#### Found by

The keeper, asking what was upstream of a funnel row that read 77 asks and 0 sales. The answer came off the store's own public surfaces — /pulse, /observatory — and one directory's probe counter, which alone runs ninety unpaid 402 handshakes a day against these doors.

#### What changed

The walk rule moved into one module (lib/walkers.ts) that the census, the monthly reclassification walk and the funnel all import, so the three cannot disagree about who walked. The reclassification walk now moves a walker's asks out of organic as a second, separately-published half — known_machinery_by_behaviour beside known_machinery_by_user_agent — so a reader can see which part of the correction is a name a machine gave itself and which part is what it did. The funnel reports asks_walked and leaves them out of every organic figure. Payments are never reclassified by behaviour: a crawler that pays is a customer, the rule the counters have always used. Tests hold the rule in one place and the three surfaces to it.

### 2026-09-03

#### What was wrong

The organic 402 count per item on /pulse and the books could drop increments under a burst of price-checks against one door. Every other hot counter had been spread over shards on 2026-08-27; the per-item challenge counter stayed one KV key per item, KV allows one write a second per key, and a write that outlived its retries was logged and dropped. The counts were presented as counts and were, under bursts, floors of unknown depth.

#### How long

From the day the meter went in until 2026-09-03, on any door polled faster than once a second — which the uptime monitors do. How many increments were lost is not recoverable: a dropped write leaves no row.

#### Found by

Our own CI log on 2026-09-02, which printed the line the gate writes when a count is dropped, "challenge count lost: KV PUT failed: 429", during an ordinary run. Nobody outside reported a wrong number, and nobody could have: the number that was wrong was the one that was never written.

#### What changed

The per-item challenge counter now shards its writes the same way the day and channel counters do, and the ledger sums shards on read instead of assigning one key's value to the row. test/hot-counter-shards.spec.ts asserts the item counter is spread across keys and that the item row still comes back as one item with the whole count; a reader that assigned instead of summed would fail it.

### 2026-09-03

#### What was wrong

The attestation spec page said, since 2026-08-20, that the draft-vauban-x402 family covered receipt-format negotiation, a claim algebra and delegation binding, and that this store's signature_jcs "already verifies under" the RFC 8785 discipline those drafts and draft-hopley-x402-canonicalisation-jcs-v1 pin. The first was stale: the consolidated draft defers the claim algebra, the lifecycle FSM and the delegation binding to companion documents with no normative content. The second was overstated: both draft families add pre-canonicalisation rules our artifacts do not meet (integer-millisecond timestamps only, NFC strings; our artifacts carry ISO 8601 dates, the spec's own test vector included), and neither assigns any verification role to an ed25519 signature. signature_jcs verifies under the raw RFC 8785 byte primitive, not under either draft's discipline.

#### How long

2026-08-20 to 2026-09-03, on the spec page every verifier is pointed at. No artifact was affected: the signatures were and are what the page's canonical-form section says they are. What was wrong was the claim of interoperability with drafts that would reject our preimages.

#### Found by

A full read of the three drafts at their current revisions, our spec page and the signer, at the keeper's request, as the AEO plan's A10 (docs/bylines/CV_PROMPT_IETF_2026-09.md). The overstatement was in a paragraph written from a summary of the drafts, not from the drafts.

#### What changed

The paragraph is replaced by relation_to_other_x402_receipt_work on the spec page: per draft, at the revision read, what it defines, what we share, and where we are not aligned, ending with the plain statement that we have no post-quantum discipline and that the conformance desk parses neither format. jcs_dual_emit now says what signature_jcs verifies under, and what it does not. test/namespace-spec.spec.ts holds the block to naming all three drafts with a revision and a date, and holds the old sentence absent.

### 2026-09-01

#### What was wrong

The public bounty board listed five doors as open that had expired unclaimed on 2026-08-27. A bounty's stored status is written at two moments — 'open' at posting, 'paid' at claim — and nothing ever wrote 'expired', so the board and its JSON repeated the stored word while the claim door, which checks the clock, would have refused every one of them. A shopper who read /bounties on any of those five days, paid one of the doors with their own wallet and claimed, would have lost the door's price and been told the bounty had expired. The room and the JSON also carried no count, so nothing on the front could say whether there was anything to walk.

#### How long

Five days, 2026-08-27 through 2026-09-01, the whole span between the first board's expiry and its next read. No claim was attempted in that window, which is the only reason nobody was refused.

#### Found by

A read of the live board during the keeper's own question about why the board was not being found — not by a test, because the listing had no test for a record aged past its expiry.

#### What changed

The board derives each bounty's status from its expiry at read time, through the same check the claim door applies, and publishes open_count beside the list. The storefront strip reads the same figure live and says how many doors are open and what is left of the week's budget, or says the board is between postings; it never prints a count from copy. test/bounty-board.spec.ts ages a record past its expiry in KV exactly as the live ones were and fails if any face — the JSON, the room, or the claim door — disagrees with the others. Reposting bounties weekly remains the keeper's press.

### 2026-09-01

#### What was wrong

The $5 Once-Over cited preflight-v1 as its headline battery while the weekly census had applied preflight-v2 since 2026-08-24. Same GET, same bytes, different headline: a door with a dollar-typed amount (or any other v2-only fold) could buy a signed ready the same week the corpus called it not_ready. The paid report already computed the v2 score and hid it in also_under as DISAGREED — so the contradiction was visible inside the artifact and still published as ready on the face a buyer hands to a stranger. Same class as 0.14: the check existed; the flagship record did not consume it.

#### How long

From the Once-Over's listing through 2026-09-01. Every report signed before this date still cites preflight-v1 and keeps that citation forever; we do not resign old artifacts.

#### Found by

The store's own roadmap, as N1 / leftover #82, after the census citation was corrected on 2026-08-26 and the paid headline was left on the loose battery.

#### What changed

AUDIT_CRITERIA_VERSION is now PREFLIGHT_BATTERY_NEXT, the same string the census cites. The paid headline and the sample headline are the v2 set; also_under carries the frozen v1 overlap. A dated note on /criteria records the instrument change. test/battery-inside-the-bytes.spec.ts fails the build if the two producers part again, and test/service-audit.spec.ts fails the paid door on a v1-only fixture (dollar-typed amount) so deleting the fold turns a signed ready green in a test that watched it happen.

### 2026-08-31

#### What was wrong

The skill bundle published to ClawHub — the copy that gets INSTALLED into somebody else's agent — priced `service_audit` at $0.10 when it has cost $5 the whole time that document has existed, and `trust_profile` at $19 after the keeper repriced it to $21. It also described the shelf as running '$0.005 to $50' when it runs $0.001 to $300, and its frontmatter advertised entry 'from $0.004' when the cheapest door is $0.001. Two failures with different shapes and the second is the worse one. The `service_audit` price was wrong in the bundle's FIRST COMMIT: nothing ever compared it to the shelf, so it was never right. The `trust_profile` price was correct when written and went stale two days later when the keeper's 2026-08-29 repricing reached the shelf, the room and the JSON, and not the bundle. A wrong price here fails silently in the worst direction: an agent budgets a tenth of what the 402 will ask, declines the purchase it meant to make, and concludes this store is unaffordable. We would never hear about it, and we cannot edit the copy already installed.

#### How long

`service_audit`: four days, 2026-08-27 to 2026-08-31, the entire life of the document. `trust_profile`: two days, from the 2026-08-29 repricing. Neither was found by anyone using them.

#### Found by

The store's own keeper, asking for the skill to be brought current — not by a check, because no check existed. Every guard on this document asked whether a thing was NAMED: the item ids, the credentials promise, the position sentence, the key registry. Not one of them looked at a number beside a name, so the bundle was free to advertise the right door at the wrong price indefinitely, and did.

#### What changed

test/skill-prices.spec.ts, shipped 2026-08-31, reads every price the bundle quotes beside a menu item and fails the build when it disagrees with MENU_ITEMS, plus the stated shelf range and the frontmatter's entry price against the real ends of the shelf. It was written before the fix and run red against the live document first — it reproduced both errors and one the overhaul had missed. Two of its three findings that day were the READER'S fault rather than the document's: a $0.004 attributed across a list boundary to the next bullet's item, and an amount the store PAYS at your till read as the item's price. Both are now regression cases in the same file, alongside the two real errors reduced to the sentences that carried them, so a future tightening that narrows the reader past what it exists to catch fails and names what it lost.

### 2026-08-29

#### What was wrong

/doors, published that morning, told a reader that two of its five paid drill-downs cover a stated term of days. Three do: the Standing Watch and the Conformance Watch at 7 days each, and the Hosted Profile at 30. The sentence was wrong the moment it shipped: the Hosted Profile was added to the list above it and the sentence below it was not re-read. The JSON twin of the same page never carried the defect, because it publishes term_days per item instead of a tally — the same page, one dialect honest and one not.

#### How long

Hours. Shipped and corrected on 2026-08-29, before the page had been up a day.

#### Found by

The store's own derived-not-typed guard, on its first run after it stopped walking a hand-typed roster of public surfaces and started walking the router. /doors was not on the old roster and could not have been — it was built after the roster was last widened by hand, which is the whole reason the roster changed.

#### What changed

The sentence derives: a helper reads term_days off the same shelf the JSON body was already reading correctly, names the items and their terms, and says 'None of them covers a stated term of days' when that becomes true. The larger fix is the guard that caught it. derived-not-typed spent its life checking seventeen paths somebody had typed — a guard against hand-typed things, keeping one — and it covered 17 of about 130 public surfaces. It now derives its roster from the router at test time and walks every static door that answers a stranger with readable text; the seventeen stay only as a floor, because a derived roster can come back empty and pass having read nothing. The same walk found the cross-origin allowance had gone stale the same way (34 of 131 doors), and that is derived now too. A count typed onto a surface built tomorrow fails the build tomorrow.

### 2026-08-28

#### What was wrong

The store's most-quoted fact — '34 of 35 hosts serve no signed offers at all' — and every signed-offers number downstream of the shared battery asserted an absence the instrument could not see. The probe read the offers extension only from the PAYMENT-REQUIRED header, while the offer-receipt convention places offers first in the 402 body — a placement our own till emits and our own battery never parsed. The free preflight served the claim, the $5 audit signed it, the $5 conformance watch signed it daily into paying customers' records, the census sealed it into the Bitcoin-anchored corpus, and /registry captioned it as the market's trust gap. The denominator also silently excluded this store's own door — the one door known to serve signed offers — and no caption said so. Whether any of the 34 served body-placed offers is unknown, which is the defect: 'at all' was published where 'in the one placement we read' was the observation.

#### How long

From the census of 2026-08-03 on the quoted copy, and in every weekly round's signed_offers aggregate since the market desk shipped. The anchored rows keep their bytes: rewriting a signed artifact to look correct is the failure this record exists to refuse — instead every stored week now reads as what it was, because the basis field below is absent from all of them.

#### Found by

The keeper, catching the market desk publishing '0% of ready doors serve signed offers' as an ecosystem fact on 2026-08-27, and the instrument audit that followed, which found the same header-only read in the one battery all five instruments share.

#### What changed

The battery reads both placements — header first (the copy our own till reads back), body second — and asserts absence only over the placements actually read; a caller that withholds the body gets an advisory that says so. The market aggregate carries OFFERS_READ_BASIS the way rails carry RAIL_BASIS, so header-only history can never silently mix with post-fix weeks in the anchored chain. A fixture door serving offers only in the body fails the build if the battery ever again claims absence from fewer placements than the store's own till emits (test/offer-placement.spec.ts, test/fixtures/doors/body-offers.json), and every caption that quotes the number now states the placement scope and the self-exclusion. The old census figure stands as a dated finding in its measured scope; the next round's number is a new dated finding, taken with both eyes open.

### 2026-08-28

#### What was wrong

The self-passport's caption said every summary value is 'DERIVED from the same locals' and 'derived while this page rendered.' The verdict, freshness, and empty failed list were literals — stamped ready/fresh whatever the live modules two fields down had concluded, including 'conflict.' The one passport whose subject the census can never probe was the one passport that could not go dark, and its chip — green by construction, dated today by construction — rendered pixel-identical to chips that earn their color the census way.

#### How long

Since the self-passport shipped.

#### Found by

The instrument audit, in-house.

#### What changed

The modules are the verdict: every module agreeing is the only way the artifact says ready/fresh; any conflict names the disagreeing modules in failed and renders indeterminate, which the chip route refuses to draw — our chip goes dark the same way anyone's does, and wears SELF on its face either way. A test plants a catalog conflict and requires the fields to turn (test/self-passport-derives.spec.ts).

### 2026-08-28

#### What was wrong

The Night Watch's shelf copy said the hourly probe tries the handle so that 'a buyer could pay.' It never checked that: the watch runs the v1 structural battery — 402, header, version, accepts — and no payability check at all. A door with a name for a payTo, a dollar-typed amount, or a testnet network read ready in 168 signed rows while the store's own free preflight v2 called the same door not ready by any reading a buyer would accept. The signed rows were honest — they cited preflight-v1 all along; the shelf was not.

#### How long

Since the watch was listed with that sentence.

#### Found by

The instrument audit, diffing the shelf copy against the battery the rows actually cite.

#### What changed

The copy says what v1 checks — shape, not payability — and points payability at the free v2 preflight by name. Words follow facts; whether the watch should fold the payability battery is a criteria decision that stays the keeper's, and until he makes it the shelf no longer makes it for him. The standing guard is the battery citation inside every signed row, which a test holds inside the signed bytes (test/battery-inside-the-bytes.spec.ts): the shelf can no longer outrun a citation any buyer can check against the row they hold.

### 2026-08-28

#### What was wrong

The conformance desk's docs promised: resolve_key false 'refuses did:web resolution,' and past the budget 'nothing is denied — signature unchecked.' The verifier library underneath, given no fetch of its own, fell back to the bare platform fetch whenever no key was established and the kid was did:web — which is exactly the declined path, the exhausted-budget path, and the failed-resolution path. On the three paths that promised no request, the desk could make a raw, redirect-following, unbudgeted request to a stranger's host in the caller's name. And a resolution we attempted and failed — the issuer's DID host slow from our vantage for three seconds — was booked as the artifact's does_not_conform: our blindness published as their defect.

#### How long

Since the desk shipped.

#### Found by

The instrument audit, reading the verifier's fallback against the desk's promises.

#### What changed

The desk resolves exactly once, through its guarded fetch; the verifier now receives a fetch that refuses, so the fallback cannot fire. A signature left unchecked for our reasons reads could_not_check, never does_not_conform; a kid absent from a document we did read stays the document's fact. The test counts fetch calls per key_resolution state (test/conformance-desk-egress.spec.ts) — the only way a promise about not fetching can be held.

### 2026-08-28

#### What was wrong

The advisory behind every signed-offers figure was named `no-signed-offers`, and the census sentence derived from it read 'the rest ask to be paid on their word alone'. Both asserted a fact about the ENDPOINT. What the probe establishes is narrower: one challenge, at one path, carried no offer-receipt offers. That single observation cannot separate a door that serves no signed offers, one that serves them at a placement or path this probe did not look at, and one that serves them under a convention this battery does not recognize — and only the first would be about the door. The other two are facts about our probe, published as the operator's. The direction of the error is what makes it serious rather than untidy: this store SELLS conformance checking, so an ungranular statistic saying the ecosystem is 0% compliant is one we profit from believing.

#### How long

Since the advisory was named, and in every weekly signed_offers aggregate and /registry caption derived from it. The placement half of this defect was corrected the same day (the entry below); this is the CLAIM half, which that fix did not reach — a correctly-measured number can still be described as more than it is.

#### Found by

CV, in the review that became task #73, and named by the observatory's own doctrine document as the most urgent item in it (docs/OBSERVATORY.md §18) — written by this house against this house, and then left standing for a while, which is the part worth recording.

#### What changed

The advisory is renamed `signed-offers-not-in-challenge` — the observation, not the verdict — and its detail enumerates the three readings it cannot separate, with a falsifier an operator can walk for free. The census stops publishing only a numerator: `not_found_in_challenge` and `present_but_unparseable` are counted so the buckets sum to the denominator exactly, and `cannot_distinguish` ships the limits beside the number everywhere it travels. The public sentence states the remainder as counted rather than assumed and says WE DID NOT FIND THEM IS NOT THEY DO NOT HAVE THEM. Rows sealed under the old name keep their bytes and are joined at read, never rewritten. test/signed-offers-granularity.spec.ts fails the build if the advisory reverts to naming the endpoint, if the buckets stop summing, or if the sentence reasserts the absence.

### 2026-08-28

#### What was wrong

The 2026-08-26 correction on this page promised 'a test that holds the citation to account… so a row can never again name criteria the code does not apply.' The test that shipped compared the battery's check list to a function that returned that same list — a constant checked against itself. Deleting the checks from the probe would have left it green. The promise in this record was not kept by the mechanism that shipped beside it, which is the worst place in the store for that to be true.

#### How long

Since that correction shipped, 2026-08-26 to 2026-08-28.

#### Found by

The instrument audit, reading the test the correction cites against the code it claims to hold.

#### What changed

The citation is held by behavior now: a stubbed door with an unpayable payTo, a decimal amount, and a testnet network must each come back not_ready through the census's own probeHost (test/census-folds-the-trio.spec.ts) — the same red-test shape that already held the rail fold — so deleting a fold turns a door's verdict green in a test that watched it happen, not a list equal to itself. Rule 46 gets this entry as another face: a guard comparing a constant to itself is a guard that argues for the lie, and it argues hardest when it stands inside a correction.

### 2026-08-28

#### What was wrong

The $1 passport refresh was sold with 'the newest observation wins in BOTH directions — a broken finding turns the chip off,' and the $19 trust profile's own copy promised 'a host that breaks mid-term shows broken on its own page.' The passport and the chip kept the promise; the profile page and index never read the refresh at all. A door that broke mid-term, with the break recorded by a paid refresh, went dark on its chip and its passport while staying ready-side on the paid standing page — the one URL its operator hands to counterparties — until the next weekly round.

#### How long

Since hosted profiles shipped.

#### Found by

The instrument audit, in-house.

#### What changed

The profile view derives from the same newest-wins fold the passport uses, so the two surfaces can no longer disagree about which observation is newest. A test breaks a profiled host mid-term with a refresh and requires the standing page to say broken that hour and the index to drop the name (test/passport-refresh.spec.ts) — the mechanism is the shared code path plus the test that walks it, not a matching sentence.

### 2026-08-28

#### What was wrong

After earlier corrections re-worded /registry's prose — signed offers are 'present and structurally valid,' never 'verifiable'; doors are 'answering a well-formed challenge,' never 'working' — the JSON-LD beside that prose kept publishing 'working doors serving verifiable signed offers (percent)' as a bare percentage. The code's own comment says the machine-readable half matters more, because indexers quote it verbatim and cannot see a caveat in a paragraph. It was the half left uncorrected.

#### How long

Since the prose corrections landed.

#### Found by

The instrument audit, in-house.

#### What changed

The JSON-LD names use the corrected vocabulary and the percentage ships beside its numerator and denominator as their own properties, so no indexer has to quote a ratio without its population again. A test parses the served structured data, bans the retired words from every variableMeasured name, and requires the count and denominator properties beside the percent (test/registry-claim.spec.ts) — the machine half now has the guard the prose half always had.

### 2026-08-26

#### What was wrong

The store's paid doors refused valid payments that arrived under the header name X-PAYMENT — x402 v1's name for what v2 calls PAYMENT-SIGNATURE, and still what much of the live ecosystem sends. A buyer holding a correctly signed envelope got a 402 instead of their goods. The store then compounded it: when this was reported, the reporter was told the claim was false, on the strength of three places in our code that read both header names. None of those three accepts a payment. Two write a decline reason after the 402 is already decided and one decides whether pre-payment guards apply; the acceptance decision belongs to a layer below all of them. Call sites were read and mistaken for behaviour.

#### How long

Since the v2 migration, on every paid door. The store never measured how many buyers spoke the older name, so the number of refused sales is unknown and cannot now be recovered.

#### Found by

CV reported it from live behaviour and was told he was mistaken. Cairn then settled it with half a cent: the identical envelope sent under both names on a cold walk, 402 under X-PAYMENT and settled under PAYMENT-SIGNATURE, published as a transcript.

#### What changed

The payment adapter now accepts the envelope under either name, and only that name aliases — a blanket fallback would be a guess nobody asked for. A test sends the same envelope under both headers and requires the same outcome, and separately requires that X-PAYMENT-SIGNATURE is NOT treated as an alias, so the shim cannot quietly widen. Nothing else changed: signature verification, schema validation and settlement are untouched, and PAYMENT-SIGNATURE remains what every surface asks for.

### 2026-08-26

#### What was wrong

Every row of the weekly census cited the wrong criteria. Each row carries a `battery` field whose entire purpose is to say which published battery produced that verdict, and every row said preflight-v1. The round had not run v1 since 2026-08-24, when it was deliberately changed to fold the Solana rail-receivability read into its verdict — a v2 rule that v1 explicitly does not apply — so that the corpus would stop contradicting the free preflight in public. Two days later v2 gained the consistency trio (payable payTo, atomic amount, mainnet network) and the round did not fold that either. So the census matched neither published battery: it cited v1, scored the rail read like v2, and ignored the trio like v1. Those rows are hash-chained and Bitcoin-anchored, which means the mislabel is durable and carries our signature. The verdicts were defensible; the label on them was not, and a verdict that cites criteria nobody applied cannot be checked by the stranger it was published for.

#### How long

Two days, 2026-08-24 to 2026-08-26, across the rounds signed in that window. No round in that window was re-signed: those rows keep their bytes, because rewriting a signed artifact to look correct is the failure this record exists to refuse.

#### Found by

Found in-house while scoping an unrelated item — the fresh-set surface's missing per-row conditions — by reading what the census actually folds against what its rows claim. Nobody outside reported it; it would have been invisible from outside, which is the argument for reading one's own signed fields against one's own code on purpose.

#### What changed

The round now applies v2 in full — the rail read and the trio — and cites preflight-v2, derived from the version constant rather than typed. The mechanism that keeps it true is a test that holds the citation to account: it reads every check the cited battery adds and requires that the round can actually fail a door on each one, so a row can never again name criteria the code does not apply. A door with an unpayable payTo, a decimal amount or a testnet network now scores not_ready in the census, as it already did at the free preflight.

### 2026-08-25

#### What was wrong

Every signed offer and every signed receipt this store issued carried a `payload` field. The x402 Signed Offers and Receipts spec permits `payload` for EIP-712 only and says it MUST be omitted for JWS, which is the format we emit — so the store published a MUST-level conformance violation on every paid door, while selling conformance checking of other people's offers and receipts. The envelope also described `acceptIndex` as binding the offer to a rail; it is not part of the signed payload and must not be relied on for that.

#### How long

From when signed offers shipped until 2026-08-25, on every paid door.

#### Found by

Our own reading of the spec, and only barely. The investigation that led there was about header SIZE, and the argument for dropping the field was that nothing was lost by removing a duplicate — true, mechanically, and silent on whether the wire format permitted it. Reading the spec is what turned a tidying into a defect, and it is what found the receipt half, which no byte-counting argument would ever have reached.

#### What changed

The field is gone from both envelopes and the acceptIndex claim is corrected in the text that describes it. Conformance tests now assert the envelope shape against the spec rather than against what the code already emitted — the earlier tests passed because they required the violation.

### 2026-08-04

#### What was wrong

The public organic-settlement count read 22 when the honest number was 3. The other 19 were the store's own money: cross-model agent-UX test walkers (research into how cheaply-run agents handle x402 purchases) bought real items from freshly spun-up wallets that were not yet listed in the house register, so the till booked family purchases as market demand — the exact corruption the register exists to prevent, caused by our own instrument.

#### How long

Roughly a day across two test rounds (2026-08-03 to 2026-08-04), on every surface that shows the organic figure.

#### Found by

The keeper, reading his own office and refusing the flattering number: he had 3 organic sales, the page said 22, and he asked for the correction rather than the credit.

#### What changed

Three mechanisms, no intentions. (1) Every walker wallet is now in the house register, and the pinned rule is LIST BEFORE FIRST PURCHASE — the same guard the store's own shopping script has always enforced for itself. (2) A reclassification ledger: the misbooked settles are subtracted from organic and added to house AT READ, with the raw counters left exactly as written, because an edited counter is an erasure and an adjustment beside it is a record; the stats now carry a reclassified_house field so the correction itself is visible, not silent. (3) This entry, and a test that walks the whole correction path — the lever refusing unlisted wallets, the snapshot freezing, the corrected figure at read, and the raw counter left untouched — so the mechanism fails the build before it can fail the books. The corrected organic count is the number the store stands on, and it is 3.

### 2026-08-01

#### What was wrong

The refund policy shipped saying “nobody in the x402 ecosystem has shipped true conditional release yet,” and the store's own problem ledger said the same. False from the moment it was written: Boson Protocol's x402B — non-custodial contract escrow with on-chain dispute resolution, exactly the thing the sentence denied existed — had been on mainnet, including Base, since 2026-06-08, seven weeks before we wrote it.

#### How long

Under a day on the live policy — published in the early hours of 2026-08-01, corrected the same day. But the claim was born false, which is worse than going stale: nothing changed under us, we simply had not looked.

#### Found by

An outside deep-research pass the keeper commissioned on the conditional-release problem, whose report named x402B as the shipping baseline — then verified by us against the live web before recording, because the vetting rule cuts both ways: the same pass that checks a report's claims against our code has to check our published claims against the report's findings.

#### What changed

The policy sentence now names the shipping alternative, dates it, and says why this store still does not run one (a contract to operate and arbitrate is infrastructure a one-person shop must not become) — the reader gets the real trade-off instead of a flattering absence. The mechanism: any published claim of the shape “nobody has built X” is a claim about the whole world at a moment, and it now ships with the date it was checked or it does not ship. The problem ledger's matching entry was corrected in the same pass.

### 2026-07-31

#### What was wrong

/stack told buyers that if this store's signing key were lost, “every artifact ever issued becomes unverifiable.” That was never true, and it was the scarier half of the sentence. The public key and the exact signed bytes are already published and already copied — out of our hands by design — so anything signed stays checkable by whoever holds it whatever happens to us. What a lost key actually costs is the FUTURE: nothing new could ever join the record. The same entry also said the key had “no substitute and no recovery,” which stopped being true the day a paper backup existed. And separately, /attestation's statement of exactly which fields a certificate signature covers was a hand-written list that had fallen a day behind the code — it omitted made_by, then the five payment fields, on the one page whose whole job is telling a reader which bytes are covered.

#### How long

The unverifiable claim: since /stack was published on 2026-07-29, three days. The stale field list: about a day, from when made_by shipped.

#### Found by

Ourselves, on a deliberate read-every-page pass the keeper asked for after a run of small nuanced slips. Notably NOT by a test: every claim here was prose, and prose about code is the category with no compiler.

#### What changed

Both fixed, and both structurally rather than by editing a sentence. The field list on /attestation is now DERIVED from the same CERT_FIELDS array the signing code walks, so the page cannot describe a different set than the one being signed, and a test fails the build if any signed field goes unmentioned. The /stack entry now says what a lost key actually costs, states that recovery covers loss and not theft, and points at key_history. The lesson recorded rather than the instance: a prose list beside a code list is two sources of truth for one fact, which is the same defect as a hand-typed rotation count and a hand-typed “never rotated” line, both of which broke the same week.

### 2026-07-31

#### What was wrong

Two things, and the second is the one that matters. FIRST: the store had no recoverable copy of its signing key, and said the opposite by implication for nine days — /stack called the key a dependency with no substitute, /wind-down promised every signature stays checkable forever, and neither page mentioned that the single private key existed in exactly one place with no way to read it back. Cloudflare Worker secrets are write-only, which is correct, and means the copy taken at setup was the only one there would ever be. No copy was taken. Not a decision; nobody thought that far ahead. SECOND: the line published beside the key itself read "This key, this wallet, this domain, NEVER ROTATED" — and the store rotated its signing key that afternoon, which left a boast about a streak sitting on the most machine-read surface here, hours after it stopped being true. The same deploy served key #2 with an in-service date of 2026-07-22, nine days before it existed, on a field a holder uses to place an artifact in time.

#### How long

The missing backup: from 2026-07-22 to 2026-07-31, the whole life of the first key. The false identity policy and the wrong service date: under an hour, between the secret changing and the sweep that followed it.

#### Found by

Ourselves, and by the only method that would have worked: writing the procedure down. The gap did not surface from thinking about key management, which we had done that morning — it surfaced at step one of an actual paper-backup ceremony, at the line that said "get the seed on screen," because there was nowhere to get it from. A published protocol was what turned an assumption into a step somebody had to perform. The identity-policy lie was caught by the keeper reading the live key endpoint immediately after the swap, which is the same habit that has now found three of these.

#### What changed

The store performed its first key handover, under the succession protocol it had published that morning and under every line of it: the new key announced before it signed anything, the announcement itself signed by the OUTGOING key and verifiable at /api/verify/handover_1, the retired key published forever with its service dates so every artifact issued under it stays attributable. It was not a drill and is not described as one. Structurally: key history is now a registry rather than an assumption, every verify response names which published key signed a thing — and says so out loud when a signature matches NO key we have ever published, which was previously reported as simply valid; the rotation count and the current key's service date are both DERIVED from that registry rather than typed, because a typed count is a claim with a timer on it, which is precisely what the "never rotated" line was. The new key was written on paper and verified FROM the paper, on two sheets, before it signed anything. Ten tests that pinned the old wording failed and were rewritten to assert the commitment rather than the count. And the cause is fixed at its root: `npm run keys:generate` now prints a warning before the number saying it invents a NEW key and cannot show you your existing one — the keeper reached for it looking for the live seed, reasonably, because it is the only key-shaped command in a repo with one key.

### 2026-07-30

#### What was wrong

On the day this store took its first payment from a stranger, the page built to watch for exactly that still said zero — that not one client outside the house had ever presented a payment signature. The census grouped clients by user-agent alone and marked a whole group as house the moment ANY event in it was house-flagged, then skipped it. A user-agent is a bucket rather than a person, and the emptiest bucket is "(no user-agent)", which the keeper's own scripted tests and a hand-rolled buyer both fall into. So the proprietors testing their own till made every outside client sharing a user-agent string invisible, on the single number the whole store is built to watch.

#### How long

From the day the census shipped. It could only ever be seen on a day the number was supposed to change, and that day was the first one.

#### Found by

The keeper, reading his own office the hour the sale landed — and reading it generously, as a window-boundary quirk rather than a bug. It reproduced in three lines.

#### What changed

Clients are now keyed by user-agent AND house flag, so a house event still counts as house exactly as before and no longer swallows everyone standing next to it. The reproduction is a permanent test — one house settle and one outside settle sharing a user-agent must show the outside buyer — alongside its opposite, that the fix never lets house traffic read as a customer, since trading an undercount for that overcount would be far worse. The page's verdict was always computed rather than written, so no copy needed editing: fixing the books fixed the sentence, which is why it is built that way.

### 2026-07-30

#### What was wrong

The listing spec told buyers a lucky was "graded honestly, by a person." No person grades a lucky. The animal, the note and the strength all come from a hash of the certificate id, and the code that does it says so in its own comment: "the keeper does nothing per order." The true part — that he wrote the herd and weighted the odds — was real; the per-charm human judgement was not. It rode into the OpenAPI summary, menu.json, the x402 discovery document and skill.md.

#### How long

Live on every machine surface for five days.

#### Found by

Nobody, for five days. Then by scoping an unrelated feature: a maker's mark for the shelves where a buyer cannot tell whether a person or a script made the pick. Asking who made the pick is what surfaced a shelf whose answer had been written down wrong.

#### What changed

The line says what the code does. The structural half is the point: a maker's mark is now a signed certificate field derived from one table keyed by item, so a shelf cannot describe its own provenance, and a test walks all three copy maps — the OpenAPI summary, the listing spec and the storefront returns — failing the build if any of them claims a person on a shelf whose fulfilment path has none. The claim and the code are tied together now; they were not before, which is why they drifted.

### 2026-07-30

#### What was wrong

Certificates could not actually be verified by the person holding one. The key and the signature were real and correctly shaped, and /api/verify — the endpoint that exists for nothing but third-party checking — never published what the signature covers, so there was no way to reconstruct the signed bytes except by guessing. Worse, two fields shown on certificates were not signed at all: a buyer's tag, and the `attests` hash that binds a certificate to the settlement observation it vouches for. An unsigned binding can be altered without breaking the signature, so the one field whose whole job was to make one artifact answer for another was the one field the signature did not cover.

#### How long

The documentation gap since the endpoint existed. The two unsigned fields since 2026-07-28, when both were added and the canonicalizer was not.

#### Found by

A partner agent, from outside, holding a real certificate — he ran the ed25519 himself against every plausible canonicalization, watched all of them fail, and confirmed the crypto before reporting it rather than passing along a suspicion.

#### What changed

The endpoint no longer describes the canonical form, it SERVES it: every signed artifact now returns signed_payload, the exact string the signature covers, so verification is one library call with nothing guessed. The certificate canonicalizer now walks a declared field list, and a type-level check fails the build if a field is ever added to a certificate without being signed — the class of bug, not just its two instances. Certificates minted before the fix still verify under the form they were actually signed with, and say on their face which fields that signature leaves out. And the test that missed this now exists: verification in CI re-derives the bytes from the SERVED response and checks them with the raw ed25519 library, because every previous test verified through the same function that signed, and a function's blind spots are invisible to itself.

### 2026-07-29

#### What was wrong

This store told visitors that "CI validates the catalog against it on every build," and told machine readers that field order was "validated in CI." There was no CI. Four hundred tests, run exclusively by hand.

#### How long

For as long as those sentences existed — the tests were always real, the sentence about when they run was not.

#### Found by

Us, while working out how the keeper could publish a skill from a phone. Nobody was looking for it.

#### What changed

The claim was made true rather than softened: CI now runs the typecheck and the full suite on every push and every pull request. The sentence that was false is the sentence that now describes a workflow file.

### 2026-07-28

#### What was wrong

Five pages of the store's own back room had no way back to anything. Each rendered itself as the desk's tab, which draws the only link home as un-clickable bold, so landing on one left the keeper with the browser's back button.

#### How long

From the day each reading shipped.

#### Found by

The keeper, unable to reach half his own office.

#### What changed

The navigation is now derived from one list rather than written per page, so a new page cannot be added without appearing in it. Four tests sweep every page: each reaches every other, each marks only itself, each keeps a way out.

### 2026-07-28

#### What was wrong

The census page told the keeper that "the decline reasons are on the desk." There was no desk. The reasons had been recorded since the instrument went in and nothing anywhere rendered them.

#### How long

From the day the census shipped until somebody went looking.

#### Found by

The keeper, following our own instruction and hitting nothing.

#### What changed

The decline desk was built, and a test now asserts that every page promising a link actually links somewhere that exists. A sentence pointing at a page nobody built now fails the build.

### 2026-07-26

#### What was wrong

Every surface of this store said refunds were "automatic." The code never did it. A refund here was always a person keeping his word, which is a fine promise and a different one.

#### How long

Live on every surface for five days.

#### Found by

An outside model, repeating our own wording back to us. Nobody here noticed.

#### What changed

The wording now says what the code does. More importantly: every claim the store makes about itself is walked by a test in CI, so a promise the code cannot keep fails the build instead of shipping. That test exists because of this entry.

### 2026-07-25

#### What was wrong

Parameter guards fired BEFORE the payment gate, so an indexer asking a paid route what it cost got a 400 error instead of a price — and concluded we were not an x402 endpoint at all.

#### How long

Since the affected items were listed.

#### Found by

A directory's probe report: three of six endpoints answered. The three that did not were ours to fix.

#### What changed

Guards moved behind the gate, and a test now asserts that an UNSIGNED request to any paid route gets a 402 with the terms stated rather than a 400. The store cannot again refuse to quote a price to something trying to read one.

## Count

90

## Corrections URL

<https://scvd.store/corrections>

## Mailbox

<https://scvd.store/api/letter>

## Invitation

If you find another, the mailbox at /api/letter is free and a human reads it. A correction costs us nothing except the writing down, and the writing down is the point.
