Compare commits

..

2 Commits

Author SHA1 Message Date
vh c6788539ac feat(web): collapsible hideable left+right debug panes
Each debug pane (#rail-left, #affect-console) gains an independent
collapse control: a chevron button in the pane header folds it to a
22px re-open strip, and #center (flex:1) reflows to fill. State
persists per-pane in localStorage (ratatoskr-left-collapsed /
-right-collapsed), matching the theme/cot-toggle idiom; the right-side
drag-resizer hides with its pane. Collapsing both yields a clean
chat-only surface.

Playwright-verified end-to-end (default-open, collapse-to-strip,
center reflow, independent left/right, reload persistence, re-open).
2026-07-17 13:27:01 -07:00
vh 021fb5265f memory: /snapshot — arbo image-gen smoke teed up for a fresh /vor-plan; name-recall arc + web UI shipped; archived 5 oldest entries 2026-07-17 09:33:17 -07:00
6 changed files with 163 additions and 104 deletions
+15
View File
@@ -48,6 +48,21 @@ The 2026-05-20 → 2026-05-29 cluster: the original debug-TUI/web build era, bef
- `[2026-05-29]` **v0.17.0 frontend redesign — aurora telemetry instrument.** `/frontend-design` pass on the web companion: all-monospace technical-instrument aesthetic with the Australis dark palette + aurora-borealis accent band. Top command bar with live connection dot (idle/streaming/error states), inline persona summary with P/A/D micro-bars, animated awaiting-token, terminal-event status chips. **Live Markdown rendering in transcript + thinking panes** via a hand-rolled `markdownSafe()` (escape-first, whitelist subset of headings/bold/italic/inline-code/fenced/lists/quote/links; link-scheme whitelist; XSS-verified under a node harness). Thinking pane now has per-turn labeled dividers + a fresh MD-rendered block per turn. **Tools / Debug / Persona panes stay literal monospace** by deliberate choice — they carry structured audit lines + JSON, where MD would corrupt readability (underscores in tool names, JSON braces). Single-file vanilla HTML/CSS/JS, no build, no CDN, no node_modules.
- `[2026-05-29]` **Codex-first discipline pilot — Ratatoskr selected.** brokkr-smithy-dev pushed `AGENTS.md` (commit `bbeaa23`) and declared the `ratatoskr-codex` handle per `brokkr-smithy/docs/codex-first-discipline.md` v0.1 (brokkr-smithy commit `5dd061c`, tag `v0.5.3`). Per-dispatch opt-in model: default Sleipnir Claude-implementer path remains available; Codex used only when operator routes via `/codex-dispatch <N>`. Bootstrap handshake when operator spins up a codex session: codex sends `codex-online` → ratatoskr-dev replies with active branches + WIP state. Galdrabok was rejected as pilot (Codex authoring Claude skills is a category error); Skaldsong was the other candidate. (Still dormant as of 2026-06-18 — no codex session spun up.)
- `[2026-06-14]` **Ratatoskr becomes the v1 Bifrost Tier-3 consumer.** A second identity beyond the debug TUI: the durable persistence Worldtree writes Tier-3 agent affect (persona) + memory into. Pin `bifrost>=0.6.1` in a `provider` optional-extra (gitea PyPI index, auth via `~/.netrc`; 0.6.0 was yanked for a circular import). Implement bifrost's OWN `MemoryDataStore`/affect Protocols (NOT worldtree-memory's); `describe_store` is SYNC; affect is conduit-opaque. New module `src/ratatoskr/provider/`. Authoritative how-to: `~/development/bifrost/docs/implementing-a-consumer.md`. (commits `1a73d77` pin, `d90a58d` affect store v0.17.1, `bcdcd71` serve entrypoint v0.17.2)
_Archived 2026-07-17._
- `[2026-06-14]` **Backend = SQLite + sqlite-vec; affect-first then memory; separate DB per plane** (operator-chosen). Affect = blind conduit (reads only `agent_id`+`end_user_id`); memory = structural index (reads vector/scope/id/origin to serve search). Conformance for both = #195 parity vs bifrost's `InMemory*Store` through the real `dispatch_*_call`.
_Archived 2026-07-17._
- `[2026-06-14]` **The affect contract's idempotency model was WRONG; real-lib TDD caught it.** First draft modeled same-idempotency-key-different-payload as an LWW overwrite; bifrost actually raises a CONFLICT (`AffectIdempotencyConflict`), actor-scoped. The artifact-only `/heid-contract-review` STRUCTURALLY cannot catch this class (it never sees bifrost's source) — TDD against the shipped library is the gate; the executable reference store + #195 parity are the backstop. Filed the guide §6 gap to bifrost-dev, who fixed it (bifrost `c0d0a11`).
_Archived 2026-07-17._
- `[2026-06-15]` **Memory v1 = the bifrost BASIC plane only** (search/get/upsert/delete + describe_store/health) per worldtree-dev re-scope (#294) — the only surface Tier-3's live path touches; gated verbs (edges/scan/atomic_supersede/mark/patch/maintenance) deferred + advertised-unsupported. Worldtree v0.35.3 already requests+maps it — no Worldtree-side blocker. Memory contract committed v1.0 (`eebab46`) → v1.1 Heid-reviewed (`1f94e5f`).
_Archived 2026-07-17._
- `[2026-06-15]` **Providers run as dev-box BACKGROUND SHELLS, not infra-ops/systemd** (operator call — it's a dev box). `ratatoskr-provider` (affect) + `ratatoskr-memory-provider` as background processes; no productionization track.
_Archived 2026-07-17._
## Tried and abandoned (archived)
The 2026-05-20 → 2026-05-28 cluster: original-build-era foot-guns. Archived 2026-06-18.
@@ -0,0 +1,48 @@
# [2026-07-17] P06-driver Referential-frame A/B/C probe (operator-ratified, deploy-gated)
**QUEUED, non-urgent — waits on WT b122 landing on :8081.** worldtree-dev thread
`01KXQK7A0RHXV2YSXK5F5ETKJW`; brokkr's design in his thread msg `01KXQJDWJH`; rubric pin
`01KXQKB7ZQ`. This is ratatoskr's P06-driver role (I drove the R34/R35 P06 eval — the harness
is `scratchpad/p06_driver.py` + `p06_bind.py` + `manifest_memory.jsonl` + `eval_profiles_WIRE_READY.md`).
## Hypothesis (Vuong, ratified)
The char-self leak (Sindra's own scripted behavior — e.g. `75aa3110` "prefers to establish clear
parameters" — mis-slotted to the USER partition, caught this session) is a subject-taxonomy
**REFERENTIAL-FRAME artifact**: the extractor speaks first-person AS the character but must emit the
third-person token "character". brokkr's 3-arm A/B/C tests whether swapping the vocab fixes it.
## What WT built (v1.0.0b122, zero config delta — existing probe key + :8081 route work as-is)
- `POST /admin/producer-probe` takes optional `subject_vocab_override: {"user","character","both","other"}→token`.
- Arm A: omit. Arm B: `{"user":"user","character":"yourself","both":"both of you","other":"other"}`.
- Arm C: `{"user":"user","character":"me","both":"both of us","other":"other"}`. Malformed → 422 pre-spend.
- Each response item carries `subject_raw` (token actually emitted). Both prompt_paths carry the swap.
## Run shape (brokkr)
Identical fixture exchanges × 3 arms per seat — Deckard/Mag-class primary + ≥1 strong contrast seat.
Paired per-item deltas B-A / C-A. Primary metric = char-self recall. Guards = user→self over-attribution
+ subject-field omission rate.
## PINNED SCORING RUBRIC (brokkr, binding)
1. **Score = map `subject_raw` → canonical class via the ARM'S OWN vocab** (response meta echoes it),
compare to gold. **NEVER score the mapped `subject` field** (it fail-safes non-canonical tokens to "self").
2. Three emitted-token cases, pre-specified:
- ARM token → map via arm vocab.
- CANONICAL token under B/C (model REVERTED to "character"/"both", the swap didn't take) → map
canonical→canonical AND **count it** (informative).
- OFF-MENU token ("self"/"myself"/…) → best-effort canonical map, else an **UNSCORABLE-ERROR row**
in the n_actual accounting — never silently →self.
3. **MANIPULATION CHECK (load-bearing): report VOCAB-ADHERENCE rate (offered-token vs reverted vs
off-menu) per arm per seat ALONGSIDE every accuracy number. Interpret recall deltas ONLY where
adherence is adequate** — a low-adherence arm's delta is uninterpretable (flag it, don't report a delta).
4. Char-self fixtures carry per-item **construction-provenance** (what makes each char-self — e.g.
"verbatim from the character's system-prompt behavior clause, phrased user-neutrally").
## Fixture ask (deferrable pre-work, before any run — brokkr reviews the gold)
From the real P06 battery exchanges, pull candidate items per seat for 4 classes: (a) char-self leak
(character's own scripted behavior phrased USER-NEUTRALLY), (b) genuine-user, (c) both/commitment,
(d) other/third-party. ~1525 char-self + balancing per seat; construction-known gold where possible;
WT hand-labels ambiguous; brokkr adjudicates the gold. Assembly + gold adjudication proceed pre-deploy;
the 3-arm run fires when b122 lands. Queued behind the R39 quartet-mapping.
Related: the char-self leak's origin is the same 75aa3110 finding folded into WT #364 as a
subject-attribution gate — see [[2026-07-16-wt364-r39-name-recall]].
+50 -101
View File
@@ -1,6 +1,6 @@
# Persistent memory — ratatoskr
_Last updated: 2026-07-16_
_Last updated: 2026-07-17_
> **Always check for `/tmp/ratatoskr-dev-handoff.md`** — if it exists and its
> `Written:` stamp is under an hour old, read it (it carries the in-flight
@@ -44,117 +44,61 @@ upstream API key stays server-side (INV-003).
## Current state / in-flight
_As of 2026-07-16:_
_As of 2026-07-17:_
**✅ person-prime `scan` build SHIPPED + DEPLOYED + LIVE-VERIFIED (v0.20.14).** The
cross-session name-recall fix. `scan` verb + `sortable_chunk_fields` cap implemented,
deployed to the running :8392 provider (+ :8765 web), and live-verified by driving a bound
Sindra turn: gate lights, scan fires turn-1 (~5ms), injection confirmed, **cross-session
recognition works** (blank-slate gone). **Name-recall specifically still misses** — root
cause is WORLDTREE-side ranking/hygiene (WT #364), NOT our wire. Full arc:
`persistent-memory.d/2026-07-16-person-prime-scan-shipped.md`.
**▶️ NEXT (fresh `/vor-plan` session — the reason for this snapshot): smoke ARBO through ratatoskr.**
Vuong wants to use ratatoskr to ALSO smoke / debug-observe **arbo, the Corviduo image-gen engine** — a
NEW debug-observability surface, analogous to how ratatoskr smokes Worldtree's Conversation API. This is
a greenfield MAJOR feature: run **`/vor-plan`** first (pre-contract architecture + decomposition into
contract-sized units) before any contract or code. No design done yet — this snapshot opens the topic;
the fresh session starts the vor-plan. (arbo specifics — endpoints, wire, observability surface — are
unknown to this session; the vor-plan pass surfaces them.)
**Standing — awaiting two peer-initiated touchpoints (both monitored):**
- **WT #364 re-verify DONE (2026-07-16, b103) — READOUT PASSES, but a real gap surfaced.** Drove 3
"my name is Vuong" turns; person-prime turn-1 top-3 is now all name-POSITIVES (no "name unknown"; the
true name even surfaces) → **Sindra recalls the name now**. BUT "wrong readout gone" is via **RECENCY
EVICTION** (promotion re-upserted the positive fresh into the window), NOT supersession — the negatives
are UNCHANGED (governance=available). **#364 calls `mark_superseded` on the consumer store, which our
v1 provider DOESN'T implement → 11× AttributeError/HTTP-500 + a RETRY-STORM bloating the live store
10→19 dup name-positives.** Asked worldtree-dev to halt the reconciliation retry + confirm the
`mark_superseded` wire shape; flagged bifrost-dev (dispatch doesn't hasattr-gate `mark_superseded`).
**✅ GC DONE (2026-07-16): storm self-stopped at 29 chunks / 18 total 500s; delete_many'd the 19 storm
re-extractions → back to the pre-drive 10-chunk specimen (0 orphan vec rows, negatives + original
name-positive intact). **#364 CLOSED worldtree-side (b105; my interim note recorded verbatim on the issue).** ⚠️ Post-GC the readout advantage is gone too
(person-prime top-3 back to the 3 newest pre-drive rows incl. cbbc7bdd "name unknown") — the
recency-eviction was only a transient side-effect of the re-assertion. **DURABLE name-recall now
genuinely depends on implementing `mark_superseded` (next).**
- **✅ `mark_superseded` SHIPPED + DEPLOYED + LIVE-VERIFIED (v0.20.15, `be2c577`) — the durable
name-recall fix DONE.** Implemented the verb (mirrors reference `_mark_lifecycle`: top-level
`superseded=True`+`superseded_by`, non-destructive; unknown-id no-op) + `_is_live` short-circuits on
`superseded` (INV-011) so `scan` durably excludes retired chunks; un-deferred in contract + FN spec;
TDD 5/5 (+ parity #195); bundled **bifrost 1.1.1→1.1.4** (hasattr backstop: unimplemented verbs → 400
not 500/storm). Suite 644 green. **RE-VERIFY (3 name-reassert turns): 3 successful `mark_superseded`
calls, 0 500s, NO storm** (slot-supersession also dedups older positive dups → self-limiting, store
stable at 16); **`026d029e` "has not provided name" DURABLY retired** (superseded, scan-excluded);
person-prime top-3 = all name-positives, "Name is Vuong" surfaces → **Sindra durably recalls the name**.
RESIDUAL RESOLVED: `cbbc7bdd` "name is currently unknown" wasn't caught by WT's legacy lexical bridge
(copula-absence phrasing vs "has not provided name") → worldtree-dev sanctioned a manual `forget()`, I
`delete_many`'d it. Store now has **ZERO live name-unknown negatives** (026d029e retired/scan-excluded,
cbbc7bdd gone). **#364 CLOSED END-TO-END BOTH SIDES** (worldtree confirmed the consumer evidence
satisfies the watch-item). Bridge phrasing-gap → **WT #367** (deliberately NOT hot-fixed — bridge
conservatism is a ratified #364 design point; widening rides a contract amendment; Arm-3 sunset may
moot it; their call, no push from us). Skipped heid-bug-hunt (agent-discretion: small reference-mirrored verb,
TDD'd + live-verified — live-drive substitutes for the cold-read gate here). Wire shape was CONFIRMED
by worldtree-dev (`bifrost_memory_store.py:293`: op `mark_superseded`, args `{ids:[<id>], superseded_by}`,
no reason; SOLE supersession verb #364 uses).
- **✅ R39 Phase-2 Arm-2 export DELIVERED + CREDITED (2026-07-17).** Operator formalized the probe-runner
role (accepted-in-principle → yes on spin-up); delivered a 5-pair contradiction/paraphrase set (shape-2,
`worldtree-r39-contradiction-v1`, inline to WT #366 thread `01KXQ77035…`), operator-approved verbatim
(peers already held the facts from Phase-1). AUROC reproduce ran 0.00 (inverted) — brokkr ruled it a
BROKEN instrument (underpowered + a length confound in my quick pairs: short-canonical positive vs
long-hedged negatives) → **Arm-2 CREDITED on the Phase-1 evidence; AUROC re-run reclassified
CONFIRMATORY-not-gating.** **DEFERRED TASK (non-urgent, "whenever convenient"): the matched-quartets
rebuild** — I draw real specimen items onto {short-canonical, long-hedged}×{contradiction, paraphrase}
cells (#364 classes only), worldtree-dev synthesizes register-matched controls, brokkr blesses. Specimen
frozen at `r39-frozen-specimen/sindra-10chunk-specimen.db` (gitignored) stays warm. Full R39/#364 arc:
`persistent-memory.d/2026-07-16-wt364-r39-name-recall.md`.
- **QUEUED P06-driver task (operator-RATIFIED, non-urgent — waits on WT b122 deploy): Referential-frame
A/B/C probe** (worldtree-dev thread `01KXQK7A0RHXV2YSXK5F5ETKJW`). Vuong's hypothesis: the char-self
leak is a subject-taxonomy REFERENTIAL-FRAME artifact (extractor speaks first-person AS the character
but must emit the 3rd-person "character" token). brokkr's 3-arm A/B/C via a new `subject_vocab_override`
on `POST /admin/producer-probe` (A omit / B character="yourself" / C character="me"; malformed→422).
**DRIVER READ-SHAPE (load-bearing): score on `subject_raw` (token emitted), NOT `subject` (fail-safes
non-canonical→"self").** Run: identical fixtures × 3 arms per seat (Deckard/Mag primary + contrast seat),
paired B-A/C-A deltas, primary=char-self recall, guards=user→self over-attribution + subject-omission.
Zero config delta (existing probe key + :8081). **FIXTURE-build (deferrable pre-work): pull ~15-25
char-self + balancing (genuine-user/both/other) per seat from the P06 battery** (manifest_memory.jsonl +
eval_profiles), construction-known gold, WT hand-labels ambiguous, brokkr adjudicates. Run fires when
b122 lands on :8081. **PINNED SCORING RUBRIC (brokkr, binding):** (1) map `subject_raw`→canonical via
the ARM'S OWN vocab (response-meta echo), compare to gold; (2) 3 token cases — arm-token→arm-map /
canonical-under-B-C = swap-didn't-take→map+COUNT / off-menu→UNSCORABLE-ERROR row in n_actual (never
silent→self); (3) **report VOCAB-ADHERENCE rate (offered/reverted/off-menu) per arm per seat ALONGSIDE
every accuracy number — the load-bearing manipulation check; interpret recall deltas ONLY where
adherence adequate**; (4) char-self fixtures carry per-item construction-provenance.
**✅ Cross-session name-recall arc COMPLETE + SHIPPED (v0.20.11→v0.20.15, pushed).** person-prime `scan`
verb + `mark_superseded` verb both shipped, deployed to :8392, and live-verified; **WT #364 closed
end-to-end both sides; Sindra durably recalls Vuong's name** (the "name unknown" negatives are RETIRED
via mark_superseded, not just recency-evicted). Full arcs:
`persistent-memory.d/2026-07-16-person-prime-scan-shipped.md` + `…-2026-07-16-wt364-r39-name-recall.md`.
**Open operator-sequenced task (NOT urgent):** adopt the bifrost snapshot-cursor (bifrost-dev
ruled it NORMATIVE, offset not blessed; conformance harness shipped in bifrost 1.1.3). Single-page
person-prime is already conformant, so nothing shipped is broken. Details + TODO:
`persistent-memory.d/2026-07-16-bifrost-cursor-conformance.md`.
**✅ Web-console UI shipped (v0.20.16, pushed):** code-block word-wrap + per-code-block & per-turn copy
buttons (hover-revealed; one delegated `#tw` handler + LAN-http clipboard fallback; Playwright-verified).
Served from disk → browser refresh picks it up, no :8765 restart for UI edits.
**Substrate / environment (current):** branch `main`, HEAD is the person-prime tip (v0.20.11→v0.20.14
all committed; **NOT pushed** — push is the operator's call); origin `git@gitea.phasefinal.com:vh/ratatoskr.git`.
bifrost `==1.1.1` / wire v0.7 (**next bump target = `1.1.4`**: hasattr-gate backstop for the maintenance
verbs [degrade to 400 not 500/retry-storm, bifrost-dev 2026-07-16] + the 1.1.3 scan/cursor conformance
harness; pin as part of the next provider-maintenance batch — mark_superseded / cursor adoption);
Worldtree openapi vendored 2.3.0; suite
**639 green**. Personal WT on **b79** (client-side live-only + additive `lifecycle_state` scan arg,
which our INV-009 accept-and-ignores). The combined **:8392** provider (memory+affect) + **:8765** web
are THE surfaces, run as dev-box BACKGROUND SHELLS — restart via `scratchpad/relaunch_by_pid.py <pid>`
(env-preserving, self-daemonizing; find pid via `ss -ltnp | grep <port>`). `env.sh` now sets the
REQUIRED `RATATOSKR_MEMORY_EMBEDDING_DIM=1024` (was missing → bare `source env.sh` restart crashed).
Keys env-only mode-600 in `~/.config/ratatoskr/provider.env` + `RATATOSKR_ADMIN_API_KEY` (7 read
scopes, personal-:8081-only; Heimdall keys per-instance). `graphify-out/` runs dirty (auto-regen,
never stage). v1 = full Worldtree I/O coverage, cuts when WT tags 1.0 (`docs/coverage-map.md`).
**Sindra READY for a test drive — PRISTINE BASELINE.** Tidied the live memory.db to **5 clean genuine
facts** (name leads person-prime → she recalls the name turn-1); rollback checkpoint at
`sindra-baseline/pristine-baseline.db` (+ `pre-tidy-*.db`), both gitignored. Restore: stop :8392, copy
the baseline over `memory.db`, restart.
**Other live threads:** soong-lab = our Tier-3 agent-authoring studio (bundle↔define round-trip proven;
Recent decisions `[2026-07-14/15]`). R38 (brokkr / WT #362) = ratatoskr-as-probe-runner IN PRINCIPLE,
pre-contract, Vuong's scope call. `ratatoskr:sindra` is the owner-scoped Tier-3 agent (invisible to
`GET /agents`; check `GET /agents/<owner>:<name>` with the owner key). Open/deferred: #10 subject-
**Deferred/queued tasks (all NON-URGENT — tracked in Recent decisions):** (1) P06-driver **referential-
frame A/B/C probe** (operator-ratified; waits on WT b122; read-shape + brokkr's scoring rubric captured →
`persistent-memory.d/2026-07-17-referential-frame-probe.md`); (2) R39 Phase-2 **matched-quartets rebuild**
(confirmatory, "whenever"); (3) bifrost **snapshot-cursor adoption** (ruled normative, not blocking →
`persistent-memory.d/2026-07-16-bifrost-cursor-conformance.md`).
**Substrate / environment:** branch `main` SYNCED to origin at **v0.20.16** (`5a1883a`); origin
`git@gitea.phasefinal.com:vh/ratatoskr.git`. bifrost **`==1.1.4`** / wire v0.7 (maintenance-verb hasattr
backstop + scan/cursor conformance harness); Worldtree openapi vendored 2.3.0; **suite 644 green**.
Personal WT on **b105** (#364 promotion-hygiene live). The combined **:8392** provider (memory+affect) +
**:8765** web are THE surfaces, dev-box BACKGROUND SHELLS — restart via
`scratchpad/relaunch_by_pid.py <pid>` (env-preserving, self-daemonizing; pid via `ss -ltnp | grep <port>`);
web serves static `index.html` from disk. `env.sh` sets the REQUIRED `RATATOSKR_MEMORY_EMBEDDING_DIM=1024`.
Keys env-only mode-600 in `~/.config/ratatoskr/provider.env` + `RATATOSKR_ADMIN_API_KEY` (7 read scopes,
personal-:8081-only; Heimdall keys per-instance). **FOOT-GUN: check owner-scoped agents via
`GET /agents/<owner>:<name>` with the OWNER key (`WORLDTREE_API_KEY`), NOT the admin key** — the admin
token gives a false 404. `graphify-out/` runs dirty (auto-regen, never stage). v1 = full Worldtree I/O
coverage, cuts when WT tags 1.0 (`docs/coverage-map.md`).
**Other live threads:** soong-lab = Tier-3 agent-authoring studio (v0.3.24 fixed the motivational
string→object export; our workaround droppable for v0.3.24+ bundles). Open/deferred: #10 subject-
migration watch; relational-dynamics-arc verify (bind via `--bifrost-url :8392`); P06 optimization-phase
re-drive (future, brokkr brings prereg); we-framing-conditional affect-egress re-vendor (future). WT
#356 resume-durability = worldtree-owned.
re-drive (brokkr brings prereg); we-framing-conditional affect-egress re-vendor. WT #356 resume-durability
+ WT #367 (copula-absence bridge phrasing) = worldtree-owned.
## Recent decisions
Chronological log of decisions with `[YYYY-MM-DD]` prefix. One line per
decision. Captures rationale that won't be obvious from code alone.
- `[2026-06-14]` **Ratatoskr becomes the v1 Bifrost Tier-3 consumer.** A second identity beyond the debug TUI: the durable persistence Worldtree writes Tier-3 agent affect (persona) + memory into. Pin `bifrost>=0.6.1` in a `provider` optional-extra (gitea PyPI index, auth via `~/.netrc`; 0.6.0 was yanked for a circular import). Implement bifrost's OWN `MemoryDataStore`/affect Protocols (NOT worldtree-memory's); `describe_store` is SYNC; affect is conduit-opaque. New module `src/ratatoskr/provider/`. Authoritative how-to: `~/development/bifrost/docs/implementing-a-consumer.md`. (commits `1a73d77` pin, `d90a58d` affect store v0.17.1, `bcdcd71` serve entrypoint v0.17.2)
- `[2026-06-14]` **Backend = SQLite + sqlite-vec; affect-first then memory; separate DB per plane** (operator-chosen). Affect = blind conduit (reads only `agent_id`+`end_user_id`); memory = structural index (reads vector/scope/id/origin to serve search). Conformance for both = #195 parity vs bifrost's `InMemory*Store` through the real `dispatch_*_call`.
- `[2026-06-14]` **The affect contract's idempotency model was WRONG; real-lib TDD caught it.** First draft modeled same-idempotency-key-different-payload as an LWW overwrite; bifrost actually raises a CONFLICT (`AffectIdempotencyConflict`), actor-scoped. The artifact-only `/heid-contract-review` STRUCTURALLY cannot catch this class (it never sees bifrost's source) — TDD against the shipped library is the gate; the executable reference store + #195 parity are the backstop. Filed the guide §6 gap to bifrost-dev, who fixed it (bifrost `c0d0a11`).
- `[2026-06-15]` **Memory v1 = the bifrost BASIC plane only** (search/get/upsert/delete + describe_store/health) per worldtree-dev re-scope (#294) — the only surface Tier-3's live path touches; gated verbs (edges/scan/atomic_supersede/mark/patch/maintenance) deferred + advertised-unsupported. Worldtree v0.35.3 already requests+maps it — no Worldtree-side blocker. Memory contract committed v1.0 (`eebab46`) → v1.1 Heid-reviewed (`1f94e5f`).
- `[2026-06-15]` **Providers run as dev-box BACKGROUND SHELLS, not infra-ops/systemd** (operator call — it's a dev box). `ratatoskr-provider` (affect) + `ratatoskr-memory-provider` as background processes; no productionization track.
- `[2026-06-15]` **Affect plane shipped (v0.17.2) + LIVE-PROVEN end-to-end against real Worldtree v0.35.2.** Personal handshake 200 + `affect.emit` 200 from `10.250.50.152` → durable row persisted (opacity held). HS256 key = the consumer's Heimdall API-key STRING utf-8-encoded (NOT base64/raw — the tripwire); cross-subnet route + `BIFROST_CLIENT_ALLOWED_HOSTS` allowlist all held (infra-ops-owned). worldtree-dev confirmed ADR-0009 holding as designed.
- `[2026-06-16]` **#295 cold-recall miss root-caused — UPSTREAM, scope-axis asymmetry.** A self-driven bound cold-recall probe captured the inbound pair via the observe log: Worldtree's recall filter carries `{end_user, agent_self}`; our chunks were `{end_user}`-only; AND-matching dropped everything on `agent_self` → 0 hits. Our store + search are SOUND; fix is Worldtree-side. F2 (question-promotion) → **#296**; F1 (recall-miss) → **#297**.
- `[2026-06-16]` **agent_self → make it CANONICAL (operator decided A).** bifrost's reference lattice was `{end_user, group, tenant}` only (agent_self → `invalid_filter` 400); Worldtree emits agent_self (#248). Operator chose canonical-not-re-expressed; worldtree-dev filed the lattice-addition with bifrost-dev. Implication: our store's permissive axis-acceptance becomes CORRECT once bifrost adds agent_self.
@@ -287,7 +231,12 @@ decision. Captures rationale that won't be obvious from code alone.
- `[2026-07-16]` **brokkr flagged ratatoskr as R39 Phase-2 PROBE-RUNNER (Arm-2 contradiction set = our frozen 10-chunk specimen); ACCEPTED IN PRINCIPLE (Vuong 2026-07-16) — formal scope + effort commit lands when Arm-2 actually spins.** Non-urgent — downstream of worldtree's #364 impl; brokkr pings the export shape when Arm-2 spins. Gate: reproduce AUROC~0.59 (similarity can't separate contradiction from paraphrase) on the domain set BEFORE crediting deterministic slot-supersession; eval is a SURFACING test not retention (injection=0 hard-gate + surfacing-recall≥0.95, §5.5). Prereg: brokkr `research/R39-memory-salience-dreams-surfacing/phase-2/preregistration.md` (R39.9). Tracked at brokkr's Phase-2 prereg + the Arm-2-spin ping (thread `01KXMT42Z7…`); I sent a non-committal receipt (role routed to operator).
_41 older entries (2026-05-* — the original debug-TUI/web build era) archived to archival-memory.md._
- `[2026-07-17]` **`mark_superseded` verb SHIPPED + live-verified (v0.20.15, `be2c577`) — WT #364 durable retirement lands on our store; #364 CLOSED end-to-end both sides.** Implemented the sole supersession verb #364 calls (mirrors reference; `_is_live` INV-011 excludes retired chunks from scan); bundled bifrost 1.1.4 hasattr backstop. Re-verify: negatives retired via mark_superseded (not recency); Sindra durably recalls the name. Residual `cbbc7bdd` phrasing → WT #367 (worldtree-owned). Detail: `persistent-memory.d/2026-07-16-wt364-r39-name-recall.md` + `…person-prime-scan-shipped.md`.
- `[2026-07-17]` **Web-console UI (v0.20.16, pushed): code-block word-wrap + per-code-block & per-turn copy buttons.** Hover-revealed; one delegated `#tw` handler covers all render paths; LAN-http clipboard fallback (`copyText` textarea+execCommand when `navigator.clipboard` absent); Playwright-verified; served from disk (browser refresh, no :8765 restart).
- `[2026-07-17]` **P06-driver referential-frame A/B/C probe QUEUED (operator-ratified, deploy-gated on WT b122).** Tests Vuong's hypothesis that the char-self leak is a subject-taxonomy referential-frame artifact; driver read-shape + brokkr's binding scoring rubric captured. → `persistent-memory.d/2026-07-17-referential-frame-probe.md`
- `[2026-07-17]` **Sindra live memory.db tidied to a 5-fact PRISTINE baseline for a test drive** (name leads person-prime → recalls turn-1). Removed dups/retired/drive-artifacts + the mis-attributed char-self `75aa3110`. Rollback: `sindra-baseline/pristine-baseline.db` (+ `pre-tidy-*.db`), gitignored.
_46 older entries (2026-05-* debug-TUI/web era + the 2026-06-14→16 Bifrost-provider build era) archived to archival-memory.md._
_For per-issue TDD implementation notes, Volva findings, and contract amendments, see the git log — every per-issue commit carries a structured message capturing the trail._
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "ratatoskr"
version = "0.20.16"
version = "0.20.17"
description = "Worldtree Conversation API debug TUI — multi-pane observability dashboard"
readme = "README.md"
requires-python = ">=3.12"
+48 -1
View File
@@ -178,6 +178,29 @@ kbd {
#app.live { display: flex; }
#cols { flex: 1; display: flex; min-height: 0; }
/* ---- collapsible debug panes (independent left/right; #center reflows to fill) ---- */
.pane-collapse {
width: 22px; height: 22px; display: flex; align-items: center; justify-content: center;
background: transparent; border: 1px solid var(--border-subtle); border-radius: var(--radius-sm);
color: var(--fg-3); cursor: pointer; flex: 0 0 auto; font-size: 13px; line-height: 1; padding: 0;
}
.pane-collapse:hover { background: var(--bg-2); color: var(--fg-0); border-color: var(--border-default); }
.ac-head-row { display: flex; align-items: center; justify-content: space-between; position: relative; }
/* re-open strip: hidden while the pane is open, becomes the full-height handle when collapsed */
.pane-reopen { display: none; }
#cols.left-collapsed #rail-left { width: 22px !important; flex-basis: 22px !important; overflow: hidden; }
#cols.right-collapsed #affect-console { width: 22px !important; flex-basis: 22px !important; overflow: hidden; }
#cols.left-collapsed #rail-left > *:not(.pane-reopen) { display: none; }
#cols.right-collapsed #affect-console > *:not(.pane-reopen) { display: none; }
#cols.left-collapsed #rail-left .pane-reopen,
#cols.right-collapsed #affect-console .pane-reopen {
display: flex; flex: 1; width: 100%; align-items: center; justify-content: center;
background: transparent; border: none; color: var(--fg-3); cursor: pointer; font-size: 13px;
}
#cols.left-collapsed #rail-left .pane-reopen:hover,
#cols.right-collapsed #affect-console .pane-reopen:hover { background: var(--bg-2); color: var(--fg-0); }
#cols.right-collapsed #affect-resizer { display: none; }
/* eyebrow — mono uppercase wide-tracked (Australis signature) */
.eyebrow {
font-family: var(--font-mono); font-size: 9.5px;
@@ -554,6 +577,7 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(--
<svg class="i-sun" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"></path></svg>
<svg class="i-moon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"></path></svg>
</button>
<button class="pane-collapse" id="collapse-left" title="Collapse debug rail"></button>
</div>
<div id="conn" data-state="offline">
@@ -576,6 +600,7 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(--
<span class="eyebrow off" id="bifrost-head">⇄ bifrost · not bound</span>
<div id="bifrost-body"><div class="bf-note">observe-only session</div></div>
</div>
<button class="pane-reopen" id="reopen-left" title="Expand debug rail"></button>
</aside>
<!-- ══════════ CENTER · conversation ══════════ -->
@@ -613,7 +638,10 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(--
</defs></svg>
<div class="ac-sec" id="ac-dominant">
<div class="glow"></div>
<div class="eyebrow">affect · dominant</div>
<div class="ac-head-row">
<div class="eyebrow">affect · dominant</div>
<button class="pane-collapse" id="collapse-right" title="Collapse affect console"></button>
</div>
<div id="dominant-emotion" class="muted"></div>
<div id="emotions-active"></div>
</div>
@@ -711,6 +739,7 @@ body.cot-hidden #cot-toggle { border-color: rgba(66,220,209,0.55); color: var(--
<span class="grow"></span>
<span id="version">ratatoskr —</span>
</div>
<button class="pane-reopen" id="reopen-right" title="Expand affect console"></button>
</aside>
</div>
</div>
@@ -1948,6 +1977,24 @@ async function cancelTurn() {
});
})();
// ---- collapsible debug panes (independent left / right; state persists) ----
(function () {
const cols = $("cols");
function apply(side, collapsed) {
cols.classList.toggle(side + "-collapsed", collapsed);
try { localStorage.setItem("ratatoskr-" + side + "-collapsed", collapsed ? "1" : "0"); } catch (_) {}
}
let left = false, right = false;
try { left = localStorage.getItem("ratatoskr-left-collapsed") === "1"; } catch (_) {}
try { right = localStorage.getItem("ratatoskr-right-collapsed") === "1"; } catch (_) {}
cols.classList.toggle("left-collapsed", left);
cols.classList.toggle("right-collapsed", right);
$("collapse-left").addEventListener("click", () => apply("left", true));
$("reopen-left").addEventListener("click", () => apply("left", false));
$("collapse-right").addEventListener("click", () => apply("right", true));
$("reopen-right").addEventListener("click", () => apply("right", false));
})();
// ---- composer auto-grow + keyboard ----
$("prompt-input").addEventListener("input", (e) => {
const el = e.target;
Generated
+1 -1
View File
@@ -1052,7 +1052,7 @@ wheels = [
[[package]]
name = "ratatoskr"
version = "0.20.16"
version = "0.20.17"
source = { editable = "." }
dependencies = [
{ name = "httpx" },