feat(byoa): name the project in the wake digest
A BYOA agent that sits in several project groups had no way to tell them apart. `loadInbox` selected the conversation's title, kind and topic but not its project, so the wake digest's per-conversation header never mentioned one — while the cloud turn has rendered `Project: <name>` all along (turn.ts). The migration that added `conversations.project_id` even says it is "surfaced to agents in the wake prompt"; for BYOA it was not. The consequence is the one reported in #45: with nothing distinguishing the groups, everything the agent has learned reads as one undifferentiated context, and work from one project gets quoted as background in another. Carry `project_id` / `project_name` on the inbox row and render a `Project:` line above the existing `Topic:` line. The join is a PK lookup on a tiny table, placed inside the CTE that already walks the agent's conversations, so it does not disturb the query whose plan the surrounding comments were written to protect. The fields are optional on InboxRow rather than required-nullable: not every row source selects them, and direct chats are genuinely project-less. A conversation without a project renders byte-identically to before. The header build moves into a small exported `conversationHeader()` so it can be tested without booting a runner — the same reason `renderInboxDigest` and `resolveEngineModel` are exported in this file. This is the prerequisite for scoping memory by project, not that scoping itself; see the issue thread for why the mechanism proposed there needs rework.
X
Xialie Zhuang committed
bbaf6aec0ee0e1d50ce17d0a59309bf2b8977c1d
Parent: 2c9d17e