feat: live mental-game rituals in Cash mode
Brian's own rituals (mined from his logs) become first-class, live tools instead of post-hoc recap sections: - Scar Note — instructive mistakes with the punt/cooler/standard distinction. - Confidence Bank — good process, banked regardless of result. - Alligator Blood — invokable adversity state; she suggests it when he's card-dead/short/stuck, and her coaching register shifts while it's on (live state injected into context per-turn via chat._mode_state_note). - Reset — tilt circuit-breaker; mental marker only, stats stay continuous. poker_rituals table + log_ritual/list_rituals/set_alligator/alligator_active; 4 tools added to the Cash toolset and taught in the mode card; HUD gains a 🐊 banner + Confidence Bank + Scar Notes panels; recap grounded via _rituals_block. tests/test_modes.py +5 ritual tests; 41 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -106,3 +106,62 @@ def test_log_stack_tool_handler(lyra):
|
||||
assert "450" in out and "150" in out # confirms stack + live net
|
||||
# graceful when there's no number
|
||||
assert "number" in tools.dispatch("log_stack", {}, {}).lower()
|
||||
|
||||
|
||||
# --- mental-game rituals ---
|
||||
|
||||
def test_ritual_tools_in_cash_only(lyra):
|
||||
_, _, modes, tools = lyra
|
||||
cash = _names(tools.specs(modes.CASH.tools))
|
||||
talk = _names(tools.specs(modes.TALK.tools))
|
||||
rituals = {"scar_note", "confidence_bank", "alligator_blood", "reset_ritual"}
|
||||
assert rituals <= cash
|
||||
assert not (rituals & talk)
|
||||
|
||||
|
||||
def test_scar_and_confidence_capture(lyra):
|
||||
_, poker, _, tools = lyra
|
||||
poker.start_session(stakes="2/5", buy_in=500)
|
||||
tools.dispatch("scar_note", {"content": "punted bottom set", "classification": "punt"}, {})
|
||||
tools.dispatch("scar_note", {"content": "ran KK into AA", "classification": "cooler"}, {})
|
||||
tools.dispatch("confidence_bank", {"content": "disciplined river fold"}, {})
|
||||
|
||||
scars = poker.list_rituals(kinds=("scar",))
|
||||
assert len(scars) == 2
|
||||
assert {s["classification"] for s in scars} == {"punt", "cooler"}
|
||||
conf = poker.list_rituals(kinds=("confidence",))
|
||||
assert len(conf) == 1 and "fold" in conf[0]["content"]
|
||||
# bogus classification is dropped, not stored
|
||||
tools.dispatch("scar_note", {"content": "x", "classification": "nonsense"}, {})
|
||||
assert poker.list_rituals(kinds=("scar",))[-1]["classification"] is None
|
||||
|
||||
|
||||
def test_alligator_toggle_and_state(lyra):
|
||||
_, poker, _, tools = lyra
|
||||
poker.start_session(stakes="2/5", buy_in=500)
|
||||
assert poker.alligator_active() is False
|
||||
tools.dispatch("alligator_blood", {"on": True}, {})
|
||||
assert poker.alligator_active() is True
|
||||
tools.dispatch("alligator_blood", {"on": False}, {})
|
||||
assert poker.alligator_active() is False # latest toggle wins
|
||||
|
||||
|
||||
def test_rituals_in_hud(lyra):
|
||||
_, poker, _, tools = lyra
|
||||
poker.start_session(stakes="2/5", buy_in=500)
|
||||
tools.dispatch("scar_note", {"content": "overplayed top pair"}, {})
|
||||
tools.dispatch("confidence_bank", {"content": "good value bet"}, {})
|
||||
tools.dispatch("reset_ritual", {"content": "lost a flip"}, {})
|
||||
tools.dispatch("alligator_blood", {"on": True}, {})
|
||||
|
||||
r = poker.hud()["rituals"]
|
||||
assert r["alligator"] is True
|
||||
assert len(r["scars"]) == 1 and len(r["confidence"]) == 1 and len(r["resets"]) == 1
|
||||
|
||||
|
||||
def test_rituals_require_live_session(lyra):
|
||||
_, poker, _, tools = lyra
|
||||
# tools degrade gracefully (no exception) when nothing is open
|
||||
assert "no live session" in tools.dispatch("scar_note", {"content": "x"}, {}).lower()
|
||||
with pytest.raises(ValueError):
|
||||
poker.log_ritual("scar", content="x")
|
||||
|
||||
Reference in New Issue
Block a user