Summary
SyncNotify::on_sync fires for every remote insert, with no way to tell an
initial catch-up sync (a device pulling existing rows on fresh login/first
open) apart from a live incremental change from a peer. Both arrive as
ChangeSource::Remote. The result downstream: logging in on a new/reset device
floods the user with notifications for the household's entire pre-existing
history ("Plan de la semana — hay novedades", one per existing row), even though
nothing actually just happened.
Repro (consumer side)
- App with a
SyncNotify policy on a household table (meal plan / shopping list).
- Clear local state (or install on a new device) and log in to an account whose
household already has data.
- Initial sync applies all existing rows as
Remote inserts → on_sync fires
for each → a burst of "new activity" notifications for old data.
Why the consumer can't fully fix it
- The policy CAN suppress self-authored rows (comparing a stored
added_by
user id to the current user) — we do this now. But rows authored by other
household members during catch-up still notify, which is wrong: it's history,
not new activity.
ChangeSource::Remote { peer_site } carries only the originating device site
id. There's no signal for "this batch is initial hydration vs a live delta,"
and no per-change timestamp/watermark the policy could compare against a
session-start marker.
Request
Expose enough for a policy to distinguish initial catch-up from live changes.
Any one of:
- A variant/flag on
ChangeSource (or SyncEvent), e.g.
Remote { peer_site, initial_sync: bool }, set true while applying the
backlog a peer sends on (re)join, false for live gossip deltas.
- A
SyncEvent field for the change's logical clock / commit time, so the
consumer can gate on "newer than the local session-start watermark."
- A builder/engine hook to suppress
on_sync entirely during the initial
hydration window (fire only for changes applied after steady state).
Option 1 is the smallest and most direct. Happy to test against the
Mediterranea household-plan / shopping-list notifications.
Context
Related to #113 (same SyncNotify path). The self-authored half is fixed
consumer-side; this initial-sync half needs the upstream signal.
Summary
SyncNotify::on_syncfires for every remote insert, with no way to tell aninitial catch-up sync (a device pulling existing rows on fresh login/first
open) apart from a live incremental change from a peer. Both arrive as
ChangeSource::Remote. The result downstream: logging in on a new/reset devicefloods the user with notifications for the household's entire pre-existing
history ("Plan de la semana — hay novedades", one per existing row), even though
nothing actually just happened.
Repro (consumer side)
SyncNotifypolicy on a household table (meal plan / shopping list).household already has data.
Remoteinserts →on_syncfiresfor each → a burst of "new activity" notifications for old data.
Why the consumer can't fully fix it
added_byuser id to the current user) — we do this now. But rows authored by other
household members during catch-up still notify, which is wrong: it's history,
not new activity.
ChangeSource::Remote { peer_site }carries only the originating device siteid. There's no signal for "this batch is initial hydration vs a live delta,"
and no per-change timestamp/watermark the policy could compare against a
session-start marker.
Request
Expose enough for a policy to distinguish initial catch-up from live changes.
Any one of:
ChangeSource(orSyncEvent), e.g.Remote { peer_site, initial_sync: bool }, set true while applying thebacklog a peer sends on (re)join, false for live gossip deltas.
SyncEventfield for the change's logical clock / commit time, so theconsumer can gate on "newer than the local session-start watermark."
on_syncentirely during the initialhydration window (fire only for changes applied after steady state).
Option 1 is the smallest and most direct. Happy to test against the
Mediterranea household-plan / shopping-list notifications.
Context
Related to #113 (same
SyncNotifypath). The self-authored half is fixedconsumer-side; this initial-sync half needs the upstream signal.