use-setup-connect.tsMerge remote-tracking branch 'origin/staging' into feat/inbox-client-composed-feed
# Conflicts:
# apps/mail/app/(full-width)/onboarding/page.tsx
# apps/mail/modules/conversations/components/LeftSidebarContent.tsx
# apps/mail/modules/inbox/components/InboxList.tsx
# apps/mail/modules/inbox/hooks/use-inbox-items.ts
# apps/mail/tests/modules/inbox/feedPartialFailure.test.tsxSep 1, 2026, 11:58 AMuse-setup-pipeline.tsfeat(onboarding): a setup flow that shows you the product while you configure it
Adds `/onboarding-setup` — a sidebar-driven flow over the four surfaces a new
user actually has to configure (Inbox, sub-inboxes, Tasks, Pipeline), each step
paired with a live preview of the real product rather than a screenshot of it.
Reachable from the profile menu as "Set up Cedar".
Two inbox-creation races surfaced by clicking through the template gallery are
fixed on the way, since the flow leans on that path hard:
- Per-mutation `invalidateQueries` lost rows. Create #1's refetch was issued
after #2 had written its optimistic row, so a server list predating #2 landed
last and overwrote it — the row vanished and the template card flipped back to
unselected. Now the last create to settle does the single refetch.
- Two adds fired back to back both read the cache before either had written to
it and claimed the same position, so a run of template clicks piled up at one
index and the tab strip reordered itself on refetch. Positions are now issued
from a carried-forward high-water mark.
A failed create drops only its own row instead of restoring a whole snapshot,
and `removeInbox` no longer swallows the rejection — callers holding their own
selected-state need to hear about it, or the row returns while the card stays
deselected.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 31, 2026, 10:48 PMuse-setup-settings.tsfeat(onboarding): a setup flow that shows you the product while you configure it
Adds `/onboarding-setup` — a sidebar-driven flow over the four surfaces a new
user actually has to configure (Inbox, sub-inboxes, Tasks, Pipeline), each step
paired with a live preview of the real product rather than a screenshot of it.
Reachable from the profile menu as "Set up Cedar".
Two inbox-creation races surfaced by clicking through the template gallery are
fixed on the way, since the flow leans on that path hard:
- Per-mutation `invalidateQueries` lost rows. Create #1's refetch was issued
after #2 had written its optimistic row, so a server list predating #2 landed
last and overwrote it — the row vanished and the template card flipped back to
unselected. Now the last create to settle does the single refetch.
- Two adds fired back to back both read the cache before either had written to
it and claimed the same position, so a run of template clicks piled up at one
index and the tab strip reordered itself on refetch. Positions are now issued
from a carried-forward high-water mark.
A failed create drops only its own row instead of restoring a whole snapshot,
and `removeInbox` no longer swallows the rejection — callers holding their own
selected-state need to hear about it, or the row returns while the card stays
deselected.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 31, 2026, 10:48 PMuse-setup-splits.tsfeat(calendar,tasks): mint real Zoom meetings, and two fixes for surfaces that lied
Zoom reaches a Google Calendar event through the vendor's Workspace Add-on running
INSIDE Google, never through an external API client. Probed live against two accounts:
all 17 calendars report `allowedConferenceSolutionTypes: ["hangoutsMeet"]`, so the
`addOn` option added in ead6b26a4 was unreachable code — and had it rendered, Google
would have answered "Invalid conference type value". Cedar now holds a Zoom OAuth token
per user, mints the meeting through Zoom's own API, and writes the join details onto the
event. That is what Superhuman does, and there is no Calendar-API shortcut they know
that we do not.
The driver implements the existing OAuth interface, which buys the sealed AES-GCM state,
`initiateOAuth`'s URL builder, and `refreshMcpConnection`. The last is load-bearing
rather than convenient: Zoom rotates the refresh token on every refresh and kills the old
one, so two concurrent refreshes presenting the same stored token leave it dead — exactly
the failure the single-flight coalescing there already exists for. The row is written
`direct_oauth`, never `external_mcp`, because every MCP surface selects on that column and
an agent enumerating tools from api.zoom.us should not be possible.
Attachment goes to `location` (the only field that renders on every Google client),
`description` (a fenced, idempotent dial-in block — recreating the meeting REPLACES it
rather than appending beside it, which is what a "does it already contain this URL?"
check gets wrong), and `conferenceData` best-effort. `addOn` is gone from both
`createRequest` enums, the agent tool, the chat route, and `CalendarEvent.conferenceType`;
describing an existing conference is still allowed, because that is what a Zoom meeting is
by the time it reaches the event body. Inert until ZOOM_CLIENT_ID is set.
Two unrelated fixes, both reported by the same customer:
- "Search a deal…" searched every conversation the user owned. Cedar mints one per
unrecognised correspondent, so on the reporting account 117 conversations held 6 deals
and typing "gmail" returned a column of recruiters' addresses. `dealsOnly` narrows to
the AOPs the user actually works — `isNoOp = false` being their own declaration that
Cedar does work there — and falls back to today's behaviour for the 18 of 109 active
accounts that have no workable AOP.
- Every task surface splits due-now from upcoming at `endOfToday()`, read inside memos
whose dependencies are all data. Nothing in them moves when the day does, so a tab left
open past midnight files everything due TODAY under Upcoming, out of its group column,
which then collapses into the hidden-columns rail for being empty. `useDayKey` is the
missing dependency.
Staged whole-tree, not session-scoped: this branch is shared with a concurrent session
whose in-flight work (the board's Done lane, the calendar drag-settle animation, the
onboarding setup flow, the task-groups CLI) is entangled with these changes both within
files and across them — CalendarView passes props DayColumn only accepts in its
uncommitted form — so a scoped commit would not have compiled. That session likewise
swept this change's crm.ts and NewTaskDialog edits into a5fc7b295.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Sep 1, 2026, 10:35 PMuse-setup-task-groups.tsfeat(onboarding): a setup flow that shows you the product while you configure it
Adds `/onboarding-setup` — a sidebar-driven flow over the four surfaces a new
user actually has to configure (Inbox, sub-inboxes, Tasks, Pipeline), each step
paired with a live preview of the real product rather than a screenshot of it.
Reachable from the profile menu as "Set up Cedar".
Two inbox-creation races surfaced by clicking through the template gallery are
fixed on the way, since the flow leans on that path hard:
- Per-mutation `invalidateQueries` lost rows. Create #1's refetch was issued
after #2 had written its optimistic row, so a server list predating #2 landed
last and overwrote it — the row vanished and the template card flipped back to
unselected. Now the last create to settle does the single refetch.
- Two adds fired back to back both read the cache before either had written to
it and claimed the same position, so a run of template clicks piled up at one
index and the tab strip reordered itself on refetch. Positions are now issued
from a carried-forward high-water mark.
A failed create drops only its own row instead of restoring a whole snapshot,
and `removeInbox` no longer swallows the rejection — callers holding their own
selected-state need to hear about it, or the row returns while the card stays
deselected.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 31, 2026, 10:48 PM