CedarCopilot wants to merge 2 commits into staging from fix/dm-container-kind
Live on prod, no production signal yet
Strict CloudWatch fallback found 98 prod failure log lines for [UpdateExternalCrmWorkflow] Driver update failed (Value \), up from 25 in the comparable baseline, but this domain-wide failure family is not tied to this intent.
Strict CloudWatch fallback found 3 recent prod failure log lines for mirror.upsertEmailThread failed (write CONNECTION_CLOSED aws-1-us-east-2.pooler.supabase.com:6543), but the same failure had 8 log lines in the comparable pre-deploy baseline. Libra is not blaming this PR.
Libra has verdicts on 0 of 2 tracked behaviors on prod; 2 are still being checked. Libra checks hourly for 3 days after each deploy.
Three bodies of work that ended up on one branch. The email-attachment work described in the original body of this PR already merged via #2578 , it is not in this diff.
262db9f42, b575e3919, 7ae255e41, 9c0ef6215, 22ad9d296)Authored in a concurrent session. Every Files-tab action used to wait for a server round trip and a refetch before anything moved , a delete with External drives open took ~2.6s, because invalidateFiles awaited four query families and two of them are Google. Now the cache moves in the same frame as the click, with a real inverse mutation (files.restoreNode) behind Undo rather than a cached copy.
The pipeline is cancel → snapshot → patch → mutate → reconcile/rollback → settle. Cancelling first is the step that is easy to omit and impossible to notice missing: global defaults are refetchOnWindowFocus + refetchOnMount, so a read started when the window regained focus (exactly what happens returning from the Google Picker) resolves after the patch and writes the old list back , the "it deletes and then pops back in" report.
8f5c1445d)Three findings from reviewing the above:
removeMany rolled the whole batch back on any failure, putting rows the server really deleted back into the cache while the toast beside them named a single failure. pinDrive already had this right , take back only what failed. The whole-batch snapshot is still used when every delete failed, the one case where restoring everything is correct.message.startsWith('Cannot restore '). The classification lived in prose, so rewording the sentence would silently turn a CONFLICT the toast can explain into an opaque 500. Now a DocumentRestoreConflictError, matched on the type.nextNoteName counted any leaf starting with note, so a user's own notes-from-kickoff pushed the auto-name past the rows that exist , a tab with one note handed out note_3. Anchored to /^note(_\d+)?$/.The bulk-delete regression test asserts the cache through a bare hook probe, not the DOM through <FilesTab>: settle invalidates, the stubbed listChildren answers, and that refetch decides what is on screen , so a DOM assertion passes for the broken rollback too. Verified failing before the fix, passing after.
playbook-webhook-sources.ts matched registrations on sourceType + sourceRef (a bare Slack channel id) + enabled, with no workspace predicate , workspaceId was threaded all the way into dispatchSlackChannelSources and used only in log lines. Slack guarantees a channel id is unique within a workspace, not across them, so tenant isolation rested on ids not colliding rather than on the query. Raised by Greptile against #2575; the code was already on staging.
findWorkspaceUserIds resolves the workspace's Cedar users via connection.externalId , the same join slack-events-webhook.ts already uses , and is called only after a channel match, so the overwhelmingly common zero-registration path pays nothing. scopeSourcesToWorkspace is pure, so the boundary is testable without a database. It fails closed: an empty set, or a failed lookup, fires nothing. Foreign drops log cross_workspace_drop with the owner id, since either two workspaces share a channel id or a registration outlived its owner's Slack connection , both warrant a look.
pnpm run autofix:local green: 2,622 mail tests, 7,466 server tests, oxlint and deps:check clean.settleEach , release/fail settle every pending call the same way and can only produce all-succeeded or all-failed, never the partial case the bug lived in.Libra has not measured any production surfaces for this change yet.