'no orders found to match with FAK order' is the #1 miss class (13 of the
last 48h's misses) — the copy lands in the crater the sharp just swept,
before makers requote. Instead of recording the miss at the first
rejection, hand the OPEN to Copybot.fak_requote_retry: sleep fak_retry_s
(default 10, 0 disables) OUTSIDE the bot lock, then re-run the whole gated
buy path (fresh quote, price guard, depth gate) exactly once, mirroring
the webhook call site's fill drain so a retry fill books lag + bet rows.
A second rejection records the miss tagged 'twice (re-quote retry)'.
Paper-parity: the hook is installed in both modes, and PaperExecutor's
FAK model re-decides on the fresh book. tests/test_fak_retry.py covers
hook scheduling, no-double-count sizing (their_size=0 re-entry), ADD and
non-FAK bypasses, and the end-to-end retry thread.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DEPTH GATE (copytrade.book_depth + gate in _handle_their_buy, fitted on
131 book-annotated fills): pre-order, skip if spread>0.08 (market mid-move,
median |slip| ~14%) or ask5c<$50 (dust books mispriced every fill), else
cap the stake at 10% of 5c ask depth (keeps impact <~2%; >20% of depth made
>+2% slip 33-50% likely). Fail-open: a failed book fetch declines to bind.
This is what lets stakes scale — binds mainly on slow-market wallets like
0xbadaf319 (median 23% of depth at $40-100 stakes). config.depth_gate;
paper+live inherit DEFAULT_CONFIG.
GUARD: counterfactuals VALIDATED the 0.05 absolute guard — it sits at the
EV knee (0.05-0.10 moves ≈ breakeven, >0.10 = -20% ROI). No change, comment
records the evidence. (The +9-14% lag-drift tail in deep esports books is a
detection-lag problem the depth gate can't see; RTDS ~1s already addresses
it — protected max_price is the backstop.)
CLOB_USER: UserFillsListener streams our order/trade lifecycle from
ws-subscriptions-clob/ws/user (auth = client.credentials, the SDK's derived
L2 creds; all-markets, no per-market mgmt). A matching order id triggers an
IMMEDIATE resolve_pendings() — in-play holds adopt on match, not on the 60s
tick. Events only TRIGGER; get_order stays the arbiter (2026-07-12
anti-phantom-cash invariant intact). resolve_pendings now re-entrancy-locked
(ws + heartbeat race). 60s poll stays as the fallback; ws failure degrades
to today. Live role only.
Also: sub-$1 BUY amount bumped to the $1 venue minimum (share-flooring
shaved gated $1.00 stakes to $0.99 — 7 of 13 live rejections).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- H3 (burst overflow): per-wallet trade cursor + paginated activity fetch
(up to 5×100, walks back to the last processed timestamp) — a gkmg-scale
clip burst can no longer scroll past a single newest-100 page. Cursor
only advances after a fetch; 600s overlap re-serves boundary rows into
the seen-tx dedupe. offset pagination verified against the data-api.
- clone-guard: Bearer auth (fine-grained PATs reject the 'token' scheme)
with unauthenticated fallback + 40-hex sanity on the answer — Fly's
shared egress IPs rate-limit the anonymous path.
- preflight_live.py rewritten for the unified SDK: deposit-wallet auth,
pUSD collateral, order-book reach, RTDS stream delivery, geo verdict.
- ledger-drift ALARM floor 1c → 5c (4dp fill rounding accumulates pennies
across 60+ copies; the check stays for real bugs — it caught $15.45 and
$7.24. The self-heal path keeps its own threshold.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 phantom-cash incident (+$7.86 book-only, alarms caught it):
overlapping pendings on one token each read the same balance drop via
max(matched, diff) — one real 1.48-share sell booked 3×. No real money
moved wrongly (the CLOB rejects oversells); the book just self-inflated.
Fixes: (1) order's own size caps every adoption fill; (2) the balance
diff is consulted ONLY when the exchange no longer answers for the order
(a definitive killed/0 is final); (3) SELL adoptions cap at book
holdings; (4) ONE outstanding pending per token — engine buy/sell and
exit-retries refuse while the resolver owns a token. Regression suite:
the incident scenario books exactly the real fill; phantoms zero.
Surgery (machine stopped): cash → chain $11.206, the two poisoned bets
corrected from real chain fills (residual adjustment −$0.08), drift 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- failed mirror-exits queue for up to 10 heartbeat retries (recovered
exits ping Discord; exhaustion pages ⚠ EXIT STUCK and the position
rides knowingly; in-play holds hand to the pending registry). 3 stub
paths pass incl. the 1.6 spec's fail-fail-fill.
- every RTDS Set E detection appends a durable shadow-ledger row
(lat_s + which trigger won) that rides the publish commit — the 24h
go/no-go data for flipping RTDS on the live app.
- start.sh verifies the boot clone's HEAD against the GitHub API and
re-clones stale replicas (bit twice today).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1. Caps retired: risk block mirrors the paper sentinels; sizing is the
paper bot's 4%-of-equity (class_pct 0.04/0.12), floored at the venue's
$1 min order (4% of a $22 book is $0.89 — sub-min stakes died at the
gate). bankroll rebased to the real $22.28 equity; spend tracker reset
(the confusing $35 is gone with the daily cap).
2. Price guard is now ABSOLUTE +0.05 (both books): 0.14→0.15 follows,
0.14→0.20 skips. The relative 5% blocked one-tick moves on cheap
in-play books.
3. Pending-order registry: in-play 'delayed' holds are no longer cancelled
at 20s — the executor hands them to state.pending_orders with full copy
context; the heartbeat resolver adopts the fill whenever it lands
(bets/my_pos/cash/ledger, TTL 600s → cancel + honest miss). Recovers
Rune-Eaters-class holds (+$7.50 forfeited by the old cancel).
5 stub-client paths pass incl. adopt + expire.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nine fills across both books were followed (tx in seen) and then died
without a trace: _live_price None (no ask — the sharp is the maker on
weekly scalars) and live ORDER FAILED both returned silently. A blocked
or rejected OPEN is a missed bet; now recorded with its true reason.
Allowance ruled out (max-uint on all three exchange contracts).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- start.sh: COPYBOT_ROLE=live — unarmed (missing LIVE_PRIVATE_KEY /
LIVE_FUNDER_ADDRESS / LIVE_CONFIRM) idles in geocheck, no clone, no
book, no orders; armed runs config.live.example.json + own state file
copybot_state.live.json, --live, poll mode (webhook stays on paper).
- confirm_live: accepts the phrase from LIVE_CONFIRM env — the USER
types it into flyctl secrets set (rule 0.7 human checkpoint, headless);
wrong value aborts, unset disarms at next boot.
- config.live.example.json: Set E + pinned floors (mirrors paper),
bankroll $50 @ 10% = $5 stakes, caps untouched (rule 0.6), leaked
Discord webhook URL removed (ROTATE it — was committed publicly).
- fly.live.toml: separate app wwf-copybot-live, arn, no inbound, no
checks, role env baked.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The execution engine was load-bearing from archive/ — the one thing in
there that wasn't retired. Now at repo root next to copybot.py; the two
archived scripts that imported it as a sibling get a parent-path shim.
fly.toml gains an http /health check so Fly restarts a dark machine
(self-heal); the notify half is the GH Actions watchdog (next commit).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Moved the 8 tested-and-failed strategy tools into archive/ (copytrade, backtest,
edge_research, lookback, table_77, lp_screener, lp_paper, xarb) with an
archive/README explaining each. Root now holds the keepers: insider.py (made
self-sufficient — dropped the copytrade load_json dependency) and smart_money.py
(data foundation). New FINDINGS.md is the honest scorecard: six systematic
public-data edges all efficient/illusory, the win-rate survivorship-bias
finding, and the one real signal (z-score improbability + funding clustering).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The scanner measured win rate over /closed-positions only, but Polymarket
only redeems winning shares — losers sit unredeemed in /positions at
curPrice 0 and never enter closed-positions. That made win rates wildly
inflated (e.g. 90.6% vs a true 48.3%). Win rate now unions both endpoints
over a 90-day window. With the honest metric, ~no top wallet exceeds ~60%;
true rates cluster near 50%.
Also:
- backtest.py: replay a watchlist over a recent window, fill at historical
price, mark outcomes from resolution. A 7d run of 4 top wallets returned
-48%, confirming flat-size entry-copying is -EV at ~50% hit rates.
- copytrade.py: add max_position_usd cap (proportional adds could otherwise
balloon one position to the whole exposure limit) and Discord webhook
alerts on every would-be trade.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Watches a wallet list and copies trades onto your account: % -of-bankroll
sizing, proportional entry/exit mirroring, 5% price guard, and a no-backfill
rule for positions held before start. Paper mode by default; live trading is
gated behind config + --live + a typed confirmation, with hard risk caps
(per-trade, daily, total exposure, open positions, price bounds). Live
execution via py-clob-client (lazy import). Credentials/state gitignored.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>