DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path change-requests/cr-companion-actor-serialization-fix-v0_1.md

Change Request — Companion-actor serialization fix (Memory room 500) — v0.1

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


Plain-language summary

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.

The bug (grounded)

The fix

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.

Step 0 — frontend check before the engine fix (read-only, no build)

Confirm against frontend loomworks + engine d32c99b:

  1. Where the frontend consumes 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?
  2. Is there display logic keyed to kind (icon, label, "by you" vs "by the Companion")? If companion arrives, does it render sensibly or fall through to a broken/empty state?
  3. The wire model — does the frontend's actor type (in memory.ts or equivalent) also enumerate kinds, and would it need companion added to match?
  4. Confirm the engine fix pointschemas.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.

The build — steps

Per-step commits, suite green at each, halt-before-push.

Step 1 — engine: allow 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).

Step 2 — frontend (only if Step 0 found it needed)

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

Acceptance

What this unblocks

Note on cleanup (separate, do alongside)

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.