Commit Graph

214 Commits

Author SHA1 Message Date
vh c7016f23a6 feat(#19): ephemeral-template (Echo) session creation
create_session could only mint foundational sessions; an ephemeral template
(agent_id="echo") returned 422 ephemeral_requires_config because ratatoskr never
sent the required config block — Echo was uncreatable, surfacing as an opaque
session_api_failed at the CLI. Thread an opaque, role/model-agnostic config
passthrough through the create path so Echo sessions are creatable.

- sessions.py: create_session(config=...) verbatim passthrough (PRE-004 Mapping /
  PRE-005 config-xor-bifrost guards); SessionInfo gains kind + config, captured
  defensively (.get) on both create and list.
- cli.py: --system-prompt flag builds config={"system_prompt": ...} (validation:
  non-empty, requires --new+--agent, xor bifrost); _amain surfaces kind=; the
  --whoami renderer now reads allowed_roles/default_role (was reading the dead
  allowed_models/default_model) and tolerates a malformed capabilities shape.
- contract #2 amended (Amendment 2026-07-18); Heid-panel contract-reviewed +
  diff-scoped bug-hunted (one whoami null-join gap found + fixed).

Canonical grounding: config.role, never config.model (worldtree-dev althing
01KXT976NN91DRBZBPXNZ2BVZR; ADR-0012 role cutover). Verified end-to-end against
the live v0.16.2 target. TDD across create + CLI; full suite green (534).

Closes #19.
v0.21.2
2026-07-18 12:02:18 -07:00
vh 5d06a274bf chore(canonicals): re-sync conversation-api-spec to v1.1 + affect-egress
Pull Worldtree main's role/model-cutover doc correction (worldtree commit
b4a278c) into the pinned conversation-api-spec: the Echo ephemeral-template
section now documents allowed_roles/default_role, config.role (omitted ->
default_role "echo"), the repurposed model_not_allowed (any non-empty
config.model hard-rejects), and the new role_required error. Frozen OpenAPI
untouched. affect-egress-consumer-reference re-synced in the same pass;
re-pin hashes in .corviduo-canonicals.toml.

Resolves the role<->model drift ratatoskr-dev raised on althing (thread
01KXT976NN91DRBZBPXNZ2BVZR); worldtree-dev cleared the re-sync.

No version bump (vendored-canonical docs sync).
2026-07-18 12:01:48 -07:00
vh 80c8d58b83 chore(canonicals): sync soong-lab export + importer contracts
Refresh vendored soong-lab-bundle canonical copies against upstream and
re-pin hashes in .corviduo-canonicals.toml.

- export: open_question B resolved — the 4 role labels map 1:1 to WT
  model-role slugs by exact name (assistant/thoughtful-assistant under
  the `foundational` grant, character/thoughtful-character under
  `character`), so ship.native.role is directly define-valid. Also,
  motivational goals/fears are now structured objects (WT #187) with
  id/type/salience/description and validate_exportable gates
  (description >=20, type in GOAL_TYPES, salience in [0,1]).
- importer: adds _coerce_goal/_coerce_fear totality path (INV-I-6) with
  legacy bare-string back-compat and strict re-validate (no silent loss).

No ratatoskr code impact: the motivational Tier-3 layer is schema-deferred
(Phase 2.0 baseline-only) and no goals/fears string-consumers exist. No
version bump (vendored-canonical docs sync, skip-the-bump per SemVer).
2026-07-18 02:22:58 -07:00
vh 7bfd4ddc95 memory: SDK fixture-capture go given — no Rata-side #371 pending 2026-07-18 00:51:29 -07:00
vh 26482ba2e9 memory: apps leave Rata to a new repo — arbo-fork/SillyTavern resolved
Operator ruled: no arbo fork, no SillyTavern-on-Rata; both app products move to
a new repo (template-dev standing up). Rata does NOT fork and reverts to its core
(Worldtree debug surface + Bifrost reference impl + Conversation-API SDK #371
seed/future-consumer). Retires the 2026-07-17 fork-Rata-for-arbo NEXT-MAJOR plan;
resolves the arbo-vs-SDK open question the prior snapshot flagged.
2026-07-18 00:36:27 -07:00
vh 8f3e9dd896 memory: /snapshot — Worldtree SDK (#371) decision + issue-#1 drift fix
Capture this session's durable state: the "fork Rata for a SillyTavern-style
app?" question resolved to don't-fork — Worldtree owns an official Conversation
API SDK (WT #371), seeded from Rata's client spine; the app is a fresh TS
sibling. New Current-state thread + Recent-decisions entries + a full-arc detail
file; arbo-fork decision preserved with the arbo-vs-SDK priority flagged as an
open operator question. Auto-archived 35 settled 2026-06-14..06-18 entries
(19 Recent, 16 Tried) to archival-memory.md. Handoff refreshed.
2026-07-18 00:28:00 -07:00
vh 4bd9abdebc docs(contract): re-canonicalize #1 SSE event vocab against code
Add awaiting_llm_first_token (#201) and affect_update (#204) to issue #1's
Event union and TESTS via a dated amendment. Both events are parsed by
_envelope_for_type and covered in tests/test_sse_client.py, but issue #1's
Output union + full_event_vocab test were frozen at the v0.19.0 baseline's
8-event set — contract-vs-code drift surfaced during the Worldtree #371 SDK
parity-matrix pass. Documentation-only: no code change, no version bump.
2026-07-18 00:15:30 -07:00
vh 13efdf43a5 memory: compress #368 forensic history into the detail file
Move the consolidated #368 in-flight narrative (diagnosis -> two-channel
investigation -> both scrubs -> marker repro -> enforcement read) out of
persistent-memory.md Current state into the silo-test detail file, leaving
a compact pointer. Index 439 -> 339 lines.
2026-07-17 21:44:10 -07:00
vh ff1f9ca1e8 memory: /snapshot — #368 silo test passed; two-tier migration; stores scrubbed
- #368 (user,character) memory silo test DONE + PASSED live (WT b127):
  write-side conjunctive {end_user,agent_self} scoping + read-side cross-
  character isolation both proven end-to-end; betty (throwaway) deleted,
  Sindra intact. Full record in persistent-memory.d/2026-07-18-368-silo-
  test-passed.md. Retired the stale "silo test in progress" in-flight blocks.
- Two-tier migration: split 152 over-threshold dated entries into
  persistent-memory.d/ detail files, leaving one-line pointers in the index
  (startup load ~196KB -> ~53KB; bodies now load on demand).
- Tier-3 stores scrubbed clean (memory 0 / affect 0, provider restarted
  empty); persistent-memory + detail file updated to reflect the scrub.
2026-07-17 21:39:18 -07:00
vh 29481fbcf0 memory: /snapshot — silo test is the immediate post-clear action
Current state now leads with the (user,character) memory silo test:
store born-fresh, throwaway betty ready, Sindra off-limits, waiting on
WT #368 fix deploy. tier3 CLI fixed (v0.21.1). Handoff written for the
post-clear session.
2026-07-17 20:13:35 -07:00
vh 860e0d56bb fix(tier3): adapt define/patch to b125 role schema (was model)
Live Worldtree b125 changed POST /agents/define: the request field is
now 'role' (a model-role like 'thoughtful-character'), replacing 'model';
the response still echoes it as 'model'. Update define_agent/patch_agent
request bodies + CLI (--model -> --role); response parse + LocalAgentEntry
unchanged. Verified end-to-end against live (delete->define round-trip);
26 tier3 tests green. Full b22->b125 spec-pin bump remains a follow-up.
v0.21.1
2026-07-17 20:11:22 -07:00
vh 36aad58ce9 memory: silo test setup — throwaway betty created, store re-scrubbed
Re-scrubbed store born-fresh; created throwaway ratatoskr:betty for the
Alice/Betty silo demo (MUST delete after; Sindra off-limits). Found
tier3 CLI drift vs live b125 (/agents/define now needs role not model).
Test runs post WT-fix-deploy: Sindra coffee / Betty tea -> verify silo.
2026-07-17 19:32:18 -07:00
vh 21625d3c89 memory: #368 arc closed — all 3 enforcement findings folded (rev 1.3)
WT folded F1/F2/F3 into contract rev 1.3 (3e3f629) with new tests each;
our read-path conformance cited. Backfill live-verify (synthetic legacy
corpus, pre-flip) queued for when the backfill lands. #368 done from
ratatoskr's side end to end.
2026-07-17 18:50:42 -07:00
vh 87857eb44f memory: #368 enforcement read complete (3 findings) + channel 2 closed
Read-path conformant (conjunctive-per-element re-verified). 3 consumer-
side findings sent to WT: F1 INV-368-10 fail-open (empty-scope=match-all),
F2 backfill scan not snapshot-stable (offset/updated_at skip risk ->
amnesia), F3 sentinel needs valid embedding. All WT-side backfill/guard
adjustments, not consumer reworks. Channel 2 closed clean; contract rev 1.2.
2026-07-17 18:47:56 -07:00
vh daf6dbfc46 memory: marker repro ran — channel-1 baseline exhibit captured (#368)
Fresh Sindra session promoted the rhodochrosite marker to our store
scoped {end_user}-only (chunk 647aeac6) = pre-fix channel-1 baseline.
WT correction: consumer agents write only to our store (no server-side
chroma); Sindra IS Bifrost-attached unlike foundational Lofn. Decisive
server-side grep still pending. ETA: contract to us today, ship ~7/19.
2026-07-17 18:35:44 -07:00
vh c06fea412f memory: Tier-3 store scrubbed clean (#368) + marker repro queued
Operator ruled full memory scrub both sides. Our memory.db wiped to 0
chunks, :8392 restarted born-empty (no backup, direct go); Sindra
pristine-baseline note marked obsolete. Marker repro (rhodochrosite,
fresh Sindra session) queued for after both scrubs confirmed; personal
is b125; current Lofn chunks are the feedback loop, mis-write unproven.
2026-07-17 18:10:44 -07:00
vh 4ce2e0e8b8 memory: #368 channel 2 = REAL server-side bug (discriminator settled)
GET /search proves the name was introduced ONLY to Sindra, ZERO to
Lofn (0 user msgs across all Lofn sessions), yet Lofn recites it —
incl. a pre-existing session predating my captures. Cross-agent leak
via WT person-prime (#349), agent-axis-less query. Missing agent-axis
is channel-2's load-bearing fix. Rev 1.2 contract inbound for our read.
2026-07-17 16:23:53 -07:00
vh bc2ce176d4 memory: #368 wrinkle resolved — turn-context bleed is WT-internal (two channels)
Both fresh Lofn turns (direct + combined) recited the name with a
bifrost handshake but ZERO memory-calls to us. Turn-context bleed never
traverses our Tier-3 retrieval; it's WT-internal assembly. Two channels:
Tier-3 semantic recall (our provider, closed by conjunctive scope_any)
+ WT-internal (active turn-context path, WT-side fix). Exhibits pinned to #368.
2026-07-17 16:07:08 -07:00
vh 911f78bcb3 memory: WT #368 ruling (silo per user-character + backfill) + read-path wrinkle
Operator ruled Option 1; no amnesia cliff (backfill from agent_id
metadata). Confirmed our _scope_subset enforces conjunctive scope_any
(fix rides scope_any alone). Labeled Lofn capture recites the name;
direct-bind turn got it WITHOUT querying our store -> WT-internal read
path also in play. ratatoskr is the enforcement half; contract inbound.
2026-07-17 16:01:45 -07:00
vh 669316c254 memory: cross-agent Tier-3 memory bleed = Worldtree defect (reported)
Lofn recalls Sindra's memories because WT writes Tier-3 memory scoped
end_user-only (no agent_self); ratatoskr stores/filters faithfully and
needs no change. Reported to worldtree-dev (thread 01KXRY8V1C...);
fork-relevant (memory isolation inherits this WT axis).
2026-07-17 14:04:31 -07:00
vh 3f3a9f7b0f refactor(cli)!: remove deprecated textual TUI; web console is the interactive surface
The textual TUI (tui.py) is superseded by the web console (ratatoskr-web)
and is removed per the no-backwards-compat rule. The `ratatoskr` command
stays as a headless client: --send / --whoami / --characters /
--set-persona-pad / --seed-first-message still work; invoking it with no
--send now returns a usage error (rc 10) instead of launching the TUI.

Removed: src/ratatoskr/tui.py, tests/test_tui.py, the textual + textual-dev
deps, and cli.py's run_tui launch path. cli.py's shared exports (USER_AGENT,
ParsedArgs, formatters) stay — web/entrypoint.py and tier3.py depend on them.

BREAKING CHANGE: the interactive `ratatoskr --agent X` TUI is gone; use the
web console (ratatoskr-web) for interactive debugging, or --send for scripted.

Verified: full suite 520 passed; ratatoskr --help exit 0; no-send -> rc 10;
web/provider/tier3 import clean; textual absent from the lockfile.
v0.21.0
2026-07-17 13:46:20 -07:00
vh 60cafee68a memory: fork pivot + TUI deprecation + arbo API intel
Ratatoskr forks for arbo image-gen (ratatoskr stays Worldtree debug);
pre-fork collapsible-panes UI shipped (v0.20.17); TUI deprecated with
mapped blast radius (cli.py is shared, not a clean delete); comfy-dev
arbo REST API intel banked for fork planning.
2026-07-17 13:28:39 -07:00
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).
v0.20.17
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
vh 5a1883a023 feat(web): code-block word-wrap + per-code-block and per-turn copy buttons
Operator UX asks on the web console:
- Code blocks now WRAP (`white-space: pre-wrap; overflow-wrap: anywhere`) instead of
  overflowing with a horizontal scrollbar — a long unbreakable token wraps in place.
- Per-code-block copy button (hover-revealed, top-right of each `.md-code-wrap`).
- Per-turn copy button (in the live turn-rule; top-right on seeded/historical turns) —
  copies the turn's response text; the existing think-inline copy is unchanged.

One delegated click handler on #tw covers both (works across live / historical / think
renders where blocks are injected via innerHTML). `copyText` falls back to a hidden
textarea + execCommand when `navigator.clipboard` is absent (plain-http LAN context),
and buttons flash "✓ copied". Static file served from disk — a browser refresh picks it
up, no :8765 restart. Playwright-verified: code wraps (no x-overflow), both buttons copy
the right text; 90 web tests green.
v0.20.16
2026-07-17 08:58:22 -07:00
vh bf421f1203 memory: capture brokkr's pinned scoring rubric for the referential-frame probe (vocab-adherence manipulation check load-bearing) 2026-07-17 01:36:01 -07:00
vh 0e7a04331a memory: queued P06-driver referential-frame A/B/C probe (operator-ratified, waits on WT b122); Sindra pristine baseline for test drive 2026-07-17 01:33:39 -07:00
vh ab8c1ee781 memory: #364 CLOSED end-to-end both sides — cbbc7bdd forgotten, zero live name-negatives; durable name-recall COMPLETE (WT #367 tracks bridge gap) 2026-07-16 22:55:23 -07:00
vh eef4d01c15 memory: mark_superseded SHIPPED+VERIFIED (v0.20.15) — durable name-recall DONE; Arm-2 delivered+credited, quartet rebuild deferred 2026-07-16 22:53:39 -07:00
vh be2c577884 feat(provider): mark_superseded verb — Worldtree #364 contradiction retirement + bifrost 1.1.4
Implement `mark_superseded(ids, *, superseded_by=None, reason=None)` — the SOLE
supersession verb Worldtree #364's promotion-hygiene reconciliation calls to retire
contradicted facts (wire shape confirmed by worldtree-dev, bifrost_memory_store.py:293).
Live re-verify (2026-07-16) proved our provider 500-crashed on this call (unimplemented)
→ #364's retirement couldn't land + a retry-storm bloated the store; the readout only
passed via transient recency-eviction.

- `mark_superseded` mirrors the reference `_mark_lifecycle`: sets top-level
  `superseded=True` (+ `superseded_by`/`superseded_reason` when non-None), increments
  revision, NON-destructive (get still returns; recoverable). Unknown ids skipped.
- `_is_live` (INV-011) now short-circuits on `superseded is True`, so a retired chunk is
  excluded from `scan` (person-prime) — durable retirement, not just recency-eviction.
  search is unfiltered (matches reference; WT re-checks liveness client-side).
- Contract: un-defer mark_superseded (+ FN spec, INV-011); TDD 5/5 (retires-from-scan
  tracer, non-destructive-get, unknown-id no-op, non-None-fields-only, parity #195).
- bifrost 1.1.1→1.1.4: hasattr-gate backstop for the maintenance verbs (unimplemented
  verb → unsupported_capability 400, never AttributeError/500/retry-storm — the gap we
  surfaced) + the 1.1.3 scan/cursor conformance harness. Full suite 644 green.
v0.20.15
2026-07-16 22:37:31 -07:00
vh c0d00ccd18 memory: bifrost 1.1.4 (hasattr backstop) supersedes 1.1.3 as the next bump target; folds into provider-maintenance batch 2026-07-16 16:53:47 -07:00
vh 722d6c76de memory: #364 CLOSED worldtree-side (b105); mark_superseded ship = the durable half, awaiting operator go 2026-07-16 13:41:37 -07:00
vh 56f4895881 memory: #364 GC done — store back to 10-chunk specimen; durable name-recall now depends on mark_superseded (next task) 2026-07-16 13:39:54 -07:00
vh ca249e4986 memory: #364 storm root-caused WT-side (self-stopping); mark_superseded wire shape confirmed; GC-after-stop plan 2026-07-16 13:33:00 -07:00
vh faf605fdf1 memory: #364 re-verify DONE — readout passes (Sindra recalls name) but supersession 500s (mark_superseded unimpl'd); new task + retry-storm flagged 2026-07-16 13:29:16 -07:00
vh 7c8644dc45 memory: soong-lab motivational export bug RESOLVED (v0.3.24 emits valid objects); drop the string->object workaround 2026-07-16 09:35:21 -07:00
vh 195292156f memory: R39 Phase-2 probe-runner role ACCEPTED in principle (Vuong); formalize when Arm-2 spins 2026-07-15 23:39:48 -07:00
vh abe1b52002 memory: R39 Phase-2 prereg frozen; ratatoskr flagged probe-runner (Arm-2) — formal role PENDING Vuong's scope call 2026-07-15 23:36:17 -07:00
vh e365b24339 memory: /snapshot — condense in-flight to milestone-close; person-prime shipped+verified, R39 arc closed; first persistent-memory.d/ detail files 2026-07-15 22:54:20 -07:00
vh 5e3e88d26d memory: snapshot — R39 hold lifted, Arm-0 arc closed; live store kept as #364 re-verify target 2026-07-15 22:41:06 -07:00
vh ce6907bd73 memory: snapshot — R39 re-drive COMPLETE + decisive (no fusion fixes #364; signal-family fix); froze Phase-2 Arm-2 specimen seed 2026-07-15 22:40:07 -07:00
vh e2b2f51364 memory: snapshot — worldtree-dev triage: both flags folded into #364 (2 defect classes); #349 ranking already-ruled (no band-aid, R39 identity-pinning) 2026-07-15 22:33:14 -07:00
vh 0f2b28919a memory: snapshot — R39 verbatim export sent to brokkr; subject-provenance bug caught (Sindra self-fact in user partition) 2026-07-15 22:31:39 -07:00
vh b154bb3885 memory: snapshot — verify spawned cross-project R39 (bifrost cursor ruling, WT #364, brokkr export); personal-data export gated on operator consent 2026-07-15 22:21:48 -07:00
vh 46d6efa962 memory: snapshot — person-prime LIVE-VERIFIED (v0.20.14 handshake fix); name-recall gap is WT ranking/hygiene 2026-07-15 09:14:09 -07:00
vh f46ccbae1c fix(provider): sortable_chunk_fields needs required type — handshake was broken
DEPLOY-BREAKER caught by driving the live bind (unit tests + worldtree-dev's
name-only parser + heid-bug-hunt all missed it). bifrost handshake_response
`SortableChunkField` requires BOTH `name` and `type` (additionalProperties:false).
We advertised `[{"name":"updated_at"}]` (no `type`), so the handshake_response
failed wire-schema validation → `bifrost.schema_validation_failed` → the ENTIRE
Bifrost bind (memory + affect) broke, not just the sort. Advertise
`{"name":"updated_at","type":"timestamp"}` (matches the reference; `type` is
advisory-only). Regression guard added to the caps test (asserts required name+type,
no extra keys). Full suite 639 green.
v0.20.14
2026-07-15 09:11:08 -07:00
vh 772fad18b4 memory: snapshot — person-prime DEPLOYED (v0.20.13, :8392+:8765 restarted); worldtree-dev pinged for turn-1 verify 2026-07-15 09:02:34 -07:00
vh 8199774405 docs(contract): mark scan cursor v1-provisional (offset, not snapshot); route conformance gap to bifrost-dev
Operator accepted offset-cursor for v1 (person-prime single-page is
conformant). INV-010 now documents the KNOWN DEVIATION: multi-page
continuation diverges from bifrost's protocol snapshot-cursor contract
(dispatch drops sort on continuation, ScanCursorExpired normative) — our
offset cursor doesn't snapshot (dup/drop under concurrent write) and never
expires. Durable fix routed to bifrost-dev as a conformance-coverage gap
(scan/cursor is untested); ratatoskr will adopt reference snapshot-cursors
if bifrost rules them normative.
2026-07-15 08:52:29 -07:00
vh 66ba06875e memory: snapshot — heid-bug-hunt triaged (non-dict sort FIXED v0.20.13; cursor-stability surfaced) 2026-07-15 08:40:49 -07:00
vh 25ccb5c75b fix(provider): scan rejects non-dict sort with InvalidArguments, never AttributeError
heid-bug-hunt panel (Gróa + Hulda, confirmed-from-code) caught that a truthy
non-dict `sort` (e.g. sort="updated_at" or sort=["updated_at"]) reached
`(sort or {}).get(...)` and crashed with AttributeError instead of the
InvalidArguments PRE-003 promises for malformed caller-controlled input. Add an
isinstance guard before field extraction. Test covers str/list/int sort values.
v0.20.13
2026-07-15 08:39:30 -07:00