Big poker mode changes and hotfixes. #5
Reference in New Issue
Block a user
Delete Branch "fix/mi50-summary-cap-fallback"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Chat only ever lived in SQLite's `exchanges` table (what was *said*); tool calls were transient — logged to the in-memory ring buffer and gone at end-of-turn. This adds a persistent record of what Lyra *did* and exports the two merged into one transcript. - memory: new `tool_events` table + `add_tool_event`/`tool_events` accessors; `delete_session` cascades to it. - chat: persist each tool call (name/args/result) right where it fires, in both the non-stream and stream paths. Move the user `remember` to just after assembly so its timestamp precedes mid-turn tool events — keeps the export in true chronological order (and records when the message actually arrived). - transcript: new module renders a session as Markdown (Brian/Lyra speech with ⚙ tool-call lines interleaved) or JSON (machine-readable event stream). - server: GET /sessions/{id}/export?format=md|json (attachment download). - ui: ⬇ Export button by the session selector (Markdown or JSON). Doubles as the receipt for "did the tool actually fire?" — the thing that was invisible when she'd reply about a hand without logging it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The HUD's "her notes" panel showed any journal/note entry in the session's time window — which swept in her *autonomous* journaling (dream-cycle reflections, thought loop, existential musings) that merely overlapped in time. So a poker session displayed her feelings, not the night. Fix both halves: - Identity: the `note` tool stamps `source=poker:{id}` when a session is live, so a session note is identifiable by construction. The HUD filters on that tag (kind='note' only) instead of a time window — her journaling has a different source and can never leak onto the poker HUD. `journal_write` stays her private journal and never shows here. - Behavior: the Cash card now tells her to use `note` as a running SESSION LOG — factual beats a hand/stack log misses (table dynamics, Brian's arc, momentum), beat-reporter not diarist — and explicitly keeps feelings/reflection off the table. The note tool spec echoes this for the live-session case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Phase 4. A Players page that browses the whole villain file (named + nameless, expandable to episodic recall — reads, notable hands, stats, descriptors) and, at the top, the identity-resolution queue: possible-merges (same/different/dismiss) and needs-clarification tasks. Rename a nameless villain, set category, or run a dupe scan inline. - poker.players_overview() for the list. - routes: /players (page), /players/data, /player/{id}/data, POST /player/{id} (rename/retag), POST /identity/{id}/resolve, POST /players/scan. - nav: 👤 Players. Full suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Follow-up to the /players build: - the new POST /player/{id} collided with the existing PATCH route (F811); fold the name→named-flip into the existing PATCH and point the UI at it. - villain_recall / update_player returned the raw row including descriptor_embedding (bytes) → PydanticSerializationError on the API. Strip it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The name-flip fallback returned villain_recall's nested {player:{...}} shape, breaking r.json()["player"]["name"]. Always return update_player's flat row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Addresses "no way to edit hands" and cleaning up misattributed ones: - hand viewer (/hand/{id}) gets an "✎ Edit this hand" panel: position, cards, board, your net, tag, lesson → Save (existing PATCH), plus Delete. - "Not my hand" → POST /hand/{id}/disown → poker.disown_hand clears the flat hero fields and rewrites structured with hero_involved=false, so a hand mislabeled as Brian's becomes a clean observed hand (replay stops showing him as hero). 1 test. Full suite 156 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Prior commit misread "TAG" as an imperative ("tag this on his file"); it's actually a player's handle (his initials). Rewrite the Cash-card rule around the real gap: any "<player> did X" (limped/called/raised/shoved) is a read → add_read log-first, every time. Player names are often short handles/initials (Tag, JD, Wheelz) — use whatever he calls a person as-is, never as a poker term. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>- The roster card's empty-state string had a broken apostrophe escape ("who\\'s") that terminated the string early — a syntax error that killed the whole session.html script, so the HUD only rendered from a stale cached shell. Reworded to drop the apostrophe. - Add a middleware that sets Cache-Control: no-cache on HTML/JS so a PWA can't keep serving a stale shell after a deploy (iOS heuristically caches when no cache header is present — the reason a hard refresh + reopen didn't update). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Observed live: an overheated MI50 returns a single char repeated ("?????") as a successful 200, which neither the timeout nor the exception fallback catches — so a degraded GPU would silently save capped garbage gists. Validate each summary call's output: flag text (>=24 non-space chars) whose most-common non-whitespace char exceeds 50%, raise DegenerateOutput, and let the existing retry->cloud fallback handle it. Real prose (top char <20%) won't false-positive; short output is exempt; cloud garbage raises rather than looping. Tests: _looks_degenerate flags repeated-char / passes real prose / ignores short; degenerate MI50 output falls back to cloud; cloud garbage raises. 177 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015yrEb5qpPGv2FjyxrB7LLk