Logging a stated hand was unreliable and got worse mid-session: same model, same
hand, clean history logged 4/4 but the real session's history logged 0/4. Root
cause: memory.recent() rebuilt past turns as "hand -> narration" with the tool
calls stripped (they live in tool_events), so the model's own context became
few-shot examples training it, mid-conversation, to STOP calling tools. Even a
maximal "LOG FIRST, no exceptions" prompt scored 0/5 — it's structural, not wording.
Two-part fix (both, per the system-of-record frame):
- A (guarantee): chat._ensure_hand_logged — on a HAND turn that's Brian's OWN hand,
if the model didn't log it, force record_hand (tool_choice). Guarded to hero hands
(looks_like_hero_hand) so an observed hand is never force-logged as his. Adds
tool_choice passthrough to llm.chat_call; surfaces msg_type on TurnContext.
- B (heal forward): mind._history_with_tools makes each assistant turn's tool calls
visible in reconstructed history ("record_hand -> Hand #62"), so the demonstrated
pattern stops being "hand -> narrate". Recovers natural logging as logs accumulate.
Verified: force guard returns record_hand on the polluted context; full respond_stream
logs Hand #63 end-to-end on a clean session. 7 guard tests; suite 219 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The HAND fragment let her narrate a finished board from memory: she called
quad kings "kings full" and never noticed Brian FLOPPED quads, then wrapped it
in variance-evens-out / resilience filler. Two fixes to _F_HAND:
- Correctness: at a showdown where both hands are known, call analyze_spot on
the full board to confirm made hands + winner BEFORE commenting; name his hand
class by the street it mattered ("flopped quads"). The eval already existed —
she just never reached for it on a resolved hand. (It also catches impossible
cards, e.g. a villain card already on the board.)
- Register: ban reflexive praise / variance-evens-out / life-lesson / cross-hand
pep talk; if there's genuinely no leak, say so instead of inventing a takeaway.
Surgical here; the full voice pass stays with the persona branch.
Verified live on the exact quad-kings hand (cloud/gpt-4o-mini): she now logs,
calls analyze_spot, reads quads-vs-quads correctly, and calls it a cooler with
no leak. Guard tests added. Full suite 212 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Probed the heuristic against live-style messages and fixed 6 real gaps:
- action verbs missed -ing forms ("TAG's been limping") → no READ
- the descriptor-subject regex required words between "the" and the noun, so
"the whale called" missed → now handles bare "the <noun>"
- player departures ("TAG busted", "TAG left") weren't TABLE → added _DEPART
(gated to non-first-person so "I busted, heading home" isn't a roster op)
- the bare word "stack" made strategy questions ("should I stack off?") classify
as LOG → LOG now needs a number/result word AND excludes questions
- thin MENTAL lexicon → added coolered/sick/brutal/run bad/etc.
21-case probe (13 former misses + 8 regression guards) all green; folded into the
suite as 5 hardening tests. Full suite 201 green. classify() stays the swappable
seam for an LLM/MI50 upgrade later.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The standalone piece, not yet wired. lyra/poker_prompts.py:
- classify(user_msg, roster_handles=()) — pure 7-type classifier
(READ|HAND|TABLE|MENTAL|STATUS|LOG|CHAT), READ ranked above HAND so a villain's
action lands on their file not Brian's. Roster-aware (seated handles passed in),
handles poker shorthand (AKs) and strategy questions (→ CHAT not a logged hand).
The swappable seam for an LLM/MI50 classifier later.
- BASE — lean always-on poker rules distilled from the monolith (log-first + tool
routing, identity rules, rituals, equity, session_state).
- FRAGMENTS + fragment_for — per-type response-shape contracts.
13 unit tests incl. the READ↔HAND boundary. Full suite 193 green. Wiring next.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>