feat: auto-accumulating villain dossiers + player lookup (poker B)
Named players in recorded hands now auto-enrich a persistent dossier, and stats
emerge once the sample is big enough — laying groundwork for A.
- poker: player_observations table (per named player per hand: vpip/pfr/saw_flop/
showed/cards/summary); record_hand auto-links named players via link_hand_players;
player_profile(name) returns dossier + reads + shown hands, with inferred
VPIP/PFR/WTSD gated behind MIN_STATS_SAMPLE (12) so thin samples don't lie;
list_players()
- player_profile tool ("what do I know about X"); thin files return a blunt
"don't generalize" directive
- persona: she MUST call player_profile before discussing an opponent and answer
only from it — fixes observed confabulation (she invented a whole read from one
hand / from memory). Verified: now reports only the real logged hand.
- tests: observation linking, profile, stat-emergence at sample threshold
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -116,6 +116,40 @@ def test_list_recent_hands(lyra):
|
||||
assert hh and hh[0]["hole_cards"] == "QQ" and hh[0]["stakes"] == "1/3"
|
||||
|
||||
|
||||
def test_player_observation_and_profile(lyra):
|
||||
poker = lyra
|
||||
sid = poker.start_session(stakes="1/3", buy_in=300)
|
||||
parsed = {"hero_pos": "BB",
|
||||
"players": [{"pos": "BTN", "name": "Round Mike"}, {"pos": "BB", "name": None}],
|
||||
"actions": [{"street": "preflop", "pos": "BTN", "action": "raise", "amount": 12},
|
||||
{"street": "preflop", "pos": "BB", "action": "call"},
|
||||
{"street": "flop", "board": ["7d", "2c", "5h"]},
|
||||
{"street": "flop", "pos": "BTN", "action": "bet", "amount": 15}]}
|
||||
hid = poker.store_hand_history(parsed, session_id=sid)
|
||||
assert poker.link_hand_players(hid, parsed, session_id=sid) == 1 # only the named player
|
||||
prof = poker.player_profile("mike")
|
||||
assert prof["player"]["name"] == "Round Mike"
|
||||
assert prof["observations"] == 1
|
||||
assert prof["stats"] is None and "small_sample" in prof # too few hands for stats
|
||||
|
||||
|
||||
def test_player_stats_emerge_with_sample(lyra):
|
||||
poker = lyra
|
||||
sid = poker.start_session(stakes="1/3", buy_in=300)
|
||||
raised = {"players": [{"pos": "BTN", "name": "LAG"}],
|
||||
"actions": [{"street": "preflop", "pos": "BTN", "action": "raise", "amount": 10}]}
|
||||
folded = {"players": [{"pos": "UTG", "name": "LAG"}],
|
||||
"actions": [{"street": "preflop", "pos": "UTG", "action": "fold"}]}
|
||||
for i in range(poker.MIN_STATS_SAMPLE):
|
||||
p = raised if i % 2 == 0 else folded
|
||||
hid = poker.store_hand_history(p, session_id=sid)
|
||||
poker.link_hand_players(hid, p, session_id=sid)
|
||||
prof = poker.player_profile("LAG")
|
||||
assert prof["stats"] is not None
|
||||
assert prof["stats"]["hands"] >= poker.MIN_STATS_SAMPLE
|
||||
assert 30 <= prof["stats"]["vpip_pct"] <= 70 # ~half were voluntary
|
||||
|
||||
|
||||
def test_poker_tools_dispatch(lyra):
|
||||
from lyra import tools
|
||||
assert "started" in tools.dispatch("start_session", {"stakes": "1/3", "buy_in": 300})
|
||||
|
||||
Reference in New Issue
Block a user