Benchmark governance

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:

"getJson returns null on any !res.ok — 429 INCLUDED — and kalshiSeries turned that null into markets = []. A throttled request contributed zero candidates with no error, no warning and no count, and because the fan-out is a Promise.all over 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:

  1. 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.
  2. Broader book coverage at settle time — fixing the fetch rather than the admission. Note that 264bbe88 already 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".
  3. 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.

The rest of the set
Methodology change & consultation
What counts as a material change, the 14-day consultation window, and why changes are prospective.
Data licence & rights
What the free tier grants, what attribution it requires, and what commercial use needs.
The loop architecture
The nine scheduled agents that cultivate indices, which one may publish, and the six mechanisms that assure accuracy.
The confirm gate
What human confirmation covers — merges only — and how to read the provisional and single-venue counts.
Restatement policy
The three narrow conditions under which a published value may be corrected — and the many under which it may not.
Cessation & fallback
What happens when a benchmark cannot be computed, and why the history stays published forever.
Conflicts & the conflict wall
The wall between index operations and the trading circuit, the field crew rule (no trading, no relaying, latency never sold), and standing disclosures.
Data-error playbook
Detection, triage, quarantine — and the commitment to disclose errors nobody noticed.
Complaints & challenges
How to challenge a value, a rule, or a constituent. No account required.
Settlement-reference licensing
What licensing a benchmark to settle against requires — and why publication alone does not grant it. Reading a value is free; referencing it in something that settles is not the same act.
Determination, disruption & cessation
Written for contracts rather than charts: who determines a final value, the disruption fallback ladder, and why a refusal is not a cessation.
The independent committee seat
The seven-part independence test, published before a candidate exists; the power to block rather than comment; and what the administrator may do while the seat is vacant.
Incident process
Who is paged, what they do, and what gets published when the machinery fails — as distinct from a wrong value, which is the data-error playbook.