Commit Graph
69 Commits
Author SHA1 Message Date
KoalaTrapLord 8a6fbfaa8a fix: 3 post-refactor bugs (COMMANDER_META, PRECON_INDEX, startup)
Task 1: Move BUILTIN_COMMANDERS + load_commander_meta() to shared.py
        Fix import_routes.py to use _shared.COMMANDER_META (module ref)
Task 2: Rewrite precon.py to use _shared.PRECON_INDEX (module ref)
Task 3: Add @app.on_event('startup') safety net for uvicorn --reload
2026-03-14 19:08:21 +00:00
KoalaTrapLord 36077c94ab refactor: extract 49 endpoints into 5 route modules
- Extract collection (10), deckbuilder (18), precon (4), import (5), lab (12) routes
- All share helpers/models/state from routes/shared.py
- Gut lab_api.py from 8872 to 4487 lines (57 remaining endpoints)
- Delete routes/_wire.py and routes/_autoload.py (replaced by include_router)
- Add _scryfall_fuzzy_lookup to shared.py
- 106 total endpoints verified: 49 extracted + 57 remaining
2026-03-14 18:55:32 +00:00
KoalaTrapLord 2c6748a736 feat(brain): swap default model to GPT-OSS 20B via Ollama (localhost:11434) 2026-03-14 14:34:14 -04:00
KoalaTrapLord 585cc1d4a3 feat(engine): load learned_weights.json automatically via load_weights() 2026-03-14 14:30:28 -04:00
KoalaTrapLord c52eb1c3ef refactor: extract all shared state, helpers, models into routes/shared.py 2026-03-14 03:15:12 -04:00
KoalaTrapLord d68b2368b4 fix: remove export_deck_to_sim and _edhrec_cache* from _wire.py (not yet in lab_api.py) 2026-03-14 03:02:45 -04:00
KoalaTrapLord 8d1a916f04 feat(ml): add update_weights.py — outcome-weighted RL learning from decision logs 2026-03-14 02:58:32 -04:00
KoalaTrapLord 2b2383f5c8 wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 02:02:53 -04:00
KoalaTrapLord 911fde9f5f wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 02:02:26 -04:00
KoalaTrapLord 6799f0c402 wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 01:57:18 -04:00
KoalaTrapLord da4e225db0 wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 01:55:50 -04:00
KoalaTrapLord 71428c89db docs: add ROUTES_WIRING.md — final integration instructions for lab_api.py
Explains exactly what 2 lines to add to lab_api.py to activate
all 5 routers. Part of Batch 6/6.
2026-03-14 01:50:47 -04:00
KoalaTrapLord c14402494b feat(routes): add _autoload.py — FastAPI startup event that wires routers
Adds an @app.on_event('startup') hook that imports routes._wire.
This means lab_api.py needs zero changes — the routers self-register
when the app boots. Drop this file into the repo root and it works.

Alternatively, add to lab_api.py after app creation:
    from routes import _autoload  # noqa
2026-03-14 01:49:52 -04:00
KoalaTrapLord 5ea512bfef feat(routes): add _wire.py — registers shared symbols and includes all routers
Called via `import routes._wire` at the bottom of lab_api.py (after all
symbols are defined). Registers every shared object into routes.shared
and mounts all five APIRouters onto the FastAPI app.

Batch 6/6 — final wiring step.
2026-03-14 01:49:18 -04:00
KoalaTrapLord d92345927f refactor: Batch 5 — routes/deckbuilder.py (deck CRUD, cards, analysis, recs, bulk-add, export) 2026-03-14 01:47:04 -04:00
KoalaTrapLord e1a46202b2 refactor: Batch 4 — routes/collection.py (collection CRUD, import, export, scryfall cache) 2026-03-14 01:46:33 -04:00
KoalaTrapLord 553e07980f refactor: Batch 3 — routes/import_routes.py and routes/precon.py 2026-03-14 01:45:58 -04:00
KoalaTrapLord b0666bb3fd refactor: Batch 2 — routes/lab.py (simulator, status, decks-list, profiles, analytics, deepseek) 2026-03-14 01:45:17 -04:00
KoalaTrapLord 4b1d2f71f5 refactor: Batch 1 — add routes/ package with shared state, config, and models 2026-03-14 01:44:37 -04:00
KoalaTrapLord 2d02fcc770 Add files via upload 2026-03-14 01:00:25 -04:00
KoalaTrapLord 3d00b68566 Delete lab_api_patched.py 2026-03-14 00:59:15 -04:00
KoalaTrapLord dda82ad1e6 Add files via upload 2026-03-14 00:55:54 -04:00
KoalaTrapLord 6c547664fb Delete lab_api.py 2026-03-14 00:55:32 -04:00
KoalaTrapLord d95f0b57c0 fix: commander card correctly flagged in deck tracker
Two fixes:
1. _parse_text_decklist(): replace fragile startswith() section-header
   detection with case-insensitive regex so [Commander], [Main], [Deck]
   etc. are always recognised regardless of capitalisation.

2. add_deck_card endpoint: when a card is added with is_commander=1,
   also update the deck-level commander_name + commander_scryfall_id
   so the portrait and top-bar label stay in sync.
2026-03-14 00:48:19 -04:00
KoalaTrapLord 264fb33957 fix: commander card correctly flagged in deck tracker
Two fixes:
1. _parse_text_decklist(): replace fragile startswith() section header
   detection with proper case-insensitive regex so [Commander], [Main],
   [Deck] etc. are always recognised regardless of capitalisation.

2. add_deck_card endpoint: when a card is added with is_commander=1,
   also update the deck-level commander_name and commander_scryfall_id
   fields so the portrait and top-bar label stay in sync without
   requiring a full reload.
2026-03-14 00:47:59 -04:00
KoalaTrapLord e4ebd84c04 test 2026-03-14 00:47:37 -04:00
KoalaTrapLord 5b072174f8 Add Phase 8 — Multiplayer (Human vs Human + AI) 2026-03-14 00:33:24 -04:00
KoalaTrapLord 661ca9618b Add GUI framework decision and two-phase frontend plan 2026-03-14 00:30:36 -04:00
KoalaTrapLord 7b5c9bdcc6 Update LLM model to GPT-OSS 20B (Q4_K_M) 2026-03-14 00:23:12 -04:00
KoalaTrapLord 6c5c55b637 Add Commander GUI + LLM Opponents roadmap 2026-03-14 00:20:41 -04:00
KoalaTrapLord f05067bbfe feat(brain): pipe GameResult winner_seat + per-player life totals into flush_log() for RL training 2026-03-14 00:13:50 -04:00
KoalaTrapLord dfc1f46097 fix(ui): merge duplicate .stat-card declarations in premium layer 2026-03-14 00:10:14 -04:00
KoalaTrapLord 6cafa36ce4 feat(rules): add load_weights() / save_weights() for simulation-driven weight learning 2026-03-13 23:58:59 -04:00
KoalaTrapLord 7df6b95b4c feat(ui): add premium upgrade layer to global.css 2026-03-13 23:51:47 -04:00
KoalaTrapLord 812e5b34ca feat(tests): add pytest infrastructure and test coverage for models, rules, and sim engine (closes #28) 2026-03-13 22:30:40 -04:00
KoalaTrapLord 8c89119ba1 chore: add requirements.txt for pip install compatibility (closes #29) 2026-03-13 20:53:31 -04:00
KoalaTrapLord b1891c58f8 fix(deps): declare all runtime dependencies in pyproject.toml (closes #29) 2026-03-13 20:53:18 -04:00
KoalaTrapLord b5e7705100 feat(ui): 4-player deck slots, seat colors, chart support (Task 2C) 2026-03-13 19:08:53 -04:00
KoalaTrapLord 4c7c3495fb feat(api): accept 2-4 decks in batch start, dynamic Java CLI args (Task 2C) 2026-03-13 18:59:25 -04:00
KoalaTrapLord c1371849e5 feat(api): accept 2-4 decks in batch start, dynamic Java CLI args (Task 2C) 2026-03-13 18:58:33 -04:00
KoalaTrapLord 3190fa3702 feat(api): accept 2-4 decks in batch start, dynamic Java CLI args (Task 2C) 2026-03-13 18:56:58 -04:00
KoalaTrapLord 9f48e056ff feat(ui): 4-player deck grid, seat colors, responsive breakpoints (Task 2C) 2026-03-13 18:55:17 -04:00
KoalaTrapLord 841e861bea feat: N-player deepseek engine (Task 2A — Issue #27)
- run_n() accepts 2-4 decks; run() wraps for backward compat
- _select_attack_target() heuristic for multiplayer combat targeting
- N-player elimination order tracking with finish positions
- Removal scans all opponents for scariest creature
- ML snapshot captures all N players
- Log entries use per-seat boards dict with legacy boardA/boardB for 2-player
2026-03-13 16:58:23 -04:00
KoalaTrapLord 0be8841cec feat: N-player engine turn loop (Task 2A — Issue #27)
- engine.py: new run_n() method accepts 2-4 decks; run() wraps for backward compat
- _select_attack_target() heuristic: attack weakest non-eliminated opponent
- N-player elimination order tracking with correct finish positions
- Removal spells scan all opponents for best target
- Game logs use per-seat boards dict with boardA/boardB legacy keys for 2-player
- Tested: 2/3/4-player, elimination order, attack targeting
2026-03-13 16:54:55 -04:00
KoalaTrapLord ddc0e4fc05 fix: preserve is_commander flag when loading .dck files
Two places lost the commander flag:

1. _load_deck_cards_by_name() .dck fallback — used a flat in_cards
   boolean for [Main], [Deck], and [Commander] sections so it couldn't
   tell which section a card came from. Now tracks current_section and
   sets is_commander=1 for cards in [Commander].

2. parse_dck_file() — stored section='Commander' in the card dict but
   the frontend filters on c.is_commander, not c.section. Now includes
   is_commander: 1/0 alongside the existing section field.
2026-03-13 20:20:18 +00:00
KoalaTrapLord a1fd290d5f refactor: adopt Python logging module with named loggers
Replace all print() calls with structured logging using the Python
logging module. This provides:

- Named loggers per subsystem: commander_ai_lab.api, .batch, .sim,
  .coach, .deckgen, .collection, .scanner, .ml, .cache, .pplx
- Dual output: console (StreamHandler) + rotating file (RotatingFileHandler)
  at logs/commander-ai-lab.log (25 MB x 5 backups = 125 MB max)
- Configurable via env vars: CAL_LOG_DIR, CAL_LOG_MAX_MB, CAL_LOG_BACKUP_COUNT
- --verbose / -v flag for DEBUG-level output
- overnight-run.py: separate rotating log at logs/overnight-run.log (10 MB x 5)
- Sub-module loggers in ml/, scanner/, deck_sources/, src/ all propagate
  to the root commander_ai_lab logger
- Stripped redundant [TAG] prefixes from messages (logger name carries context)
- Format: '2026-03-13 14:00:00 INFO  [commander_ai_lab.batch] message'

Files changed: lab_api.py, overnight-run.py, and 11 sub-module .py files
176 total print() calls converted (101 in lab_api.py, 76 in sub-modules)
2026-03-13 18:09:52 +00:00
KoalaTrapLord 8d2e6199db feat: Scryfall response caching with SQLite
- _ScryfallCache class: thread-safe SQLite cache for raw Scryfall JSON
  responses, keyed by name|set_code|collector_number, 7-day TTL
- _fetch_scryfall_api() wrapper: checks cache first, live HTTP on miss,
  caches successful responses + resolves spelling normalization
- Refactored _enrich_from_scryfall() to use cache — all 3 callers
  (collection import, deck card add, re-enrich) benefit automatically
- Rate limiting only on actual HTTP calls, not cache hits
- REST endpoints: GET/DELETE /api/cache/scryfall, POST .../evict
- Fixed VACUUM-inside-transaction bug in clear()
- Configurable TTL via SCRYFALL_CACHE_TTL env var
2026-03-13 15:25:30 +00:00
KoalaTrapLord 3d8e81f88e Phase 2: score_card() num_opponents scaling + enrich_card() determinism fix (#32)
- score_card() now accepts num_opponents: int parameter (default 1)
- Keywords/effects scale with pod size via _MULTI_OPP_SCALING dict
- Multiplayer-specific oracle patterns: 'each opponent', pillowfort, 'each player'
- Board wipe and counter spell bonuses scale with opponent count
- Expanded keyword coverage (double strike, first strike, hexproof, indestructible,
  menace, vigilance, ward, infect, annihilator, cascade, defender)
- Triggered ability bonuses: ETB, attack triggers, dies triggers
- enrich_card() replaced random.randint() with hashlib.md5 name-based hash
  for deterministic CMC estimation across games (#32)
- Backward compatible: existing score_card(card, weights) calls unaffected
2026-03-12 20:22:44 +00:00
KoalaTrapLord 648e1b8d38 Fix simulator button stuck on Running — to_dict() backward compat
GameResult.to_dict() now returns both legacy keys (winner, playerA, playerB)
that the UI expects AND new N-player keys (winningSeat, playerResults) for
the Java BatchResult schema.
2026-03-12 18:25:22 +00:00
KoalaTrapLord de4f119d40 Phase 1: N-player data model refactoring
- New PlayerResult dataclass with seat_index, name, life, eliminated, finish_position, stats
- Refactored GameResult to use players: list[PlayerResult] + winner_seat (no hardcoded 2-player fields)
- Backward-compat @property accessors (player_a_stats, player_b_stats, winner, etc.) for existing consumers
- SimState.battlefields is now per-player (list-of-lists) with helper methods:
  get_battlefield(), add_to_battlefield(), remove_from_battlefield(), all_battlefield_cards()
- Updated engine.py, deepseek_engine.py, deepseek_brain.py to use per-player battlefields
- GameResult.to_dict() matches Java BatchResult schema (playerResults array)
- lab_api.py and experiments.py unchanged — backward-compat properties handle all existing access patterns
2026-03-12 18:10:57 +00:00