exit-link-on-space.test.tsfix(drafting): the drafts a send leaves behind, the drafts nobody sees, and the link Space ate Three A5 items, all in the gap between a draft existing in Gmail and Cedar knowing about it. Leftover drafts after a send (Vooma, Horison). Gmail retires the draft that was actually sent; nothing retired the others, and a send without a draftId only deleted one when an emailHeaderMessageId/id happened to ride along. So a thread that had collected a second Cedar draft kept it, and the rep found a stale pre-send copy under a message they had already sent — 77 of these across 21 accounts in three weeks. mail.send now sweeps the thread afterwards, deleting only drafts Cedar authored (checked against analytics_draft_actions, the same authorship record the rewrite path adopts by). Fire-and-forget: the mail is sent, and nothing here may fail that. Drafts with no task at all. The chat/headless save-draft path created a real Gmail draft and attached it to nothing — 90% of emailResponses drafts and 100% of preMeetingPrep drafts in the week to Aug 30 had no user_tasks row pointing at them, so the user could not open, close or track them and nothing could find them to clean up. It now upserts the draft task the on-event path has always created, via the same idempotent upsertDraftTask, skipping interactive surfaces where the draft card already carries its own task descriptor. Link formatting (Concentrate). ExitLinkOnSpace bound Space globally and called unsetLink() whenever the caret was anywhere inside a link — and unsetLink extends over the whole mark range on a collapsed selection, so editing a word in the middle of a hyperlink and pressing space stripped the href off the entire link, with the next autosave writing the de-linked body to Gmail. It now acts only at the END of a link, which is the case it was written for; mid-link it declines and the space types normally. The Link mark is inclusive only when autolink is on, which the composer turns on, so the extension does still have a job. Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 30, 2026, 9:19 PMlist-exit-on-empty.test.tsfix(mail): clear 309 typecheck errors and 5 live ReferenceErrors apps/mail 792 -> 483. Jest stays green at 111 suites / 1071 tests. The single biggest cluster was one missing line: tsconfig pins `types` to ["node","vite/client","jest"] and jest.setup.js is a .js file outside `include`, so the @testing-library/jest-dom matcher augmentation never entered the program — 170 errors from `expect(...).toBeInTheDocument()` and friends. A 4-line jest-dom.d.ts clears all of them. Stripping @jest/globals from 22 test files was a prerequisite, not a tidy-up: only the globally-injected `expect` picks up that augmentation. The other 145 test files already used injected globals, so this also converges on the dominant convention. Do not install @jest/globals. The rest: CRM store test fixtures still extending state that moved to conversationsSlice in Dec 2025 and importing a deleted CRMTypes module; barrel files re-exporting modules that no longer exist (each one an import-time throw); a locally-declared SelectorItem whose module was deleted; sanitizeJson taking `object` when its body explicitly handles primitives and both callers already cast. Five of these were live runtime bugs, not type noise: - setForcePropagate(false) in the AOP-save onSuccess threw on EVERY successful playbook save (cedarAdmin/page.tsx, admin/page.tsx) - backendResponsiveness referenced in a useMemo dependency array, evaluated every render, while the memo body no longer mentions it - "Force re-sync" called handleForceSync() with no argument against a z.object() input that rejects undefined, so it always failed validation - an empty-string icon key produced `Icon === ''`, i.e. <'' /> - showOverlay leaked an unknown attribute onto a Radix DOM node Worth knowing separately: the 792 were invisible. Plain tsc reported 3, because a syntax error elsewhere in the tree makes TypeScript skip ALL semantic checking. One stray comma blinds the entire typecheck. Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 2, 2026, 2:11 PM