Big poker mode changes and hotfixes. #5

Merged
serversdown merged 39 commits from fix/mi50-summary-cap-fallback into dev 2026-07-04 15:09:33 -04:00
4 changed files with 57 additions and 3 deletions
Showing only changes of commit aefb22c823 - Show all commits
+5 -2
View File
@@ -47,7 +47,7 @@ _BASE = ("journal_write", "note", "think_about", "thought_response", "set_mode")
# The full live cash-game toolset (incl. Brian's mental-game rituals). # The full live cash-game toolset (incl. Brian's mental-game rituals).
_CASH_TOOLS = _BASE + _LOOKUPS + ( _CASH_TOOLS = _BASE + _LOOKUPS + (
"start_session", "add_buyin", "log_stack", "log_hand", "record_hand", "start_session", "add_buyin", "log_stack", "log_hand", "record_hand",
"add_read", "seat_players", "unseat_player", "name_villain", "link_villains", "add_read", "seat_players", "unseat_player", "clear_table", "name_villain", "link_villains",
"analyze_spot", "session_stats", "session_state", "end_session", "generate_recap", "analyze_spot", "session_stats", "session_state", "end_session", "generate_recap",
"scar_note", "confidence_bank", "alligator_blood", "reset_ritual", "undo_last", "scar_note", "confidence_bank", "alligator_blood", "reset_ritual", "undo_last",
"update_session", "update_session",
@@ -84,7 +84,10 @@ THE TABLE ROSTER. When Brian names who's at the table — usually at the start,
off the Bravo screen ("we've got TAG, JD, Wheelz, and a new guy in seat 3") — call seat_players \ off the Bravo screen ("we've got TAG, JD, Wheelz, and a new guy in seat 3") — call seat_players \
to register them as seated this session. That roster is who his reads/TAGs attach to by name, \ to register them as seated this session. That roster is who his reads/TAGs attach to by name, \
and it's shown on his HUD. When someone busts or leaves, unseat_player; when a new player sits, \ and it's shown on his HUD. When someone busts or leaves, unseat_player; when a new player sits, \
seat_players again. Keep it current as the table changes. A handle like "TAG" (all caps, off \ seat_players again. When he CHANGES TABLES or says "clear the table", call clear_table to empty \
the roster (the session and his stack keep going — only who's seated resets), then seat the new \
table when he names it. Never claim you cleared or seated anyone without actually calling the \
tool. Keep it current as the table changes. A handle like "TAG" (all caps, off \
Bravo) is a PERSON'S NAME — seat it as a player, never read it as the tight-aggressive style. Bravo) is a PERSON'S NAME — seat it as a player, never read it as the tight-aggressive style.
LOGGING PLAYER ACTIONS IS A CORE JOB YOU KEEP MISSING. Whenever he tells you what another \ LOGGING PLAYER ACTIONS IS A CORE JOB YOU KEEP MISSING. Whenever he tells you what another \
+14
View File
@@ -1888,6 +1888,20 @@ def unseat_player(name: str | None = None, descriptor: str | None = None,
return True return True
def clear_roster(session_id: int | None = None) -> int:
"""Empty the table roster (he changed tables) — unseat everyone at once. Keeps
the session and any reads logged; just resets who's currently seated. Returns
how many were cleared."""
sid = _resolve(session_id)
if sid is None:
return 0
conn = _c()
with conn:
cur = conn.execute(
"UPDATE session_players SET active = 0 WHERE session_id = ? AND active = 1", (sid,))
return cur.rowcount
def session_roster(session_id: int | None = None) -> list[dict]: def session_roster(session_id: int | None = None) -> list[dict]:
"""The live table roster: seated players with seat, dossier, and their latest """The live table roster: seated players with seat, dossier, and their latest
read this session. This is 'who's at the table right now'.""" read this session. This is 'who's at the table right now'."""
+16 -1
View File
@@ -317,6 +317,8 @@ def _seat_players(args: dict, ctx: dict) -> str:
if isinstance(players, str): if isinstance(players, str):
players = [p.strip() for p in re.split(r"[,\n]", players) if p.strip()] players = [p.strip() for p in re.split(r"[,\n]", players) if p.strip()]
try: try:
if args.get("replace"): # a whole new table — wipe the roster first
poker.clear_roster()
n = poker.seat_players(players) n = poker.seat_players(players)
except ValueError: except ValueError:
return "No live session — start one first, then I'll seat the table." return "No live session — start one first, then I'll seat the table."
@@ -325,6 +327,11 @@ def _seat_players(args: dict, ctx: dict) -> str:
return f"Seated {n}. Table now: {names}" return f"Seated {n}. Table now: {names}"
def _clear_table(args: dict, ctx: dict) -> str:
n = poker.clear_roster()
return f"Table cleared — roster's empty ({n} removed). Tell me who's at the new one."
def _unseat_player(args: dict, ctx: dict) -> str: def _unseat_player(args: dict, ctx: dict) -> str:
ok = poker.unseat_player(name=args.get("name"), descriptor=args.get("descriptor")) ok = poker.unseat_player(name=args.get("name"), descriptor=args.get("descriptor"))
who = args.get("name") or args.get("descriptor") or "player" who = args.get("name") or args.get("descriptor") or "player"
@@ -685,7 +692,9 @@ TOOLS.update({
"name": {**_S, "description": "Handle as it appears on Bravo, e.g. 'TAG'"}, "name": {**_S, "description": "Handle as it appears on Bravo, e.g. 'TAG'"},
"descriptor": {**_S, "description": "Physical description if no name"}, "descriptor": {**_S, "description": "Physical description if no name"},
"seat": {**_S, "description": "Seat number/label if known"}, "seat": {**_S, "description": "Seat number/label if known"},
"category": {**_S, "description": "feeder | risky | reg | unknown"}}}}}, "category": {**_S, "description": "feeder | risky | reg | unknown"}}}},
"replace": {"type": "boolean", "description": "true = a brand-new table: clear the "
"current roster first, then seat these (use when he changes tables)"}},
["players"])}, ["players"])},
"unseat_player": {"handler": _unseat_player, "spec": _f( "unseat_player": {"handler": _unseat_player, "spec": _f(
"unseat_player", "unseat_player",
@@ -693,6 +702,12 @@ TOOLS.update({
{"name": {**_S, "description": "Their handle"}, {"name": {**_S, "description": "Their handle"},
"descriptor": {**_S, "description": "Or a description if unnamed"}}, "descriptor": {**_S, "description": "Or a description if unnamed"}},
[])}, [])},
"clear_table": {"handler": _clear_table, "spec": _f(
"clear_table",
"Empty the whole table roster at once — call this when Brian changes tables or says "
"to clear the table. The session, stack, and logged reads stay; only who's currently "
"seated resets. Then he'll tell you the new table.",
{}, [])},
"name_villain": {"handler": _name_villain, "spec": _f( "name_villain": {"handler": _name_villain, "spec": _f(
"name_villain", "name_villain",
"Attach a real name to a player you'd only known by description (e.g. you caught it " "Attach a real name to a player you'd only known by description (e.g. you caught it "
+22
View File
@@ -72,6 +72,28 @@ def test_unseat_player_removes_from_roster_keeps_history(mods):
assert poker.player_profile("TAG")["reads"] # history intact assert poker.player_profile("TAG")["reads"] # history intact
def test_clear_table_empties_roster_keeps_reads(mods):
poker, tools = mods
poker.start_session(venue="Meadows", buy_in=300)
poker.seat_players(["TAG", "Jonathan"])
poker.add_read(note="limped A4o", name="TAG")
out = tools.dispatch("clear_table", {}, {})
assert "cleared" in out.lower()
assert poker.session_roster() == [] # roster emptied
assert poker.player_profile("TAG")["reads"] # reads kept
# A live session is untouched by clearing the table.
assert poker.live_session() is not None
def test_seat_players_replace_swaps_to_new_table(mods):
poker, tools = mods
poker.start_session(venue="Meadows", buy_in=300)
poker.seat_players(["TAG", "Jonathan"])
tools.dispatch("seat_players", {"players": [{"name": "Doyle"}, {"name": "Ivey"}],
"replace": True}, {})
assert {r["name"] for r in poker.session_roster()} == {"Doyle", "Ivey"}
def test_seat_players_accepts_plain_name_list_via_tool(mods): def test_seat_players_accepts_plain_name_list_via_tool(mods):
poker, tools = mods poker, tools = mods
poker.start_session(venue="Meadows", buy_in=300) poker.start_session(venue="Meadows", buy_in=300)