A price oracle tells you what something is worth. This measurement tells you whether you can sell it, and what it costs when you do. On 2026-09-04 this page reported that a $100,000 sale of QQQ returned 0.03%. On 2026-09-25 the same measurement, run at block 72,245,711 against every venue we could enumerate, put the cost of the same sale at 0.35% — and SPY at the same size at 0.41%. What changed between the two dates is not the market; it is the list of venues we were looking at (error 12).
PoolManager at the same block, it returned $99.67: the pool that wins at that size cannot fill the $10,000 probe that selects our pool table, so it was never a candidate — error 11. A second AMM deployment on this chain was outside that scan: on a round trip it returned 99.90% at $100 and $99,736 at $100,000, where the v4-only figure was $30; a one-sided sale returns less — error 12. USDG-quoted pools only.Published slippage figures almost always come from a single aggregator. This measurement queries six at once: CoW, KyberSwap, ParaSwap, 0x, 1inch and LiFi. Same moment, same token, same notional size, taking the best result a buyer could actually get.
The gap is not a few basis points. It is several times over.
| Token | Size | ParaSwap only | KyberSwap only | Best of six |
|---|---|---|---|---|
| LDO | $100,000 | −11.29% | −4.22% | −0.71% |
| LDO | $1,000,000 | no quote | −85.14% | −8.51% |
| PENDLE | $100,000 | no quote | −6.61% | −0.79% |
| PENDLE | $1,000,000 | no quote | −60.23% | −49.12% |
| CRV | $100,000 | −6.06% | −2.38% | −1.82% |
| MKR | $100,000 | −3.99% | −1.01% | −1.01% |
| UNI | $1,000,000 | −6.65% | −1.94% | −1.21% |
| AAVE | $1,000,000 | −3.58% | −2.38% | −1.06% |
The extreme case is LDO at $1M: KyberSwap alone reports −85%, best-of-six is −8.5%. Anyone writing "on-chain liquidity is terrible" from a single source is off by a factor of ten.
This is not a question of one aggregator being consistently better. Change the notional and the winner changes:
| Token | $100 | $1,000 | $10,000 | $100,000 | $1,000,000 |
|---|---|---|---|---|---|
| WETH | 1inch | 1inch | 1inch | 1inch | 1inch |
| LINK | 1inch | 1inch | 1inch | 1inch | KyberSwap |
| MKR | KyberSwap | KyberSwap | KyberSwap | KyberSwap | KyberSwap |
| CRV | 1inch | 1inch | 1inch | 1inch | KyberSwap |
| LDO | 1inch | 1inch | 1inch | CoW | CoW |
| PENDLE | 1inch | 1inch | 1inch | 1inch | CoW |
Jupiter is the only quotable source on Solana, so the figures below are subject to the finding above and probably overstate the true cost. They are included because the magnitudes still say something.
A note on what these numbers mean. "−92.90%" means: at current on-chain liquidity, a sell order of that size would be filled down to that level. It does not mean "you will lose 92%". An order that size would most likely be refused rather than filled, and you can split it or route through a CEX. What the number tells you is the cost of dumping it in one go, and that at $1M these tokens have no executable market at all.
The $10,000 tier is closer to a real position: BONK −28.70%, PYTH −15.25%, WIF −3.40%, JTO −2.42%. All are CEX-listed tokens with meaningful daily volume.
Everything this section said in the version published on 4 September is void: that six of eight tokenized stocks could not be sold, that $100 of SPY returned $0.90, and that AAPL fell off a cliff above $1,000. None of it holds.
The cause was mine, not the market's. The scan that builds the pool table silently skipped block ranges that failed. It found about 55 pools where the chain has 25,122, and the handful it did find were mostly the shallow ones. I measured those and reported the result as a property of the asset.
| Claim | Published (v17) | Corrected |
|---|---|---|
| SPY, sell $100 | 0.90% · PUBLISHED IN ERROR | 99.93% |
| AAPL, sell $10,000 | 2.82% · PUBLISHED IN ERROR | 99.85% |
| Tokens that cannot be sold | six of eight · PUBLISHED IN ERROR | one of nine |
build_pool_table.py.Twelve rounds over 5.1 hours, every 30 minutes, each pinned to a single block. Every size filled in every round; nothing was unquotable. Where a figure moves between rounds, the p10–p90 range is given underneath.
| Token | $100 | $1,000 | $10,000 | $100,000 |
|---|---|---|---|---|
| SPY | 99.93% | 99.93% | 99.91% | 99.71% |
| AAPL | 99.93% | 99.92% | 99.85% | 99.06% |
| GOOGL | 99.99% | 99.95% | 99.53% | 97.97% |
| NVDA | 99.99% | 99.89% | 99.48% | 96.50% |
| TSLA | 99.89% | 99.77% | 99.07% | 96.75% |
| RDDT | 99.32% | 99.32% | 99.24% | 93.12% 90.1–96.6 |
| AMC | 99.75% | 99.62% | 97.08% 86.1–99.0 | 74.55% 28.5–83.6 |
| GME | 99.49% | 99.37% | 97.97% 36.9–98.6 | 17.33% 3.7–22.5 |
| QQQ | 6.46% | 1.83% | 0.26% | 0.03% |
QQQ is where this table's own method shows its limit. At the $100,000 rung this table reports 0.03%, and that figure is v4-only: a second AMM deployment on the same chain returned 99.90% at the same block (error 12). At $100 and $1,000 this table was wrong — the excluded pool wins there, and quoting it lifts those rungs from 6.46% and 1.83% to 99.67% and 98.62%. The reason is in how the table is built: pools are selected with a $10,000 probe, and a pool that cannot fill $10,000 is dropped before it is ever a candidate. The pool that wins QQQ at small sizes is one of those — it is absent from the table by construction, not by accident.
Quoted instead against every initialized QQQ/USDG pool in the v4 PoolManager, at three pinned blocks — the all-venues figures are in error 12:
| block | $100 | $1,000 | $10,000 | $100,000 |
|---|---|---|---|---|
| 54,088,399 (09-04) | 99.67% | 98.62% | 0.26% | 0.03% |
| 61,129,566 (09-12) | 99.29% | 99.21% | 91.11% | 0.03% |
| 70,427,772 (09-23) | 97.34% | 2.19% | 0.35% | 0.04% |
The pool that serves the small sizes is one contract, 0xf9568ec0… (fee 0.30%), and its capacity — the largest notional it will quote — went $9,841 → $10,506 → $287 across those three blocks: a fall of about thirty-four times in nineteen days, after rising once first. So the size QQQ can absorb is not a property of the token. It is however much capital someone is willing to leave in a cheap pool. At the $10,000 rung alone the answer went 0.26% → 91.11% → 0.35%, a factor of more than three hundred. Naming a collapse threshold would be naming one day's reading.
Unaffected: every other token on this chain returns at least 93% through the $10,000 size; at $100,000 only GME and AMC fall further, to 17% and 75%. Both statements were re-checked against the chain at the same blocks and hold.
GME and AMC are where size still bites, and they are the two tickers retail sentiment concentrates in. Both are fine up to $1,000. GME at $100,000 returns 17% and never exceeded 23% in any round; AMC at the same size ranges from 28% to 84% depending on when you ask. The medians alone would hide that: the reason both carry a range is that a single number would misrepresent them.
One observation, not yet a finding. Both GME and AMC improved markedly during the window — GME at $10,000 went from about 30% to 98% and stayed there, while AMC at $100,000 climbed steadily from 18% to 83% without reversing. The two shapes are different enough that they are unlikely to share a cause, and neither is explained by anything measured here. This is a single day's observation. Whether it repeats is not something one session can establish, and it is recorded here as an open question rather than a result. As of 2026-09-06 GME has reverted below 25% at $100,000 and is still falling; the shape does not persist. That is being measured and will be reported separately.
Update, 2026-09-14. The direction held and the path was not straight. GME at $100,000 fell from a daily median of 95.3% on 2026-09-05 to 5.1% on 2026-09-14, measured over 48 rounds a day, but not monotonically: it rose on 09-11, 09-12 and 09-14, reaching 15.1% on 09-12 before falling back. The sentence above is a point-in-time reading and holds as of its own date.
Every figure above comes from an on-chain call, and an on-chain call at a given block height is deterministic: the same inputs produce the same output for anyone, at any time, in any language.
So each round of measurement emits a hash whose preimage contains only fields a third party can reproduce exactly:
| In the hash | Why |
|---|---|
| Block height | State anchor |
| poolId | Identifies the pool |
| Input amount (raw integer) | Call parameter |
| Midpoint amount (raw integer) | Tokens received before selling back |
| Output amount (raw integer) | Chain return value, deterministic |
| Status | Filled / insufficient liquidity |
| Timestamps, network latency | ✗ excluded: nobody else can reproduce them |
| Slippage, recovery and other derived floats | ✗ excluded: float serialisation differs across languages |
Verified in practice: replaying every round trip independently for the first v2 round (block 54,088,399) reproduces the recorded hash byte for byte.
This page ships with the raw data and the verification script, with no third-party dependencies (code/evm.py is a from-scratch implementation needing only Python 3 and curl):
code/verify.py — replays every quote at a given block, recomputes the hash, compares it to the recorddata/snapshot-v18-12r/rounds.jsonl and quotes.jsonl.gz (v2 rounds; the defective v1 data is quarantined below, excluded from every conclusion)code/rhchain.py — pool enumeration and Quoter calls; stock_pools.json is the pool table from a full-chain scanREADME.md — the full rhdepth-v2 specification and run instructionsSERIALIZATION-NOTE.md — the round-hash serialization in prose, so a second implementation need not read the reference codeEvery figure on this page corresponds to a snapshot of 12 rounds ending at block 54,270,401, published as data/snapshot-v18-12r/. That directory does not change after publication, so its checksums will always match. Collection continues in the dated live directories under data/, which grow past what this text describes.
You need an archive node for Robinhood Chain to recompute the published snapshot (historical eth_call). The public endpoint rpc.mainnet.chain.robinhood.com keeps only a short rolling window of state: between about 3,100 and 5,900 blocks — roughly five to ten minutes — observed across 2026-09-11 to 2026-09-15. The window moves, and different state-reading methods have disagreed at the same depth, so treat it as a range rather than as a figure. An archive endpoint has no such window. Corrected 2026-09-15: this paragraph previously said "~128 blocks" — about thirteen seconds — understating the window by a factor of twenty-four even at the lowest value observed. A round taken within that window can therefore be recomputed against the public endpoint with no key and no archive access.
| export RHCHAIN_RPC="https://<archive endpoint>" python3 code/verify.py 54088399 |
What this gives you is verifiability, not decentralization. The right to publish these hashes is centralised, and that is a fact. But it does not ask you to trust the publisher: replay the block, and it either matches or it does not. The thing being trusted is arithmetic, not me.
Recomputing a round proves the numbers were not changed. It does not, on its own, prove they were not computed today. An append-only ledger on Robinhood Chain records each round's hash, so the commitment carries its own timestamp — the one in the transaction that wrote it.
Deployed on the Robinhood Chain iteration network (chainId 46630) at 0xc4f7c2ed489d9f521d65b43cc4929d3c642c6fb9, in block 119,878,215, transaction 0xa0dd3b2f…, canon rhdepth-v2. Those values are transcribed from deployments.jsonl in the ledger repository, which is append-only and is the place to check them; as of 2026-09-22 02:35 UTC there was no deployment on mainnet (chainId 4663). That is a statement about a moment, not a plan: deployments.jsonl is the file to check, and it is append-only, so a mainnet entry appearing there later does not change this sentence.
One round, one call:
| cast call 0xc4f7c2ed489d9f521d65b43cc4929d3c642c6fb9 \ "getRoundHash(uint64)(bytes32,uint8)" 61129566 \ --rpc-url https://rpc.testnet.chain.robinhood.com |
Compare what comes back against the roundKeccak and canon for that block in data/. A returned canon of 0 means the round was never recorded, which is unambiguous because the contract refuses to deploy with canon 0 and every recorded round therefore carries 2 or more; it is not a round stored as zero.
As of 2026-09-16 the ledger was deployed and empty: latestCommittedBlock() returned 0, and the call above returned zeros. The backfill of the published rounds was written and rehearsed but not yet executed. The ledger is an additional anchor, not the primary one. The primary anchor is that rounds.jsonl is published in git: any change after the fact stays in the history. A ledger can be redeployed; the published record cannot be quietly rewritten.
Update, 2026-09-19 — the backfill has run. The call above now returns 0x2c645bebf891401f1fd75a39168496a88a45bfed59105c42f780f5b65421a2d2 and canon 2 for block 61,129,566. That answer will not change: the watermark only moves forward, so no block at or below it can be written — an attempt reverts with BlocksNotIncreasing.
610 rounds are committed, through block 64,907,249, in ten transactions. Publication continues daily while commits are written in batches, so the newest published rounds are not on the chain yet — 96 rounds as of 2026-09-19 (2026-09-17 and 2026-09-18). At that same date, a round published after 2026-09-16 returns canon 0, while block 61,129,566 returns canon 2. Both are reproducible today, which is the cheapest way to check that canon 0 means what this page says it means.
Update, 2026-09-23 — the ledger is now on mainnet, and everything above stays true. A second EvidenceLedger was deployed on Robinhood Chain mainnet (chainId 4663) at 0x7f5446b920e09531f443ce951076cbaed09dfab6, in block 70,145,346, transaction 0x854d1b03…, canon rhdepth-v2, owner 0x6768cEF3…. That key has never owned the iteration-network ledger, and that is checkable rather than asserted: contract 0xc4f7c2ed… has exactly one OwnershipTransferred event — 0x0 to 0x9d55…35E2, in its own deployment block — and no OwnershipTransferStarted at all, so ownership there never moved. The backfill of 850 published rounds through block 69,196,861 landed in fourteen transactions. The paragraphs above are not superseded: they are statements about chainId 46630, which still holds what they say it holds, and the watermark there only moves forward.
The same round returns the same hash on both chains. Block 61,129,566 returns 0x2c645bebf891401f1fd75a39168496a88a45bfed59105c42f780f5b65421a2d2 and canon 2 on mainnet as well — the hash is the round's own, and the canon is what the commit passes in, so neither depends on which ledger you ask. A round that was quarantined rather than published — block 53,808,204, in a rhdepth-v1 directory — returns canon 0 on both, and now does so by construction: it sits below the first committed block, and the watermark has passed it.
Every prediction market shows a price on its interface. Pull the actual order book and few of them can be traded.
More interesting than an outright empty book is the one-sided market: real depth on the ask, dozens of levels absorbing tens of thousands of dollars, while every bid sits at a dust price of 0.01. You can buy in at 0.99; when you want out, 0.01 is the only bid. Plenty of levels, all at prices that cannot catch you.
| Keyword | Matched | No 24h volume | Checked | Tradeable | One-sided | Borderline | Empty |
|---|---|---|---|---|---|---|---|
| bitcoin | 238 | 54 | 78 | 0 | 47 | 15 | 16 |
| ethereum | 188 | 62 | 66 | 0 | 46 | 4 | 16 |
| election | 1,154 | 900 | 108 | 8 | 86 | 7 | 7 |
| fed | 82 | 65 | 75 | 14 | 31 | 14 | 16 |
| trump | 510 | 107 | 114 | 4 | 27 | 71 | 12 |
| nba | 69 | 65 | 59 | 21 | 33 | 2 | 3 |
| china | 24 | 9 | 24 | 2 | 14 | 3 | 5 |
| gpt | 100 | 26 | 72 | 7 | 27 | 11 | 27 |
| Total | 2,365 | 1,288 | 596 | 56 | 311 | 127 | 102 |
Two details stand out.
For bitcoin and ethereum, the tradeable count is zero. Across 144 checked books, not one had both sides standing; they are almost all one-sided or empty. Meanwhile nba has 21 of 59 tradeable and fed has 14 of 75. A busier topic does not mean a more tradeable one.
54.5% of matched markets had no trades in 24 hours. Searching election returns 1,154 markets, 900 of them silent. On the interface they look identical to the active ones.
Every one of these is attached to the number it touched and to the side of publication it fell on, and what each corrupted is corrected where it lives. This section is here because it is the reason the figures on this page can be trusted — not a reason they cannot.
This section does not usually appear in a report like this. It is here because it explains something more important: why almost nobody does independent executability measurement.
Not because it is hard, but because instruments lie quietly. Nineteen errors, each producing a precise number that looked like an insight. Eight were caught before anything was published. Eleven were not — 08, 09, 10, 11, 12, 13, 14, 15, 16, 17 and 18 — and what each one corrupted is corrected where it lives. One of those eleven was reported by a reader rather than found here, which had not happened before. Another of them is the correction to that one, which carried an error of its own. A process that genuinely self-corrects will eventually catch something late; what matters is which side of publication each one landed on, so each entry carries its side and this paragraph counts them.
1e6; the book path did not. So "average price to fill $10,000" always equalled the top-of-book price and the whole ladder was flat. 99.9% of rows looked like this, and not one of them raised an error.n_ask was always 1. Apply a "≥ 3 ask levels" test and it fails 100% by construction. That was an artefact of our collection, not a property of their market. Publishing that about a regulated exchange once would be enough to destroy the "independent measurement" claim.active=true&closed=false, and those two flags do not exclude expired markets. 74% of the list was dead, the 20,000-market budget was spent on them, and the cursor never reached the currently active set. The symptom was "searching bitcoin returns 3 results". It also contaminated the statistics: dead markets have no book, so they were classified as empty quotes and dragged the tradeable share down.bid1 = 0, so spread = ask − 0 = ask. Whenever the ask was cheap (say 0.05) the spread came in under 0.10 and passed the test, for a market with not a single bid in it. The output before the fix read "spread 1.000 · ✅ tradeable", which is self-contradictory. Correcting it cut that category by more than half.stock_pools.json. That file was built on 2026-09-04, and the last pool in it was initialised at block 53,983,886. A round taken on 2026-09-12 sits at block 61,129,566 — 7,145,680 blocks later. In between, a QQQ/USDG pool was created that the table never saw. The $100 QQQ figure measured 6.58% against that table; measured against the chain, it is about 95.56%. One cell, one date, no error message: the table was not wrong, it was out of date. This is not the same defect as #08 — #08 was a scan that returned incomplete results, this is a complete snapshot of an earlier chain. What caught it was a question about provenance: which date is that table from? Nothing in the monitoring had a reason to look. The fix is not to rebuild the table in place — replaying an old block against a new table produces different rows and a different hash, so every already-published round would fail verification at once. What is needed is a versioned table: each round records which table it was replayed against, and the verifier selects by record. That is a change to the serialisation contract, so it is scheduled deliberately rather than patched in.$10,000 buy and dropped if it cannot fill one, so a pool that can fill $300 and not $10,000 is never a candidate — and $100 and $1,000 are exactly the sizes at which such a pool wins. Quoted against every initialized QQQ/USDG pool in the v4 PoolManager rather than against the table (a second AMM deployment was outside that scan — see error 12), at this page's own window block 54,088,399, QQQ returns 99.67% at $100 and 98.62% at $1,000. The table said 6.46% and 1.83%, and the sentence built on it said QQQ cannot be sold at any size. The pool doing that work is one contract, fee 0.30%, and its capacity — the largest notional it will quote — has been $9,841 → $10,506 → $287 across three pinned blocks, so what QQQ can absorb is not a property of the token at all. Unlike the entry above, rebuilding the table does not fix this — the probe would still be there. The fix is to select pools per size rather than once, which changes the method and is scheduled as such. Found 2026-09-23, after the ten above and after the film that names them. It was caught by a question that needed an archive endpoint to answer: does that cell survive a quote against every pool on the chain, at the block it claims?PoolManager’s Initialize events — a method that finds only venues matching a pattern we already knew. Re-enumerating by counterparty flow (each stock token’s Transfer logs, asking every address that both sends and receives it what it is) found at least three more venue classes, including pools from two further factories and a reserve-based AMM that is not standard UniV2. The fee tiers are not a fixed menu either (values of 50, 150 and 250 all appear). At this page’s own window block the QQQ figures were wrong at every rung and always in the same direction: the venue absorbing the order looked far worse than it was. Corrected, using the same method this page’s table uses (both legs quoted against the same pinned block’s book):| block | $100 | $1,000 | $10,000 | $100,000 |
|---|---|---|---|---|
| 54,088,399 | 99.8999% | 99.8984% | 99.8837% | 99.7363% |
| 61,129,566 | 99.8999% | 99.8984% | 99.8839% | 99.7371% |
| 70,427,772 | 99.8999% | 99.8986% | 99.8857% | 98.1465% |
fee() field within an hour and got three values, and all three assumed someone had mistyped. The field moves with the block. Separately, a quarantined dataset was read here as if it were the published series, because its quarantine lived only in a directory name that did not survive syncing.(1−f)² almost exactly — the price impact is undone by the leg that retraces it — which is why a realised round trip cannot see depth at all. Quoting both legs against a held-constant book costs roughly twice the one-sided impact plus the fees, and it degrades with size. So no number in the table changes; the label does. And it exposes a deeper problem with the field we proposed to the SEC: a round trip blends the buy and sell directions, while a forced seller walks one. The raw fields for the anomalous cell (block 70,427,772, $100,000): buy side 1.7354%, sell side 0.1214% — a 14.3× asymmetry, because the liquidity is lopsided. A forced seller faces the sell side only.err_record() took the first 0x… string it found in the human-readable part of a JSON-RPC error and reported ten characters of it as a selector. It was the leading four bytes of the stateRoot of the block that round was pinned to, and a 60-character truncation then in place had cut it six characters short of the closing bracket, so it did not look like the start of a bracketed string. Nothing reverted: the public endpoint was pruning the pinned block's state while the round was still running (missing trie node / layer stale), and a round takes 110–122 s against a state window this page measures at five to ten minutes. It was published before it was understood — in addendum 3 of the second series' pre-registration — and corrected in addendum 4. The collector now takes selector only from error.data, records a failure kind, and retries a state-unavailable call. Same class as the truncation itself: a quantity produced by our own parsing, read as a property of the object. Found 2026-09-27, after publication. The film says thirteen and card 4 shows 13 — both are dated 2026-09-26 artefacts, and this is the fourteenth.uiMultiplier(), ERC-8056 — and the issuer's own docs add that their oracle already incorporates the multiplier into the price. This project first reported "no getter we could find", having guessed at names like index() and sharePrice() instead of reading the extension. Corrected the same day, and the exposure this described is narrower than first written: an oracle-priced collateral value is not carrying this drift.) Three published texts said otherwise — "each token carries a per-asset index, observable on chain" (pre-registration addendum 2, §3), "Each tokenised stock … carries a per-asset index" (measurements/index-priced-test/README.md), and a docstring in code/read_accrual_index.py that described the log as holding a fixed-point index in one of its words. Each reads as something a reader can go and fetch, and a reader who goes looking finds two amounts instead. The same addendum states the mechanism correctly in its §1, which is how this survived: one document, one precise passage and one loose one, and the loose one was the passage likely to be quoted. All three now carry the correction, in the form each document allows: the pre-registration is dated and nothing below its banner is ever edited, so the banner states that §3's wording is withdrawn and the original sentence stays visible underneath; the measurement note and the docstring are corrected in place and say in the file which description was wrong. Found 2026-09-29, after publication, by writing the letter that the description was meant to support.eth_getBalance returns historical state is not available, while eth_getLogs over the same fifty-block range returns 524 events, and events are still served 20,000,000 blocks back — at 50,000,000 the query times out, which is a timeout and not an absence. So where events are served, realised execution over a past period is publicly recheckable, and that sentence had been denying it. A reader reported this, by pulling the event logs by hand; of the entries caught after publication it is the first that was not found inside this project. The claim is now read from a re-runnable measurement — code/measure_retention.py and measurements/rh-retention/retention-2026-10-09.json — instead of being held as a literal, and the generator refuses to publish an issue without it. Same family as several entries above: a limit on what I could obtain, written as a property of the thing.deepest_logs_served_blocks_back. Re-measured on 2026-10-11 with nothing changed but the span, fifty blocks narrowed to five: the same depth answers in under two seconds and returns thousands of rows. Logs are served at least 50,000,000 blocks back. What the earlier run found there was the cost of an unfiltered query, not the edge of the index — and this endpoint has two query caps, neither of them retention: 10,000,000 blocks of span and 10,000 matched rows, each named by the node in its own refusal. The probe now separates proven (rows came back), from answered (returned without error, which a node that has dropped its log index can also do), from refused, and escalates to a narrower span before concluding anything from a refusal. Published in this archive and in the measurement artifact of 2026-10-09; corrected where both live. Found 2026-10-11, after publication.error and the brackets computed over them — our own request rate reading as the chain’s retention. Pacing and a backoff fixed that. The fix then produced a quieter one: a rung whose answer was historical state 602f…3c429 is not available — unambiguously pruned — was classified as rate-limited, because the verdict was decided by testing whether the message contained 429, and that block’s state root happens to end in those digits. The rung was dropped from the retention bracket without a word. A status code is now matched as a whole token, never as a substring of a message that carries an opaque identifier, and the classifier has a drill whose arms are seven real messages from this endpoint — including that one — which must land in seven different buckets. Found 2026-10-11, before any figure from the rebuilt probe was published.Measuring at all can get you rate-limited. ParaSwap (now Velora) allows roughly 5,000 calls a day on the free tier, counted per egress IP rather than per key, and not separated by domain. We sent 5,622 in a day and got a solid 11 hours of 429s starting 23:31 UTC on 31 August, until the rolling window cleared.
0x disabled our key entirely on 4 September, after two notices about the quote-to-fill ratio. We stopped calling them rather than retrying, and 0x is excluded from the comparison until that is resolved.
But the barrier is not uniform, and that turns out to be the more useful finding. Asked the same question, 1inch replied that quote-only use is fine, that they have no quote-to-fill rule, and that they had never throttled a single one of our calls — with the condition that the free tier is for non-commercial use, which this is. So "independent measurement is impossible" is not an industry fact. It is the result of asking each provider, one at a time, and getting different answers. The barrier is not the code and not a universal policy. It is that almost nobody asks.
Admitting what is missing is more credible than pretending to be complete. Most of these errors surfaced only because figures were checked against the raw data; two of them survived to publication and were caught only when a re-run forced a correction. "Only about 10% of Polymarket markets are tradeable" was written into external copy and then withdrawn; "on-chain tokenized stock pools are all empty" had an entire section drafted before it was overturned. This is the reason to write a verification tool: the first errors it catches are your own.