memory: snapshot — #18 CLOSED end-to-end + v0.18.0 (composite both-plane binding)
#18 D1 SHIPPED: build_combined_provider_app on :8392 wraps bifrost 0.10.0's public build_combined_app over both stores + the shared affect read route; one bound WT session drives memory.* AND affect.* through one endpoint; op-feed plane='combined' per-path. Shipped v0.17.15 (affect.fetch, the strong-or-absent prerequisite) -> v0.17.16 (composite) -> v0.17.17 (#17 op-feed field-name fix) -> v0.18.0 (publishing minor). Suite 503 green. Live-smoke PROVEN at wire+dispatch (real stores + bifrost 0.10.0 on a running :8392): handshake grants both caps, PAD read route serves real sindra PAD, both planes dispatch at one bound session_id. WT-driven turn gated on infra-ops adding :8392 to WT's BIFROST_CLIENT_ALLOWED_HOSTS (requested). New decisions: reference-impl-adopt-canonical (operator); v1-derived-from-WT-I/O-coverage (operator). New foot-guns: memory-store check_same_thread bug (same as affect D2, exposed by the contract-mandated search test via TestClient); :8392 infra-allowlist gate; heid-review test-fidelity nudge cascaded into 2 latent-bug fixes.
This commit is contained in:
+50
-38
@@ -1,6 +1,6 @@
|
||||
# Persistent memory — ratatoskr
|
||||
|
||||
_Last updated: 2026-06-18_
|
||||
_Last updated: 2026-06-19_
|
||||
|
||||
This file captures durable intent and supporting evidence (goals, decisions,
|
||||
foot-gun warnings, in-flight state) across context resets. Read it at session
|
||||
@@ -41,37 +41,39 @@ upstream API key stays server-side (INV-003).
|
||||
|
||||
_As of 2026-06-19:_
|
||||
|
||||
**#18 DELIVERABLE 2 SHIPPED + PUSHED — the persona-telemetry gap is CLOSED.** The web
|
||||
pane now renders live PAD/valence for Tier-3 agents from OUR `:8390` affect store
|
||||
(`v0.17.14`, `39eebd1`, suite **482 green**, **pushed to origin**). Three pieces:
|
||||
provider read route `GET /affect/state/{agent_id}` (non-bifrost, added to the affect app
|
||||
via `app.add_route` — keeps `/bifrost/*` top-level + op-feed-skipped); web proxy
|
||||
`GET /api/affect/{agent_id}` (server-supplied `end_user_id`, colon-id `quote()`'d,
|
||||
`RATATOSKR_AFFECT_READ_URL` config, default `127.0.0.1:8390`); pane affect-render
|
||||
(`renderAffectPane`/`loadAffect`, honest pad+valence+emitted_at, labelled "affect", NO
|
||||
fabricated Tier-1 fields, explicit empty-state, 2s post-turn poll). Live-smoke + a
|
||||
Playwright DOM check PROVEN against real sindra/vuong PAD. The push also published the
|
||||
previously-held **#17** arc (`v0.17.8`→`v0.17.13`) — origin/main is now fully caught up.
|
||||
**#18 CLOSED end-to-end — the composite ships (`v0.18.0`).** Both deliverables landed.
|
||||
**D2** (PAD read-endpoint, `v0.17.14`) renders live PAD/valence in the web pane from our
|
||||
`:8390` store. **D1** (composite endpoint, `v0.17.16` `7f4ceaa`) — `build_combined_provider_app`
|
||||
(`provider/combined.py`) on `:8392` wraps bifrost's public `build_combined_app` over BOTH
|
||||
stores + mounts the SHARED affect read route (`add_affect_read_route`); one bound Worldtree
|
||||
session drives memory.* AND affect.* through ONE endpoint. Op-feed derives plane per request
|
||||
path (`plane='combined'`). Published as **`v0.18.0`** (`359dbb1`). Suite **503 green**.
|
||||
|
||||
**#18 DELIVERABLE 1 (composite `:8392` endpoint) — PARKED on bifrost** (tracked Gitea #18).
|
||||
Routed to bifrost-dev for a public `build_combined_app` rather than hand-rolled from
|
||||
bifrost privates (debug-surface-uses-canonical principle). bifrost-dev confirmed it: clean
|
||||
additive minor (~`v0.9.0`), design locked (advertise-by-presence handshake, per-route
|
||||
call-time isolation), slotted AFTER WT #289. FR-1 RESOLVED — composite is bifrost-only,
|
||||
ZERO Worldtree change (single-endpoint caps-routed, worldtree-dev code-verified). NEXT:
|
||||
when bifrost ships `build_combined_app`, **repin + reimplement D1 against it** (per-plane
|
||||
failure status + op-feed plane-per-request derivation already specced in the issue).
|
||||
Nothing blocks on our side.
|
||||
**LIVE-SMOKE PROVEN at wire+dispatch** (real stores + bifrost 0.10.0 on a running `:8392`):
|
||||
handshake grants BOTH caps by store presence; the PAD read route serves real sindra PAD; a
|
||||
memory `search` + an affect `emit` both dispatch through the one endpoint at a single bound
|
||||
`session_id` with the op-feed deriving plane per path. **The only un-run leg is a
|
||||
Worldtree-DRIVEN turn — GATED on infra-ops adding `http://10.100.10.50:8392` to WT's
|
||||
`BIFROST_CLIENT_ALLOWED_HOSTS`** (`:8390/:8391` allowlisted, `:8392` not → bind 422s; requested
|
||||
via infra-ops `01KVHWJGTT…`). FR-1 already code-verified the WT side (one BifrostClient, both
|
||||
stores attach off one endpoint iff caps granted), so this is empirical confirmation of
|
||||
known-good behavior, not open risk.
|
||||
|
||||
**OPERATOR SESSION STATE — running shells are PRE-#18 code (foot-gun).** web `:8765` +
|
||||
affect `:8390` + memory `:8391` are the prior session's background shells running OLD code
|
||||
(no read route; web has no `RATATOSKR_AFFECT_READ_URL`). To see D2 live in the operator's
|
||||
own session, RESTART `:8390` (affect provider, new code → gains the read route) + `:8765`
|
||||
(web, new code + `RATATOSKR_AFFECT_READ_URL=http://127.0.0.1:8390` + `RATATOSKR_END_USER_ID`).
|
||||
This session's live-smoke used THROWAWAY `:8393`/`:8766` instances vs the same `affect.db` to
|
||||
avoid disrupting them. Consumer/owner key = `wt_live_d81b…`; providers SQLite + sqlite-vec,
|
||||
`memory.db`/`affect.db` at repo root (affect.db has live sindra PAD: vuong pleasure 0.146,
|
||||
familiarity 0.589, interaction_count 8).
|
||||
**bifrost repinned 0.8.0 → 0.10.0** (floor, `provider` extra). 0.10.0 made `affect.fetch`
|
||||
MANDATORY (strong-or-absent: `_supports_affect_plane` requires `affect_supported`+`emit`+`fetch`,
|
||||
gating EVERY affect op incl. emit) — so the repin FORCED `affect.fetch` (`v0.17.15`, conformed
|
||||
to bifrost's reference `InMemoryAffectStore.fetch` → `{found, snapshot?}`) or our shipped affect
|
||||
plane would 400. The composite's affect cap depends on it.
|
||||
|
||||
**OPERATOR SESSION STATE — running shells are PRE-#18 code (foot-gun).** web `:8765` + affect
|
||||
`:8390` + memory `:8391` are the prior session's background shells running OLD code. A
|
||||
throwaway **`:8392` composite smoke instance is RUNNING** (background, NEW code, shared
|
||||
`affect.db`/`memory.db` — the two-process topology, proven). To see the full stack on new code,
|
||||
RESTART `:8390`/`:8765` from current code (D2 web needs `RATATOSKR_AFFECT_READ_URL`); the `:8392`
|
||||
smoke instance is ready for the WT-turn once `:8392` is allowlisted. Consumer/owner key =
|
||||
`wt_live_d81b…` (`~/.config/ratatoskr/provider.env`, mode 600, rotate via infra-ops); providers
|
||||
SQLite + sqlite-vec, `memory.db`/`affect.db` at repo root (affect.db: live sindra PAD vuong
|
||||
pleasure 0.146, familiarity 0.589, 8 interactions).
|
||||
|
||||
**Tier-3 memory PROVEN end-to-end** (earlier this session): `ratatoskr:terse-probe`
|
||||
cold-recalled a seeded user fact (scope_any → 1 hit @ cosine 0.6994), and the verbose
|
||||
@@ -84,15 +86,15 @@ linguistic layer → Worldtree #305). `:8081` runs v0.36.0.
|
||||
(separate `consumer_agents` table) — invisible to `GET /agents`; check via
|
||||
`GET /agents/<owner>:<name>` with the owner key.
|
||||
|
||||
**Standing:** Worldtree spec pin v0.35.16 (`f1b59f8`); bifrost 0.8.0 / wire v0.6
|
||||
(`scope_all`+`scope_any`); WT handshake now advertises `bifrost_version 0.6.0` (worldtree-dev
|
||||
honesty-fix FYI `858ba58` — we don't pin/assert it, no-op our side). Heimdall key env-only
|
||||
at `~/.config/ratatoskr/provider.env` (mode 600); rotate via infra-ops. `graphify-out/`
|
||||
runs dirty (auto-regen, not chased). Open issues: #10 (subject migration), #11 (AdminEvents
|
||||
pane) — deferred; **#18** (D2 PAD-read SHIPPED `v0.17.14`; D1 composite PARKED on bifrost
|
||||
`build_combined_app`). Codex-first pilot dormant.
|
||||
**Standing:** Worldtree spec pin v0.35.16 (`f1b59f8`); **bifrost 0.10.0 / wire v0.6**
|
||||
(`scope_all`+`scope_any`). Heimdall key env-only at `~/.config/ratatoskr/provider.env` (mode
|
||||
600); rotate via infra-ops. `graphify-out/` runs dirty (auto-regen, not chased). Open issues:
|
||||
#10 (subject migration), #11 (AdminEvents pane — the next-reachable Worldtree-I/O coverage gap,
|
||||
unblockable via an `admin.events.read` scope request) — deferred; **#18 CLOSED** (D1+D2 shipped,
|
||||
`v0.18.0`). Codex-first pilot dormant.
|
||||
|
||||
Branch: `main` (== `origin/main` @ `39eebd1`). Remote: `origin → git@gitea.phasefinal.com:vh/ratatoskr.git`.
|
||||
Branch: `main` (== `359dbb1`, tag `v0.18.0`) — **4 commits AHEAD of `origin/main` (`39eebd1`),
|
||||
not yet pushed** (push is the operator's call). Remote: `origin → git@gitea.phasefinal.com:vh/ratatoskr.git`.
|
||||
|
||||
## Recent decisions
|
||||
|
||||
@@ -127,6 +129,12 @@ decision. Captures rationale that won't be obvious from code alone.
|
||||
- `[2026-06-18]` **#18 D2 implemented via direct in-session TDD (suite 470→482).** Provider read route `GET /affect/state/{agent_id}` added via `app.add_route` (NOT an outer `Mount` — keeps `/bifrost/*` top-level so the existing route test + the op-feed path-check stay valid); web `GET /api/affect/{agent_id}` proxy (server-supplied `end_user_id`, colon-id `quote()`'d, `RATATOSKR_AFFECT_READ_URL`); pane renders the affect-emit shape honestly. Contract `docs/contracts/issues/18.contract.md` (D2-scoped; D1 deferred). **heid-code-review panel (Gróa 5 / Hulda 3 / Regin 0): 1 real INV-001 drift + 4 test-gaps, all fixed.** No contract amendments (code was wrong, contract was right).
|
||||
- `[2026-06-19]` **#18 D2 SHIPPED (`v0.17.14`, `39eebd1`) and the full #17+#18 arc PUSHED to origin.** Live-smoke PROVEN against real data (throwaway `:8393`/`:8766` vs the real `affect.db` → real sindra/vuong PAD through the full web→provider chain; Playwright DOM check confirmed the pane render + the F1 fix — no fabricated "neutral"). The push carried 9 previously-held commits incl. the deliberately-unpushed #17 (`v0.17.8`→`v0.17.13`); origin/main now == `39eebd1`, tag `v0.17.14`.
|
||||
|
||||
- `[2026-06-19]` **bifrost repinned 0.8.0→0.10.0; `affect.fetch` became MANDATORY (strong-or-absent).** 0.10.0's `_supports_affect_plane` requires `affect_supported`+`emit`+`fetch` and gates EVERY affect op — an emit-only store 400s. Implemented `affect.fetch` (`v0.17.15`, `ca6af6b`) conformed to bifrost's reference `InMemoryAffectStore.fetch` (`{found, snapshot?}`): the forced D1 prerequisite + a new Worldtree I/O point consumed. Flagged the now-stale consumer-guide line to bifrost-dev (fixed `a2e6d62`).
|
||||
- `[2026-06-19]` **#18 D1 SHIPPED — composite `build_combined_app` on `:8392` (`v0.17.16`, `7f4ceaa`); #18 CLOSED; published `v0.18.0` (`359dbb1`).** `build_combined_provider_app` wraps bifrost's public builder over both stores + the shared read route; op-feed `plane='combined'` per-path. Direct in-session TDD; heid-code-review panel (Gróa/Hulda/Regin) returned ZERO drift. Live-proven at wire+dispatch; WT-turn gated on infra-ops `:8392` allowlist.
|
||||
- `[2026-06-19]` **op-feed handshake field-name fix (#17, `v0.17.17` `d60b77d`): `capabilities_requested`→`capabilities`.** The summary read a field that never exists on the wire (bifrost reads `capabilities`, `_protocol.py:181`) → caps_requested was always null. Surfaced by the heid panel (Regin) during the D1 review — a latent #17 bug, not D1 drift.
|
||||
- `[2026-06-19]` **Ratatoskr is a REFERENCE implementation of the Worldtree/Bifrost standard (operator).** Adopt the dep's canonical way (even if ours works); INFORM of drift/gaps; ADVISE a different approach only when ours is genuinely better (dep owner decides), never unilaterally fork. [auto-memory `feedback-ratatoskr-is-a-reference-impl-adopt-canonical`]
|
||||
- `[2026-06-19]` **Ratatoskr v1 is DERIVED from Worldtree I/O coverage (operator) — no self-defined feature ROADMAP.** v1 = consume all of Worldtree's I/O points, reached when Worldtree hits 1.0; the convergence target is a coverage map, not a 3–7 capability list. [auto-memory `project-ratatoskr-v1-derived-from-worldtree-io-coverage`]
|
||||
|
||||
_41 older entries (2026-05-* — the original debug-TUI/web 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._
|
||||
@@ -156,4 +164,8 @@ defense against re-attempting the same cul-de-sac.
|
||||
- `[2026-06-18]` **Rationalized away a KNOWN contract-invariant deviation during TDD — only the cross-model code-review caught it.** #18 D2's `loadAffect` called `setPersonaStrip(snap)`, which renders `dominant_emotion || "neutral"`; the affect snapshot has no `dominant_emotion`, so it fabricated a "neutral" emotion — violating the very INV-001 ("no synthesized Tier-1 fields") I had WRITTEN. I knew the strip did this and talked myself into it as acceptable. Neither the design panel nor TDD caught it (unit tests don't exercise the JS render); the post-implementation `/heid-code-review` did (Gróa + Hulda both). **Lesson: a known deviation from a contract invariant is drift even when you've rationalized it — flag it, don't argue yourself past it; the post-implementation cross-model review is the backstop for author-rationalized drift, distinct from the design-stage panel.**
|
||||
- `[2026-06-18]` **Latent SQLite thread-safety bug in the affect store, surfaced ONLY by the new HTTP read route.** `open_affect_store` created the connection without `check_same_thread=False`; the bifrost emit path never tripped it (uvicorn's loop ran on the connection's creating thread), but the `TestClient`-driven read route runs handlers off a worker thread → `sqlite3.ProgrammingError`. Fix: `check_same_thread=False` (safe — the event loop serializes access) + explicit `PRAGMA busy_timeout=5000` (don't rely on sqlite3's `timeout=5.0` default). **Lesson: a sqlite-backed ASGI app needs `check_same_thread=False`; the HTTP-layer test exposed what the direct-store-method tests structurally couldn't.**
|
||||
|
||||
- `[2026-06-19]` **The SAME `check_same_thread` sqlite bug recurred in the MEMORY store — exposed by the contract-mandated `search` dispatch test (TestClient = worker thread).** Heid's test-fidelity finding (the D1 dispatch test used `describe_store` where the contract says `search`) → fixing it to `search` tripped `sqlite3.ProgrammingError` because `open_memory_store` also lacked `check_same_thread=False`. Fixed (mirrors affect INV-006). **Lesson: this bug is PER-STORE — every sqlite-backed ASGI store needs `check_same_thread=False`; an HTTP-layer (TestClient) test exposes what direct-store tests can't, and the composite serving memory over HTTP makes it bite.**
|
||||
- `[2026-06-19]` **Full WT-driven `:8392` live-smoke is infra-gated — `:8392` not in WT's `BIFROST_CLIENT_ALLOWED_HOSTS` (bind 422s).** New provider ports are NOT auto-allowlisted (only `:8390/:8391` are). Self-driven dispatch (minted consumer-key JWTs → `:8392`) is the wire-proof; the WT-turn needs infra-ops to add `:8392` (requested `01KVHWJGTT…`).
|
||||
- `[2026-06-19]` **heid-code-review pulled MORE weight than its own "marginal" self-assessment.** The panel returned zero drift, but its single test-fidelity finding CASCADED into 2 real latent-bug fixes when applied (the memory `check_same_thread` bug + Regin's op-feed field-name bug). **Lesson: a contract-fidelity nudge can transitively expose bugs the test never reached — don't dismiss a "marginal" finding by its count.**
|
||||
|
||||
_18 older entries (2026-05-* — the original debug-TUI/web build era) archived to archival-memory.md._
|
||||
|
||||
Reference in New Issue
Block a user