fix(gateway): manual verify mirrors channel + contact from assistant when gateway is missing the row#30584
Merged
Merged
Conversation
…DB when gateway is missing the row POST /v1/contact-channels/:id/verify was 404ing on any channel that existed in the assistant DB but not yet in the gateway DB — i.e. every channel created before the dual-write was wired. ContactStore.markChannelVerified now backfills the channel and its parent contact into the gateway DB from the assistant DB before attempting the verify write. - New private helper ContactStore.mirrorChannelFromAssistantIfMissing: reads the channel + parent contact from the assistant DB and inserts both into the gateway DB via INSERT ... ON CONFLICT DO NOTHING. Refuses to mirror (returns false) when the assistant channel references a missing contact (broken state, logs a warn). - markChannelVerified now calls the mirror helper first; returns null only when neither DB has the channel. - handleVerifyContactChannel doc comment updated to mention the backfill. - Tests: 4 new cases (gateway-empty mirror+verify, orphan-channel refusal, mirror idempotency across calls, gateway-precedence when both sides hold the channel). 10/10 pass; 124 gateway test files green; tsc + lint clean. The mirror direction (assistant → gateway, on read-miss) is the migration-window pattern for gateway-native operations during the gateway-security-migration: assistant DB is present-day source of truth, gateway DB is back-filled lazily as contacts are touched.
dvargasfuertes
approved these changes
May 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
POST /v1/contact-channels/:id/verify404'd on any contact channel thatlived in the assistant DB but not yet in the gateway DB — i.e. every
channel created before the dual-write was wired. Verify now backfills the
channel + its parent contact from the assistant DB into the gateway DB
before attempting the verify write.
Why
Gateway-security-migration window: assistant DB is present-day source of
truth, gateway DB is back-filled lazily as contacts are touched. Users
see channels in the assistant UI whose ids the gateway has never heard
of; the verify endpoint should fix-then-flip, not reject.
How
New private helper on
ContactStore:trueif the gateway already has the channel.assistantDbQueryand inserts both into the gateway DB withINSERT ... ON CONFLICT DO NOTHING(idempotent, concurrent-safe).false(and emits a warn log) when the assistant channelreferences a missing contact — broken state, don't paper over it.
markChannelVerifiednow calls the helper first and returnsnullonlywhen neither DB has the channel.
Tests
10/10 pass on
gateway/src/__tests__/contact-store-mark-channel-verified.test.ts:then verifies.
contact (returns null, nothing landed in gateway).
each in
contacts+contact_channelsafter N invocations).mirror, no overwrite of an existing gateway contact).
Mock structure: per-test
fakeAssistantDbkeyed by id; assistantDbQueryroutes to channel/contact maps; assistantDbRun records calls for
inspection.
Locally:
gateway && bunx tsc --noEmit→ cleangateway && bunx eslint <touched> --max-warnings 0→ cleangateway && bun test src/__tests__/contact-store-mark-channel-verified.test.ts→ 10/10 pass
gateway/scripts/test.shfull suite → 124/124 test files passRelated
read-miss for a gateway-native mutator (the verify endpoint).