id: 566b6cfe43d44e6ab0ebbd2a323230d2
parent_id: 
item_type: 1
item_id: b7492324f4d64486ba79ea00e636d2ec
item_updated_time: 1781519289849
title_diff: "[{\"diffs\":[[1,\"Live Integration — Server & Scrapers Architecture\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":49}]"
body_diff: "[{\"diffs\":[[1,\"# Live Integration — Server & Scrapers Architecture\\\n\\\n**Status:** Phase 2 (server core) complete — 2026-06-15\\\n**Design plan:** `super_marvin/.kilo/plans/live-integration-torn.md`\\\n**Related:** [Vision — Poker AI Testbed & Live Server](joplin://b7bf3a077c064d8493373a3661adc702), [Prototype: Web Traffic Interception](joplin://6794e0bb60ae4da68720868546ddf628), [Browser Extension](joplin://c994139aac9245c79da7923dbe8579b3)\\\n\\\n---\\\n\\\n## Goal\\\n\\\nConnect super-marvin bots to real poker sites/applications. First target: **Torn City** poker\\\npage (browser → TamperMonkey). Architecture is site-agnostic: the server never contains\\\nsite-specific parsing.\\\n\\\n## Repository split (confirmed)\\\n\\\n| Repo | IDE | Role |\\\n|------|-----|------|\\\n| `super_marvin` (RustRover) | Rust | `poker_protocol` + `live_server` workspace crates |\\\n| `super-marvin-userscripts` (WebStorm) | JS/TS | npm-workspace monorepo: `shared/` + one folder per site (`torn/`) |\\\n| `super-marvin-scrapers-native` (RustRover) | Rust | **Deferred** — native desktop scrapers |\\\n\\\n## Transport: event stream (chosen)\\\n\\\nThe Java JointBot `BotServer` was event-driven (UDP multicast, XML). We modernize to **JSON over\\\nHTTP** but keep the model: the scraper streams discrete `TableEvent`s; the server keeps a per-table\\\nstate machine and returns the decision inline on `waiting_for_action`. (A snapshot-per-decision\\\nmodel was considered and rejected as less robust.)\\\n\\\n```\\\nTamperMonkey (browser)            native client (future)\\\n   torn/*.user.js\\\n        │  POST /api/event(s)           │\\\n        ▼                               ▼\\\n   ┌─────────────────────────────────────────────┐\\\n   │  super_marvin / live_server (Axum)          │\\\n   │  event → TableState (GameInfo) → bot.act()   │\\\n   │            ▼                                │\\\n   │   holdem_bots engine (auto-selected bot)    │\\\n   └─────────────────────────────────────────────┘\\\n```\\\n\\\n## Events (poker_protocol::TableEvent)\\\n\\\n`table_profile` (format/limit/seats — drives auto-detect), `game_start`, `deal` (hole/flop/turn/\\\nriver), `player_action` (check/fold/bet/raise/call/small_blind/big_blind/ante), `waiting_for_action`\\\n(triggers decision), `win`, `showdown`, `game_over`, `table_remove`. Cards are 2-char strings.\\\n\\\n## Bot auto-detection (format × limit × seats)\\\n\\\n`configs/live_bots.toml` maps profiles → bot config files. The most specific match wins; falls\\\nback to `default`. Bands: hu (1-2), six_max (3-6), full_ring (7+). At startup every referenced bot\\\nTOML is registered with the engine; `live_server` instantiates the selected bot per table via\\\n`holdem_core::game::bot_factory::create_bot`.\\\n\\\n## super_marvin additions\\\n\\\n```\\\npoker_protocol/          # canonical types, site-agnostic\\\n  src/lib.rs             # Card, GameType, BotAction, DecisionResponse\\\n  src/events.rs          # TableEvent, EventResponse, GameFormat, SeatBand, …\\\nlive_server/\\\n  src/main.rs            # bootstrap: config, bot selection load+register, routes, serve\\\n  src/config.rs          # LiveServerConfig (bind_addr, bots_config_path, bot_config_path, max_tables)\\\n  src/bot_selection.rs   # BotSelectionConfig: profile resolution + register_all + read_bot_name\\\n  src/handlers.rs        # /health, /api/info, /api/tables, POST /api/event, /api/events\\\n  src/session.rs         # SessionStore: table_id → Arc<Mutex<TableSession>>\\\n  src/table_state.rs     # event → GameInfo state machine + bot lifecycle (decide on waiting_for_action)\\\n  src/adapter.rs         # engine Action → BotAction\\\n  src/error.rs           # ApiStatusError → JSON\\\nconfigs/live_server.toml # gateway config\\\nconfigs/live_bots.toml   # bot-selection profiles (default cash_nl, sng_gen2, mtt→sng_gen2)\\\n```\\\n\\\n`table_state.rs` is the Rust analogue of JointBot `TableManager`: it accumulates events into\\\nrunning table state (seats, stacks, wagers, board, pot, current_bet, blinds, street, button/sb/bb),\\\ndrives the bot's `HoldemPlayer` lifecycle (game_start_event, hole_cards_dealt, stage_event,\\\naction_event, act, game_over_event), and builds a `GameInfo` on each step.\\\n\\\n## Endpoints\\\n\\\n| Method | Path | Behavior |\\\n|--------|------|----------|\\\n| GET | `/health` | `{status,tables}` |\\\n| GET | `/api/info` | name, version, bots_configured, default_bot, max_tables |\\\n| GET | `/api/tables` | `{count}` |\\\n| POST | `/api/event` | single event; decision inline for `waiting_for_action` |\\\n| POST | `/api/events` | batch; returns envelope of last event |\\\n\\\nRun: `cargo run -p live_server`.\\\n\\\n## super-marvin-userscripts\\\n\\\n`shared/` mirrors the event protocol (`types.ts`) + transport client (`sendEvent`/`sendEvents` via\\\n`GM_xmlhttpRequest`, `fetch` fallback). `torn/` ships a stub `collectEvents()` + `executeAction()`\\\nloop; Phase 3 fills in real Torn DOM scraping. Build: `npm run build` → `torn/dist/torn.user.js`.\\\n\\\n## Verification (Phase 2)\\\n\\\n- 18 unit tests pass (poker_protocol + live_server: bot-selection resolution, session store,\\\n  table-state state machine incl. blinds/pot GameInfo, fold/call via built-in bots).\\\n- End-to-end smoke: posted `table_profile` (cash NL 2-seat) → resolved `cash_nl`; full event stream\\\n  (game_start → deal hole → SB/BB → waiting_for_action) → real engine decision returned inline.\\\n\\\n## Phases\\\n\\\n1. **Phase 1 — Scaffolding** ✅ crates, build pipeline, stubs.\\\n2. **Phase 2 — Server core** ✅ event protocol, bot auto-detect, state machine → engine decisions.\\\n3. **Phase 3 — Torn scraping** — inspect Torn poker DOM/network; implement `collectEvents()` +\\\n   `executeAction()`; live single-table loop.\\\n4. **Phase 4 — Hardening** — GameInfo fidelity tuning vs engine, session/hand lifecycle edge cases,\\\n   reconnect/retry, throttling, hand-history logging, multi-table.\\\n\\\n## Open items / known caveats\\\n\\\n- **GameInfo fidelity:** the server-built `GameInfo` approximates engine state from events. Move\\\n  quality depends on this matching exactly what the engine produces; needs validation against real\\\n  Torn event streams (Phase 3) and possibly unit tests against the engine's own `GameInfo` snapshots.\\\n- **`actions_this_hand`** is left empty in the server-built `GameInfo`; the `StrategyBot` derives its\\\n  action history from its own `ActionRecorder` (fed via `action_event`), so this is not blocking, but\\\n  any strategy reading `actions_this_hand` directly would see empty data.\\\n- Server stays site-agnostic; `poker_protocol` stays free of network/runtime deps.\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":6317}]"
metadata_diff: {"new":{"id":"b7492324f4d64486ba79ea00e636d2ec","parent_id":"2c8da247905946c3aa19eb4936e16323","latitude":"0.00000000","longitude":"0.00000000","altitude":"0.0000","author":"","source_url":"","is_todo":0,"todo_due":0,"todo_completed":0,"source":"joplin-desktop","source_application":"net.cozic.joplin-desktop","application_data":"","order":1781514355871,"markup_language":1,"is_shared":0,"share_id":"","conflict_original_id":"","master_key_id":"","user_data":"","deleted_time":0},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-06-15T10:36:55.111Z
created_time: 2026-06-15T10:36:55.111Z
type_: 13