Version. v0.1
Date. 2026-06-25
Author. Claude.ai, grounded on Claude Code (CC) read-only engine traces.
Status. Findings record. Confirms the four Bin-3 capability gaps from the Companion design, sorts them by what building each entails (engine / Companion / both), surfaces the structural insight that two of them share a root, and records the Operator's structure decision. Produces a grounded, cost-sorted build queue. No build authorized; each item becomes its own scoping note → CR, fresh.
Grounds on. CC read-only traces (2026-06-25) of /operator/converse, the conversation/turn wiring, orchestration aggregates, and the voice frontend. The Companion design document (loomworks-companion-design-v0_1), which named these four as Bin 3 ("genuinely missing engine capability"). The engagement-identity decision record (addressing context).
The Companion design named four capabilities the ideal Companion needs that the engine doesn't obviously provide. This record confirms each against the live engine and — more usefully — establishes what building each one actually costs. The result reshapes "four things to build" into a sorted queue:
host_account.current_engagement_id), not a new subsystem. This is the structural decision, and it was settled (field, not table).
The one real structural decision — where the Companion's "here" lives — is settled: a current_engagement_id field on host_account. Everything else follows from cost and dependency.
Confirmed. No engine notion of "current engagement." Addressing resolves on display_identifier client-side (EngagementList.tsx:137 — address = row.display_identifier ?? project_id).
What converse persists between turns: only a flat conversation_turns log. There is no conversation_id, no session_id, no session/context table. Each turn row carries (person_id, engagement_id?, role, content, classified_intent, …); record_turn writes one row per turn, get_recent_turns reads history keyed by (person_id, engagement_id). So a "conversation" is implicit — the set of turns for a person+engagement pair — not a stored entity. Converse is stateless per call plus a project_id (engagement id) supplied by the caller every turn; the only cross-turn memory is the turn log read back as history.
Durable "here": there is no conversation/session record to extend. The natural home is a new structure — minimally a per-person focused-engagement field on the existing host_account (which already holds personal_engagement_id + companion_name, the per-person host state), or a dedicated session/context table.
Verdict: CONFIRMED-GAP · both (engine persists current-engagement; Companion sets/reads it) · needs new structure — minimal form is a new current_engagement_id field on host_account.
Confirmed. No single per-engagement four-room composite exists. /operator/dashboard is a cross-engagement rollup (active / needs-you / recent across all the person's engagements), not per-engagement. /operator/projects/{id}/story is a stub — returns "Project narratives are coming soon"; not built, and narrative-shaped, not state-shaped. memory_status is partial — Memory↔Manifestation freshness counts plus downstream impact for one engagement, but not the full held / manifested / shaped / rendered / needs-me.
Assemblable today from existing per-room list endpoints — assertions (held/committed), manifestations, shape-events, renders, considerations, /me/dashboard/needs_you — via client/orchestration fan-out, no new engine route strictly required. A clean one-call "where is Goosey" would want a new engine aggregate endpoint for efficiency and a stable contract, but does not require one.
Verdict: CONFIRMED-GAP · both (Companion-side fan-out over existing reads works now; optimal is a new engine aggregate) · needs new structure only if done engine-side (a new composite endpoint); otherwise orchestration over existing routes.
Confirmed input-only. Voice input is browser SpeechRecognition (useVoiceListening.ts + engagement-navigation). Voice output: none — no speechSynthesis / SpeechSynthesisUtterance / .speak( anywhere in the frontend, and no spoken-form / TTS / audio-out of a response anywhere in the engine.
Where it would live: pure frontend. The engine already returns companion_message text — that is the spoken form. TTS is the browser SpeechSynthesis API reading companion_message; no engine involvement (no spoken-form endpoint, no server-side audio synthesis).
Verdict: CONFIRMED-GAP · Companion work only · extends existing — speak the existing companion_message via browser SpeechSynthesis; no new structure, no engine change.
Confirmed absent. No anaphora / ordinal / referent resolution in converse today. The classifier extracts explicit references only — commit_assertion pulls held_reference as the literal number(s) the Operator named ("commit held 3" → "3"). The single cross-turn carry is the commit-confirmation turn (carry held_reference forward on "yes") — an explicit number, not a resolved anaphor/ordinal. There is no structured "things just shown" referent set with object ids maintained between turns. (Converse does pass recent_turns history into the LLM prompt, so the model may loosely resolve some anaphora, but nothing deterministic maps "the second one" → a specific id.)
Seam — both, by path:
Verdict: CONFIRMED-GAP · both (Companion-side substitution for surface-rendered references; engine-side for pure-conversational/voice) · needs new structure engine-side (a per-conversation referent set, dependent on the same missing session structure as gap 1); Companion-side extends existing rendering state.
There is no per-conversation server-side state object. A "conversation" today is implicit — just the set of turns for a person+engagement pair in conversation_turns. So the Companion has nowhere durable to hold anything between turns except the flat turn log.
Both the spine (current-engagement, gap 1) and the engine-side of reference resolution (the referent set, gap 4) need exactly this missing place. Build gap 1's structure and gap 4's engine-side extends it; skip it and both stay blocked. This is the single load-bearing structural decision in the whole queue.
Gaps 2 and 3 are independent of this root: gap 2 is assemblable now (a new endpoint is an optimization), and gap 3 is frontend-only and engine-free.
The Companion's "here" lives as a current_engagement_id field on host_account — single focused engagement per person.
host_account already holds the per-person host state (personal_engagement_id, companion_name), so this extends an existing table rather than introducing a subsystem.When gap 4's engine-side is built, its per-conversation referent set hangs off this same per-person context (extending the field's home, or promoted alongside it if the table is introduced by then).
| Order | Gap | Engine work | Companion work | Depends on | Cost |
|---|---|---|---|---|---|
| A | 3 — TTS | none | speak companion_message via browser SpeechSynthesis | nothing | nearly free, frontend-only |
| B | 1 — Current-engagement (spine) | add current_engagement_id to host_account; converse reads/writes it | set/read the focus; resolve "open X" → set focus | nothing | small engine change + Companion wiring |
| C | 4 — Reference resolution | per-conversation referent set (extends B's structure) | substitute "the second" from rendered lists (can precede C) | engine-side depends on B | Companion-side cheap now; engine-side rides on B |
| D | 2 — Composite read | optional new aggregate endpoint | fan-out over existing per-room reads works now | nothing (optimization) | do when fan-out gets slow or a stable contract is wanted |
Reading the order:
current_engagement_id on host_account) but it unblocks voice-direct ("open Goosey" resolves to a held "here") and is the structure C extends.Each queue item becomes its own scoping note → CR, drafted fresh per session discipline (scoping a build is a distinct activity from this design/investigation thread).
The natural first scoping note is B — the current-engagement spine, now fully grounded: a current_engagement_id field on host_account, converse reading/writing it, the Companion setting it on "open X" and reading it for "here". A — TTS — is an independent, near-free frontend piece that can be scoped in parallel whenever wanted.
DUNIN7 — Done In Seven LLC — Miami, Florida Companion Bin-3 capability gaps — findings and engine-work queue — v0.1 — 2026-06-25