The drain proposed 2,750 commits over the Class A + B-high scope (1,932 true-drain + 818 re-point),
of which 141 were held for manual review (graded-via-fuzzy and Latin-script foreign titles), leaving
2,609 clean commits recommended for auto-apply. (Source: M3_DRAIN_DRYRUN.md,
m3_dryrun_proposed_changes.jsonl parsed = 2,750 commit + 437 demote; flagged = 141; clean = 2,609.)
Measured against the pinned after-state, the drain's live contribution is (this count held identical across all five reads, 15:38 through 20:30 (five hours), because it counts a closed cohort, so it is a stable headline, not a snapshot):
| Drain contribution (live, stable across 15:38 / 15:48 / 16:08 / 16:16 / 20:30) | Rows |
|---|---|
| Clean commits live on their proposed id, first-pass | 2,454 |
| Re-applied by the platform team after the tidy (committed-to-proposed, near-miss cleared) | 27 |
| Clean commits live on their proposed id, total | 2,481 |
| Clean commits no longer live (delisted, aged out of the table; 0 read null) | 128 |
| Drain-attributable live commits | 2,481 |
Decomposition of the drain by mechanism (from the dry-run, the framing the client asked for):
tcg_product_id and the matcher committed a fresh id at
confidence >= 0.70. This is net-new catalog coverage.Why this figure and not the raw band delta. The band moved from 5,592 (pre-drain, recon16) to
3,442 at the 20:30 pin (it was 3,377 at the 15:38 / 15:48 / 16:08 reads, 3,430 at 16:16, and 3,442 at
20:30). That movement is NOT the drain's effect, and it is not even stationary: the live sync churns the band
on its own cycle (it commits, purges, and re-tags rows between any two reads), which is exactly why the band
total itself drifts read-over-read. The honest attributable number is the 2,481 clean dry-run commits that
are verifiably live on their proposed id, a count that held identical across all five reads because it
measures a closed cohort the sync cannot grow. Read plainly: the drain is a batch acceleration of work the
live sync does piecemeal anyway, executed once, audited, with the risky cases held back.
Of the 2,609 clean commits, 2,481 landed and stayed on their proposed id; the other 128 have since aged out of the listings table entirely (delisted on eBay). 0 read null at the pin and 0 landed on an id other than the one proposed, so the apply wrote exactly the dry-run's proposed ids and the only attrition since is natural delisting (2,481 + 128 = 2,609). This is the closed accounting that makes 2,481 a fact and not a snapshot: the cohort is fixed at 2,609, every member is either live-on-proposed or aged-out, and the split held identical from 15:38 to 20:30.
Per-stratum shift, from the pre-fix matcher revision to the drain revision, scored against the 6,190-row
labeled sample. The priority stratum is the headline; the overall number is roughly flat and is deliberately
not the headline (the client's framing, carried from M3_BASELINE.md). The flagship game's name is withheld;
its strata are labeled flagship_* here.
| Stratum | n | Pre precision | Drain-revision precision | Pre recall | Drain-revision recall |
|---|---|---|---|---|---|
| flagship_high | 3000 | 99.23% | 99.39% | 94.53% | 92.07% |
| flagship_mid | 1500 | 97.59% | 96.49% | 91.79% | 77.10% |
| ambiguous_set | 39 | 88.57% | 86.67% | 79.49% | 66.67% |
| graded | 500 | 82.29% | 78.65% | 81.16% | 71.92% |
| other_games_matched | 200 | 73.53% | 73.05% | 63.13% | 61.62% |
(Source: the pre-fix and drain-revision scorer outputs, per-stratum block. flagship_high 99.39% / 92.07% and flagship_mid 96.49% / 77.10% re-verified in the drain-revision output.)
The story: flagship_high precision holds at 99.39% across the fix window. The priority game stays high and stable, which is the win. Coverage falls in the lower strata as the matcher gets more conservative. This is the precision-for-coverage trade by design: most of the commit-to-abstain flips are the matcher correctly declining to commit a multi-card lot, a graded slab, or a sealed box to a single-card product (the mid-title-quantity-as-lot, graded-routing, and precon-box-to-sealed fixes).
Overall caveat (carried verbatim from M3_BASELINE.md): the sample's ground-truth labels are the
platform's own, mostly pre-fix output, not an independent oracle, so a "coverage drop vs GT" is frequently
the matcher declining a pre-fix mis-commit, not a regression. The overall number is roughly flat to slightly
down with the priority stratum holding; an earlier draft had the overall framing inverted and this report
inherits the corrected, re-scored spine.
What safely stays abstained for offline review after the drain. The truly abstained queue is a slow-drifting
pinned snapshot, not a fixed fact: it sits on the live band, which is an open population the sync ingests new
near-misses into every cycle. It is 2,281 at the 20:30 pin (recon19), up from 2,269 across the four
15:38 / 15:48 / 16:08 / 16:16 reads, a +12 drift over four hours. The earlier reads were clustered in a
38-minute window, which made the open population look stationary; the four-hour read shows it is not.
| Residual cohort | Rows |
|---|---|
| Truly abstained, still in the near-miss band (offline-review queue); 20:30 snapshot, drifted +12 since 16:16 | 2,281 |
| Higher-risk commits held back at apply (graded-via-fuzzy + Latin-script foreign) | 141 |
The 2,281 is the genuine residual: rows with a null tcg_product_id still sitting in the active 0.50-0.70
band, snapshotted at 20:30 (live-confirmed). It is the offline-review queue, and it drifts upward because the
sync keeps adding fresh near-misses. The 141 held commits are the dry-run earning its keep (the matcher's
encoded rule: a wrong match is a wrong arbitrage): the live sync would commit these graded/foreign rows
blind; the drain surfaces them for manual routing instead.
Per-game band composition is a growing snapshot, pinned to 20:30: pokemon 2,021, one-piece 514, flagship 438, dragon-ball-super 261, yugioh 207, lorcana 1 (band total 3,442). This is the whole band, not the residual; it churns read-over-read (the band was 3,377 at the three earliest reads, 3,430 at 16:16, and 3,442 at 20:30, with pokemon and one-piece carrying most of the growth). Do not read the per-game row as steady state.
NOT counted as residuals: the band rows that carry a committed tcg_product_id yet are still tagged
near-miss. At the 20:30 pin this was 1,161 (1,108 at the three earliest reads, 1,161 at 16:16; split 70
drain-re-tagged + 1,091 non-drain). Like the abstained residual, it is an open, sync-driven count, not a
fixed one: it holds across a short window then steps up as sync cycles re-stamp committed rows. A post-pin
re-read confirms this (Observation 2). These are not residuals and not drain leftovers. They are a live-sync
data-hygiene issue (below).
1. The band is an open, self-churning population, and the abstained residual drifts with it. The platform's live sync daemon commits, purges, and re-tags near-miss rows every cycle, so the band is a population the sync keeps feeding, not a fixed set. The clearest evidence is the abstained residual itself: it read 2,269 across the four 15:38 / 15:48 / 16:08 / 16:16 reads (a 38-minute window) and 2,281 at 20:30, a +12 drift over four hours. The 38-minute clustering made it look stationary; the four-hour read disproves that. The band total tracks the same way (3,377 -> 3,430 -> 3,442). So the band's 5,592 -> 3,442 movement is partly (and non-stationarily) the sync's own work, not the drain. The drain is a one-shot, audited batch acceleration of what the sync does piecemeal; the only figure that reads as a fact is the 2,481 verified-live clean commits, stable across all five reads because it counts a closed cohort (2,609 = 2,481 live + 128 aged out) the sync cannot add to. This is why Section 1 reports the drain's contribution as the closed-cohort count, not the band swing.
2. A near-miss-tag hygiene issue that grows in steps with the sync (the concrete follow-up for the
platform team). Band rows that are committed (carry a tcg_product_id) yet are still tagged near-miss
numbered 1,108 across the 15:38 / 15:48 / 16:08 reads, 1,161 at 16:16, and 1,161 again at the 20:30 pin.
That 16:16-to-20:30 hold is a lull between sync cycles, not stability: a post-pin re-read shows the count
stepped to roughly 1,760 in the active band and about 1,950 across all bands (committed rows carrying a
near-miss tag regardless of band or status). The 20:30 decomposition is 1,091 non-drain rows (live-sync
commits that never cleared the near-miss columns) plus 70 that the live sync re-tagged after the platform
team's clear. The mechanism is the sync's match-preserve step: it restores a prior committed match onto a
row that re-parsed as a near-miss but does not clear the freshly-set near-miss columns, so each cycle
re-stamps a fresh batch of committed rows and the count steps up over time. This is NOT the drain and NOT a
residual; it is a one-line follow-up (clear the near-miss columns on any row that reaches a committed state,
mirroring the rematch write). The platform team's tidy already cleared the drain's own near-miss tags (the
27 re-applied rows verify cleared, manual overrides untouched). Because it steps up every cycle, the
clear-on-commit fix is the durable resolution, and the sooner it ships the smaller the one-time cleanup.
[Update, 2026-06-02: the platform team shipped the clear-on-commit fix plus a guarding invariant trigger to
production; this issue is closed.]
Five live read-only reads span 15:38 / 15:48 / 16:08 / 16:16 / 20:30 (2026-05-27). The first four
were clustered in a 38-minute window; the fifth (recon19, 20:30) is four hours later. What held vs drifted
across that span is itself a finding: the closed-cohort drain count (2,481) held identical across all five;
the open-population band figures (abstained residual, band total, per-game) drifted; committed-still-tagged
held at 1,161 from 16:16 to 20:30 (a lull between sync cycles) then stepped up after the pin to roughly 1,950
across all bands, confirming it too is an open, sync-driven count. All 2026-05-27 after-state figures pin to
20:30; the hygiene step-up is a post-pin re-read.
| Claim | Verified against |
|---|---|
| Abstained residual 2,281 at 20:30 (was 2,269 across 15:38 / 15:48 / 16:08 / 16:16; +12 over 4h, open population) | recon19.out (2,281 at 20:30) + four earlier read-only reads |
| Band total 3,442 at 20:30 (3,377 at 15:38 / 15:48 / 16:08, 3,430 at 16:16; drifts read-over-read) | recon19.out (3,442 at 20:30) + earlier reads |
| Committed-still-tagged 1,161 at the 20:30 pin (1,108 through 16:08; split 70 + 1,091), a lull; post-pin re-read ~1,760 in-band / ~1,950 all-bands, stepping up with the sync | recon19.out (70 / 1,091) + post-pin read-only re-read |
| Per-game band composition at 20:30 (pokemon 2,021 / one-piece 514 / flagship 438 / dragon-ball-super 261 / yugioh 207 / lorcana 1; sums to 3,442) | recon19.out 20:30 2026-05-27 |
| 2,481 clean commits live on proposed id (2,454 first-pass + 27 re-applied; 0 null, 0 on other id), stable across all five reads; closed accounting 2,481 + 128 = 2,609 | recon19.out indexed temp-table join, 2026-05-27 |
| 2,750 proposed = 1,932 true-drain + 818 re-point; 2,609 clean, 141 flagged | m3_dryrun_proposed_changes.jsonl (parser) + the dry-run revision-comparison output |
| 27 re-applied: committed-to-proposed, near-miss cleared, manual override untouched (27/27/27/0) | recon19.out |
| 6 reverts: null product id, manual-override false, near-miss cleared | recon19.out |
| The one matcher-adjacent commit landed after the drain revision is documentation-only and band-neutral (0 band rows at the documented tier's ids, 0 clean-commit ids in its id range, no code hunk in the diff) | diff of the post-drain commit + live band checks at the 20:30 pin |
| Per-stratum precision/recall | the pre-fix and drain-revision scorer outputs |