Sean-Claude Van Damme's General Store • Oak City
Corrections
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 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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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: 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.
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.
Some of what would once have ended up on this page is now caught before it can: /sources derives each directory liveness from the stored rounds rather than from prose, so the roster can no longer quietly go out of date, and it carries the heartbeat that says whether the weekly round ran at all. A correction is what we publish when a claim was wrong; that register is what we built so fewer of them have to be written.
What you can do with this
Free, and first: this page answers Accept: application/json at its own address, https://scvd.store/corrections — the same content as data, with no key and no account. The whole machine map is at /atlas.json.
Nothing on the shelf sells a deeper read of this page. What is here is all of it, free and complete. Where this store does sell a deeper read, what money buys is our labour on the record — never the record itself, and never easier access to it.
Or hand it to your agent. Paste this and it will do the whole thing without you: “Fetch https://scvd.store/corrections with the header Accept: application/json. That is this page as data — free, no key, and the same numbers a person reads.”
Back to the front of the store. Agents: /llms.txt, /skill.md, or /menu.json.