diff --git a/persistent-memory.md b/persistent-memory.md index b211be3..bd6c5a6 100644 --- a/persistent-memory.md +++ b/persistent-memory.md @@ -41,7 +41,7 @@ upstream API key stays server-side (INV-003). _As of 2026-07-06 (session cont.):_ -**SHIPPED — web UI redesign via Claude Design (`v0.20.0`, MINOR, operator-approved).** The Claude Design prototype **`Ratatoskr Console.dc.html`** (project `bc0b65d1-a33e-422a-8bc1-3635c9112775`) was pulled via `DesignSync get_file` (design scopes already granted this session — no `/design-login` needed) and adapted into `src/ratatoskr/web/static/index.html`: translated OUT of the `.dc.html` dialect (``/``/``/`{{}}`/`DCLogic`/external `_ds/` CSS — none runnable) into single-file/no-CDN/vanilla, with ALL real `/api/*` fetch + SSE wired into its DOM (endpoint set + SSE vocab unchanged from the prior SPA — ported verbatim, only DOM hooks re-targeted). New shape = a **3-column command-console**: left engine-ticker rail (DEBUG+ADMIN+tool/turn-lifecycle MERGED into one timeline via `tickerAdd` + a tools-armed chip list + a FULL-detail Bifrost rail pane) · center conversation (per-turn INLINE chain-of-thought, replacing the Think pane) · right RESIZABLE affect console (dominant/canonical-mood centerpiece + bipolar PAD faders EACH with a turn-to-turn Δ+sparkline + a P×A mood orbit + relations metric rows + canonical directive). ADDED (round 2, operator-requested): a **light/dark theme toggle** (dark default; FULL token override — surfaces+fg+borders+accent-as-text, since the designer's light theme only did surfaces → would've been light-on-light) + a **full-detail Bifrost pane** (endpoint/connected/consumer/caps/tools) + fixed the **engine-ticker spine** (was a container-anchored `::before` that scrolled out of view on auto-scroll → re-anchored to a content-height `.ticker-inner` wrapper) + **per-fader PAD turn-to-turn Δ+sparkline** (fills the room beside each meter, from the deduped-per-turn AFFECT_HIST) + an **INLINED data-URI favicon** (operator's `/home/lkraven/rata.png` — chibi aurora squirrel — downscaled 1024→64px via PIL, ~8.6KB base64, kills the /favicon.ico 404). ALL server routes UNCHANGED (**84 web tests green**). Verified BOTH lenses: `pytest tests/test_web_*` (84) + node Playwright drove the real UI end-to-end against personal :8081 (session open → Sindra seeded greeting → live turn SSE → affect console + relations + bifrost detail; theme toggle + PAD deltas + ticker spine + no-favicon-404 all confirmed, dark+light screenshots). `:8765` restarted on the new code. Contract `web_debug_surface.contract.md` amended in-commit (v0.20.0 presenter renames: `renderBifrostState`→`renderBifrost`, `renderAffectPane`→`renderConsole`, `setPersonaStrip` removed; INV-001/INV-004 held). **HONEST-SHAPE call (INV-001, agent-discretion within settled policy):** the dominant-emotion centerpiece shows a real OCC emotion (Tier-1) OR the CANONICAL mood word (Tier-3 e.g. Sindra→"positive and energized", dimmed) OR "—", NEVER a fabricated emotion; the affect-derived grid drops non-emitted intensity/decay-τ, shows only real/client-derived cells. **OPEN (operator's call):** the per-fader PAD Δ placement is a sensible default — operator offered to have the designer spec the exact treatment (hooks are in place to swap it). +**SHIPPED — web UI redesign via Claude Design (`v0.20.0`, MINOR, operator-approved).** The Claude Design prototype **`Ratatoskr Console.dc.html`** (project `bc0b65d1-a33e-422a-8bc1-3635c9112775`) was pulled via `DesignSync get_file` (design scopes already granted this session — no `/design-login` needed) and adapted into `src/ratatoskr/web/static/index.html`: translated OUT of the `.dc.html` dialect (``/``/``/`{{}}`/`DCLogic`/external `_ds/` CSS — none runnable) into single-file/no-CDN/vanilla, with ALL real `/api/*` fetch + SSE wired into its DOM (endpoint set + SSE vocab unchanged from the prior SPA — ported verbatim, only DOM hooks re-targeted). New shape = a **3-column command-console**: left engine-ticker rail (DEBUG+ADMIN+tool/turn-lifecycle MERGED into one timeline via `tickerAdd` + a tools-armed chip list + a FULL-detail Bifrost rail pane) · center conversation (per-turn INLINE chain-of-thought, replacing the Think pane) · right RESIZABLE affect console (dominant/canonical-mood centerpiece + bipolar PAD faders EACH with a turn-to-turn Δ+sparkline + a P×A mood orbit + relations metric rows + canonical directive). ADDED (round 2, operator-requested): a **light/dark theme toggle** (dark default; FULL token override — surfaces+fg+borders+accent-as-text, since the designer's light theme only did surfaces → would've been light-on-light) + a **full-detail Bifrost pane** (endpoint/connected/consumer/caps/tools) + fixed the **engine-ticker spine** (was a container-anchored `::before` that scrolled out of view on auto-scroll → re-anchored to a content-height `.ticker-inner` wrapper) + **per-fader PAD turn-to-turn Δ+sparkline** (fills the room beside each meter, from the deduped-per-turn AFFECT_HIST) + an **INLINED data-URI favicon** (operator's `/home/lkraven/rata.png` — chibi aurora squirrel — downscaled 1024→64px via PIL, ~8.6KB base64, kills the /favicon.ico 404). ALL server routes UNCHANGED (**84 web tests green**). Verified BOTH lenses: `pytest tests/test_web_*` (84) + node Playwright drove the real UI end-to-end against personal :8081 (session open → Sindra seeded greeting → live turn SSE → affect console + relations + bifrost detail; theme toggle + PAD deltas + ticker spine + no-favicon-404 all confirmed, dark+light screenshots). `:8765` restarted on the new code. Contract `web_debug_surface.contract.md` amended in-commit (v0.20.0 presenter renames: `renderBifrostState`→`renderBifrost`, `renderAffectPane`→`renderConsole`, `setPersonaStrip` removed; INV-001/INV-004 held). **HONEST-SHAPE call (INV-001, agent-discretion within settled policy):** the dominant-emotion centerpiece shows a real OCC emotion (Tier-1) OR the CANONICAL mood word (Tier-3 e.g. Sindra→"positive and energized", dimmed) OR "—", NEVER a fabricated emotion; the affect-derived grid drops non-emitted intensity/decay-τ, shows only real/client-derived cells. **OPEN (operator's call):** the per-fader PAD Δ placement is a sensible default — operator offered to have the designer spec the exact treatment (hooks are in place to swap it). **`v0.20.1` patch (operator-reported UI):** fixed the relations sparkline overflowing onto the `n` (evidence-count) column — the sparkline grows one char/sample (HIST_CAP=24) and overflowed its fixed grid cell, covering `n`; now capped (relations last-8, faders last-7) + `overflow:hidden` clip; verified via Playwright injecting a 24-sample history (sparkline→n bounding-box overlap = 0). ADDED native `title` mouseover hints on all 3 PAD faders + every relationship metric row (meaning + range; static METRIC_HINTS, esc()'d). Added `state.lastSnap` (console can re-render without a refetch). Playwright-verified. **SHIPPED THIS SESSION (all pushed; origin/main == `d75c4e8`; code tip `v0.19.9`) — details in Recent decisions:** the whole **#347 authored-history-write** arc landed end-to-end — OpenAPI re-vendor 2.2.0->2.3.0 (`75da676`), the CONSUMER side (`v0.19.6`: `write_authored_history` + `get_session_messages` + `--seed-first-message`, **live-proven on personal :8081** via a rule-based Heimdall allow — the PDP is rule-based NOT scope-on-key, policy user_id=ratatoskr->ALLOW/others->DENY-hide-404), persona_state `{pad:{pleasure,arousal,dominance}}` canonical alignment (#317) + Tier-3 prose re-vendor (`v0.19.7`), the **first-message-preset AUTO-SEED** (`v0.19.8`: new module `ratatoskr.first_message` wired into all 3 session-create paths, best-effort never-raise/never-block; heid-code-review + heid-bug-hunt hardened), and the web now RENDERS the seeded first-message (`v0.19.9`: new `GET /api/sessions/{id}/messages` route + SPA `loadTranscript`, Playwright-verified). Coverage-map re-converged **REST 19/41**. **Sindra:** her card was PATCHed (the `Startup:` workaround moved into a #347 first-message; non-destructive PATCH — OCEAN/persona/memory intact), and she's currently **RESET clean (0/0)** on the provider stores. diff --git a/pyproject.toml b/pyproject.toml index a6dab09..2c5110f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "ratatoskr" -version = "0.20.0" +version = "0.20.1" description = "Worldtree Conversation API debug TUI — multi-pane observability dashboard" readme = "README.md" requires-python = ">=3.12" diff --git a/src/ratatoskr/web/static/index.html b/src/ratatoskr/web/static/index.html index c82e30b..b10a5d0 100644 --- a/src/ratatoskr/web/static/index.html +++ b/src/ratatoskr/web/static/index.html @@ -395,7 +395,8 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(-- .fader .d { font-family: var(--font-mono); font-size: 9px; min-height: 11px; color: var(--fg-muted); } .fader .d.up { color: var(--aus-bright-green); } .fader .d.dn { color: var(--aus-bright-red); } -.fader .sp { font-family: var(--font-mono); font-size: 9px; color: var(--aus-cyan); letter-spacing: 1px; min-height: 11px; } +.fader .sp { font-family: var(--font-mono); font-size: 9px; color: var(--aus-cyan); letter-spacing: 1px; min-height: 11px; max-width: 46px; overflow: hidden; white-space: nowrap; text-align: center; } +.fader[title], .mrow[title], #affect-derived .dcell[title] { cursor: help; } #fader-p .fill { background: linear-gradient(180deg, var(--aus-bright-green), var(--aus-green)); box-shadow: 0 0 10px rgba(81,224,138,0.35); } #fader-a .fill { background: linear-gradient(180deg, var(--aus-blue), var(--aus-bright-blue)); box-shadow: 0 0 10px rgba(99,136,216,0.3); } #fader-d .fill { background: linear-gradient(180deg, var(--aus-bright-cyan), var(--aus-cyan)); box-shadow: 0 0 10px rgba(66,220,209,0.35); } @@ -419,7 +420,7 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(-- .mrow .md { font-size: 9px; } .mrow .md.up { color: var(--aus-bright-green); } .mrow .md.dn { color: var(--aus-bright-red); } -.mrow .msp { color: var(--aus-cyan); letter-spacing: 1px; font-size: 9px; } +.mrow .msp { color: var(--aus-cyan); letter-spacing: 1px; font-size: 9px; overflow: hidden; white-space: nowrap; } .mrow .mn { color: var(--fg-muted); font-size: 9px; } .mrow .mdesc { color: var(--fg-3); font-style: italic; font-size: 9.5px; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } #affect-console.narrow .mrow { grid-template-columns: 92px 50px 46px minmax(0,1fr); } @@ -562,17 +563,17 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(--
-
+
P
-
+
A
-
+
D @@ -930,10 +931,11 @@ function renderRelations(snap) { const d = trendDelta(hist); const dcls = d.startsWith("▲") ? "up" : d.startsWith("▼") ? "dn" : ""; const nlab = (n !== undefined && n !== null) ? "n" + esc(n) : ""; - return `
${esc(label)}` + const hint = METRIC_HINTS[label] || ""; + return `
${esc(label)}` + `${esc(num(val))}` + `${esc(d)}` - + `${esc(sparkline(hist))}` + + `${esc(sparkline((hist || []).slice(-8)))}` + `${nlab}` + `${esc(trendDesc(hist))}
`; }; @@ -983,10 +985,19 @@ function setFaderTrend(axis) { const dEl = $("pad-" + axis + "-d"), spEl = $("pad-" + axis + "-sp"); dEl.textContent = d; dEl.className = "d " + (d.startsWith("▲") ? "up" : d.startsWith("▼") ? "dn" : ""); - spEl.textContent = sparkline(hist); + spEl.textContent = sparkline(hist.slice(-7)); // cap width — the fader column is narrow } +// mouseover hints for each relationship metric (native title tooltips). +const METRIC_HINTS = { + "warmth": "Warmth — affective closeness / bond toward this entity. 0 cold (stranger) ‥ 1 deep warm bond. Durable: accumulates across turns.", + "trust·ability": "Ability trust — belief this entity is competent / capable. 0 ‥ 1.", + "trust·benev": "Benevolence trust — belief this entity means well toward you. 0 ‥ 1.", + "trust·integ": "Integrity trust — belief this entity is honest / principled. 0 ‥ 1.", + "agency": "Agency — this entity's perceived autonomy / capacity to act. 0 ‥ 1.", +}; // Unified console render for both Tier-1 persona_state and Tier-3 affect snapshots. function renderConsole(snap) { + state.lastSnap = snap; const pad = snap.pad || {}; setFader("p", pad.pleasure); setFader("a", pad.arousal); setFader("d", pad.dominance); setFaderTrend("p"); setFaderTrend("a"); setFaderTrend("d"); diff --git a/uv.lock b/uv.lock index bd87a65..ed82ec1 100644 --- a/uv.lock +++ b/uv.lock @@ -1052,7 +1052,7 @@ wheels = [ [[package]] name = "ratatoskr" -version = "0.20.0" +version = "0.20.1" source = { editable = "." } dependencies = [ { name = "httpx" },