Document: cr-companion-actor-serialization-fix-v0_1
Version: v0.1
Date: 2026-06-29
Type: Phase change request — engine (a response-schema fix), with a frontend Step-0 check.
Consumer: Claude Code (executor).
Branch base: engine main @ d32c99b.
Origin: Live grounding found E0060 (Houseplant/Fenwick)'s Memory room shows "Couldn't load this room." Root cause: a response-schema Literal that omits companion, so every Memory room containing a Companion-authored assertion 500s. Pre-existing defect, not caused by the inbound demo.
Priority: Ahead of the date/ambient fix (#3) and the inbound /inbound route — this is a live bug breaking real rooms, AND it blocks #3 from being safe (a date-enabled Companion authoring watering assertions would re-break the room until this is fixed).
The Companion can write facts into Memory (that's how Fenwick's watering history got there). But the read side of the API can't render a fact the Companion wrote — it only knows about facts from people, contributors, and agents, not the Companion itself. So the moment a Memory room contains anything the Companion authored, the whole room fails to load with a 500 error. This fixes the read side to recognize Companion-authored facts. The risk to watch: don't just move the crash from the server to the browser — confirm the frontend can display a Companion-authored fact once the server stops rejecting it.
ActorRef (domain model, memory/base.py:66) allows kind ∈ {contributor, agent, person, companion}.ActorRefResponse (API response model, schemas.py:2511) allows only {contributor, agent, person} — companion is missing._actor_to_schema (assertions.py:77) raises a pydantic ValidationError (input_value='companion').GET /engagements/{id}/assertions 500s; the frontend fetchAssertionsPage catch renders "Couldn't load this room."
Add companion to ActorRefResponse's kind Literal, mirroring the domain ActorRef — so Companion-authored assertions serialize and render.
But not blindly — the Step-0 check (below) confirms the frontend can handle a companion actor kind once the server emits it, so the fix doesn't relocate the 500 to a client that doesn't expect companion.
Confirm against frontend loomworks + engine d32c99b:
ActorRefResponse.kind — the Memory room / held-card rendering path (the contributedBy.{kind, name} the card shows). Does it handle an arbitrary/unknown kind gracefully, or does it switch on a closed set of {contributor, agent, person} and break/blank on companion?companion arrives, does it render sensibly or fall through to a broken/empty state?memory.ts or equivalent) also enumerate kinds, and would it need companion added to match?schemas.py:2511 ActorRefResponse Literal; confirm nothing else downstream (other response models, validators) also narrows the kind and would still reject companion.
Report 1–3 — whether the frontend handles companion or needs a small addition. If the frontend would break on companion, the fix is two-sided (engine emits it + frontend renders it); if the frontend handles unknown kinds gracefully, the fix is engine-only. Don't move the 500 to the client.
Per-step commits, suite green at each, halt-before-push.
companion in ActorRefResponse
Add companion to the ActorRefResponse kind Literal (schemas.py:2511), mirroring ActorRef. Confirm (Step-0 #4) no other response model narrows the kind and still rejects it.
Suite expectation: a Companion-authored assertion serializes through _actor_to_schema without ValidationError; GET /engagements/{id}/assertions returns 200 for an engagement with Companion-authored assertions (E0060-shaped); a regression test pins this (the bug had no test catching it).
If the frontend breaks on companion: add companion to its actor-kind model + render it sensibly (a "by the Companion" label/treatment). If Step 0 found it handles unknown kinds gracefully, skip — engine-only fix.
Suite expectation: the held card renders a Companion-authored assertion (the "by the Companion" attribution shows, or at minimum renders without breaking).
The E0006 inbound demo served its purpose. Tear down the residue: deactivate the "Inbound Seam Demo (curl)" contributor on E0006 and discard held assertion #4 (the test-engagement cleanup rule). (The accidental commons contributor on …0002 was already deactivated.)
DUNIN7 — Done In Seven LLC — Miami, Florida Change Request — Companion-actor serialization fix (Memory room 500) — v0.1 — 2026-06-29 Pre-existing engine defect: ActorRefResponse (schemas.py:2511) omits companion from its kind Literal, while the domain ActorRef permits it — so every Memory room with a Companion-authored assertion 500s (E0060/Fenwick is the live case; blast radius = any companion-memory room). Fix: add companion to ActorRefResponse, mirroring ActorRef. Step 0 (frontend check) FIRST so the fix doesn't relocate the 500 to a client that can't render companion — engine-only if the frontend handles it, two-sided if not. Regression test pins it (the bug had none). Lands BEFORE the date/ambient fix (#3), because a date-enabled Companion authoring assertions would otherwise re-break the room. Base engine d32c99b.