Finding — the WETX coverage breach, August 2026
Why WETX refused for five consecutive days, the change that caused it, and what is still not established. Published because an availability figure without the incidents behind it is a number nobody can check.
Status: finding. Written 2026-08-20 by the index administrator, as the written note required by
oracle build item O0.1.
Scope: WETX weight-basis coverage; the admission path in lib/indices/eligibility.ts and the
candidate pool in lib/indices/pool.ts. Measured from content/indices/benchmarks/*.json at commit
cd1ba96a.
No published value changes as a result of this note, and none is restated. Every row discussed here published what the methodology told it to publish, including the five that published nothing.
1 · What happened
WETX printed insufficient_data on five consecutive days. The refusal is recorded verbatim on the
2026-08-14 row:
class: "data-availability",rule: "min-weight-coverage"— "Weight-basis coverage 79.60% is under the 95.00% floor: of 4324 admitted constituents, 3442 carried an observed two-sided resting depth, 0 were served with at least one side empty, and 882 had no ladder served by any venue. The books were not delivered; the board itself is not in question."
The canonical universe, the admitted count and the unobserved count, read from the rows:
| Date | Universe | Admitted | Observed | Unobserved | κ | Margin vs 95% |
|---|---|---|---|---|---|---|
| 08-12 | 6,211 | 3,416 | 3,328 | 88 | 97.42% | +2.42pp |
| 08-13 | 6,056 | 3,446 | 3,355 | 91 | 97.36% | +2.36pp |
| 08-14 | 10,356 | 4,324 | 3,442 | 882 | 79.60% | −15.40pp |
| 08-15 | 10,995 | 4,488 | 3,560 | 928 | 79.32% | −15.68pp |
| 08-16 | 10,628 | 4,561 | 3,600 | 961 | 78.93% | −16.07pp |
| 08-17 | 11,117 | 4,567 | 3,601 | 966 | 78.85% | −16.15pp |
| 08-18 | 11,370 | 4,395 | 3,505 | 890 | 79.75% | −15.25pp |
| 08-19 | 7,991 | 3,437 | 3,418 | 19 | 99.45% | +4.45pp |
Nothing broke in mark collection. The observed count went up through the outage — 3,355 on the last good day, then 3,442 / 3,560 / 3,600 / 3,601 / 3,505. This was not a venue outage and not a collector failure. The denominator moved.
2 · The cause
The canonical universe nearly doubled on the first refusal day: 6,056 → 10,356. Admitted rose by 878; unobserved rose by 791. Within rounding, every constituent the widening added was one with no served book.
The change that did it is in the repository, dated to the day: 264bbe88, 2026-08-14,
"fix(pool): declaring more Kalshi series was making the board SMALLER". It replaced a
top-12-per-category cap with a rule admitting every Kalshi series carrying more than one open
event — 160 declared series to 284.
The same commit message describes, in its own words, the mechanism that then starved those admissions of books:
"
getJsonreturns null on any!res.ok— 429 INCLUDED — andkalshiSeriesturned that null intomarkets = []. A throttled request contributed zero candidates with no error, no warning and no count, and because the fan-out is aPromise.allover every declared series, widening the declaration widened the throttling. Every log said success."
So the sequence is: the declaration widened → the universe doubled → ~880 newly-reachable Kalshi markets cleared eligibility → the same widening throttled the fetch that would have served their books → the weight basis was computed over a population 20% of which had no ladder → the floor refused.
The floor did exactly its job. It is the reason WETX declined to print rather than publishing a number computed off 79% of its own weight basis. That is the whole purpose of the guard, and it fired on the first day it was needed.
2.1 · The unobserved were not junk markets, and this is the sharpest fact in the note
It is tempting to read 882 had no ladder served by any venue as "882 low-quality listings". It is
the opposite, and admission proves it. A constituent only reaches the weight basis by clearing
spread-too-wide (lib/indices/eligibility.ts:281), and maxSpread is constructed only from
listings carrying both a bid and an ask (lib/indices/benchmarks.ts:561-563); one-sided books are
refused earlier at consolidation as no-two-sided-book; and a liquidity floor of minVolume: 250
applies.
Every one of those 882 constituents therefore had a two-sided touch quote, inside the spread band, above the volume floor. What was missing was not a market and not a book — it was the ladder: the settle-time order-book call that turns a touch into a depth measurement.
So the gap is between the nomination feed (which had them) and the settle-time fanout (which
did not get them). That is a throughput failure, and it points at exactly the rate-limit hazard
264bbe88 documented on the way in. The bucket reading 0 were served with at least one side empty
does not mean the books were thin; it means a ladder is returned in full or not at all.
2.2 · One hypothesis tested and rejected
WETX carries venueWhitelist: ["polymarket"] on every row while its 08-14 composition contains 167
Kalshi constituents, which reads as an unenforced whitelist. It is not. The field is documented at
lib/indices/universe.ts:534 as "Venues admitted BEYOND the CFTC-regulated default" — an
additive admission statement, not a restriction. Kalshi is admitted by the default set. There is
no leak, and the fix is not enforcement.
3 · What is not established
Stated so nobody builds on a guess.
- Why 2026-08-19 recovered is only partly explained. Admitted returned to its pre-change level (3,437 against 3,446 on 08-13) while the universe stayed elevated at 7,991 — still 32% above the pre-change 6,056. The newcomers stopped being admitted; they did not start being served. What rejected them cannot be determined from the ledger, for the reason in §3.1.
- The exposure has therefore not gone away. The universe is still a third larger than it was on 08-13, and nothing in the admission path requires a served book. A repeat needs no new cause.
3.1 · The instrumentation gap that makes §3 unanswerable
WETGRI rows carry rejected: { count, byRule }. WETX and WETFRAG rows carry nothing. The data
exists in the pipeline — wetxPass.rejected and fragPass.rejected are computed and passed around
in scripts/index-settle.ts — and the row writer drops it for two of the three.
And the per-day composition archive
(content/indices/benchmarks/compositions/wetx/<date>.json) holds only the observed
constituents: 3,442 rows on 08-14, with columns ["eventId","p","liquidity"]. The 882 that had no
served book are named nowhere. They are a count and nothing else.
So the desk can say that 882 constituents were unobserved on 08-14 and cannot say which, from
which venue, or how newly listed — the three facts that would have identified this in an hour
rather than by archaeology. That is the gap O0.1 closes.
4 · The other three benchmarks, measured
O0.1 asks whether the same exposure sits under WETGRI, WETFED and WETFRAG. Printing is not
headroom, so this was measured rather than inferred, and the answer is not the one the question
expects:
| Coverage (κ) | Exposure | |
|---|---|---|
| WETGRI | 1.00 — universe 112, observed 95, missingBasis: 0 |
Real coverage, and it is complete. Not exposed. |
| WETFRAG | null by construction | "κ is null because this benchmark carries no weight basis — it is equal-weighted or derived by methodology, so there is no coverage to measure." |
| WETFED | null by construction | "a constant-maturity meeting strip… no admitted roster, no weight basis and no canonical universe. All three §2.6 quantities are NOT APPLICABLE." |
WETX is the only benchmark in the family with a live coverage exposure. The other three cannot breach a coverage floor because two of them have no coverage quantity at all, and the third is at 100%.
That is a finding about the family, not a clean bill of health. It means a coverage floor protects exactly one benchmark, and the other three are protected — where they are protected — by different gates. WETFRAG's two refusals (08-06 and 08-13) are not coverage refusals at all:
class: "thin-board",rule: "min-constituents"— "5 genuinely multi-venue constituent(s) out of 1308 admitted, against a 10 minimum. The venues answered; too few of their questions coexist on more than one venue today to read fragmentation from."
WETFRAG's constituent count over the fourteen days runs 5, 11, 18, 22, 23, 23, 11, 5, 21, 18, 21, 29, 28, 11. It does not sit above its floor; it oscillates across it, and its failure mode is a shortage of genuinely cross-venue questions rather than undelivered books.
5 · The headroom finding, which matters more than the outage
Over the eight days before the breach, WETX's median margin over the 95% floor was about 2 percentage points, and on 2026-08-08 it was 0.51pp.
A system with half a percentage point of margin does not need a disaster to refuse. It needs a Tuesday. The five-day outage is not an anomaly against a healthy baseline — it is what a system with no headroom does the first time its universe moves. Any remedy that restores printing without restoring margin has fixed the symptom.
6 · The remedy that will not be chosen
Lowering the coverage floor. It would work, immediately, and it would be wrong.
The floor is the guard. Moving a guard because it fired is how an index quietly stops meaning
anything. It is also a material methodology change under
methodology-change.md, which would put the reasoning through a 14-day
consultation and into public view — and any proposal to move it should have to survive that.
7 · The remedy
7.1 · Instrument the admission path first. No fix should be chosen before §3 is answerable.
Concretely: record rejected: { count, byRule } on WETX and WETFRAG as WETGRI already does, and
record the composition of the unobserved — by venue — rather than only its count. This is
additive disclosure: it enters no formula and no checksum.
By venue, and not by listing age, because listing age is not available. No open/listing time
reaches admission at any layer: not PoolCandidate, not RawContract, not EligibilityInput, not
CanonicalConstituent, not MemberMark — every one of them carries closeTime and none carries an
open time. Listing.openTime exists in the identity layer and the close never populates it, and
every committed registry.json entry carries firstSeen: 2026-08-14, the day that file was created.
Testing an age hypothesis is a producer change, not a query — which is a further reason §2.1's
throughput reading, which can be tested from venue response codes, should be tested first.
7.2 · Then choose from three costed candidates, in preference order:
- An admission guard requiring an observed two-sided book before a constituent enters the weight basis. This attacks the cause directly: a market with no book would never have entered the denominator, and the 08-14 universe doubling would have moved the universe without moving coverage at all. It is very likely itself a material methodology change, and that is a feature of the governance rather than friction in it.
- Broader book coverage at settle time — fixing the fetch rather than the admission. Note that
264bbe88already established that pacing alone does not clear Kalshi's rate limit: forty series fetched sequentially at 120ms spacing still returned four 429s. A request that never succeeds must be reported, not folded into the shape of "this series has nothing open". - An explicit published treatment for un-laddered admissions — the weakest of the three, because it changes what the number means rather than what it is computed from.
7.3 · Restore margin, not merely printing. The O0.1 gate is fourteen consecutive closes at
≥3pp of headroom over the floor, not fourteen consecutive prints. On the record above, WETX
cleared that bar on six of the eight pre-breach days and on 08-19. Six of nine is not a feed.
8 · Bearing on the oracle
O0.1 gates all of O1.* and this note does not close it. What it establishes:
- the cause is identified and is in the repository, with a commit;
- the recovery is not identified, and cannot be from stored data;
- the instrumentation to make it identifiable is specified in §7.1 and is additive;
- the exposure persists — the universe remains 32% above its pre-change size;
- and the fourteen-close headroom clock has not started.
A signed feed over this publisher would convert an operational gap into a cryptographically attested one. The gate stands.