componentsfix(tasks): do not let the exit animation wipe a failed completion Ordering regression from making the completion write immediate. The row is removed from the store 500ms after the click so the completion animation can finish. While the write sat at t+5s that removal always came first, so a failure rolled back afterwards and the restore stuck. An immediate write can fail well inside 500ms — an auth error, an offline fetch rejecting straight away — and the still-pending removal then wipes the row the error handler just put back. The user gets "Failed to complete task" AND loses the task, which is a worse outcome than the bug this change set out to fix. The animation timer now respects a `completionFailed` flag set last in the write's error handler, so it cannot observe a half-done rollback. Covered by a test that fails without it. Also: absolute imports for `SidebarConversation` in the four sidebar files, per the repo convention (Greptile's one outstanding finding on this PR). Co-Authored-By: Claude Opus 5 (1M context) <<email>>Sep 4, 2026, 12:45 AM2 defectshooksfix(sidebar): the latest event can be absent, and the type now says so `latestEvent: events[0] ?? null` read as ALWAYS PRESENT. `noUncheckedIndexedAccess` is off, so TypeScript believes `events[0]` on an array always returns an event — it does not model "slot 0 of an empty list". It then reasons that the left side of `??` can never be nullish, treats the `null` branch as dead, and discards it. So every consumer was told `latestEvent` is a thing that is always there, while the value is null on every deal with no events yet. `filterConversationsByQuery` guarding it with `?.` is the tell: the author knew, the type did not. Annotating the const does NOT fix this — TypeScript keeps the declared type on paper but narrows the variable to the non-null version at every use, so the object literal still picks up the narrowed one. `Array.prototype.at` is typed `T | undefined` unconditionally, so `events.at(0) ?? null` leaves nothing to narrow and the union survives. That unblocked the two sidebar test fixtures, which were building the DETAIL projection and handing it to functions that take the LIST one — the exact conflation the hook's own note says "took four casts, and their effect was that a reader reaching for one of those fields compiled clean and read `undefined` at runtime". Rebuilt against the real wire row: FLAT (the route spreads `hydrated.conversation` and hangs the joins beside it), `occurredAt` an ISO string rather than a `Date`, no `conversationScope`/`overviewItems`/`lastReviewedAt`, and no `emailEvent`/`summary` on the event — which is why subject search goes through `title`. Built once and referenced twice, since the second copy is what drifts. Three casts gone; the one left is the 43-column company row the haystack reads a single field off, and it says so. apps/mail types:test: 67 -> 52. All 40 conversationsPage tests pass. Co-Authored-By: Claude Opus 5 (1M context) <<email>>Sep 9, 2026, 9:11 PM2 defectsslicefix: coerce legacy 'strength' sortDimension so crm.listConversations validates Stale localStorage/preset sort configs still held the pre-rename 'strength' dimension, which the backend enum ('value' | 'signal') rejected — failing crm.listConversations dozens of times a day. Normalize on read and at both backendSortBy construction sites so no stale enum reaches the server. Co-Authored-By: Claude Opus 4.8 (1M context) <<email>>Jul 24, 2026, 10:25 AMutilsfix(tasks): do not let the exit animation wipe a failed completion Ordering regression from making the completion write immediate. The row is removed from the store 500ms after the click so the completion animation can finish. While the write sat at t+5s that removal always came first, so a failure rolled back afterwards and the restore stuck. An immediate write can fail well inside 500ms — an auth error, an offline fetch rejecting straight away — and the still-pending removal then wipes the row the error handler just put back. The user gets "Failed to complete task" AND loses the task, which is a worse outcome than the bug this change set out to fix. The animation timer now respects a `completionFailed` flag set last in the write's error handler, so it cannot observe a half-done rollback. Covered by a test that fails without it. Also: absolute imports for `SidebarConversation` in the four sidebar files, per the repo convention (Greptile's one outstanding finding on this PR). Co-Authored-By: Claude Opus 5 (1M context) <<email>>Sep 4, 2026, 12:45 AM1 defect