You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sharing a consolidated map of an audit pass I ran on packages/sync-rules over the past two weeks for anyone who wants the silent-row-loss shape spelled out in one place. Eight PRs filed; five merged, one open, three closed as of June 8 after maintainer feedback that the engine's preferred direction is Unicode-aware JS, not ASCII-only SQLite parity. Including the closes for posterity since the discussion itself is informative.
The common shape (for the merged set): a SQL operator that the sync-rules engine evaluates in JavaScript on the server compiles cleanly and runs without errors, but disagrees with SQLite (which the client runs) at the operator's edge. The server and client return different rows for the same input. No exception, no log line — just a silent miss at the bucket boundary.
Closed — preferred direction is Unicode-aware JS; if the SQLite client wants alignment it can enable ICU. Engine team suggested overriding upper()/lower() in the client wa-sqlite expression engine to use JS Unicode-aware semantics for consistency.
Every PR ships a regression test in packages/sync-rules/test/src/sync_plan/evaluator/sqlite_semantics.test.ts. The merged set fails on main pre-fix and passes after. The closed set's tests would need to invert direction (assert Unicode-aware JS behavior, not SQLite ASCII parity) to fit the engine's preferred semantics. The same checks have surfaced equivalent bugs in Rocicorp Zero (#6083, #6088), InstantDB (#2714), ElectricSQL (#4437 open), Dexie (#2306 open), RxDB, and TanStack DB (#1574); the operator-direction question is repo-by-repo.
The checker is open source if you want to run it against your own sync layer:
a length(content) > N or substring(content, …) over content with emoji / CJK / astral scripts → numbers diverge by 2x vs SQLite, but the engine considers JS code-unit count the right answer — so the divergence is a spec question, not a bug, until the client also adopts Unicode-aware overrides
a upper(name) / lower(name) over non-ASCII data → same spec question
For client-side alignment, an ICU-enabled SQLite build will give you the same Unicode-aware results the Service returns. Otherwise you accept JS / SQLite ASCII drift on those operators.
Disclosure: I am the author of the eight PRs. I previously did a 48-hour paid hardening sprint against this same engine. Open to scoping another against the adjacent surfaces (the inverse-direction client overrides @simolus3 mentioned, replication-mongo / replication-postgres filter evaluators, bucket-parameter querier comparison) if there is interest — happy to scope inline or by email.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Sharing a consolidated map of an audit pass I ran on
packages/sync-rulesover the past two weeks for anyone who wants the silent-row-loss shape spelled out in one place. Eight PRs filed; five merged, one open, three closed as of June 8 after maintainer feedback that the engine's preferred direction is Unicode-aware JS, not ASCII-only SQLite parity. Including the closes for posterity since the discussion itself is informative.The common shape (for the merged set): a SQL operator that the sync-rules engine evaluates in JavaScript on the server compiles cleanly and runs without errors, but disagrees with SQLite (which the client runs) at the operator's edge. The server and client return different rows for the same input. No exception, no log line — just a silent miss at the bucket boundary.
Merged (Sprint #1, May)
NOToverNULLWHERE NOT nullable_flagandWHERE state NOT IN ...againstNULL%did not span\n; backslash-escaped wildcards leaked throughCAST(integer / numeric)CAST('-12abc' AS integer)returned NaN instead of-12na / 0threw JSInfinity/NaNrather thanNULLjson_eachOpen
JOINon aliased primaryClosed by maintainer
upper()/lower()upper()/lower()in the client wa-sqlite expression engine to use JS Unicode-aware semantics for consistency.length()(code points vs UTF-16 code units)substring()(code points vs UTF-16 code units)Reproductions
Every PR ships a regression test in
packages/sync-rules/test/src/sync_plan/evaluator/sqlite_semantics.test.ts. The merged set fails onmainpre-fix and passes after. The closed set's tests would need to invert direction (assert Unicode-aware JS behavior, not SQLite ASCII parity) to fit the engine's preferred semantics. The same checks have surfaced equivalent bugs in Rocicorp Zero (#6083, #6088), InstantDB (#2714), ElectricSQL (#4437 open), Dexie (#2306 open), RxDB, and TanStack DB (#1574); the operator-direction question is repo-by-repo.The checker is open source if you want to run it against your own sync layer:
→ silentdrop (
npm i silentdrop)→ silentdrop-llm for the agent-output equivalent
How this surfaces in your deployment (refined)
If your
sync-rules.yamldoes any of the following, you may be exposed:JOINwhere the primary table wears a bare alias and the joined table is referenced unaliased → silently empty client database (this is the fix(sync-rules): surface JOIN clauses in Sync Streams as a loud error (#565) #662 case, fix in progress)length(content) > Norsubstring(content, …)over content with emoji / CJK / astral scripts → numbers diverge by 2x vs SQLite, but the engine considers JS code-unit count the right answer — so the divergence is a spec question, not a bug, until the client also adopts Unicode-aware overridesupper(name)/lower(name)over non-ASCII data → same spec questionFor client-side alignment, an ICU-enabled SQLite build will give you the same Unicode-aware results the Service returns. Otherwise you accept JS / SQLite ASCII drift on those operators.
Disclosure: I am the author of the eight PRs. I previously did a 48-hour paid hardening sprint against this same engine. Open to scoping another against the adjacent surfaces (the inverse-direction client overrides @simolus3 mentioned, replication-mongo / replication-postgres filter evaluators, bucket-parameter querier comparison) if there is interest — happy to scope inline or by email.
Tracking pages, all PRs, and booking page consolidated at https://silentdrop-sravan.vercel.app.
Beta Was this translation helpful? Give feedback.
All reactions