feat: undo / delete logged entries (fix fat-fingered live logging)

Previously the only delete was whole-session, so a mis-logged stack or a
mis-parsed hand was stuck on the HUD. Now:

- undo_last tool ("scratch that") — deletes the most recent hand/stack/read/
  scar/confidence/reset in the live session; added to the Cash toolset.
- poker.delete_hand/stack/read/ritual + delete_entry dispatch + undo_last.
- DELETE /session/entry/{kind}/{id} endpoint.
- HUD: per-row × delete buttons on hands, confidence-bank, and scar-note rows
  (stack/read deletes via the tool). Row ids now surfaced in the hud() bundle.
- test_modes.py +2 (undo_last across kinds, tool handler); 46 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 04:32:04 +00:00
parent df591e4e01
commit 67cf51a53f
6 changed files with 182 additions and 8 deletions
+40
View File
@@ -175,6 +175,46 @@ def test_session_state_readback(lyra):
assert "great river fold" in out
def test_undo_last_and_delete_entry(lyra):
_, poker, modes, tools = lyra
assert "undo_last" in modes.CASH.tools
poker.start_session(venue="Meadows", stakes="2/5", buy_in=500)
h1 = poker.log_hand(position="UTG", hole_cards="AA")
h2 = poker.log_hand(position="BTN", hole_cards="72o")
poker.log_stack(600); poker.log_stack(420)
poker.log_ritual("scar", content="punted")
poker.log_ritual("confidence", content="good fold")
# undo removes the most recent of each kind
assert "72o" in poker.undo_last("hand")
assert [h["hole_cards"] for h in poker.list_hands()] == ["AA"] # h2 gone, h1 stays
assert "420" in poker.undo_last("stack")
assert poker.current_stack() == 600
assert "punted" in poker.undo_last("scar")
assert not poker.list_rituals(kinds=("scar",))
assert poker.list_rituals(kinds=("confidence",)) # untouched
assert poker.undo_last("hand") is not None # h1
assert poker.undo_last("hand") is None # nothing left
# direct delete-by-id dispatch
assert poker.delete_entry("ritual", poker.list_rituals(kinds=("confidence",))[0]["id"]) is True
assert poker.delete_entry("bogus", 1) is False
def test_undo_last_tool(lyra):
_, poker, _, tools = lyra
poker.start_session(stakes="1/3", buy_in=300)
poker.log_hand(position="CO", hole_cards="KK")
out = tools.dispatch("undo_last", {"what": "hand"}, {})
assert "scratched" in out.lower() and poker.list_hands() == []
# no live session -> graceful
poker.end_session(cash_out=300)
assert "no live session" in tools.dispatch("undo_last", {"what": "hand"}, {}).lower()
# nonsense target
poker.start_session(stakes="1/3", buy_in=100)
assert "one of" in tools.dispatch("undo_last", {"what": "banana"}, {}).lower()
def test_list_and_delete_session(lyra):
_, poker, _, tools = lyra
keep = poker.start_session(venue="Meadows", stakes="1/3", buy_in=300)