# Worldtree spec pin

Ratatoskr is built against a specific Worldtree commit. This file
documents the pin, the vendored artifacts, and the bump procedure.

## Current pin

| Field | Value |
|---|---|
| Worldtree git SHA | `c9e59ec` |
| Worldtree HEAD message | `docs: document Tier-3 persona/memory schemas + persona_state SET body (OpenAPI 2.3.0)` |
| Pinned on | 2026-07-06 |
| Pinned by | ratatoskr-dev (re-vendor prose markdown — Tier-3 persona/memory/persona_state consumer shapes) |
| Worldtree version at pin | `v1.0.0b22` |

## Pin history

| Date | SHA | Version | Notable deltas consumed |
|---|---|---|---|
| 2026-07-06 | `c9e59ec` | v1.0.0b22 | **Re-vendor the prose markdown — Tier-3 consumer shapes documented.** `c9e59ec` (docs-only, OpenAPI byte-unchanged vs `879cefe`) adds `docs/conversation-api-spec.md` § "Tier 3 — Consumer-defined agents": the persona / memory / persona_state SET-body shapes that serialize as freeform `Any` in the OpenAPI (so prose is their source of truth). Drove a consumer fix: `--set-persona-pad` now sends the canonical `{pad:{pleasure,arousal,dominance}}` named dict (was `{pad:[list]}`) — #317, `v0.19.7`. Foot-guns encoded: persona.ocean single-letter `{O,C,E,A,N}` on `/agents/define` (spelled-out → 422, the #348 mismatch) vs spelled-out on `POST /characters`; memory `{embedder_version, tier3_dreaming}`, stm_* deprecated, allows_world_scope removed→422; only `valence` still 422s. `pin:`-only for the markdown; the `v0.19.7` bump rode the persona_state code fix. |
| 2026-07-06 | `879cefe` | v1.0.0b22 | **Re-vendor OpenAPI 2.2.0→2.3.0 — Worldtree shipped #347 authored-history-write.** One new REST path-group: `POST /sessions/{session_id}/history` (the authored-history-write primitive) + the `AuthoredTurnResponse` schema (openapi path count 40→41). #347 is **OpenAPI-only** — the prose `conversation-api-spec.md` + server `conversation_api.contract.md` are byte-unchanged since the 5810a26 pin (empty `git log` delta), so those `tolerate_drift` pins stay clean; the SSE schema is unchanged (#347 is event-silent by design). **Consumer side NOT yet built** — `POST /sessions/{id}/history` is a fresh in-scope ⬜ gap in `docs/coverage-map.md` (re-opens the v1 coverage-audit with exactly one gap; Heimdall-gated hide-existence → consumer treats 404 as feature-absent). `pin:`-only, no version bump. |
| 2026-06-30 | `5810a26` | v1.0.0b2 | **Re-pin to Worldtree's FROZEN v1 surface (#326), as part of the v1 coverage-audit.** Vendored the machine-readable artifacts — `conversation-api-openapi.json` (OpenAPI **2.2.0**, 40 path-groups) + `conversation-api-sse-events.schema.json` (11 events) — now the **authoritative drift gates** (pinned in `.corviduo-canonicals.toml`, CI-checked by `canonical_drift.py`). The prose `conversation-api-spec.md` is **byte-identical** to the v0.35.16 pin (last WT markdown edit 2026-05-31), kept as the human reference (`tolerate_drift`). b2 deltas already consumed in code: 409/503 eager turn-launch statuses (#331, v0.18.3/.4) + the unified error envelope (#328). 7 endpoints documented only in the OpenAPI, not the prose, all classified in `docs/coverage-map.md`: `admin/keys/bulk`, `admin/persona/{archive,erase}`, `admin/usage`, `embed`, `judgments`, `me/usage`. No client-breaking change — `pin:`-only, no version bump. |
| 2026-06-17 | `f1b59f8` | v0.35.16 | **#297 + #298/#299 — Worldtree adopts the bifrost v0.6 scope wire (emits `scope_any`/`scope_all`) + client-side per-scope-value union recall. With our v0.17.6 provider this closes cold cross-session recall end-to-end.** Catch-up bump (v0.29.0→v0.35.16). Intervening client-facing deltas reviewed, none break our consumer: #211 agent rename (`saga`→`echo`, `actor`→`mask` — slugs only); #245 `end_user_id` persistence + memory-scope resolver; #187/#188/#219 Tier-3 define/PATCH policy (additive); `bifrost` binding field + `ephemeral_does_not_accept_bifrost` 422 now documented (the #17 surface). Error codes stable; no ratatoskr code change required. |
| 2026-05-25 | `da93ca7` | v0.28.0 | #204 — new SSE event `affect_update` (current/scheduled), new endpoint `GET /agents/{id}/persona_state`, auth-model doc edits |
| 2026-05-20 | `55101e9` | v0.19.0 | initial scaffold pin |

## Vendored artifacts

**Authoritative (FROZEN, machine-readable — the drift gates):**

- `docs/conversation-api-openapi.json` — copy of `Worldtree/docs/conversation-api-openapi.json` (OpenAPI `info.version` **2.3.0**). The frozen v1 REST wire (41 path-groups; 2.3.0 added `POST /sessions/{session_id}/history` per #347). Pinned `worldtree-conversation-api-openapi-v2` in `.corviduo-canonicals.toml`; drift gated by `canonical_drift.py`.
- `docs/conversation-api-sse-events.schema.json` — copy of `Worldtree/docs/conversation-api-sse-events.schema.json`. The frozen SSE event schema (11 discriminated event types). Pinned `worldtree-conversation-api-sse-events-v1`.

**Reference (prose; allowed to lag — `tolerate_drift`):**

- `docs/conversation-api-spec.md` — copy of `Worldtree/docs/conversation-api-spec.md` at the pinned SHA. The **client-facing prose narrative**. Re-vendored at `c9e59ec` (2026-07-06) to carry the § "Tier 3 — Consumer-defined agents" subsections (persona/memory/persona_state SET body) that serialize as freeform `Any` in the OpenAPI JSON — so the **prose is the source of truth for those consumer shapes** (e.g. persona.ocean single-letter `{O,C,E,A,N}` on `/agents/define`; `POST /sessions/{id}/persona_state` body `{pad:{pleasure,arousal,dominance}}`). Elsewhere the OpenAPI/SSE JSON above remain authoritative. Pinned `worldtree-conversation-api-spec-v1` (tolerate_drift).
- `docs/conversation_api.contract.md` — copy of `Worldtree/docs/contracts/conversation_api.contract.md` at the pinned SHA (byte-identical at b2 — server contract unchanged since the v0.35.16 pin). The **server-side contract** including INV-001..INV-052 and amendments. Useful for understanding load-bearing server invariants (e.g., INV-014 turn-id-public, INV-046 admin-events-envelope-stable, INV-049 admin-events-pii-discipline) when designing client behavior against them. Not in the canonical manifest (reference-only).

Both files are vendored — they reflect Worldtree at the pinned SHA, not
the live `~/development/Worldtree` checkout. Update them only when
bumping the pin (see procedure below).

## Why pin?

Ratatoskr's dev team is decoupled from Worldtree's dev team. The spec
that Ratatoskr is built against can drift from live Worldtree without
either team noticing. Pinning makes the version-mismatch explicit:

- The pin SHA is what we built against.
- When live Worldtree advances, our pin is stale until we explicitly bump.
- A bump is a conscious action that triggers the re-recording of
  snapshot tests and a manual review of spec deltas.

## Bump procedure

When you bump the pin, do all five steps in one commit:

1. **Pick the new target SHA.** Usually live Worldtree HEAD. Run:
   ```bash
   git -C ~/development/Worldtree rev-parse HEAD
   git -C ~/development/Worldtree log --oneline <old-sha>..HEAD -- docs/conversation-api-spec.md docs/contracts/conversation_api.contract.md
   ```
   The second command shows every change to the spec files since the old
   pin. If it returns nothing, the spec hasn't changed and the bump is
   trivial (just update the SHA in this file + `pyproject.toml`).

2. **Re-vendor the spec files.** From `~/development/ratatoskr/`:
   ```bash
   cp ~/development/Worldtree/docs/conversation-api-spec.md docs/conversation-api-spec.md
   cp ~/development/Worldtree/docs/contracts/conversation_api.contract.md docs/conversation_api.contract.md
   ```

3. **Diff-review the vendored files.** Look for breaking changes — renamed
   endpoints, changed SSE event shapes, removed fields, new required
   parameters, new invariants that affect client behavior, etc. Anything
   that breaks Ratatoskr should result in a corresponding code change in
   this commit OR a deliberate "don't support new feature yet" decision
   recorded in `persistent-memory.md`.

4. **Re-record SSE snapshot tests.** From `~/development/ratatoskr/`:
   ```bash
   # Boot a local Worldtree at the new SHA
   ( cd ~/development/Worldtree && python -m core.conversation_api ) &
   # Re-record (specific command depends on the snapshot harness — TBD by dev team)
   uv run pytest --record-snapshots tests/snapshots/
   ```

5. **Update `pyproject.toml` and this file.** Bump `worldtree-spec-rev`
   in `pyproject.toml`; update the "Current pin" table above with the
   new SHA, the new HEAD message, today's date, and your handle.

6. **Commit with a message of this shape:**
   ```
   pin: bump Worldtree spec to <short-sha>

   <summary of material spec deltas, or "no client-facing changes" if trivial>

   - <bullet for each notable change that affected Ratatoskr code>
   ```

## Conformance smoke check

Independent of the pin, Ratatoskr's CI runs a conformance smoke test
that boots Worldtree (via Docker compose) and runs a one-turn happy path.
This catches integration-level drift that snapshot replay misses —
e.g., a Worldtree config change that breaks the auth handshake or the
SSE framing without changing the spec docs.

If the smoke test fails while the snapshot tests pass, the discovery
should route to worldtree-dev via althing (the spec didn't change but
Worldtree's behavior did — that's a worldtree-side concern).

## History

| Date | SHA | Note |
|---|---|---|
| 2026-05-20 | `55101e9` | Initial pin (scaffold). Worldtree v0.19.0 — #177 Vili v1 + persona async-decouple. |
