Skip to content

docs/SCORE_CALIBRATION.md

English governs the contract statements on this page. Contract names, addresses and numbers are shown as they are on the chain.

Score calibration

What the basic scan does when pointed at real tokens on a real chain, what it got wrong, and what was changed because of it.

This document exists because a risk score that has never been checked against reality is a number, not a measurement. The current run is from 2026-09-26, engine 1.12.0, basic tier, on 84 tokens from Robinhood Chain mainnet and a rugged set of 32. It is gate 4 of docs/LAUNCH_READINESS.md. The first calibration, four tokens with engine 1.2.0 on 2026-09-08, is kept in §7 as history.

There is no accuracy claim here, and there will not be one. "99 % accurate" would require a labelled ground truth for what a rug is, and no such thing exists. What can be said is narrower and checkable: which specific findings fired on which specific tokens, which of those were wrong, what was done about the wrong ones, and which rugs the engine did not flag.


1. The set, and how it was labelled

1.1 Where the tokens come from

The set is read from the chain, not chosen by hand. services/watchdog/scripts/calibration.ts runs the watchdog's own discovery over blocks 69,245,956 to 71,745,956: 2,500,000 blocks, about 2.9 days of chain time, ending about 400,000 blocks (11 hours) before the run so that every token in it has had time to either survive or not. That window held 313 graduations, 7,024 hookless standalone pools and 33,588 launches.

KindHow it was pickedWhy it is in the set
GraduatedPons graduations in order, up to 60The case the product exists for: people can buy it
Standalone poolhookless v4 pools in order, up to 80, until five liquidity pulls are foundThe only place a liquidity pull is likely: Pons locks its graduation position
Fresh launcheight launches, evenly spaced through the windowThe overwhelming majority of what the chain makes
StablecoinUSDGA token that should not read as a rug
Tokenised equityAAPL, SGOV, GLD, SPCXSame, on a very different contract shape

The mixed set that came out is 84 tokens: 60 graduated, 11 standalone pools (every rug and survivor among the 80 pools read, and the first five untraded), 8 fresh launches, USDG and four equities.

A second pass, the rug hunt, labelled the first 219 of the 313 graduations the same way and scanned only the collapses their own insiders or first-minute buyers sold (§1.3, §4). Those are about one collapse in six, so finding enough of them takes far more graduations than the mixed set holds. Its files are in docs/calibration/2026-09-26/hunt/.

1.2 How a token is labelled

Every label comes from the token's own pool events. Nobody's opinion of a token is an input.

  • collapse: over at least 20 swaps, the last swap price is at most a tenth of the highest one. hoursPeakToTenth records how fast it fell. A fall to a tenth within minutes of the peak is what a dump looks like; a slow fade over days is what abandonment looks like.
  • lp-pull: the value of the pool's open positions fell below a fifth of its peak. Every position is valued at one reference price, the last swap's, so a range order and a full-range position are compared by what they hold, not by liquidity units (§2.8).
  • survived: at least 20 swaps and neither of the above.
  • untraded: fewer than 20 swaps.

A graduated token is labelled from its own graduation pool. The PoolGraduated event gives the position id, the position manager gives the pool it sits in, and ownerOf gives who holds it. §2.1 is why this matters.

1.3 Who sold the fall

A collapse is what a rug looks like from the chain, and it is also what a token everybody simply stopped wanting looks like. So every collapse also carries who sold it, measured between the peak and the fall to a tenth.

  • A sell is a transaction in which the Uniswap v4 PoolManager's balance of the token rose. Its sellers are the addresses whose balance fell in that transaction. Router hops net to zero, so no router is ever mistaken for the seller.
  • Insiders are:
  • the deployer, from the launchpad's own TokenLaunched event;
  • wallets that bought within 10 blocks (one second) of the launch;
  • wallets in a launch bundle within the first minute. A bundle is one buy that delivered to three or more wallets, or five or more buys in one block, by at least three wallets, each receiving 0.1 % to 10 % fewer tokens than the one before: the same spend repeated up a rising curve.
  • First-minute buyers are everybody who bought within 600 blocks (60 s) of the launch, insiders included. That group is too broad to call insiders. A Pons token can graduate 45 seconds after launch, and then everybody who bought on its curve bought in the first minute.
  • dumpBy is insiders when insiders sold at least half of the fall, early-buyers when first-minute buyers did, and others otherwise.

Tokens an insider moved to a fresh wallet before selling are not followed. Both shares are therefore lower bounds.

1.4 What the scan could see

Every token was scanned at the basic tier at the head of the run, between blocks 73,027,295 and 73,119,040; each row records its own analyzedAtBlock. The public RPC keeps no historical state, so a collapsed token cannot be scanned as it was before it collapsed. A collapsed row shows how the engine reads the aftermath. §4 separates the findings that would read the same before the dump from those that would not.

The files are docs/calibration/2026-09-26/tokens.jsonl (one row per token, with every finding, every unmeasured signal and the report hash), summary.md and history-cache.json (the labels and the dump attribution). The run of the day before, with engine 1.10.0 on the same window, is docs/calibration/2026-09-25/. That is the run whose findings were checked by hand in §2.


2. What was wrong, and what changed

The 2026-09-25 run with engine 1.10.0 was read finding by finding against the chain, and so were the runs with 1.11 and the first cuts of 1.12. Eight defects were in the engine and two in the calibration method. One more was a rug pattern the engine did not see at all. Every engine change is pinned by a test using the shape measured on chain: services/watchdog/test/launchpad-holders.test.ts, and liquidity-enumeration.test.ts and liquidity-units.test.ts for §2.7.

2.1 The calibration measured the wrong pool (method)

The first run labelled a graduated token from "the deepest v4 pool with a priced pair". Pons often graduates into a pool paired with a tokenised equity, with its own hook. Positions 3,100,357, 3,105,185 and 3,112,919, for example, sit in pools paired with NVDA (0xd0601ce1…9eec) under the Pons hook. The engine does not price that pair, so the script skipped it and measured a side pool instead. That happened for 12 of 60 graduated tokens: all three labelled lp-pull and all nine labelled untraded. The 38 collapses and 10 survivors had been measured on the right pool.

None of the three "liquidity pulls" was one. Each graduation position is held by PonsV2LaunchLocker (0x267444d0…4952), which cannot release it. What moved was other people's liquidity in side pools:

  • 0xd62971d5…f38e held a full-range position added at block 69,608,477, 25,000 blocks before the graduation. It was removed at block 70,064,908. The script's window started at the graduation, missed the add, and saw a net liquidity of −13.46e18.
  • 0x952e51b8…d9a9 and 0x6afc1e6c…ce5e were concentrated positions managed actively. The second saw 667 liquidity changes. Liquidity units from different tick ranges were summed as if they were comparable, which they are not.

Changed. A graduated token is labelled from its graduation pool, which is found from the PoolGraduated event's position id. A position whose net goes negative is left out of the pull test, and the history says so in liquidityWindowIncomplete. Measured on their graduation pools, the three ex-"pulls" are all collapses, and of the nine ex-"untraded" seven are collapses and two survived. Across all 219 graduations read, every graduation position is held by PonsV2LaunchLocker with its code hash unchanged.

2.2 The launch locker counted as a whale (engine)

Observed. On 0x36e28df2…de54, a graduated token, one address held 94.19 % of the circulating supply. The engine raised EVM_SINGLE_HOLDER_MAJORITY: critical, 70 points. That address is PonsV2LaunchLocker. At every graduation its lockTokenSupply takes 81,632,653 tokens, 8.16 % of supply, and nothing can move them out: its only CALL pulls tokens in (bytecode read 2026-09-25). Once a collapsed token's float had been sold into the pool, the locker's tranche was most of what was left. The same finding fired on 22 of 38 collapsed graduations. On others the locker showed up as the top holder behind EVM_HOLDER_CONCENTRATION.

Changed (1.11). A listed position locker that received the token is excluded from the circulating base, as burn addresses already are, while its runtime code hash still matches the one on record. That is the rule the liquidity-lock read already used.

2.3 A bonding curve counted as a whale (engine)

Observed. On 0xa9288243…b782, a fresh launch, one address held 99.9965 % of supply and the engine raised EVM_SINGLE_HOLDER_MAJORITY. That address is the token's Pons bonding curve. Pons mints the whole supply into the curve, which sells it until graduation: the curve is the market, not a holder. The same finding fired on 6 of 8 fresh launches. This is the defect of §7.2, where the v4 PoolManager was read as a whale, on a different contract.

Changed (1.11). Pons curves share a code size (10,229 bytes) but not a code hash, because each carries its token in its immutables, so a code check cannot name one. Instead, the holder fold reads the launchpad's own TokenLaunched event in the block of the token's first mint. The curve it names is excluded from the base and treated as a source of purchases. Only the launchpad's contract can make an address a curve this way.

2.4 Routing counted as a bundle (engine)

Observed. EVM_BUNDLED_BUYS ("multiple recipients funded in single transactions") fired on 37 of 38 collapsed graduations, on 8 of 10 survivors, and on every untraded graduation. A finding that fires on everything tells a reader nothing. Reading the transactions it cited showed why:

  • 0x2125e2aa…3eaf has five recipients: the Pons hook's fee, three router hops and the buyer. That is one purchase.
  • 0x07af352b…117d has three: the hook's fee, an aggregator's fee and the buyer.

The engine counted every address a transfer touched.

Changed (1.11). A transaction delivers tokens to the addresses whose balance it raised. The hops net to zero, and early buyers are credited the same way. A v4 pool's hook now counts with its pool, because on this chain the Pons hook takes its fee in the token inside every swap. A real bundle still counts. 0x916e5ff6…5e1d funded 20 wallets one block after its token launched, and 1.11 reports it exactly as 1.10 did.

2.5 Early concentration on a token nobody had bought (engine)

Observed. Once 1.11 recognised the curve as a market, it could see purchases from it. On 0x551fccc0…cdc6 one wallet had bought 0.088 % of supply, and "a few addresses took most of the tokens sold early" became true and high. It is also meaningless. It is the defect of §7.3, a token nobody had traded called concentrated, arriving through the early-buyer heuristic instead of the holder one.

Changed (1.11). EVM_EARLY_CONCENTRATION is not evaluated when less than one per cent of supply was bought in the early window. The engine reports EVM_EARLY_VOLUME_NEGLIGIBLE instead: unmeasured, neither a finding nor reassurance. This is the rule EVM_NO_MEANINGFUL_FLOAT already applies to holders, but it is measured on what was bought, not on what is still held. On 0xa9288243…b782 eleven wallets bought 44 % of supply in the first half hour, one of them 21.6 %, and sold nearly all of it back to the curve: they hold 0.003 % now. The finding still fires there, and it is true.

2.6 A bundle split across transactions (engine, a false negative)

Observed. On 0x99c492e2…ccac, the dump attribution (§1.3) found blocks with seven, eleven and twelve separate purchases, each receiving about 2.7 % fewer tokens than the one before. That is one spend repeated up a rising curve by a script holding many wallets. Fifty-two wallets bought that token this way in its first minute. Transaction by transaction they were single buys, so 1.10 saw no bundle.

Changed (1.11, tightened in 1.12). Single-wallet purchases in one block, each 0.1 % to 10 % smaller than the one before, count as a bundle. The evidence reads "N wallets, M equal-spend purchases in block B". 1.11 asked for three such purchases. Reading its evidence on survivors showed runs of three and four next to runs of eight to eleven, and three or four is also what a launchpad's preset buy button looks like when a few people press it in the same busy block. 1.12 asks for five, from at least three wallets. Purchases of varied size landing together are what a crowd looks like, and they do not count. Tests pin all three shapes.

2.7 A partial pool search read as the token's whole liquidity (engine)

Observed. The first 1.11 run reported EVM_V4_LP_UNLOCKED ("liquidity positions are held by ordinary accounts") on 10 collapsed graduations and 5 survivors, and EVM_LIQUIDITY_CRITICAL on

  1. The 1.10 run a day earlier reported neither on a graduation. On 0x6f3d7f33…1be8 the engine saw a single pool: a USDG side pool held by an ordinary account. The locked graduation pool was not in the list at all.

The engine finds a token's pools from Initialize events in the last 3,000,000 blocks, about three and a half days. A day later, this window's graduations had aged out of it, and only younger side pools were left inside. An empty pool list from such a window was already reported as unmeasured. A non-empty one was treated as the whole list.

Changed (1.12). The holder fold finds the token's first transfer. Once it has, a token older than one window is searched again from that block to the head, in consecutive 3,000,000-block windows, at most ten (about 35 days). The LP ownership read for each pool then starts at that pool's own Initialize block. On 0x6f3d7f33…1be8 the search now finds four pools, the locked graduation pool among them, and reports thin liquidity as a measurement.

Where the search still cannot reach the first block (older than ten windows, or the wider search refused), depth below the threshold is EVM_LIQUIDITY_WINDOW_PARTIAL and the v4 lock state is EVM_LP_LOCK_UNKNOWN. Neither is a finding. Depth above the threshold is still reported, because an older pool can only add to it.

2.8 Liquidity units compared across ranges (method)

Observed. The rug hunt labelled two graduations lp-pull. Both graduation pools still held the locked full-range graduation position at 100 %. What had been withdrawn in each was a single-tick range order, 157800–158000 and 147800–148000. A liquidity unit in a one-tick range is worth a sliver of one in a full range. So that order held 68 % and 87 % of the summed units while holding little of the capital. The per-position rule of §2.1 still compared units across ranges.

Changed. Every position is valued at the last swap's price, and a pull is the open positions' value falling below a fifth of its peak. The two became a survivor and a collapse: each still holds 99 % of its peak value. The one standalone pool the unit rule had flagged was a real pull. Its four large positions were all withdrawn, and less than 1 % of its liquidity units remain. The value rule found two more (§4).

2.9 A shared router read as a shared funder (engine)

Observed. EVM_LINKED_WALLETS ("top holders share a funding source") is high and caps trust at

  1. The first 1.12 run reported it on 6 of 10 surviving graduations. On 0x866cdac5…6eea the "funder" of six top holders was 0xb92fe925…4f4f. That is a router hop, the same one §2.4 found passing tokens on in a purchase. The engine took a holder's funder to be the from of the first transfer the holder received, which for a routed purchase is the router. Everybody who bought through one router was "linked".

Changed (1.12). A holder's funder is the address that lost the most tokens in the transaction that first delivered to it, the same net-flow rule §2.4 applies to bundles. Router hops cancel out. A holder that bought from a market (a pool, a launchpad curve, the pool manager, a pool's hook) counts as resolved and linked to nobody. One funded by issuance stays unresolved, as before. A wallet spreading tokens to others in one transaction is still their funder. On 0x866cdac5…6eea the finding is gone and trust is 100.

2.10 A token on its curve called untradeable (engine)

Observed. Six of eight fresh launches read EVM_NO_LIQUIDITY_FOUND: "No pool has been created for this token … On the evidence available it is not tradeable", high, 45 points. Each was on its Pons curve and could be bought and sold there.

Changed (1.12). With no pool, and a launchpad curve that still holds some of the token, the liquidity category reports EVM_LIQUIDITY_BONDING_CURVE: unmeasured, because the curve's depth is not read. The deep tier now scores liquidity after the holder fold, as the basic tier does, because the fold is what finds the curve.

2.11 An unlocked verdict over a pool that weighs nothing (engine)

Observed. On the final 1.12 run EVM_V4_LP_UNLOCKED still fired on 7 collapsed graduations, every one of them with its graduation position locked. On 0x61bdb808…a3a2 the engine found two pools. One was the locked graduation pool, paired with an asset it does not price. The other was a USDG side pool holding 0.0002 ETH, owned by an ordinary account. The lock state is weighted by priced depth. The unpriced pool weighed nothing, however much it held, so the dust pool was "100 % of priced depth, unlocked".

Changed (1.12). While a pool the engine cannot price holds liquidity, the unlocked verdict is EVM_LP_LOCK_UNKNOWN, naming the holders it read. A locked verdict is a lower bound and still stands. Only rows that carried the finding could change, and those 16 were scanned again.

2.12 Not a defect: USDG and the tokenised equities are withheld

All five reference tokens had their score withheld: 37 % of the weight was measured, under the 60 % the engine publishes at. Each was checked, and this is the engine working as designed:

  • Holders. They cannot be folded at this tier from a public endpoint. These tokens have far more transfer history than the basic budget reads, and the endpoint throttles the reads it does make. EVM_HOLDERS_UNAVAILABLE says which of the two happened.
  • Liquidity. Not judged. These tokens are months older than the ten windows the pool search reads (§2.7), so depth below the threshold is EVM_LIQUIDITY_WINDOW_PARTIAL. On this chain they are also quote assets themselves. In the 1.10 run AAPL's search found 12 pools, all against launch tokens, and none of them priced.

In the 2026-09-08 run the engine published 60, elevated risk for both USDG and AAPL (§7.4). Now it says it could not measure enough to publish a number. For a regulated issuer's token that is the honest answer from the basic tier. The capability findings it does report are true. All five contracts are upgradeable and mintable, with privileged roles. The four equities can also be paused and can have balances seized.


3. What engine 1.12 reports on the set

3.1 The mixed set

Every row is in docs/calibration/2026-09-26/summary.md. The score column counts every row; a withheld row is one the site shows without a headline, because under 60 % of the weight was measured.

GroupnTrust (count)WithheldFindings that fire most
Graduated, collapsed5040 ×39, 20 ×6, 98 ×2, 100 ×36LIQUIDITY_LOW 38, BUNDLED_BUYS 36, HOLDER_CONCENTRATION 25, SINGLE_HOLDER_MAJORITY 6
Graduated, survived10100 ×4, 99 ×2, 98, 97, 40, 201BUNDLED_BUYS 6
Standalone pool, liquidity pulled394, 40, 202see §4
Standalone pool, collapsed1200see §4
Standalone pool, survived240, 200EARLY_CONCENTRATION 2
Standalone pool, untraded520 ×3, 40 ×20SINGLE_HOLDER_MAJORITY 2, LIQUIDITY_LOW 2
Fresh launch, on its curve840 ×4, 20, 97, 98, 1005NO_RECENT_ACTIVITY 6, EARLY_CONCENTRATION 4, NO_CODE 1
USDG1401capability findings only (§2.12)
Tokenised equities420 ×44capability findings only (§2.12)

3.2 What changed on the same tokens

56 graduated tokens were scanned on both days: with 1.10 on 2026-09-25 and with 1.12 on 2026-09-26. Counts of each finding across the 56:

Finding1.101.12Why it moved
BUNDLED_BUYS5338routing and hook fees no longer count (§2.4); three or four equal buys in a block no longer count (§2.6)
SINGLE_HOLDER_MAJORITY246the launch locker is not a holder (§2.2)
LINKED_WALLETS211a shared router is not a shared funder (§2.9)
HOLDER_CONCENTRATION1623with the locker out of the base the real top holders are measured, and tokens that read as "single holder majority" read as concentrated instead
LIQUIDITY_LOW3239measured on the graduation pool, found from the token's first block (§2.7)
EARLY_CONCENTRATION74the early-volume guard (§2.5) and purchases credited by net flow (§2.4)
V4_LP_UNLOCKED40§2.11
NO_RECENT_ACTIVITY299not the engine. The window is the last three hours, and on 2026-09-26 trading bots made buy-and-sell round trips on many of these tokens: on 0xd3cd69ad…9989, two round trips inside the window

Seven of the 56 were withheld on both days.

3.3 Collapse against survivor

On the graduated tokens, 45 of 50 collapses score 40 or less and 8 of 10 survivors score 97 or more. Most of that separation is the aftermath. LIQUIDITY_LOW fires on 38 of the 50 collapses and on 1 survivor, and a pool whose price fell to a tenth has given up most of its paired asset. It says the token is thin now. It does not say the collapse was foreseeable.

The finding that reads the launch, BUNDLED_BUYS, fires on 36 of 50 collapses and on 6 of 10 survivors. Bundled launches are common on this chain. On their own they do not tell a rug from a survivor, which is why the finding is medium and barely moves a score: a token whose only finding is BUNDLED_BUYS scores 97 or 98.

Five collapses score 97 or more:

  • 0xc8488be2…d903 and 0x8c8a99a6…8b3b faded to a tenth over 36 and 55 hours, and no insider sold into the fall. That is abandonment rather than a dump. The engine has no price-history finding, so it cannot say a token has already fallen.
  • 0x74b1123c…72ca: its graduation pool is paired with an asset the engine does not price. Thin liquidity is therefore unmeasured rather than a finding.
  • 0xbf184659…65a7 and 0x741352fa…b5cb are withheld: their holder fold ran past the basic budget, and their liquidity is unpriced too.

The survivors that score low are real findings: 0xa62f748f…8c1b has one holder with most of its float, and 0x5da9ffe4…a5a2 has thin liquidity.

3.4 After this run: engine 1.13 prices equity pairs

A fifth of Pons graduations pair with a tokenised equity (46 of 219), and on 1.12 their depth was unpriced, which is how 0x74b1123c…72ca above scored 100. Engine 1.13 prices eight equities through their ETH reference pools (docs/WATCHDOG.md). The 20 rows of this set that had unpriced liquidity were scanned again with 1.13 a day later; the rows are in docs/calibration/2026-09-26/rescan-1.13.jsonl.

  • 12 are now priced. LIQUIDITY_LOW fires on 10 of them: 9 collapses and 1 survivor.
  • Three collapses fell from 97 or 100 to 40: 0xbf184659…65a7, 0x741352fa…b5cb and 0x6971c56d…346d.
  • 0x74b1123c…72ca still scores 100. Its META pool holds about 2 ETH of depth, above the threshold, and nothing else fires. It faded over 15 hours with no insider selling: abandonment, of the kind the engine has no price-history finding for.
  • 8 stay unpriced. They pair with GLD, MSFT or an equity outside the eight.

Other differences between the two scans are the chain a day later: recent activity, and holders who moved. The tables above remain the 1.12 run.


4. The rugged set, and what the engine misses

4.1 Which tokens rugged

The rug hunt labelled the first 219 of the window's 313 graduations: 178 collapsed (81 %) and 41 survived. That the typical graduation collapses is the state of this chain, not a finding about any one token. 117 of the 178 fell to a tenth within an hour of their peak.

No graduation liquidity was pulled. All 219 graduation positions are held by PonsV2LaunchLocker, with its code unchanged, so every graduated collapse is a sale. What makes a collapse a rug here is who sold it (§1.3). Adding the standalone pools of the mixed set, the rugged set is 32 tokens:

  • 14 insider dumps: the deployer, first-second buyers and launch-bundle wallets sold at least half of the fall. In 7 of the 14 the single largest seller was the deployer.
  • 15 early-buyer dumps: first-minute buyers sold at least half, insiders less. 14 are graduated; 1 is a standalone pool.
  • 3 liquidity pulls: standalone pools whose owners withdrew the liquidity. The positions kept 2.2 %, 2.7 % and 14.6 % of their peak value.

4.2 Before and after

Every rugged token was scanned after the fact. The findings split in two:

  • Launch findings: BUNDLED_BUYS and EARLY_CONCENTRATION. Both are computed from who bought in the first 30 minutes, and the later sells do not change that. A scan taken at graduation already sees the launch bundles. These are fair evidence of what the engine would have said in time.
  • Aftermath findings: SINGLE_HOLDER_MAJORITY, HOLDER_CONCENTRATION, LIQUIDITY_LOW, LIQUIDITY_CRITICAL and V4_LP_UNLOCKED. These describe the token after the fall. They are true, but they are not a warning anybody could have acted on.

4.3 The rugged set

"Insider / first-minute share" is the share of the fall each group sold. "Top seller" is the role of the single largest seller. "Hours" is peak to a tenth.

TokenWhat happenedInsider / first-minute shareTop sellerHoursTrustLaunch findingsAftermath findings
0x2f8ec01b…0a4finsider dump0.97 / 0.97deployer0.0120BUNDLED_BUYSLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0xe3a77797…c8a8insider dump0.94 / 0.94deployer0.0820noneLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0x0590527a…ff88insider dump0.93 / 0.93deployer0.0340noneLIQUIDITY_LOW
0xcb9be307…33cainsider dump0.83 / 0.86launch-bundle020BUNDLED_BUYS, EARLY_CONCENTRATIONSINGLE_HOLDER_MAJORITY
0x6620bdbd…a0c6insider dump0.79 / 0.86first-second0.5320noneLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0x6c8c4a1d…ca3binsider dump0.79 / 0.98first-second020BUNDLED_BUYSLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0x381584d0…6b8einsider dump0.73 / 0.74deployer1.1940noneHOLDER_CONCENTRATION, LIQUIDITY_LOW
0x16ab8841…3c7einsider dump0.72 / 0.72deployer0.0940BUNDLED_BUYSLIQUIDITY_LOW
0x1cfdc5d4…51dfinsider dump0.69 / 0.71deployer0.0320BUNDLED_BUYSLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0xf7172876…954dinsider dump0.65 / 0.81first-second0.0240BUNDLED_BUYSLIQUIDITY_LOW
0x0fa68088…3d77insider dump0.62 / 0.62launch-bundle0.0620BUNDLED_BUYSLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0xf414a591…466einsider dump0.61 / 0.68deployer3.3440BUNDLED_BUYSHOLDER_CONCENTRATION, LIQUIDITY_LOW
0x8d67fc56…bacainsider dump0.59 / 0.59none of these0.0540BUNDLED_BUYSHOLDER_CONCENTRATION, LIQUIDITY_LOW
0x006fef96…2definsider dump0.57 / 0.57launch-bundle0.0220BUNDLED_BUYSLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0x30969722…d544early-buyer dump0.00 / 0.90first-minute0.0140noneLIQUIDITY_LOW
0xd2758864…97f1early-buyer dump0.00 / 0.86first-minute0.0140noneLIQUIDITY_LOW
0x5ab704ae…f20eearly-buyer dump0.25 / 0.80launch-bundle0.0140BUNDLED_BUYSHOLDER_CONCENTRATION
0x83eaa5fd…36dbearly-buyer dump0.24 / 0.76deployer040EARLY_CONCENTRATIONHOLDER_CONCENTRATION
0xbf4bdfa9…0261early-buyer dump0.12 / 0.74first-minute0.0340BUNDLED_BUYSLIQUIDITY_LOW
0xca0368bd…65d4early-buyer dump0.35 / 0.73deployer0.0140noneHOLDER_CONCENTRATION, LIQUIDITY_LOW
0x04438b3b…b995early-buyer dump0.14 / 0.68first-minute0.0140BUNDLED_BUYSLIQUIDITY_LOW
0xb8ca9477…548aearly-buyer dump0.05 / 0.62none of these0.0220BUNDLED_BUYSLIQUIDITY_LOW, SINGLE_HOLDER_MAJORITY
0x9dfee234…00c1early-buyer dump0.27 / 0.62none of these0.0140BUNDLED_BUYSHOLDER_CONCENTRATION, LIQUIDITY_LOW
0xe86b6dc3…a84dearly-buyer dump0.00 / 0.58first-minute0.8140BUNDLED_BUYSLIQUIDITY_LOW
0xeb1a6105…7a14early-buyer dump0.20 / 0.57first-minute0.1220BUNDLED_BUYSSINGLE_HOLDER_MAJORITY
0x6971c56d…346dearly-buyer dump0.05 / 0.56first-minute0.0497BUNDLED_BUYS—
0x99c492e2…ccacearly-buyer dump0.20 / 0.56first-minute0.2140BUNDLED_BUYSLIQUIDITY_LOW
0x30dd3d3d…7fc6early-buyer dump0.06 / 0.54deployer0.3840BUNDLED_BUYSLIQUIDITY_LOW
0x7efe97ba…ba26liquidity pullvalue kept 0.022——40 (withheld)BUNDLED_BUYSLIQUIDITY_LOW
0x0e9320e7…1ad8liquidity pullvalue kept 0.145——20noneLIQUIDITY_CRITICAL, MUTABLE_FEE, NO_RECENT_ACTIVITY, SINGLE_HOLDER_MAJORITY, TRANSFER_RESTRICTIONS, V4_LP_UNLOCKED
0x88042d98…9733early-buyer dump (standalone)0.00 / 0.90first-minute2.9320noneLINKED_WALLETS, LIQUIDITY_CRITICAL, SINGLE_HOLDER_MAJORITY, V4_LP_UNLOCKED
0x6b0d02d3…1e18liquidity pullvalue kept 0.027——94 (withheld)BUNDLED_BUYSOWNER_ACTIVE

All 32 score 40 or less except two. 0x6971c56d…346d has an unpriced graduation pool, and 0x6b0d02d3…1e18 is withheld with its remaining liquidity unpriced. A launch finding fires on 23 of 32.

4.4 What the engine misses

Nine of the 32 carry no launch finding. They are the false negatives:

  • The deployer sold. This covers 0xe3a77797…c8a8 (94 % of the fall), 0x0590527a…ff88 (93 %), 0x381584d0…6b8e (72 %) and 0xca0368bd…65d4 (26 %, the largest single seller). In 7 of the 14 insider dumps the deployer was the top seller. The basic tier cannot name a deployer: the pruned endpoint cannot find the creation transaction (EVM_ARCHIVE_UNAVAILABLE). That matters less than it looks, because at graduation all four were flagged as holder concentration (§4.5).
  • Snipers diluted by the crowd. On 0x6620bdbd…a0c6, wallets that bought in the first second sold 79 % of the fall. EARLY_CONCENTRATION is evaluated over 30 minutes and only while at most 50 wallets have bought. 96 bought in that window, so it was not evaluated, although the top 20 took 69 % of the buying. A first-seconds window would see this. It is not built.
  • A stampede of the whole curve. On 0x30969722…d544 and 0xd2758864…97f1, first-minute buyers sold 90 % and 86 % of the fall, and no insider is identifiable. A token that graduates in under a minute has only first-minute buyers, so this may be coordinated or may be a crowd. After the fall the engine says nothing about it. At graduation both were flagged as holder concentration (§4.5).
  • A liquidity pull with no launch warning. 0x0e9320e7…1ad8 shows only aftermath findings: liquidity critical and unlocked.
  • The standalone early-buyer dump 0x88042d98…9733 also shows only aftermath findings.

The other two pulls carry BUNDLED_BUYS but are withheld now. 0x7efe97ba…ba26's holder fold ran past the basic budget, and 0x6b0d02d3…1e18's remaining liquidity is unpriced.

4.5 At graduation, and how fast the dumps came

The collapses were scanned after the fact. Their Transfer logs are complete, though, and balances at any block fold out of them exactly. services/watchdog/scripts/replay-at-graduation.ts runs the engine's own holder logic on the balances at each graduation block, for all 216 labelled graduations the launch event could be found for. It uses the engine's exclusions and names the deployer from the launch event. The output is docs/calibration/2026-09-26/replay-at-graduation.json.

GroupnHolder finding at graduationSingle-holder majorityConcentrationDeployer the top holder
Insider dumps148447
Early-buyer dumps145053
Other collapses1502171413
Survivors3810377

Six of the seven holder-shaped misses of §4.4 were visible at graduation:

  • The four deployer dumps: the deployer held 26 % to 63 % of supply. That reads as a single-holder majority or as concentration without knowing whose wallet it is.
  • The two stampedes: concentration.

Only the first-second snipers of 0x6620bdbd…a0c6 were not. Naming the deployer from the launch event would add a name to a finding that already fires; it would not add a detection. It is not built.

Concentration at graduation is not a collapse predictor. It fires on 10 of 38 survivors and on 21 of 150 other collapses. Insider dumps are where it fires most, 8 of 14.

What decides whether a warning is any use is time. 12 of the 14 insider dumps and 13 of the 14 early-buyer dumps fell to a tenth within an hour of graduation, and half of them within four minutes. The watchdog commits its scan a median 1 h 03 min after graduation (docs/reviews/2026-09-26-gate2-coverage.md). For almost every dump here, the committed record describes the aftermath. A warning in time has to come from a scan taken at or before graduation:

  • the browser scan a visitor runs themselves, which reads the chain at that moment;
  • or scanning tokens while they are still on their curve, which the watchdog does not do today.

Two limits recur across §3 and §4:

  • Pools paired with a tokenised equity are unpriced. Pricing them would take reference pools for each equity, the way USDG is priced now.
  • The watchdog's committed scan comes too late for the fast dumps that make up most of the rugged set. That is a question of when and what the watchdog scans, not of the engine.

5. What this does not establish

  • No accuracy rate. Every number above is a count on a set chosen to cover the chain's states, not a random sample. It cannot be turned into "the engine is right X % of the time".
  • Only the holder findings before the fall. The public endpoint keeps no historical state, so every collapsed token was scanned after it collapsed (§1.4). §4.5 replays the holder findings at graduation from the Transfer logs. Liquidity and activity were not replayed. The watchdog's own batches are scans of tokens that had not yet collapsed: since batch 23 with engine 1.13, batches 19 to 22 with 1.12, and before that with 1.10. They will be re-checked against what those tokens did next.
  • Nothing about the deep or forensic tiers, BNB Chain or Solana. This run is the basic tier on Robinhood Chain.
  • Tokens older than about 35 days. The pool search reads at most ten windows back (§2.7). An older token gets no liquidity finding below the threshold and no lock state. The graduations here were one and a half to four and a half days old.
  • Launchpads other than Pons. 1.12 knows the Pons curve and the Pons locker. A curve or locker of another launchpad is still counted as a holder until it is listed in the chain registry, and would reproduce §2.2 and §2.3 for its tokens.

6. Reproducing this

cd services/watchdog
# the whole run: discovery, labels, dump attribution, a basic scan of every selected token
npx tsx scripts/calibration.ts --out <dir> --to 71745956
# the rug hunt: label the first 219 graduations, scan the insider and early-buyer dumps
npx tsx scripts/calibration.ts --out <dir>/hunt --to 71745956 --hunt 219
# a few tokens, labels and attribution only
npx tsx scripts/calibration.ts --out <dir> --no-scan --only 0x36e28df2dbf385d044897e9671681d3a6a14de54
# one token's full signal list
npx tsx src/cli.ts scan robinhood <address> --json

The script keeps discovery.json and history-cache.json in <dir> and reuses them on a rerun. discovery.json is not committed, at 18 MB; --to 71745956 reads the same 2,500,000-block window again. Copying the committed history-cache.json into <dir> keeps these labels; without it the labels are read at the new head, and a token can have collapsed since.


7. History: the first calibration, 2026-09-08 (engine 1.2.0)

Four tokens: a graduated token ("Lemon"), a fresh launch, USDG and AAPL, scanned with engine 1.2.0. That engine counted risk points, where higher was worse; the engine today reports trust, 0 to 100, where higher is better. No figure in this section can be set beside a score on the site. What the run found, and what was changed:

7.1 A graduated token reported as having no liquidity

0x20894263…1e8d ("Lemon") had graduated to a live v4 pool with a fee of 810000 (81 %) and a tick spacing of 19988. The scan probed a fixed list of fee tiers and reported EVM_NO_LIQUIDITY_FOUND, 45 risk points. Since then the scan enumerates a token's pools from the PoolManager's own Initialize events. An empty list is a finding only when the pools were enumerated; otherwise it is EVM_LIQUIDITY_NOT_ENUMERATED, unmeasured.

7.2 The Uniswap v4 singleton counted as a whale

0x364e4f0e…8844 scored 80 on EVM_SINGLE_HOLDER_MAJORITY. The holder was the v4 PoolManager, which holds every pool's tokens. Since then the PoolManager and PositionManager are excluded from the circulating base.

7.3 A token nobody had traded, called concentrated

With the pool excluded, that token's float was 764 tokens out of 1e27. When less than 1 % of supply is held outside pools, burn addresses and the token contract, concentration is not claimed. The engine reports EVM_NO_MEANINGFUL_FLOAT instead: unmeasured, neither a finding nor reassurance.

7.4 A crash, and two tokens read as elevated risk

Excluding the pool manager exposed a share computed against the wrong base. It came out at thirteen billion per cent and made basicScan throw. Excluded holders' shares are now measured against total supply. USDG and AAPL both scored 60, elevated, because their contracts are upgradeable and have owners. That is true of the contracts and says nothing about the issuers. §2.12 is what the current engine does with them instead.

The three fixes of 7.1 to 7.3 are pinned by services/watchdog/test/liquidity-enumeration.test.ts.