Strip legacy-channel payloads to {table, op} → 0.2.0-next.25 - #21
Merged
Conversation
Supabase Realtime injects its own message-uuid `id` into any broadcast payload that lacks one. The public compat channel is row-data-free by contract, so after the platform stopped putting a row id there (it was leaking primary keys on an anon-joinable channel), subscribers started receiving Realtime's uuid instead — indistinguishable from a row id to the live store, which then keyed-fetched a row that doesn't exist, applied nothing, and silently swallowed the change. Discovered by verifying the platform-side fix end-to-end on dev: the public payload still had an `id`, and it did not match the inserted row's. The doorbell now discards `id`/`row` on the legacy channel rather than trusting the transport's payload shape. A missing id is precisely the signal that makes LiveEntityStore fall back to a coalesced full reload — correct for a channel that carries no row data. Private payloads keep both fields. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Supabase Realtime injects its own message-uuid
idinto any broadcast payload that lacks one. The public compat channel is row-data-free by contract, so once the platform stopped putting a row id there (codehs/bool#570 — it was leaking primary keys on an anon-joinable channel), subscribers began receiving Realtime's uuid instead — indistinguishable from a row id toLiveEntityStore, which keyed-fetched a nonexistent row, applied nothing, and silently swallowed the change.Found by verifying the platform fix end-to-end on dev:
The doorbell now strips legacy-channel payloads to
{table, op}instead of trusting the transport's shape. Absentidis exactly the signal that makes the store fall back to a coalesced full reload — correct behavior for a channel with no row data. Private payloads are untouched (they keepidandrow).Only reachable on the fallback paths — no mint desk (older platform), revoked access, refused join — which is also where it was hardest to notice.
2 new regression tests (legacy stripped / private preserved). 152 pass, typecheck clean.