---
name: casig-gmgn-overlay-3
description: Tech Score stack part 3, 14 Sep 2026 08:00-10:00 UTC. The 380-project outcome study that rebuilt the ladder from measured win rates, the borrowed-page rule, the learned shared-address table, and the three performance bugs behind "GMGN GO takes forever". Read after casig-gmgn-overlay.md and casig-gmgn-overlay-2.md before touching /opt/casig.
sources: [cowork]
aliases: [casig part 3, tech score part 3, winners study, outcome study, substance ladder v2, shared address table]
---
Continues [[casig-gmgn-overlay-2]]. Everything in it and in [[casig-gmgn-overlay]] still applies.

# THE OUTCOME STUDY: 380 PROJECTS WITH KNOWN RESULTS
- [stated] Ben: "Looking at tech projects that do well and did well in the last month, try to identify patterns... their domains might be a bit older, or their GitHub might have a certain structure, or there might be multiple people deploying commits... There might be a solo developer pattern, a team pattern, or whatever."
`/opt/casig/winners.py` (pool / scan / report) + `winreport2.py` + `laddersim.py`. Ground truth is **/opt/trench/trench.db read-only**: `lab.peak_mcap` joined to `tok.created_ts`, last 30 days, floored at $30k peak (below that nobody bid, so tech never had a chance either way). **380 scanned: 160 peaked above $1M, 83 above $5M.**
**THE FRAME IS THE WHOLE THING: P(won | pattern), never P(pattern | won).** Every winner has a website and so does every loser. And because "has a website at all" is itself 2.3x, every other signal inherits that lift for free - so the table that sets thresholds is the SITED-ONLY one.

| signal | won inside | outside | lift | $5M lift |
|---|---|---|---|---|
| **site publishes its own contract** | 70% of 113 | 30% | **2.3x** | **2.5x** (3.1x sited) |
| has a website at all | 55% of 219 | 24% | 2.3x | - |
| **a non-template API endpoint** | 78% of 18 | 40% | **1.9x** | **2.4x** |
| **own contract code >10kb** | 71% of 34 | 39% | **1.8x** | 2.1x |
| 800+ own words | 56% of 82 | 38% | 1.5x | **1.0x sited** |
| 5+ routes | 57% of 81 | 38% | 1.5x | **1.0x sited** |
| 25+ own sentences | 52% of 60 | 40% | 1.3x | **0.9x sited** |
| github linked anywhere | 44% of 27 | 42% | 1.1x | **0.8x** |
| **domain over a year old** | **19% of 16** | 43% | **0.4x** | **0.2x sited** |

# THE TWO RESULTS THAT CHANGED THE PRODUCT
1. **COPY AND ROUTES ARE NOISE.** Among sited projects they are 0.9x-1.0x. Ben's AI-age worry is confirmed by the numbers: in 2026 a thousand words and ten routes cost an afternoon and the market prices them at nothing. They are now SUPPORTING evidence that can only break a 4/5 tie.
2. **DOMAIN AGE IS NOT WEAK, IT IS BACKWARDS.** All sixteen domains older than a year were **somebody else's website**: fastcompany.com, snowflake.com, arxiv.org, usmint.gov, nihao.com, truthsocial.com, two github.com repos, urbandictionary.com. An old domain under a new token means a deployer pasted a famous link. SNOP had reached **4 stars on urbandictionary.com** and TENDIES on memedepot.com. Now a **2-star "this is somebody else's website" flag**: `age > 365 and the ticker is not in the bare host`. Fired on exactly 14 of 380 and every one was correct.

# THE LADDER, REBUILT (patch_ladder.py, patch_five_soft3.py)
- **HARD** (costs money, time or a second person): a non-template API answering with data; own contract code >10kb; a GitHub with **2+ contributors** and active/quiet.
- **SUPPORTING** (cheap, gameable): 2+ own contracts >3kb, reads 2+ chain infra contracts, 10+ routes, 25+ own sentences.
- **THE GATE: 4 and 5 REQUIRE the site to publish its own contract address.** Strongest single mark in the study, and the old ladder only ever read its ABSENCE as meaningful.
- **5 = two hard, or one hard + three supporting. 4 = one hard. 3 = everything else with a real site.**
Simulated on the same 380 before shipping: 4-5 star won **78% vs 52%** (1.5x, up from 1.2x) and reached $5M **52% vs 22%** (2.4x, up from 1.6x). Star by star it is monotone on the $5M cut for the first time: 5 -> 60%, 4 -> 47%, 3 -> 26%, 2 -> 12%. Green+gold is **12% of the rated board**, which is what an attention filter should be. Three supporting, not two: at two, anything with one hard signal also had ten routes and the four-star rung emptied out (iteration 3 gave 8 fives and 1 four on fifty mature projects).
**Recall is deliberately traded for precision.** Green went from 49 of 219 to 27, and some real winners (GRASS $13.6M, MANY $8.3M) dropped to 3. On a board of hundreds, precision is the useful axis.

# THERE IS NO TEAM PATTERN ON THIS CHAIN, AND THAT IS THE ANSWER
Only **27 of 380** linked a GitHub at all. Of those: 20 came back unreadable, 1 empty, 2 "active" on accounts **three and four days old** with one contributor, 1 quiet with 2 people (Sparkles - the known impostor). Two of the links pointed at **github.com/anthropics/...** repos that are not theirs. Linked-GitHub lift is 1.1x on a run and **0.8x on a $5M run**. The solo-vs-team question cannot be answered here because open source is not how winners are built on Robinhood Chain. The check stays as a DISPLAY field and as hard evidence only at 2+ contributors, where it is genuinely unfakeable - it just almost never fires.
**The archetypes that do exist, by win rate:** on-chain only (own contracts, no API) 70% of 47; closed product, API only 70% of 10; front end only 52% of 118; **no website at all 24% of 161**.

# THE LEARNED SHARED-ADDRESS TABLE, `/opt/casig/sharedaddr.py`
Reading the 5-star receipts across 480 scans: **five unrelated projects were each credited with writing 0xcaf681a66d020601342297493863e78c959e5cb2** (behemothbsc.lol, jtmarlin.trade, weibocoinnews.com, jacob.onchaindocumented.com, slinkcoinrbh.lol). Also 0x1f7d7550... across mancer.xyz / pairex.market / parestocks.com, and three more pairs. That is the chain's plumbing, and claimcheck's `INFRA` set is a hand-written list that cannot keep up - the same failure mode as "renounced is meaningful".
**So count instead.** Every scan records (address, HOST) - hosts, not tokens, because fifty tokens pointing at one launchpad is one observation. `SHARED_AT = 2` distinct hosts and it stops counting as code they wrote; it moves to the supporting "reads this chain's own contracts" line. Table fills itself from ordinary traffic. The receipt now cites the LARGEST contract, so it is reproducible between scans.
**Known limit, stated on the card rather than guessed:** this cannot tell a launchpad's OWN contract from the chain's. PAIREX fell 5 -> 3 for exactly this reason and the selftest now records why. Fixing it needs the contract's deployer, which no current source gives.

# "GMGN GO TAKES FOREVER" WAS THREE SEPARATE BUGS
p90 **166s -> 42s**, worst **627s -> 173s**, and a 100-project run went 1193s -> 430s.
1. **`verify_contracts` defeated its own batching.** `code_sizes()` exists to ask the RPC about many addresses in one POST; verify_contracts called `code_size(a)` per address through a 6-thread pool, and `code_size(a)` is `code_sizes([a])`. 28 addresses = 28 round trips = 114s on downto.finance. One batched call instead. Also fixed: results are keyed lowercase, so any address published in checksum casing used to come back UNRESOLVED.
2. **A 3.6MB blob read twenty times.** commodites.market serves a 2.1MB HTML page plus 17 chunks. `target_chains` ran its eleven regexes over all of it **twice** (address_judgeable and chain_mismatch each call it). Memoised on the blob, and the signature scanners (target_chains, simulation, wallet_code, contract_claims) now read at most `SCAN_MAX = 1.5MB`. Size measurements are deliberately NOT capped - truncating those would change what they mean.
3. **A registry with 404 entries is not a registry.** The loose `name: "0x..."` pattern matched every config constant in a bundled SDK. A pattern firing more than `DUMP_AT = 150` times is reading a library's address book and is dropped; the rest caps at `MAX_CLAIMS = 60`, hard claims first. Every claim costs an RPC lookup.
4. **Tech Score was queueing on the shared GMGN bucket** despite gmgnapi's own note promising it would not: `gmgnlimit.acquire(1, priority=False)` - the second positional is `timeout`, defaulting to MAX_HOLD. Caught with py-spy on a selftest sitting at 3m40s with every worker parked in acquire. Now `acquire(1, WAIT=6.0, priority=False)`. The deployer check runs on EVERY rating, so this was the one call that could make a card wait.

# THE BLINKING LOOP, A THIRD TIME, THROUGH A THIRD DOOR
`log("%s %d stars" % (ca, sr.get("stars", 0), ...))`. `.get("stars", 0)` returns the default only when the key is MISSING; since unreachable hosts started returning `stars=None` (see below) the key is present and None, so `"%d" % None` raised **out of add_stars, after the cache was written and before save_cache** - and the worker's handler then replaced the finished record with an empty grey. grandtheifthood.xyz was re-rated every six seconds. Two fixes and both were needed: `%s` not `%d`, and **the worker no longer overwrites a record that already has a rating**. Gated in the selftest.
**A failure downstream of the answer must never destroy the answer.** That is the same lesson as the two earlier loops.

# ZERO IS NOT A SCORE
`rate()` starts at `stars=0` and the two early returns (unknown host, scan incomplete) left it there. Four tokens per hundred were storing a **0** for "we could not reach the site" - a number that gets averaged and drawn, for a statement about our own reach. Now `stars=None, unrated="unreachable" | "scan_failed"`, matching the no-website branch and the dot rule: absence is never a grade.

# A CLONE FLAG MUST KNOW WHICH ONE IS THE COPY
The shape fingerprint told us pairex.market is 72% rhtools.xyz - it cannot say which came first, only which this box scanned first, and scanning rhtools during the study was enough to demote a $500M launchpad to 2. Measured: the flag alone separates nothing (6 rows, 3 ran). Split by whether the page publishes its own contract and it separates cleanly - **4 that do, 3 ran; 2 that do not, neither did.** So a copy is called a copy only when it has neither hard evidence nor its own contract on the page; otherwise the resemblance is a note.

# /api/health IS NOT A BACKEND
Four of fifteen 4-star ratings in the first validation run were earned by a single endpoint and the endpoint was `/api/health`; two more by `/api/geo` and `/api/config`. Those ship with the framework. `TEMPLATE_PATHS` in substance.py, **unconditional** - the first version allowed them through if they returned more than two fields, and Next.js health handlers happily return five, which put STONKBROKER and PROLOGUE back on five stars. Measured: a non-template endpoint is 78% won / 50% big; template-only is chance.

# A RATING MUST NOT CHANGE BECAUSE A QUOTA RAN OUT
RAXOL: 4 stars on "public GitHub, 10 contributors, 127 repositories" in one run, 3 stars twenty minutes later with no GitHub evidence. Nothing about RAXOL changed - GitHub's 60/hour ran out mid-run, and the FAILURE was cached for twelve hours as verdict "unknown". Now: failures return **"not checked"** and are never stored (only a 404, which is a finding, is); real answers persist in `scores.db.ghcache` for a week so a deploy no longer throws away calls already paid for.

# ALSO WORTH KNOWING
- **The droplet has 961MB.** A 380-project scan was OOM-killed with no traceback at row 61: `stars._TECH` keeps a 200KB `ctext` per site plus claimcheck's fetch cache. Long study runs must append to a .jsonl, clear both caches every ~18 rows, and use 3 workers.
- **`pkill -f 'winners.py scan'` kills the ssh session running it** - the pattern matches the command's own line. Same for deploy.sh. Use a pattern the invocation cannot match.
- **stars.py loads claimcheck via `importlib.util.spec_from_file_location`, not `import`.** Wrapping `claimcheck.*` for profiling does nothing; wrap `stars.cc`.
- **The star scale now has outcome numbers behind it**: 3 stars ran 59% of the time, 4 ran 82%, 5 ran 70%, 2 ran 35%. Three is genuinely not an accusation - a majority of threes still ran - which is the argument for calling it **unproven** rather than "solid".
- **THE CAVEAT THAT TRAVELS WITH THE STUDY:** sites were scanned today, peaks happened over the last month, so a winner's site has had more reason to be kept current. The contract-address signal is the one most exposed to that (a team adds the CA when people start asking). Domain age is not exposed at all, which is why the negative result there is the firmest thing in it.

**Continued in [[casig-gmgn-overlay-4]]**, which replicated all of this on 218 unseen projects, tested four new tech concepts and rejected all four, and found that most big winners are memes the tech score is correctly silent about.

# GATE 107 CHECKS, 0 FAILED. Deployed 2026-09-14T09:38:14Z.
Four validation passes of 100 projects each (50 mature + 50 trench), `validate.py` / `validate_i1..i4.json`. Final mature spread: 5=12%, 4=12%, 3=46%, 2=8%, 1=2%, unrated 20%. Fresh: 2=46%, 3=24%, unrated 28%, green 0-2%.
**Applicable to new launches by construction:** both hard signals - a live API and own contract code - exist at minute zero. A one-hour-old token reached 5 (PonsPitch) and another reached 4 (AGI) during these runs. The rate is low on the trench board because most launches genuinely have nothing behind them.


