You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix chess.com generic-guess false positives and stale broadcast search query
A bare single-word chess.com guess (e.g. "john") could coincidentally match
an unrelated stranger's account and score "high" purely from country/games/
recency when no rating was available to catch it — locking out the SearXNG
search path that would have found the real, differently-named account.
resolve_chesscom now tracks a fourth hard-cap signal, name_ok, and prefers a
well-evidenced search hit over an untrustworthy guess winner even at a lower
raw score.
Separately, lookup.broadcasts.find_broadcast_round_ids was still building the
pre-fix search query (exact-phrase-quoted, raw "Last, First" order, a
/broadcast path fragment) that lichess.py/chesscom.py's search already moved
away from — silently missing real, findable rounds. Also raised max_results
5 -> 10, since target rounds only reliably surfaced past the old default.
Also documents five new roadmap ideas: opening-theory/blunder insights,
feeding the user's own games into opponent dossiers, personal-repertoire
matching, cloud-hosted reports, and pipeline caching/perf.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+9Lines changed: 9 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -118,6 +118,15 @@ Full URLs are auto-detected; `--site` is only needed for ID shorthands.
118
118
- Also done: game-count-aware and rating-mismatch-aware match confidence, chess.com guessing scores every candidate instead of stopping at the first hit, web search migrated from Brave to self-hosted SearXNG, a client-side engine (Stockfish by default, off until toggled, top-3 multi-PV lines) with flip/eval/best-move in an enlarged/centered games viewer, a recent-games (last 12 months) viewer for high-confidence matches, and an opt-in cross-scan dossier database.
119
119
- Verified against real data across two real tournament scans: with the games-count and rating-mismatch hard caps in place, a wrong-but-plausible candidate (large game count, matching country, but a rating far outside tolerance) correctly stays at *low* confidence instead of being fooled by the incidental signals; separately, fixing the search query construction (natural name order, unquoted, bare domain — see above) took a personalized-handle case that the guess-only path could never reach from "not discoverable at all" to "found, high confidence" once SearXNG was live, though a single self-hosted instance with only 1–2 reliably-responding engines means recall on any one query isn't 100% consistent call to call.
120
120
- Remaining: combined PDF output. A SearXNG instance still needs a card-free signup-free way to run reliably 24/7 outside a sandbox with no Docker (the one used for development here was run from source in a venv — see the setup note below) — and even with search enabled, it depends on which upstream engines happen to be responding, so this stays a best-effort discovery path, not a guarantee.
121
+
- Fixed 2026-07-10, both confirmed against real players in the recurring `WQ260708` tournament: `lookup.broadcasts.find_broadcast_round_ids` had never picked up the natural-order/unquoted/bare-domain query fix already applied to `lichess.py`/`chesscom.py`'s search (it was still exact-phrase-quoting the raw "Last, First" order and appending a `/broadcast` path fragment), silently missing real, findable rounds — and a chess.com generic single-word guess (e.g. "john") could collide with an unrelated stranger's real account and score "high" purely from country/games/recency when no rating was on file to catch it, locking out the search path entirely before it ever ran. See `_MIN_NAME_SCORE_FOR_HIGH`/`name_ok` in `pipeline/resolver.py`.
122
+
123
+
### Future roadmap ideas (not yet started)
124
+
125
+
- **Mistake/theory-deviation insights per opponent** — flag where an opponent's games diverge from known theory or contain outright blunders, not just which openings they play. Two different signals, both new: (1) "deviates from theory" doesn't need an external opening book — the megabase itself already has 11.7M games, so "theory" at any position can be derived from what the megabase's strongest/most-common continuations actually are, compared ply-by-ply against the opponent's games (`analysis/openings.py` already builds a move-tree per opponent; this would need the same tree built from megabase as a baseline to diff against). (2) "mistakes" needs actual eval, which today only exists client-side (the games-browser's Stockfish Web Worker, browser-only, nothing persisted) — a report-time version would need a server-side UCI engine pass (e.g. the `stockfish` PyPI binary wrapped via `python-chess`) over each opponent's games, which is a real new dependency and meaningfully slower per-dossier build, so probably opt-in (`--analyse-blunders` or similar) rather than default.
126
+
-**Feed your own games against an opponent into their dossier** — right now `build_dossier()` only ever sees the opponent's own games from the 5 sourcing paths; there's no way to inject *your* games against them specifically. Would need: a way to supply your own PGN pool (a file, or your own Lichess/chess.com username reused through the existing `lookup.lichess`/`lookup.chesscom` fetchers), a head-to-head filter matching the opponent's name on the *other* side of the board from you, and a distinct "vs. you" section in the report (and, per the "combined reports and databases" ask, a way to keep accumulating this across scans rather than starting over each run — `dossier/db.py`'s existing cross-scan history is the natural place this could plug in, since it's already keyed by opponent name-slug).
127
+
-**Personal repertoire vs. opponent tendencies** — let the user define their own opening repertoire (as White and Black) and have the report highlight which of the opponent's games actually entered one of those lines, i.e. "here's what they did the last N times they faced what you actually play," rather than their opening stats in the abstract. Representationally this is close to what `analysis/openings.py` already builds (a move-sequence tree per player) — the new part is a second tree (the user's own repertoire, probably authored as a small PGN of main lines) and a matching pass that walks each opponent game against it to find where the game and the repertoire diverge, then surfaces just those games instead of (or in addition to) the full opening breakdown.
128
+
-**Cloud hosting for dossiers/history, accessible from multiple devices** — today everything is local-only: HTML/MD/JSON dossier files on disk, `dossier/db.py`'s SQLite history, and the 16GB `megabase.db`. The megabase itself is impractical to host remotely at that size for a personal tool (and read-only/build-once anyway, so it doesn't need to move), but the actual per-scan outputs (dossier files + the history db) are small and are the part worth syncing — e.g. pushing rendered HTML to a static host (S3/R2/GitHub Pages on a private repo) or standing up a minimal read-only web view backed by `dossier/db.py`. Needs a real answer on access control before anything ships, since dossiers currently contain other real players' names/data with no auth model at all today.
129
+
- **Caching / faster pipeline runs** — a full `WQ260708`-sized scan (~33 players) takes on the order of 10+ minutes end to end, and re-running it (e.g. after a resolver change, or the tournament's entry list gaining a few late entrants) currently redoes *everything* from scratch for every player, including the ones that haven't changed. The known cost centers, concretely: `lookup.lichess` sleeps 1s before every game-fetch call (`_RATE_DELAY`) and `pipeline.runner` adds its own 1s sleeps around megabase/profile fetches (`time.sleep(1.0)`, `pipeline/runner.py`) — deliberate rate-limit courtesy, not accidental, so not just removable; chess.com guessing can issue up to 9 sequential profile HTTP requests per player before or in addition to a SearXNG search call; and nothing from a previous run is reused, so an unresolved or low-confidence player gets the identical (slow, and possibly still-failing) resolution attempt every single re-run. The most promising angle is probably a resolver-result cache keyed by player-name-slug with a TTL (skip re-resolving a player whose username/confidence was already established recently, similar to how `dossier/db.py` already dedupes a same-day rerun) — separately, megabase queries and broadcast-round PGN fetches (immutable once played) are also cacheable with no staleness concern at all, unlike a live Lichess/chess.com profile lookup.
0 commit comments