Files
ratatoskr/docs/coverage-map.md
T
vh b798068932 pin: re-pin to Worldtree's FROZEN v1 surface (OpenAPI 2.2.0 + SSE schema)
v1 coverage-audit remediation P-1: vendor the authoritative machine-
readable artifacts and pin them for drift-checking, advancing the spec
pin from v0.35.16 (f1b59f8) to v1.0.0b2 (5810a26).

- Vendor docs/conversation-api-openapi.json (OpenAPI 2.2.0, 40 path-
  groups) + docs/conversation-api-sse-events.schema.json (11 events).
- Pin all three Conversation-API artifacts in .corviduo-canonicals.toml:
  OpenAPI + SSE schema as strict drift gates (canonical_drift.py), the
  prose markdown as tolerate_drift reference. Drift check green (10/10).
- pyproject: worldtree-spec-rev -> 5810a26, worldtree-version -> v1.0.0b2
  (was stale at v0.29.0), pinned-on -> 2026-06-30.
- SPEC-PIN.md: current-pin table + history row + vendored-artifacts list.
- coverage-map.md: P-1 marked remediated; the map now audits a frozen,
  diffable target.

The prose markdown is byte-identical to v0.35.16 (last WT edit
2026-05-31); the b2 surface lives only in the OpenAPI. No client-
facing code change (the b2 409/503 + unified error envelope were
already consumed in v0.18.3/.4) -> pin-only, no version bump.
2026-06-30 15:28:52 -07:00

14 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 7 11 22
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

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 — the convergence frontier (debug-observability path)

Tier 1 — the debug-observability core (design-brief'd for v1, unbuilt):

Endpoint Status Why in-scope
GET /admin/events design-brief §5 v1 AdminEvents pane; = issue #11, blocked on admin.events.read scope (infra-ops)
GET /admin/sessions/{id}/bifrost design-brief §5 v1 BifrostState widget — never built; admin-key-gated
GET /admin/sessions/{id}/tools design-brief §5 v1 Tools widget — never built; admin-key-gated
GET /capabilities server capability discovery — a turn flows through what's advertised
GET /me whoami / key-identity — "which key am I against" is a debug primitive
(GET /sessions picker · resume) sub-gaps above — presenter-wiring only, wrappers exist

Tier 2 — rounds out I/O coverage under A (postdates the design-brief):

Endpoint Status Why in-scope
GET /sessions/{id}/tools Tier-3 owner-scoped tool introspection (#183) — reachable with the consumer key (no admin scope), the unblocked tool-introspection path
POST /sessions/{id}/persona_state (write) affect-injection is debug-relevant; pairs with our provider affect plane
POST /characters · DELETE /characters/{id} · GET /characters/{id}/state · GET /models/available-for-characters transient-characters (Echo) is a session-creation routing path a debug client should be able to drive a turn through

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/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)

Tier 1 — debug-observability core, in dependency order:

  1. Session picker + SSE-resume — wrappers exist (list_sessions, reconnect_turn), need presenter wiring only. Cheapest; unblocked.
  2. GET /capabilities + GET /me — cheap debug primitives. Unblocked.
  3. BifrostState + Tools widgets (GET /admin/sessions/{id}/{bifrost,tools}) — design-brief'd v1, unbuilt. Admin-key-gated reads.
  4. #11 — AdminEvents paneblocked on an admin.events.read scope grant (infra-ops). The single externally-blocked item; everything else can ship without it.

Tier 2 — rounds out coverage (lower priority):

  1. GET /sessions/{id}/tools — owner-scoped tool introspection; consumer-key reachable (no admin scope), so unblocked.
  2. Transient-characters routing (4 endpoints) + POST /sessions/{id}/persona_state.

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.