PAPER FORENSICS v1.0.0
generated 2026-08-13 04:11Z
11,882 legs · 295 open

Paper book forensics

Every position the system opened between 07-07 and 08-13 2026 — what we entered and why, what actually happened, which numbers are real, which are fabricated, and what each fix is worth in dollars. Built from paper_universal_ledger.jsonl, paper_decisions.jsonl and paper_journal.jsonl.

◆ the central issue, in one paragraph
The ledger reports −$264,733 (-30.0%). Of that, $172,080 is not a trading loss — it is 1,689 positions the price feed lost track of, each written into the book as a realised −100% despite exit_px = null. On the 10,193 positions we actually watched exit, the book is −$92,653 (-13.1%).

Both facts matter, and they point in opposite directions. The accounting bug means the reported number is wrong and every parameter tuned on it is untrustworthy. But the corrected number is still deeply negative, on every source, every exit profile, every chain, every regime and every hour of the day. Fixing the accounting does not produce a profitable system — it produces an honest one, which is the precondition for finding out why this loses.

as booked −$264,733 11,882 legs · -30.0% of $881,673 deployed
observed exits only −$92,653 10,193 legs · -13.1% — the most defensible single number
phantom (unobserved) −$172,080 1,689 legs at exactly −100%, zero of them price-confirmed
true book — bounded -264k … -78k a range, not a point — 1,689 outcomes are unknowable after the fact
quality gate coverage 2.2% of 179,809 rejections — the other 97.8% are capacity/data
score ↔ return r = 0.012 n=6,332. The score orders the queue but predicts nothing

00 Fix status — measured since deploy

paper_universal v1.8.0 shipped 439.3h ago (2026-07-25T20:50Z). Everything below is measured on real observed exits since that moment, against the counterfactual the code records at decision time — not a replay. Refreshed every 2h by paper_fix_tracker.py → thread 37479.

FIX 1 · stop inventing4511unresolved, excluded from P&L · DEAD rate 28% → 0%
PASS
FIX 2 · GMGN rescue1184positions pulled back from a false death that v1.7.3 would have booked at −100%
FIX 3 · BE_STOP vs old rule+$0n=476 · realised $0 vs counterfactual $0 · old rule would have won on 0
UNPROVEN — control arm needs n (have 1116 treat / 617 control); and BE_STOP is gated on faster marks, queue #199
FIX 4 · dead zones5profiles still arm below breakeven — BE_STOP covers them at runtime; constants deliberately not retuned

Book since deploy (observed exits only): n=5920 · −$24,031 · -6.3% · expectancy −$4 · PF 0.78 · WR 26.8%

New issue found during deploy — flagged, not silently fixed

147 historical exits (−$10,864) were booked at exactly −100% off a >99.99% single-interval price collapse — entry ~6e−05 marked at ~1e−10 inside one 5-minute poll, with the same symbol recurring. That is the dust-pool signature, not 104 independent rugs. It is the same class as the DEAD bug, but unlike DEAD (where exit_px was literally null) a real rug looks identical, so v1.8.0 flags these (suspect_price) and counts them — 44 since deploy — rather than repricing them. Repricing would be inventing an outcome, which is the exact thing Fix 1 exists to stop. Awaiting a ruling (queue #204).

01 Do we enter every trade that comes in?

Effectively yes. There is a rejection log — 179,809 entries — but it is a capacity ledger, not a quality filter. The system opens a position on anything it can still afford to hold.

rescued?69,507 (38.7%)
strict_gate_reject?61,904 (34.4%)
src_capcapacity18,529 (10.3%)
total_capcapacity8,391 (4.7%)
admission_reject?6,867 (3.8%)
no_pricedata4,718 (2.6%)
sm_distribquality3,915 (2.2%)
throttled?3,235 (1.8%)
decision_reject?2,743 (1.5%)

What the four reasons actually mean

The score is computed, then ignored

Every signal carries a score. In paper_universal.py:263 it is used once — to sort the candidate list so higher scores fill first. It is never compared against a threshold. Nothing is ever rejected for being low quality.

score bucket at entrynnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
none3861−$6+3.7%-4.1%25.9%1.13CONFIDENT79%−$19,600
80-99791−$11-7.7%-15.2%23.6%0.73CONFIDENT69%−$7,847
100+1782−$12-10.9%-15.5%24.2%0.63CONFIDENT72%−$18,388
40-59749−$12-9.1%-15.2%25.6%0.70CONFIDENT63%−$8,426
1-19278−$13-11.2%-19.6%22.7%0.58CONFIDENT65%−$3,253
20-391979−$14-10.5%-18.2%20.2%0.68CONFIDENT80%−$24,750
60-79753−$15-14.2%-19.6%23.5%0.56CONFIDENT69%−$10,389

Non-monotonic and near-random: r = 0.012 on n=6,332. The 100+ bucket is not better than the unscored bucket. Two live config files — conviction_gates.json (v1.2.0) and copy_decision_gates.json (v1.0.0) — define exactly the category weights, size-by-grade and conviction multipliers that would make this a real gate. paper_universal.py never reads either file.

02 The central bug — booking outcomes we never saw

A position is marked from a batched DexScreener call. If the batch does not return a price, fails increments; at six strikes the position is closed DEAD at a hard-coded −1.0 return — with exit_px = null. Nothing verifies the token actually died.

# paper_universal.py:416-421
cur = px_cache.get(ca)
if cur is None:
    p["fails"] = p.get("fails", 0) + 1
    if p["fails"] >= 6:
        closed.append((k, "DEAD", -1.0, None))   # ← -100% on no evidence
    continue

The v1.7.3 cliff — DEAD as a share of daily closes

0%07-07175
0%07-08125
0%07-09201
0%07-10200
0%07-11163
67%07-12418
0%07-1327
0%07-14122
0%07-1572
0%07-16191
11%07-17338
5%07-18398
0%07-19316
15%07-20307
3%07-21380
0%07-22275
58%07-23634
56%07-24865
51%07-25864
0%07-26403
0%07-27344
0%07-28363
0%07-29343
0%07-30307
0%07-31320
0%08-01366
0%08-02312
0%08-03287
0%08-04284
0%08-05297
0%08-06292
0%08-07280
0%08-08306
0%08-09344
0%08-10356
0%08-11287
0%08-12305
0%08-1315

Each bar is one day; the number under the label is total closes that day. v1.7.3 shipped on 260723 and deliberately removed the GMGN price fallback to cure a 300s cron timeout — its own comment notes the batch “typically misses ~100+” positions, then treats every miss as a death. DEAD went from ~0–15% of closes to a sustained 8%. $133,245 of the $172,080 phantom loss is in those three days.

Mass-simultaneous deaths — the tell

10-minute window (UTC)positions killed booked losshad been updistinct sources chains
07-12 16:50280−$27,585158235
07-23 18:30248−$20,038138215
07-20 23:0045−$4,27817114
07-17 12:2036−$3,7421194
07-25 00:4034−$3,730244

No market event kills 280 tokens across 5 chains and 23 independent detectors inside ten minutes — and 158 of them were trading above entry at the time. These are infrastructure outages recorded as trading losses. The two largest windows alone account for 528 of the 1,689 DEADs.

What the book is actually worth — a range, not a number

We cannot recover these outcomes. The honest treatment is a bound: the floor assumes every unresolved position went to zero, the ceiling assumes each exited at its last observed peak (impossible in practice). Peaks above 100× were dropped as feed garbage (5 legs) and the rest capped at +1000%.

scenarioassumption for the 1,689 unresolved book P&Lreturn on notionalreading
AAll unresolved = total loss−$264,380-30.0%status quo — what the ledger says today
CHalf give-back from peak−$220,313-25.0%pessimistic reconstruction
BPeak minus the profile's own trail−$112,540-12.8%what the exit engine WOULD have done
DExit exactly at peak−$78,281-8.9%unreachable ceiling

Median peak among unresolved positions was -1.0% — i.e. the typical one never ticked above its own entry-plus-slippage, which is why the pessimistic reconstructions land close to the floor. But 130 of them had been up 25% or more, and 37 had more than doubled. Those were not rugs. Best single number to quote: -13.1% on the 10,193 positions we actually observed.

03 Every trade we entered, classified

13,585 positions carry a journal entry — one verdict, one plain-language reason, one fix. Grouped, they say something the aggregate P&L cannot: the losses are not one problem, they are five, and only two of them are about trading.

UNRESOLVED_NO_OUTCOME4,506
? · 33% of journalled

(no description)

e.g. “Price feed lost this token for ? consecutive marks after 0 GMGN rescue attempt(s); retired after 8175 min with peak +12%. NO exit price exists, so no return was booked — v1.7.3 would ha”

 

NEVER_ARMED2,566
ENTRY LOSS · 19% of journalled

Never traded up to the arm threshold. The entry had no edge.

e.g. “Never traded above +25% after entry (peak -1%). No follow-through at all — the entry had no edge; price went against us from the first poll.”

ADMIT  This is the whole hole. Needs a pre-trade admission gate.

STOP_GAP1,566
EXECUTION LOSS · 12% of journalled

Stop filled far below its level — 5-min polling gap.

e.g. “Stop set at -50% but filled at -65.1% — gapped 15 points through the stop in a 5-minute polling window.”

EXEC  Faster mark loop; accept that part of this is unrecoverable in live.

ROUND_TRIP1,039
EXIT LOSS · 8% of journalled

Was genuinely profitable at peak, still closed red.

e.g. “Reached +94% (a genuinely profitable peak, breakeven was +42.9%) and still closed -12.2%. Gave back 106 points of open profit.”

EXIT  Ratchet the stop to breakeven the moment the position arms.

FEED_OUTAGE_ARTIFACT1,011
VOID · 7% of journalled

Mass simultaneous DEAD — infrastructure, not market.

e.g. “Booked -100% in a cluster of simultaneous DEADs at 07-12 16:57 UTC: the GMGN price feed dropped, the token did not necessarily rug. Outcome is UNKNOWN.”

FIX  Do not book. Write to unresolved.jsonl with pct_return=null.

CLEAN_WIN702
WIN · 5% of journalled

Trailed out properly and captured a real share of the move.

e.g. “Trailed out properly: peak +146%, captured 61.5% ($+46.15), 42% of the available move.”

KEEP  Keep. This is the shape to reproduce.

FEED_DEATH_UNRESOLVED678
VOID · 5% of journalled

Feed died on this token alone; outcome genuinely unknown.

e.g. “Closed at -100% on '6 consecutive price-feed failures' after 7205 min. exit_px is null — no trade actually happened at this price.”

FIX  Do not book. Retry via GMGN before giving up.

TAIL_WIN659
WIN · 5% of journalled

Power-law runner. This cohort carries the entire book.

e.g. “Caught a power-law runner: peaked +238%, banked 43.9% ($+36.19). This cohort is where the entire book's positive expectancy lives.”

KEEP  Protect tails: never tighten the trail on a runner.

BE_STOP_SAVE464
? · 3% of journalled

(no description)

e.g. “Peaked +11% — inside TIGHT5's dead zone (+5%..+17.6%), where the trail is priced BELOW entry. Exited flat at -1.2%; the old v1.7.3 trail would have booked -5.6%. Saved 4.5 points.”

 

DEAD_ZONE_ARM373
STRUCTURAL LOSS · 3% of journalled

Armed at a peak mathematically below its own breakeven.

e.g. “Armed at +38% (profile arms at +25%) but the 30% trail needs a peak above +42.9% to break even. Peaked +38%, so the trailing exit was priced below entry the moment it armed. Realized -2”

EXIT  Require arm > trail/(1-trail) per profile. Design bug, not variance.

BE_STOP_EARLY12
? · 0% of journalled

(no description)

e.g. “Peaked +17% — inside TIGHT5's dead zone (+5%..+17.6%), where the trail is priced BELOW entry. Exited flat at -62.7%; the old v1.7.3 trail would have booked -0.2%. Cost 62.5 points.”

 

TIME_STOP5
SCRATCH · 0% of journalled

Expiry reached with no resolution.

e.g. “Held 1.0 days to expiry and closed -11.6%. Capital was parked, not working.”

KEEP  Low volume; ignore for now.

SMART_MONEY_EXIT4
SCRATCH · 0% of journalled

Exited because the signal that got us in reversed.

e.g. “Exited on smart-money distribution at -1.9%. The signal that got us in reversed.”

KEEP  Working as designed — the only quality gate we have.

Read the grades, not the win rate

  • VOID — 6,195 positions have no knowable outcome. They should never have entered a P&L calculation at all.
  • ENTRY LOSS — 2,566 never traded up to the arm threshold. Price went against us from the first poll. No exit rule can save these; they are an admission problem.
  • EXECUTION LOSS — 1,566 stopped out below the intended level because we only look every five minutes.
  • EXIT LOSS — 1,039 were genuinely profitable at peak and still closed red. Pure give-back.
  • STRUCTURAL LOSS — 373 armed at a peak that was mathematically below their own breakeven. The config guaranteed the loss.
  • WIN — 1,361 total, of which the tail cohort carries almost all the upside (76% of gross profit comes from the top 5% of trades).

03b Trade journal — inline, one row per position

Every position with its verdict, its plain-language why, and the single actionable fix — click any row to expand them. 13,585 positions journalled; newest 2,000 shown. Sortable, filterable. Symbols link to GMGN. Regenerated by trade_journal.py v1.1.0.

exit (UTC)tokenchain sourceprofile sizereturn P&Lpeak heldexit verdictgrade

A row with a blank return is UNRESOLVED — the feed lost the token and v1.8.x refuses to invent an outcome. Those contribute exactly $0, by design.

04 The one split that explains the book

A position “arms” when it first trades above its profile's arm threshold — the moment it has actually gone up. Split the observed book on that single fact:

armed at some point $79,734 6,053 positions · $13/trade · these are profitable
never armed −$172,387 4,140 positions · −$42/trade · the entire hole
stops that never ticked up 76% 2,806 of 3,676 hard stops went straight down from entry

What this does and does not license

Among positions we actually watched, every dollar of loss sits in trades that never went up at all. The ones that did go up collectively made money, even with a demonstrably broken exit engine. That reframes the whole problem: this is an entry failure, not an exit failure. Better trailing rules cannot fix a trade that was red from the first poll.

It does not license a “filter for arming” rule. Arming is only knowable after entry. This number bounds the prize — it is not itself a strategy. Finding a pre-trade attribute that predicts arming is precisely the job an admission system exists to do.

05 Performance across every dimension we record

All tables below exclude the 1,689 unresolved positions, so nothing here is contaminated by the DEAD bug. Sorted by expectancy. profit factor < 1.00 means the cohort loses money.

By signal source — which detectors pay

source / processnnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
wallet_copy15$26+25.1%-17.6%40.0%2.86UNRELIABLE44%$403
wallet_buysize252$6+17.0%-14.4%32.5%1.72CONFIDENT83%$1,835
clu:fomo679$1+12.0%-2.7%33.4%1.61CONFIDENT76%$1,738
wc:SPRAYER18−$3+1.5%-29.2%27.8%1.07UNRELIABLE51%−$36
clu:shadow_dowville50−$4-1.6%-12.0%32.0%0.87LOW36%−$167
cipher131−$5+3.0%-9.4%33.6%1.14CONFIDENT48%−$452
sa_accum79−$5+7.8%-13.6%29.1%1.40LOW48%−$310
wallet_intel80−$7-9.0%-17.3%26.2%0.50LOW60%−$462
oggy_boost153−$7-16.9%-35.9%32.0%0.65CONFIDENT53%−$730
whalemover305−$7-4.2%-11.8%28.9%0.79CONFIDENT59%−$1,764
fomo1205−$8+4.4%-11.2%23.7%1.13CONFIDENT79%−$8,011
known_conv262−$8-6.1%-15.0%23.7%0.71CONFIDENT75%−$1,824
clu:dowville70−$8-12.3%-18.8%22.9%0.31LOW54%−$509
cluster873−$9+4.3%-17.6%24.3%1.12CONFIDENT81%−$6,732
fomo_curated945−$9-3.9%-17.7%23.2%0.87CONFIDENT77%−$7,537
oggy_kol875−$9-6.8%-14.3%23.1%0.75CONFIDENT76%−$7,109
floor_revival77−$10-10.8%-20.6%24.7%0.53LOW49%−$633
alpha_brief84−$10-6.5%-18.6%27.4%0.71LOW51%−$731
control232−$10-7.1%-27.8%18.5%0.82CONFIDENT79%−$2,083
volume_spike75−$11-12.2%-19.7%28.0%0.39LOW42%−$717
clu:sapphy61−$12-5.1%-21.9%23.0%0.75LOW56%−$631
known_dist28−$12-20.6%-30.1%10.7%0.06UNRELIABLE93%−$301
accum_engine314−$12-9.8%-17.6%26.1%0.56CONFIDENT62%−$3,357
trending423−$12-13.0%-17.6%21.7%0.41CONFIDENT64%−$4,570
inversion_alpha53−$14-18.3%-26.0%22.6%0.21LOW39%−$697
smartmoney749−$15-13.3%-20.6%22.2%0.60CONFIDENT71%−$10,468
kol:michacalls82−$17-14.2%-25.2%28.0%0.50LOW57%−$1,325
wc:shadow_dowville14−$18-15.2%-34.2%14.3%0.36UNRELIABLE81%−$227
momentum_scalp1590−$18-15.4%-21.7%19.3%0.61CONFIDENT79%−$27,276
kien_conv36−$19-12.9%-35.8%16.7%0.59LOW40%−$623
sniper223−$23-25.1%-31.5%19.3%0.26CONFIDENT67%−$4,851
trench83−$29-29.2%-42.4%20.5%0.28LOW75%−$2,310

Only two cohorts are positive and both are too small to act on (n=15 and n=17). There is no detector in this book with meaningful sample size and positive expectancy. That is the finding — not a shortlist to promote.

By exit profile

exit profilennet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
SWING5918−$8-1.6%-7.2%26.4%0.95CONFIDENT75%−$42,072
TIGHT53788−$12-8.8%-12.5%21.1%0.67CONFIDENT78%−$40,180
SNIPE127−$20-18.3%-37.3%17.3%0.51CONFIDENT74%−$2,247
TRAIL-hair350−$24-19.7%-29.2%18.6%0.45CONFIDENT81%−$7,711
MOMENTUM10−$47-37.5%-93.9%20.0%0.35UNRELIABLE94%−$443

Every profile loses. profile_for() now returns SWING for every APEX-book entry (promoted 2026-07-27, approved by Chris), so the legacy age-based SNIPE/MOMENTUM/SWING routing stays dead code. The #259 A/B config (profile_ab_config.json) keeps a 1-in-4 control slice on TIGHT5 for wallet-copy entries only — everything else routes to the live profile above. Runner bags now inherit whichever profile their parent position carried (roadmap #271, fixed 260730) rather than being force-set to one profile; only bag hard_sl stays pinned at -50% regardless of the parent's profile so bag risk behavior is unchanged.

By chain, and by market regime at entry

chainnnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
eth330−$0+3.2%-21.5%30.9%1.09CONFIDENT73%$816
base632−$5-2.0%-7.4%28.2%0.90CONFIDENT64%−$2,558
bsc2119−$11-7.7%-11.4%24.4%0.70CONFIDENT71%−$21,148
sol7011−$11-4.9%-9.7%23.3%0.85CONFIDENT78%−$68,398
robinhood101−$15-15.5%-26.8%17.8%0.42CONFIDENT74%−$1,366
regime at entrynnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
ground3773−$6+3.2%-5.0%24.7%1.11CONFIDENT79%−$17,115
poor6155−$13-9.7%-12.7%23.9%0.69CONFIDENT74%−$70,555
extreme_poor265−$20-18.2%-25.8%18.1%0.42CONFIDENT78%−$4,984

Regime is known before we enter, which makes it one of the few free filters available — but all three observed regimes lose, so there is no regime to hide in. Base is the least-bad chain and Solana carries 74% of the total loss on 69% of the trades.

By hold period — and why it is an effect, not a cause

time in positionnnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
>24h1233$2+12.4%+3.6%29.7%1.58CONFIDENT75%$3,313
4-24h2176−$3+12.3%-1.0%27.3%1.47CONFIDENT80%−$3,236
1-4h2650−$3+5.0%-1.1%30.1%1.19CONFIDENT71%−$5,118
30-60m1531−$9-10.5%-14.7%26.5%0.66CONFIDENT67%−$11,205
15-30m1269−$19-25.3%-28.5%18.1%0.29CONFIDENT73%−$22,954
5-15m1008−$38-42.5%-44.8%5.5%0.05CONFIDENT100%−$37,033
0-5m326−$52-52.2%-55.1%1.2%0.00CONFIDENT31%−$16,420

The gradient is enormous and almost entirely circular: a position exits in 0–5 minutes because it hit a hard stop, so short holds are losses by construction (297 of 326 sub-5-minute exits are stops). Do not read this as “hold longer”. Read it as: 1334 positions were dead inside fifteen minutes, costing −$53,453 — an entry-quality signal wearing a holding-period costume.

By hour of entry (ET) and weekday

entry hour (ET)nnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
20:00523$2+18.2%-4.7%26.8%1.63CONFIDENT79%$1,480
09:00364−$2+5.9%-18.0%24.5%1.20CONFIDENT85%−$132
12:00581−$2+31.4%-12.2%26.0%2.07CONFIDENT79%−$343
05:00304−$3+1.5%-10.6%28.3%1.06CONFIDENT69%−$696
10:00377−$5+1.7%-18.4%25.2%1.05CONFIDENT82%−$1,271
21:00381−$8+5.8%-16.1%24.1%1.18CONFIDENT81%−$2,584
14:00475−$9-6.9%-20.5%21.5%0.78CONFIDENT85%−$3,693
07:00523−$9-7.5%-16.4%25.4%0.73CONFIDENT73%−$4,121
15:00438−$11-9.0%-16.5%27.2%0.70CONFIDENT59%−$4,307
13:00454−$11-5.2%-15.8%25.6%0.82CONFIDENT67%−$4,476
17:00517−$11-6.1%-15.6%23.6%0.80CONFIDENT74%−$5,266
02:00291−$12-11.7%-21.0%23.4%0.61CONFIDENT75%−$3,022
00:00447−$12-10.4%-16.3%27.1%0.63CONFIDENT62%−$4,670
04:00378−$12-10.6%-18.0%26.2%0.62CONFIDENT68%−$4,022
18:00742−$12-11.8%-19.5%21.2%0.60CONFIDENT79%−$7,936
19:00435−$12-12.1%-22.2%20.7%0.64CONFIDENT80%−$4,733
03:00259−$14-10.7%-19.4%25.5%0.63CONFIDENT63%−$3,206
22:00410−$14-11.2%-20.0%23.9%0.66CONFIDENT65%−$5,261
01:00337−$14-11.1%-23.1%23.4%0.64CONFIDENT68%−$4,443
11:00376−$15-15.8%-23.4%23.4%0.51CONFIDENT65%−$5,107
08:00372−$16-15.1%-22.8%23.1%0.48CONFIDENT66%−$5,428
06:00310−$16-14.1%-22.2%24.2%0.56CONFIDENT69%−$4,537
23:00434−$16-12.8%-25.7%20.5%0.59CONFIDENT76%−$6,434
16:00465−$19-22.3%-27.8%19.4%0.33CONFIDENT80%−$8,444
weekdaynnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
Sun1485−$3+16.4%-3.0%24.4%1.56CONFIDENT83%−$2,430
Mon1322−$9-3.5%-11.3%25.1%0.89CONFIDENT74%−$10,668
Sat1676−$9-8.2%-13.0%24.8%0.72CONFIDENT72%−$13,573
Tue1686−$11-6.7%-12.6%25.0%0.78CONFIDENT74%−$17,045
Fri1495−$13-10.8%-17.5%21.8%0.64CONFIDENT78%−$16,834
Wed1260−$13-11.3%-16.8%24.9%0.62CONFIDENT72%−$14,394
Thu1269−$15-13.2%-18.6%22.1%0.60CONFIDENT72%−$17,710

Both are knowable before entry, and the spread between best and worst hour is real money per trade — but with n≈424 per bucket over a single 19-day window, treat this as a hypothesis to test out-of-sample, not a schedule to deploy. Every hour and every weekday is negative.

By wallet identity attached to the signal

identitynnet EV $net EV %CI lowwin ratenet PFgradetail %total P&Lshape
smart wallet58$1+1.9%-13.8%31.0%1.10LOW42%$122
no identity10127−$10-5.2%-8.7%24.0%0.83CONFIDENT77%−$92,412
KOL8−$47-47.5%-59.5%0.0%0.00UNRELIABLE0%−$363

Directionally the most interesting cell in the whole analysis — identity-backed signals are the only non-trivial cohort approaching break-even — but n is tiny. Worth a deliberate test, not a deployment.

06 The fixes, priced

Fixes 3 and 5 are mechanical: their value is arithmetic on trades we already observed, with no cohort selection. Fix 6 is the real prize and deliberately carries no promised number, because none can be honestly given yet.

FIX 1Stop booking unobserved outcomesCRITICAL
evidence
1,689 legs (14% of the ledger) closed with exit_px = null and were written as a realised −100%. We never saw a price. paper_universal.py:417-421 — six batch misses ⇒ −100%.
change
Route them to unresolved.jsonl with pct_return=null. Never into P&L.
worth
Removes $172,080 of phantom loss from the book. Changes real money by $0 — it changes every measurement built on top.
FIX 2Restore a price fallback before declaring deathCRITICAL
evidence
v1.7.3 (260723) removed the GMGN fallback to fix a 300s cron timeout. DEAD went from ~0–15% of closes to a persistent 57–60% the same day. Its own code comment predicted the miss volume (“typically misses ~100+”) but assumed a miss meant dead.
change
Budgeted GMGN retry (e.g. 20/cycle, oldest-first) before the 6th strike; raise strikes on tokens that have ever traded above entry.
worth
$133,245 of the $172,080 phantom loss landed in the 3 days after this change.
FIX 3Ratchet the stop to breakeven on armHIGH
evidence
3,383 positions armed (went into profit) and still closed red. Every profile arms below its own breakeven peak — a guaranteed-loss window.
change
Once armed, floor the exit at entry minus round-trip slippage. One condition.
worth
Mechanical, not curve-fitted: $41,413 recovered. Book −$92,653 → −$51,240 (-13.1% → -7.2%).
FIX 4Close the arm/trail dead zoneHIGH
evidence
Every one of the 5 profiles has arm < trail/(1−trail). TIGHT5 arms at +5% but needs +17.6% to break even. 1,467 positions armed inside that window.
change
Enforce arm ≥ trail/(1−trail) at config load; fail loudly if violated.
worth
$18,288 sat in this window. Fix 3 already neutralises most of it — this stops it recurring.
FIX 5Mark faster than the stop can gapMEDIUM
evidence
2,946 of 3,676 hard stops (80%) filled below their level, median -11 points through.
change
Sub-minute marks for armed/near-stop positions; keep the 5-min sweep for the rest.
worth
$50,642 of the gap cost. Treat as partly unrecoverable — a real memecoin dump will not fill at your stop either.
FIX 6Build actual admission controlCRITICAL
evidence
Of 179,809 rejections, 98% are capacity or data and only 2.2% are quality. The score we compute for every signal correlates r=0.012 with return and is used only to sort the fill queue.
change
A real gate: score threshold that is actually validated, identity requirement, regime veto, conviction-weighted size. Then measure it against a random control.
worth
Prize is bounded by the never-armed cohort: 4,140 positions, −$172,387, −$42/trade. Avoiding 30% of them ⇒ +$51,716.

Combined mechanical ceiling — and the honest limit

Fix 3 + Fix 5 together, applied to the observed book with no cherry-picking: −$92,653 → −$598 (-13.1% → -0.1%). Still negative. The exit engine is not why this book loses money — it is why the book gives back what it earns.

Part of Fix 5 is not truly recoverable: a real memecoin dump will not fill at your stop either. Treat $50,642 as an upper bound on that line, and Fix 3's $41,413 as solid, since it is a logic change rather than an execution assumption.

What we deliberately are not claiming

Dropping every negative-expectancy source turns the observed book from −$92,653 into roughly break-even — by keeping 946 of 10,193 trades. That is in-sample selection of the survivors and it is not a result. It is exactly the error that promoted TIGHT5 on peak-replay math and then lost ~25% live. The same applies to the hour-of-day and profile cuts. Any of these becomes real only after out-of-sample validation against the random control cohort, with FDR correction.

Equally: requiring score ≥ 40 makes expectancy worse (−$9 → −$11). That negative result is more valuable than the positive ones, because it is not selected — it kills the assumption that the score we already compute is a usable gate.

07 Should there be a system that decides what we enter?

Yes — and its first job is not to raise expectancy. It is to stop paying $100 11,882 times to learn the same lesson, and to make the lesson legible when it arrives.

What exists today

  • Capacity caps (25/source, 300 total) — fill order, not selection
  • A 30-minute signal freshness window
  • A 6-hour re-entry cooldown per token
  • A smart-money-distribution veto — the only quality rule, 2.2% of rejections
  • Flat ~$100 size × a regime multiplier — conviction never affects size
  • conviction_gates.json + copy_decision_gates.json — fully specified, never loaded

What a real admission layer needs

  1. A threshold, not a sort. Reject below it. Log the rejection with features so it becomes training data.
  2. Conviction-weighted size. The grade→size map already exists in copy_decision_gates.json (S 1.0 → D 0.0). Wire it.
  3. Pre-trade features only. Regime, hour, chain, identity, token age, liquidity, holder concentration, signal latency — anything knowable at fill time.
  4. A permanent random control. Admit a small unfiltered slice forever, or you can never prove the gate helped.
  5. Shadow-first. Score every rejected signal as if taken. Without that counterfactual the gate cannot be evaluated, only believed.

How it would learn — the loop, with the failure modes named

  1. Log every admission decision with its full pre-trade feature vector, admitted or not.
  2. Shadow-score rejections against real prices, so the counterfactual book exists.
  3. Target the right label. Not P&L — did it arm? That is the binary this book says matters, it is available far sooner, and it is far less noisy than a power-law return.
  4. Fit weekly, on pre-trade features only. Any feature not knowable at fill time is leakage.
  5. Promote on out-of-sample expectancy vs the control, FDR-corrected — never on in-sample fit.
  6. Re-measure on a rolling window. Regimes decay; a gate that worked in July is a hypothesis in August.

Named failure modes: selecting survivors in-sample (the TIGHT5 error); training on a contaminated ledger where 14% of labels are fabricated (this must be fixed first — it is why Fix 1 gates everything else); optimising win rate instead of expectancy; and starving the tail cohort that produces 76% of all gross profit by filtering for consistency.

Sequencing — why order matters more than ambition here

Fix 1 and 2 are not improvements, they are preconditions. Until the ledger stops fabricating 14% of its rows, every backtest, every parameter search and every promotion decision is being computed on noise — including any admission model trained to predict it. Ship the accounting fix, let the book run clean for a week, and only then fit anything.

Fix 3 is safe to ship in parallel: it is a one-condition logic change whose value is arithmetic on already-observed trades, and it does not depend on the accounting being correct.


paper_forensics_gen.py v1.0.0 · sources: paper_universal_ledger.jsonl (11,882 legs) · paper_decisions.jsonl (179,809) · paper_journal.jsonl (13,585) · paper_universal_positions.json (295 open)
11,882 legs roll up to 9,125 distinct positions — a TRAIL exit spawns a 25% runner-bag that later closes as its own ledger row, so counting rows overstates position count by 1.30×.
Claude → docker exec <gw> python3 /opt/data/scripts/paper_forensics_gen.py · Hermes → queue #201, thread 37479