- Shipped
- July 19, 2026 at 2:00 AM UTC
- Author
- Kamo
- Commit
- 63b2521
The counterpart AIService's outreach dispatcher calls. Without it the whole outbound path terminated in a recorded 404 - the gate authorized a touch, the message was composed, and there was nowhere to put it. Ownership stays split deliberately: AIService decides WHETHER a touch may go out and writes the text, this service places it. Writing these rows from AIService would fork ownership of the transcript to the service that owns neither the chat tables nor the socket. Two things it will not do. It never creates a conversation - outreach may resume a thread the visitor already opened, never conjure a chat window at someone who did not. And it never crosses orgs: a lead uid resolving to another org's ticket would put one org's agent inside another org's conversation, so the org is checked against the ticket rather than trusted from the caller. The message is attributed to the session member, exactly as a visitor message is - NOT to the assigned human officer. Rendering an AI-composed message as though a named, licensed person wrote it is what an AI-disclosure rule exists to prevent. ensureSubscription precedes the NATS publish because the consumer uses DeliverPolicy.New: publishing first would persist the message but drop it from every connected client. Returns both id and messageId so the outreach audit log references the message rather than the thread. 404 when no open thread exists, so the caller records a clean failure instead of assuming delivery.