CedarCopilot wants to merge 4 commits into staging from fix/dm-container-kind
Live on prod, no production signal yet
Verification cited only 15 matching post-deploy events, below the 20-event floor for calling a change verified. Nothing is failing; there is not yet enough traffic to confirm it.
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.
ingestSlackMessages derives a container's kind from the id prefix , startsWith('D') ? 'dm' : 'channel' , and Slack now issues C… ids for group DMs, so a C-shaped mpim reaches ensureContainer claiming to be a channel. COALESCE(EXCLUDED.kind, …) took that guess over a stored 'group', because the guess is not NULL.
Measured on the first real DM backfill against Invoicebutler: two mpims admitted as 'group' came back out of ingest as 'channel', carrying Slack's own mpdm-mihir--kristina141--quinnlitherland11-1 in place of the deliberate 'directmessage'.
'dm'/'group' is only ever set by a caller that RESOLVED the conversation , the admission rung asked conversations.members. 'channel' is what every prefix guess falls back to. The specific value is evidence, the general one is a default, and a default must not overwrite evidence.
display_name inverts the usual rule on a DM for a sharper reason: a channel's name legitimately changes and the newest sync is right, but a DM's name is the deliberate constant 'directmessage' (design: dm-auto-sync.md §4 Phase 1), chosen because rung 5 tokenises a container name against split_part(company_domain, '.', 1). Letting Slack's mpdm name land there feeds people's names to a rung built for cedar-acme-shaped ones and invites a link to a company that merely shares a token.
A NULL is still filled, so nothing is left nameless, and a real channel still renames.
COALESCE before being kept.vitest run src/services/channels src/services/integrations/slack , 246 passed, 26 skipped.pnpm --filter @zero/server run types , exit 0.pnpm deps:check , no violations.🤖 Generated with Claude Code
The PR changes channel-container conflict updates so resolved Slack DM/group metadata survives later prefix-based guesses while ordinary channels remain renameable.
dm and group kinds when a later upsert supplies a generic channel classification.The PR appears safe to merge, with the intended conflict-update behavior covered by focused regression tests.
The changed upsert preserves resolved DM/group metadata while retaining the existing update behavior for ordinary channels and missing names, and no concrete reachable regression remains.
| Filename | Overview |
|---|---|
| apps/server/src/services/channels/containers.ts | Updates conflict resolution to protect resolved DM/group classification and naming without preventing normal channel renames. |
| apps/server/src/services/channels/test/link-store.test.ts | Adds focused regression tests for the protected metadata and the intended channel/NULL-name exceptions. |
Reviews (1): Last reviewed commit: "fix(channels): a resolved DM keeps its k..." | Re-trigger Greptile
Libra has not measured any production surfaces for this change yet.