Update main. #6
Reference in New Issue
Block a user
Delete Branch "dev"
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?
Feedback: the push broadcast her raw internal thought ("Eelis Parssinen's victory is a reminder...") — read like a journal entry, not her texting him. Now the flow matches the intent: she thinks/journals, then *decides* "I should tell Brian about this." think() asks for an optional `reach_out` — a real text message addressed TO him in her own voice, written only when she chooses to. The ping sends that message (title "Lyra", like a text from her), never the internal thought. No reach_out = nothing sent (most thoughts stay hers). - Pinging decoupled from the salience score: her decision (a reach_out) drives it, not a threshold. PING_SALIENCE is now an optional floor (default 0.0). - Defensive: reject the placeholder echo ("reach_out"), too-short junk, or the thought pasted back as the message. - notify.push: title now optional (omitted -> cleaner text-style notification). Verified live: 3 passes kept private; a decided reach-out lands as a personal text. Suite 67 green, ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Replaces the thought loop's grist (recent-convo + her own saved narrative, the feedback-loop attractor) with a model of how a thought actually arises: seed (salience-weighted: a recent moment / resurfaced memory / feed item) -> spreading activation: embed the seed, let it light up associatively-near material across ALL her stores (conversations, gists, her own journal/ thoughts), blended by relevance + recency + noise; optional 2nd hop for leaps -> her self-narrative stays the LENS (supplied as interiority), not the input -> the thought is generated from what lit up, routed through a faculty (notice / connect / abstract / project / feel) -> journaled + embedded, so it can light up in future cycles This breaks the feedback loop structurally: the narrative is no longer reread and paraphrased each cycle; grist is genuinely associative and varied; and her past thoughts re-activate (continuity without calcification). - lyra/cognition.py (new): spontaneous_seed, activate (spreading activation), constellation_block, faculties. - memory.py: journal entries now embedded; recall_journal(); backfill_journal_embeddings() (ran once: 341 past entries embedded so her history is associatively retrievable). - thoughts.think(): new-thread mode now uses the associative engine; dropped _grist(). - tests: test_cognition.py (recall_journal ranking, activation, seeding) + fixture reloads cognition. Suite 72 green, ruff clean. Honest scope: this fixes the mechanism (how thoughts arise). The residual "be useful for Brian" voice drift is the separate model/fine-tune problem. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The control plane gains senses — cheap, deterministic, no LLM: - lyra/perceive.py: lexicon+signal heuristic → {sentiment, intensity, tilt, kind: emotional|strategic|meta|build|casual}. Good at the action-relevant signal, especially tilt (the mental-game core). Word-boundary matching so 'line' doesn't fire inside 'pipeline'. - mind: _perceive fills ctx.moment; _route keeps the manual mode as the dominant frame but, on a genuinely charged moment, adds a per-turn register nudge — tilt → "meet him there, warm and steady, don't clip into logging"; up/energized → "match his energy." Neutral turns get nothing (don't over-narrate). Injected via build_messages(moment=...). Logged to /logs for observability. - tests: perceive read (tilt/strategy/up/build/casual) + route nudge on/off. Suite 92 green, ruff clean. Complements modes (manual frame) — perceive refines register within it, doesn't override. Model routing (mind/mouth) is P3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>She was logging stacks but skipping hands — the CASH card framed logging as one of two registers, so she'd 'talk about' a hand instead of recording it (streaming returns content OR tool calls). Fixes: - CASH card: logging is mandatory and log-FIRST — trackable facts get the tool call before the reply, both not either/or, hands never skipped for conversation. - log_stack gains a note ('card dead', 'doubled up vs the LAG') -> timeline context; tool spec + handler updated. Migration adds poker_stack_log.note. - poker.timeline(): interleaves session start, stack updates (+context), hands (linkable), reads, and rituals chronologically in local time (clock.short()). Added to the hud() bundle. - Session HUD: a 📜 Timeline card renders the running log with hand links — the '10:19pm start … 1:34a doubled up, $750 (hand)' view Brian wanted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>summarize_all fanned out 8 concurrent workers, but the MI50 llama.cpp server runs a single slot (--parallel 1). Firing 8 at once queued them, blew the client timeout ('summary retry … Request timed out'), and thrashed/cancelled the KV cache — wasted compute and heat. Concurrency is now backend-aware: 8 for cloud, 1 for local/MI50. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>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