Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(auth): a work mailbox is what gets you an account

merged#2871CedarCopilot

CedarCopilot wants to merge 2 commits into staging from feat/inbox-client-composed-feed

Live on prod, 0 of 1 surfaces working, 1 day leftTimeline and evidence
  1. Opened
    Sep 21, 2026, 11:38 PM
  2. Sep 22, 2026, 12:01 AM
  3. Merged
    Sep 22, 2026, 12:24 AM
  4. Live on prod
    Sep 22, 2026, 12:24 AM
  5. Observed 0 hours, 1 surface, 0 requests
    Sep 22, 2026, 12:24 AM
  6. Watching

    Live on prod, 0 of 1 surfaces working, 1 day left

    Sep 22, 2026, 12:24 AM
  7. Pipelines steady after this deploy
    Sep 22, 2026, 12:24 AM

Behaviors Libra is checking

Finished agent threads display an orange exclamation badge over their avatar in the sidebar and chat tabs so completion while the user was away is distinguishable from an unread dot.Not checked
prod
Users who prefer reduced motion still see the working three-dot state, but the avatar and dot movement transitions and animations are disabled.Not checked
prod
Agent avatars in the conversation sidebar and chat tabs morph from the face into three bouncing dots while an agent run is processing, then return to the face when processing ends.Not checked
prod
The /login and /onboarding-login surfaces show the same actionable explanation for recognized OAuth callback errors instead of falling back to a generic sign-in message.Not checked
prod
A work_account_required failure is presented as a policy instruction to use a company account, without repeating the raw error as prose or displaying an unnecessary support code.Not checked
prod
Operators can configure comma-separated email addresses in CEDAR_SIGNUP_EMAIL_ALLOWLIST so selected consumer or disposable-mail accounts can complete signup despite the work-domain gate.Not checked
prod

Libra found 1 production surface on prod but could not judge any of them yet. 1 surface had no requests at all. Libra checks hourly for 3 days after each deploy.

Summary

Five independent changes, each small and independently tested.

The signup gate. Cedar is a work-mail product, but the gate enforcing that sat on hooks.before matching /sign-up , a route nobody reaches, because everyone signs in through the Google OAuth callback, which has no address until it has exchanged the code. The gate moves to databaseHooks.user.create.before, where every creation path converges. An org that has registered the domain still outranks the block, and CEDAR_SIGNUP_EMAIL_ALLOWLIST keeps Google's OAuth app-verification reviewers (who test from a gmail.com mailbox) able to register.

Verified it does not break adding a personal Gmail as a second inbox: both connect surfaces use authClient.linkSocial, which takes better-auth's link branch and never reaches createOAuthUser.

agent_tool_calls bounds + retention. The table is 22 GB of a 46 GB database, 18 GB of it TOAST, 4.85M rows, and nothing ever removed one. Payloads are now bounded at the write (4k chars / 50 items / 64 KB), and a dry-run-by-default pruner blanks reconstructable context-loading results at 30d and deletes at 90d. draft-email is exempt from both, because two admin routes render those payloads back as a user's complete draft history on an unbounded window.

CRM index usage. dealWasSyncedRecently and findOrCreateExternalCrmEvent filtered external_crm_data->>'dealId', which is opaque to the planner, so idx_ccu_user_object_deal_id was only usable to its first two columns. Measured in production: 42,169 heap rows fetched to return 2, at 27,874 ms, against 51 ms written against the promoted columns. Confirmed the columns are fully backfilled (migration 0003 + zero divergence in live data) before switching.

Excel export sets wrapText, so multi-line cells stop arriving looking flattened.

Agent avatar gains a working state , the face shrinks into the middle dot of a typing indicator rather than cross-fading to separate chrome , and replaces TabBotIcon in the chat tab strip.

Also includes three prior graph commits already on the branch.

Review

GateOutcome
/review2 should-fix, 2 nits, 1 type error , all fixed (0c935cd83)
/thermo-review3 should-fix, 1 nit , all fixed (6adc72ee8)
Greptile3/5 → 4/5 over 2 iterations (a0c413572, b2a42c2b4)

The findings worth naming:

  • Truncation was clipping the rows retention exists to preserve. draft-email was exempt from pruning but not from the new write-time truncation , a body over 4k was clipped and a payload over 64 KB collapsed to a summary dropping subject and recipients. Unlike a delete, a clip at write time cannot be undone.
  • Retention rewrote rows it was about to delete. The blank window is open-ended, so blanking first rewrote every row past the delete cutoff , TOAST and WAL included , moments before deleting it. Now runs delete-first.
  • The allowlist never reached the deployed services, which is the one environment it exists for.
  • The survey lied about what it would do, labelling blank-result for rows step 2 deletes. It now shares predicates with the steps, so it cannot disagree with them.

Declined, with reasons: relative imports in apps/server/scripts/ (every script in that directory does this; it sits outside the src alias root) and rounded-sm (302 uses against 2 for rounded-xs , it is the repo's normal utility).

Test plan

Every CI job run locally after merging origin/staging (55 commits):

  • autofix , check-brand-assets ✅ · oxlint@1.78.0 --deny-warnings ✅ · deps:check ✅ (no violations, 10,177 deps)
  • Typecheck (tsc) , turbo run types ✅, non-incremental (.tsbuildinfo cleared) after both generators
  • Mail app tests (Jest) , 497 suites, 4,745 passed ✅ · test:tz 5 passed ✅
  • Server tests (Vitest) , 1,093 files, 13,424 passed ✅
  • Deploy scope (bash) , 16 passed ✅

Two flakes appeared when the mail and server sui

Show production surfaces and changed-file mapping

Production surfaces

SurfaceRequestsErrorsp95UsersVerdict
/api/auth/callback/:provider0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.

Changed files → surfaces

  • .env.exampleno production surface mapped
  • .github/workflows/prod-deploy.ymlno production surface mapped
  • .github/workflows/staging-deploy.ymlno production surface mapped
  • apps/mail/app/(auth)/login/login-client.tsxno production surface mapped
  • apps/mail/app/(full-width)/onboarding-login/page.tsxno production surface mapped
  • apps/mail/app/globals.cssno production surface mapped
  • apps/mail/components/icons/agent-avatar.tsxno production surface mapped
  • apps/mail/modules/auth/utils/login-errors.tsno production surface mapped
  • apps/mail/modules/cedar-os/src/cedar-os-components/chatComponents/EmbeddedCedarChat.tsxno production surface mapped
  • apps/mail/modules/conversations/components/LeftSidebarContent.tsxno production surface mapped
  • apps/mail/modules/documents/graph/GraphDocumentView.tsxno production surface mapped
  • apps/mail/modules/graph/GraphEdgeLine.tsxno production surface mapped
  • apps/mail/modules/graph/graph-edge-actions.tsxno production surface mapped
  • apps/mail/tests/modules/graph/GraphEdgeLine.test.tsxno production surface mapped
  • apps/mail/tests/modules/graph/numeral-shape.test.tsno production surface mapped
  • apps/server/docs/agent-tool-calls-retention.mdno production surface mapped
  • apps/server/docs/bug-crm-conversation-updates-jsonb-scan.mdno production surface mapped
  • apps/server/package.jsonno production surface mapped
  • apps/server/scripts/prune-agent-tool-calls.tsno production surface mapped
  • apps/server/src/db/aop-schema.tsno production surface mapped
  • apps/server/src/db/documents-schema.tsno production surface mapped
  • apps/server/src/db/migrations/agent_tool_calls_created_at_idx.sqlno production surface mapped
  • apps/server/src/db/migrations/documents_table_type_idx.sqlno production surface mapped
  • apps/server/src/docs/multi-provider-inbox-infrastructure.mdno production surface mapped
  • apps/server/src/env.tsno production surface mapped
  • apps/server/src/lib/__tests__/email-domains.test.tsno production surface mapped
  • apps/server/src/lib/__tests__/signup-gate-hook.test.tsno production surface mapped
  • apps/server/src/lib/__tests__/signup-gate.test.tsno production surface mapped
  • apps/server/src/lib/auth.tsno production surface mapped
  • apps/server/src/lib/email-domains.tsno production surface mapped
  • apps/server/src/lib/signup-gate.tsno production surface mapped
  • apps/server/src/mastra/tools/document/graphTool.tsno production surface mapped
  • apps/server/src/services/agent-action-queue/__tests__/tool-call-payload-truncation.test.tsno production surface mapped
  • apps/server/src/services/agent-action-queue/__tests__/tool-call-retention.test.tsno production surface mapped
  • apps/server/src/services/agent-action-queue/tool-call-retention.tsno production surface mapped
  • apps/server/src/services/agent-action-queue/tool-call-truncation.tsno production surface mapped
  • apps/server/src/services/agent-action-queue/tool-calls.tsno production surface mapped
  • apps/server/src/services/crm/__tests__/crm-conversation-updates-sql.test.tsno production surface mapped
  • apps/server/src/services/crm/__tests__/external-crm-events-index-usage.test.tsno production surface mapped
  • apps/server/src/services/crm/external-crm-events.tsno production surface mapped
  • apps/server/src/services/documents/table/table-excel.tsno production surface mapped
  • apps/server/src/services/playbook/__tests__/org-chart-seed.test.tsno production surface mapped
  • apps/server/src/services/playbook/agent-defaults/org-chart.tsno production surface mapped
  • aws/lib/runtime-contract.tsno production surface mapped