`registerInboundInjection` used to index correlations by
`Date.parse(record.createdAt)` — a millisecond-precision wall-clock
value. Two inbox rows that landed in the same millisecond collapsed
onto one Map slot, and the thread-event writer lost one peer's
identity on `message_end`.
Identity now lives on `record.id`. `projectInboundMessage` allocates a
monotonic `piTimestamp` per run (base = `Date.parse(createdAt)`,
bumped to `max(base, lastAllocated + 1)` so it is always unique
within the run) and stamps that value onto the projected pi message.
The correlation registry keeps `byMessageId` as the primary index and
`byPiTimestamp` as a reverse lookup so the `message_end` callback —
which only surfaces the pi-message shape — still resolves back to the
author without depending on wall-clock precision.
The runtime message injector now defers projection to
`RuntimeBridge.projectInboundMessage` so the steered message, the
correlation entry, and the allocated timestamp stay in lockstep.
Inter-agent messages previously entered the recipient's context as a
separate prompt block (recentMessages), rebuilt every turn. This double-
charged tokens and kept messages outside pi's native AgentMessage stream.
Now at prepareRun: pull the recipient's unread inbox, project each
AgentMessageRecord into a pi user-role AgentMessage, persist to
SqliteSessionStore, and mark delivered. The recipient reads messages
as natural conversation turns in the transcript.
- db: listAgentInboxUnread + markAgentInboxDelivered (transactional)
- agent-runtime/inbox-projection.ts: AgentMessageRecord -> pi AgentMessage
- runtime-bridge.prepareRun: inject + deliver before loadMessages
- prompt-builder: delete recentMessages context block + buildMessagesSection
- message-normalize: drop unused normalizeMessagesForPrompt
- delete prompt-builder/attachment-resolver.ts (orphan after section removal)
Send path (api-server/routes-messages, ipc, UI) unchanged — inbox table
remains the UI source. Transactional delivery marking prevents duplicate
injection across runs. Failed append -> no mark -> retry on next run.