componentsfeat: UI reorganization for conversation view components
Extracts ConversationBodyContent, adds calendar RSVP banner, refactors
ConversationView/timeline components, and updates drafting/snippets UI.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <<email>>Apr 24, 2026, 12:00 AMhooksfix: deleting threads & thread loading limitApr 9, 2026, 6:01 PMutilsfix: review pass — keep the ping out of the timeline, stop a rename escaping to root
Three behavioural fixes found reviewing this branch, plus the deduplication the
review turned up.
The ambiguity ping's audit row is a dedupe key and a measurement surface, but both
conversation reads returned it unfiltered and the timeline renders any action_type
it does not recognise by de-underscoring it — so every pinged conversation would
have shown the user a pill reading "Agent aop ambiguity ping" the moment the flag
was turned on. Excluded from both reads; the ping's own dedupe query hits the table
directly and is untouched.
moveNode's new pure-rename path fell through to `null` when the parent row could not
be loaded, and `null` there means "move to the scope root" — the same teleport the
commit above it fixes, reached by a different door. It refuses now.
The select-aop tool call is deliberately deferred so `conversationId` is the
post-merge surviving id, which meant a throw out of setupConversationForAop lost the
record of what the classifier decided — exactly the run you would open the log to
diagnose. It flushes on the way out.
Deduplication, all of it drift that had already caused a bug once:
- resolveOrgId/getSessionOrgId now live in trpc/session-org.ts. user-tasks.ts had
copied one and not the other, which is why it scoped conversation lookups to the
owner while crm.ts scoped the same rows to the org — the "Untitled" task header.
- The backfill script had its own copy of the LinkedIn cold-reach classifier. A
backfill that classifies differently from ingest is how the folder=INMAIL check
survived unnoticed; it imports the real one now.
- One MAX_AOP_AMBIGUITY_ALTERNATIVES, owned by the Slack module where the
four-buttons-per-row constraint actually comes from.
Also: dropped the ping button's `aopId` arg, which agent_prompt's zod schema strips
before the agent ever sees it (the id travels in the prompt, which is what is read);
lazy-loaded TranscriptViewerModal off the root render — 10 fewer preloaded chunks
and 85 KB off the critical path, though react-markdown stays on it via a second,
pre-existing path through messagesSlice's eager renderer registry; and cleaned up
two comments orphaned by the extractions, a sideEffects note the same PR falsified,
a runbook query naming a table that does not exist, and three no-op eslint-disables.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 17, 2026, 11:58 PM