Files
ratatoskr/docs/coverage-map.md
T
vh af07a2329a feat(#2): Tier-2 — transient characters + persona-state write; audit converges
v1 coverage-audit: the last in-scope client I/O points. The audit now
CONVERGES — REST 17/40 covered with zero in-scope gaps (23 excluded-by-
design), SSE 11/11, Bifrost planes 8/8.

- sessions.py: list_character_models / create_character / get_character_state
  / delete_character (#161, character.read/write) + set_persona_state
  (POST /sessions/{id}/persona_state — freeform body, unpinned in the
  frozen surface). 200/201 -> dict (or None on 204), off-status ->
  SessionApiFailed.
- cli.py: two one-shot probes (mirror --whoami): --characters (CRUD
  lifecycle report) + --set-persona-pad "p,a,d" (requires --session).
  New ParsedArgs.characters/set_persona_pad + probe mutual-exclusion.
- Contract #2 amended (5 FNs) + validated. TDD: 7 wrapper + 5 cli tests.
  Suite 573 green; touched code ruff-clean.
- Char read side live-proven (GET /models/available-for-characters -> 200).

Coverage-map: convergence frontier CLOSED — scope-A "done" (every frozen
I/O point classified) is met; ratatoskr cuts v1 when Worldtree tags 1.0.
2026-06-30 23:57:09 -07:00

16 KiB
Raw Blame History

Ratatoskr v1 coverage map

The v1 convergence-target ledger. Ratatoskr has no self-defined feature roadmap: v1 = consume all of Worldtree's I/O points, reached when Worldtree hits 1.0 (operator, 2026-06-19; auto-memory project-ratatoskr-v1-derived-from-worldtree-io-coverage). This file is that coverage map — every Worldtree v1-frozen I/O point × ratatoskr's coverage status, so "are we at v1?" is a ledger lookup, not a judgement call.

First authored: 2026-06-30 (the v1 coverage-audit kickoff).


Frozen target

Worldtree is at v1.0.0b2 — approaching 1.0, with its wire surfaces now FROZEN (Worldtree docs/v1-schema-freeze-manifest.md, #326). The audit anchors against the frozen machine-readable artifacts, NOT the prose markdown:

Worldtree v1 surface Frozen anchor Ratatoskr role
Conversation REST API OpenAPI info.version 2.2.0 (Worldtree/docs/conversation-api-openapi.json, sha dbdf4e24…) — 40 path×method groups client (debug TUI / web)
Conversation SSE events conversation-api-sse-events.schema.json (sha 9deeebf4…) — 11 discriminated event types client
Bifrost wire (consumer protocol) wire v0.6 STABLE/FROZEN (bifrost==1.0.0) — memory + affect planes provider (Worldtree dispatches into us)

Pin drift (finding P-1) — REMEDIATED 2026-06-30. Ratatoskr formerly vendored only the prose markdown (docs/conversation-api-spec.md), which is byte-identical to live Worldtree's but frozen at v0.35.16-era content (last WT edit 2026-05-31) and does not document the b2 surface (7 endpoints below, the 409/503 on messages-POST #331, the unified error envelope #328, the SSE schema). Remediated: the OpenAPI 2.2.0 + SSE-schema JSON are now vendored and pinned (.corviduo-canonicals.tomlcanonical_drift.py gate); the prose markdown is the tolerate_drift reference. Spec pin advanced to 5810a26 (v1.0.0b2). See § Pin remediation.

7 endpoints new in b2 OpenAPI, absent from our vendored markdown: /admin/keys/bulk, /admin/persona/archive, /admin/persona/erase, /admin/usage, /embed, /judgments, /me/usage.


Scorecard

Scope mandate: A (ledger-mandate), locked by operator 2026-06-30. v1 "done" = every frozen I/O point is classified (covered or excluded-with-rationale), zero unaccounted. NOT "feature-complete client." All scope-pending rows are now resolved (§ Surface 1, scope-resolution table).

Surface Points covered-live gap (in-scope) 🚫 excluded-by-design
REST (OpenAPI 2.2.0, path groups) 40 17 0 23
SSE events 11 11 0 0
Bifrost provider planes 8 verbs 8 0 (10 gated verbs deferred)

Legend. consumed in code AND live-proven against real Worldtree · a debug-observability I/O point we should cover but don't yet (the convergence frontier) · 🚫 deliberate non-goal per the design-brief negative clauses + the A mandate. Counts are at the path-group level; mixed-method groups are footnoted (e.g. /sessions POST is but its GET picker is an unwired sub-gap).


Surface 1 — Conversation REST API (OpenAPI 2.2.0)

Covered — client path (ratatoskr's core identity)

Endpoint Status Where consumed Note
POST /sessions sessions.py:307cli.py:482,tui.py:1508,web/server.py:155 + end_user_id, bifrost binding; 404→AgentNotFound, 502→BifrostHandshakeFailed
POST /sessions/{id}/messages (turn stream, SSE) sse_client.py:484 stream_turn → cli/tui/web the primary surface; 409→AgentNotAvailable, 503→TurnLaunchUnavailable (b2 #331)
POST /sessions/{id}/turns/{turn_id}/cancel sse_client.py:581 → cli/tui/web two-stage Ctrl-C; 404/409 mapped
GET /agents sessions.py:341tui.py:1472,web/server.py:100 Tier-1 roster; merged with local index
GET /agents/{id}/persona_state sessions.py:384tui.py:1132,web/server.py:386 persona hydrate; 404/403 mapped
POST /agents/define tier3.py:175_run_define Tier-3 create
PATCH /agents/{id} tier3.py:219_run_patch Tier-3 mutate (system_prompt/model)
DELETE /agents/{id} tier3.py:242_run_delete Tier-3 hard-delete
GET /me sessions.py:411 get_mecli.py --whoami identity/whoami probe; 401→SessionApiFailed
GET /capabilities sessions.py:428 get_capabilitiescli.py --whoami Echo ephemeral-template discovery
GET /sessions/{id}/tools sessions.py:411 get_session_toolstui.py _hydrate_session_tools owner-scoped tool inventory in the TUI Tools pane (#183)
GET /admin/sessions/{id}/bifrost sessions.py:428 get_session_bifrosttui.py _hydrate_bifrost_state admin-scoped BifrostState pane (#176); admin key (RATATOSKR_ADMIN_API_KEY); live-auth-proven
GET /admin/events (SSE) sse_client.py stream_admin_eventstui.py _stream_admin_events admin lifecycle SSE stream (#11), session-filtered AdminEvents pane; admin key; live-auth-proven
GET /models/available-for-characters sessions.py list_character_modelscli.py --characters character-capable model profiles (#161)
POST /characters sessions.py create_charactercli.py --characters create transient character (#161)
GET /characters/{id}/state sessions.py get_character_statecli.py --characters live character PAD/emotions (#161)
DELETE /characters/{id} sessions.py delete_charactercli.py --characters remove transient character (#161)
POST /sessions/{id}/persona_state sessions.py set_persona_statecli.py --set-persona-pad persona-state write / affect injection (freeform body — unpinned in the frozen surface)

Sub-gaps inside path groups (the method we use is live; a sibling method on the same path is an unwired frontier item — see frontier Tier 1):

  • GET /sessionssessions.py:198 list_sessions exists, no caller: the startup session-picker (design-brief §4 v1) was never wired.
  • POST /sessions/{id}/messages + Last-Event-IDsse_client.py:524 reconnect_turn exists, no caller: the reference SSE-resume impl (design-brief §8d) was never wired.
  • GET /agents/{id} — consumer-agent lookup (GET /agents/<owner>:<name> with the owner key) is manual-curl-only, not in code.

In-scope gaps — CONVERGED (zero remaining, 2026-07-01)

Every in-scope REST I/O point is now covered. The frontier that opened this audit (the design-brief §5 observability panes + the presenter-wiring sub-gaps + the Tier-2 tail) is fully closed:

  • Session picker + SSE-resume — wired (v0.18.5.7).
  • Persona · Tools · BifrostState · AdminEvents panes — all built + live (v0.18.xv0.19.0).
  • Transient-characters CRUD + persona-state write — consumed via --characters / --set-persona-pad (v0.19.1).

The only remaining not-consumed in-scope method is GET /agents/{id} (consumer- agent lookup, manual-curl-only) — a sub-method on an already- path group, not a path-group gap. Everything else is covered or excluded-by-design below.

Excluded by design — the design-brief negative clauses

Endpoint(s) Status Rationale (design-brief / memory)
PATCH /sessions/{id} · DELETE /sessions/{id} 🚫 §4: rename/delete happen outside the tool (sessions_cli.py)
GET /sessions/{id}/messages (history) 🚫 §6: single-session live transcript, no history fetch
GET /sessions/{id} 🚫 session detail — identity is footer-visible, no detail view
GET /sessions/{id}/tool-events 🚫 §5: tool calls observed inline from SSE tool_start/tool_result; persisted-events endpoint is opt-in only
GET /admin/sessions/{id}/tools 🚫 covered-by-alternative — the owner-scoped GET /sessions/{id}/tools () serves the Tools inventory; this admin variant is only for cross-user operator debug, out of the single-session focus (§6)
GET/POST /admin/keys · DELETE/POST /admin/keys/{id} · POST /admin/keys/{id}/rotate · DELETE/POST /admin/keys/bulk · POST /admin/keys/bulk/rotate 🚫 §6: NOT a Worldtree-admin tool (key mgmt)
POST /admin/sessions/{id}/retire 🚫 admin session mutation
POST /admin/persona/{archive,erase} 🚫 admin persona GDPR ops (new in b2)
POST /admin/users/{id}/tier 🚫 admin user mgmt
GET /me/usage · GET /admin/usage 🚫 usage metering — not turn-flow observability (new in b2)
GET /healthz · GET /readyz 🚫 liveness probes — low debug value (could become a connect preflight; park)
GET /search 🚫 §5: consumer-product feature, not turn-flow (was "defer to v2")
GET/POST /uploads · DELETE/GET /uploads/{id} 🚫 §6: no uploads — consumer-product feature
GET /pending · GET /sessions/{id}/pending 🚫 §5: poll-only, no turn-flow signal (was "optional, skip")
POST /embed 🚫 embedding utility — no turn flows through it
POST /judgments 🚫 LLM-as-judge A/B eval (response_a/response_b/rubric) — standalone eval utility, not turn-flow

Scope-resolution record (the 11 rows, resolved under A)

The 2026-05-20 design-brief deferred several surfaces; the 2026-06-19 reframe ("v1 = full I/O coverage") put them back in tension. Resolved 2026-06-30 under mandate A (debug-observability identity intact; classify, don't build-all):

Endpoint(s) Resolution
GET /search · uploads (×2) · pending (×2) · POST /embed · POST /judgments 🚫 excluded — consumer-product / eval / poll utilities, not turn-flow observability
characters (×4) · POST /sessions/{id}/persona_state in-scope (frontier Tier 2) — session-routing + affect-injection debug paths

Nothing remains . The -vs-🚫 line follows the debug-observability test: does a turn flow through it / is it a layer worth watching live?


Surface 2 — SSE events (11/11 )

Every frozen SSE event type is parsed in sse_client.py:_envelope_for_type (342-411) and rendered by all three presenters (cli/tui/web). Full coverage.

text · worker_phase · thinking · text_boundary · tool_start · tool_result · done · error · cancelled · awaiting_llm_first_token · affect_update

Caveat (not a gap): affect_update is wire-verified to emit zero events for consumer (Tier-3) agents — the persona-strip SSE path never populates for them (memory 2026-06-18). The handler is correct; the upstream emitter is silent. PAD for consumer agents is surfaced via our own provider read route (GET /affect/state/{id}, #18 D2), not this event.


Surface 3 — Bifrost provider planes (8/8 , live-proven)

Ratatoskr implements the provider side; Worldtree dispatches into it. Live-proven end-to-end through real WT turns (#17/#18 smokes; combined :8392 WT-driven smoke 2026-06-20).

Memory plane — covers the entire bifrost.memory.MemoryDataStore protocol (required: describe_store, get, get_many, search, upsert_many) plus delete_many:

Verb Where
describe_store memory_store.py:140 advertises caps (sync)
search memory_store.py:224 vector recall; scope_all AND / scope_any OR
get / get_many memory_store.py:293 / :305 point reads
upsert_many memory_store.py:150 idempotent batch write; optimistic lock
delete_many memory_store.py:314 transactional delete

Affect plane — covers bifrost…InMemoryAffectStore (emit, fetch):

Verb Where
emit affect_store.py:47 conduit-opaque snapshot upsert (LWW)
fetch affect_store.py:116 {found, snapshot}; mandatory since bifrost 0.10.0 strong-or-absent gate

Plus the non-wire PAD read route GET /affect/state/{agent_id} (affect_store.py:189) and the combined :8392 endpoint advertising both caps by store-presence (combined.py:46).

Deferred-gated (advertised-unsupported, correctly out-of-scope for the basic plane): scan, get_edges_for, upsert_edges, mark_invalid, mark_superseded, patch_many, commit_checkpoint, lease_job, read_checkpoint, health. These live only in the bifrost reference extended store, not the MemoryDataStore protocol; deferred per the #294 re-scope (memory 2026-06-15). Re-evaluate only if Worldtree's Tier-3 path starts exercising them.


Convergence frontier (the v1 to-do) — CLOSED 2026-07-01

Every in-scope I/O point is covered. The frontier is empty: REST 17/40 with zero in-scope gaps (the other 23 REST path-groups are excluded-by-design), SSE 11/11, Bifrost provider planes 8/8. v1 convergence (per scope A: "every frozen I/O point classified, zero unaccounted") is met — ratatoskr cuts v1 when Worldtree tags 1.0. The arc, for the record:

Tier 1 — debug-observability core:

  1. DONE — Session picker (v0.18.7) + SSE-resume (v0.18.5/.6).
  2. DONEGET /capabilities + GET /me (v0.18.8, --whoami).
  3. DONE — BifrostState pane (v0.18.10, GET /admin/sessions/{id}/bifrost, admin-key; live-auth-proven). The Tools half was already covered by the owner-scoped GET /sessions/{id}/tools (item 5).
  4. DONE — AdminEvents pane (v0.18.11, GET /admin/events SSE, session-filtered; admin-key; live-auth-proven). #11's blocker was already satisfied (admin key carries admin.events.read). Tier 1 complete — the admin/debug-observability core (Persona · Tools · BifrostState · AdminEvents) is fully built.

Tier 2 — rounds out coverage (all that remains):

  1. DONEGET /sessions/{id}/tools (v0.18.9, owner-scoped tool inventory in the TUI Tools pane).
  2. DONE — Transient-characters CRUD (4 endpoints) + POST /sessions/{id}/persona_state (v0.19.1, --characters + --set-persona-pad one-shot probes). The last in-scope client I/O points.

Pin remediation (finding P-1) — DONE 2026-06-30

Re-pinned to the frozen machine-readable artifacts (the chosen option): conversation-api-openapi.json (2.2.0) + conversation-api-sse-events.schema.json are vendored under docs/ and pinned in .corviduo-canonicals.toml (worldtree-conversation-api-openapi-v2, -sse-events-v1), drift-gated by canonical_drift.py. The prose markdown stays as a tolerate_drift reference (-spec-v1). pyproject.toml spec pin advanced f1b59f8 → 5810a26 (v1.0.0b2); docs/SPEC-PIN.md records the bump. This map now audits a frozen, diffable target — re-running the audit is a canonical_drift.py check away.


Decisions

  1. Scope mandate — RESOLVED 2026-06-30: A (ledger-mandate). v1 "done" = every frozen I/O point classified, zero unaccounted; NOT feature-complete client. The -vs-🚫 line for the 11 formerly-pending rows is locked above (§ Scope-resolution record).
  2. Pin remediation (P-1) — RESOLVED 2026-06-30 (re-pin to machine-readable). Vendored conversation-api-openapi.json (2.2.0) + conversation-api-sse-events.schema.json as the authoritative drift gates (pinned in .corviduo-canonicals.toml, canonical_drift.py green); prose markdown kept as tolerate_drift reference. Spec pin advanced f1b59f8 (v0.35.16) → 5810a26 (v1.0.0b2). This map now audits against a frozen, diffable target.