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).
Vendor the R34/R35 psych-profile reference (Vuong-directed via brokkr) as two
pinned canonicals under docs/vendor/brokkr-r34-psych-profile/:
- brokkr-psych-profile-authoring-spec-v1 (governs on conflict)
- brokkr-psych-profile-parameters-v1 (builder-facing distillation)
Both canonical_source=brokkr-smithy, tolerate_drift; drift-clean.
Re-sync the two tolerate_drift worldtree prose pins (affect-egress-consumer-
reference, conversation-api-spec): the drift was a benign 2-line R32-1B note
(unbounded-z PAD range) documenting a change already adopted in v0.20.9, not
the anticipated we-framing conditional. All canonicals now drift-clean.
Snapshot persistent-memory.md for the execution arc: P06 memory-half driven
(308/308 clean) + scored by brokkr (R35.45) — the authored psychological_profile
is the validated mechanism for memory-salience divergence (authored 0.618 vs
stripped 0.235 null, delta +0.382); memory extraction now reasoning-off; WT #355
root-caused via ratatoskr telemetry.
No version bump: docs/vendoring + memory-snapshot only, no runtime code change.
worldtree-dev landed the Tier-3 persona/memory/persona_state prose docs
(c9e59ec) — shapes that serialize as freeform Any in the OpenAPI, so the
prose markdown is their source of truth. Re-vendored docs/conversation-api-spec.md
(tolerate_drift markdown pin; worldtree-spec-rev 879cefe→c9e59ec).
Consumer alignment: --set-persona-pad / _set_persona_probe was building
{pad:[list]}, but the canonical POST /sessions/{id}/persona_state body (#317)
is {pad:{pleasure,arousal,dominance}} (named dict). Aligned the probe to the
named dict + a len!=3 guard; updated contract #2's note, the set_persona_state
docstring, and the tests. The set_persona_state wrapper was already correct
(freeform pass-through) — only the CLI probe's body construction drifted.
Suite 602 green. (Also this session: heid-code-review on the #347 slice
returned unanimous zero drift across all three panel arms.)
Spec pin moved da93ca7 (v0.28.0) → 562001a (v0.29.0); vendored
conversation-api-spec.md + conversation_api.contract.md re-snapshotted.
The only material delta is Worldtree #201's awaiting_llm_first_token
SSE heartbeat — a top-level event (NOT a worker_phase extension, per
INV-053's three-field stability) that fires at a configurable interval
(default 5s) during the BuildingPrompt → CallingLLM gap.
Wire layer (sse_client.py):
- New `AwaitingLlmFirstToken` dataclass: sse_id / turn_id /
elapsed_ms_since_building_prompt (server-authoritative monotonic)
- Added to Event union + _envelope_for_type dispatch branch
- Without this, ratatoskr would crash on any slow-first-token turn
from a v0.29.0 server (unknown SSE event type → ValueError)
TUI layer (tui.py):
- Audit pipeline: per-event debug-pane line with elapsed in seconds
- Live transcript indicator: first heartbeat mounts a Static
("awaiting first token · 5.0s"); subsequent heartbeats update it
in place; any non-heartbeat event removes it (the gap closed)
- Turn-summary line now carries heartbeat count
- Indicator demoted via .awaiting-label CSS so it reads as ambient
progress, not content
Tests: 2 wire-layer (single + monotonic sequence) + 3 presenter
(audit line shape, single-mount semantic, indicator removal on gap
close). Suite: 318 passing.
Spec pin moved 55101e9 (v0.19.0) → da93ca7 (v0.28.0); vendored
conversation-api-spec.md + conversation_api.contract.md re-snapshotted
from Worldtree at the new SHA. The only material delta consumed in
this bump is Worldtree #204's affect_update SSE event surface.
Wire layer (sse_client.py):
- New AffectUpdate dataclass: sse_id / status / turn_id / snapshot
(snapshot is None for status="scheduled")
- Added to Event union + _envelope_for_type dispatch branch
- Without this, ratatoskr would crash on any persona-enabled turn
from a v0.28.0 server (unknown SSE event type → ValueError)
TUI layer (tui.py):
- AffectUpdate routes through the v0.10.0 audit pipeline only — one
debug-pane line per arrival with dominant_emotion + PAD for
status="current", lightweight status+turn_id for status="scheduled"
- No transcript / tools / thinking pane writes — the persona UX shape
(Persona TabPane vs sticky header line) is deferred to a separate
bump pending operator direction
Tests: 2 new wire-layer tests for current+scheduled parsing + 2 new
presenter audit tests for routing and audit-line shape.
Not yet consumed: GET /agents/{id}/persona_state endpoint (step 2 of
the integration plan).