silentdrop

June 8, 2026 · View on GitHub

Does your JavaScript database silently return the wrong rows?

silentdrop-sravan.vercel.app · the audit, the proof, and the booking page in one screen.

Client‑side, embedded, and sync databases re‑implement SQL‑ish operators — LIKE, case‑insensitive match, range comparison — in JavaScript. Subtle gaps between those JS implementations and the SQL semantics they're meant to mirror make queries silently drop or over‑match rows. No error. No crash. Just wrong data — the worst kind of bug.

As of this week I have shipped this exact bug class to seven production databases, 11 PRs in 8 days (8 merged, 1 open, 3 closed after an operator-direction call from a maintainer). Write-up: 9 silent-row-loss fixes in 7 days across 7 OSS databases.

DatabaseBugStatus
PowerSyncLIKE/range, CAST, div-by-zero, json_each, NOT-NULL semanticsmerged: #643, #644, #645, #646, #647 + paid hardening sprint
PowerSyncJOIN on aliased primary, silent zero-row syncopen: #662
PowerSyncupper/lower/length/substring ASCII vs Unicodeclosed by maintainer — preferred direction is Unicode-aware JS; client-side override scoped instead (#663, #664, #665)
TanStack DBupper/lower/ilike ASCII case foldPR open (db#1574)
Rocicorp's Zerorange/comparisonmerged (mono#6083, #6088)
InstantDB$like/$ilike newlinemerged (instant#2714)
ElectricSQLLIKE newline + escaped wildcardsPR open (electric#4437)
Dexiecase‑fold drops rowsPR open (Dexie.js#2306)

PowerSync's full audit summary with reproductions: discussions/668.

silentdrop packages that audit so you can run it against your database.

It catches real bugs

Run it against Dexie (the dominant IndexedDB wrapper, ~2M downloads/week):

$ node examples/dexie.mjs

  ✗  DIVERGENCE: ilike-casefold — Case-insensitive match must handle length-changing case folds
     equalsIgnoreCase('straße') must match 'STRAßE'. Index walks that assume case
     conversion is length-preserving (ß→SS, fi→FI, İ) silently drop rows.
     expected: ["straße","STRAßE","Straße","sTRAßE"]
     got:      ["Straße","sTRAßE","straße"]   <-- 'STRAßE' silently dropped

  ✗  DIVERGENCE: compare-nonbmp — Range comparison must order non-BMP characters by code point
     A range query over astral characters (emoji, CJK ext.) drops rows, because
     JS compares UTF-16 code units while SQL orders by code point.

  ✗ 2 silent-data-loss divergences — these queries return wrong rows

Both are genuine: the case‑fold one is reported as Dexie #2306.

What it checks

  • LIKE across newlines% must span \n (SQL semantics; RegExp without dotAll misses it)
  • LIKE metacharacter literalnessLIKE 'a.b' matches a.b, not axb (escaping)
  • Case‑fold length changesßSS, ligatures, Turkish İ must not drop rows
  • Non‑BMP ordering — range comparison must order by code point, not UTF‑16 code unit

Usage

import { check, report } from "silentdrop";

// Wire your DB's query operators (returns matching string values).
const adapter = {
  async reset() { /* clear store */ },
  async seed(values) { /* insert string values */ },
  async like(pattern) { /* run a LIKE query, return matches (omit if unsupported) */ },
  async ilike(needle) { /* case-insensitive equality */ },
  async gt(bound) { /* values > bound */ },
};

report(await check(adapter));

See examples/dexie.mjs for a complete adapter.

Need the deep version?

silentdrop catches the common cases automatically. If your database/sync layer is correctness‑critical and you want a full manual hardening pass — reduced repros + fixes + regression tests across the whole operator surface (the same work behind the 5 databases above) — I do it as a fixed $1,000 / 48‑hour sprint, no‑find‑no‑charge:

https://buy.polar.sh/polar_cl_z0eLsPUJeMwrcNs4MQPAQbKIM3Rbdb8fLDgVj2RZcmr

Smaller scope? $500 Diagnostic Fix — one operator I find a divergence on, repro + fix + PR delivered:

https://buy.polar.sh/polar_cl_G0fuUHHZ1tg9E0oe7gluje9gs44l8FAqVnfwS2AJkbw

Track record (June 2026): 8 silent-row-loss PRs at PowerSync (4 merged + 4 open), 2 each at Rocicorp Zero and Autumn (all merged), plus shipped fixes at InstantDB, ElectricSQL, Dexie, RxDB. Every bug is real and silent — no error, no log, just wrong rows.

License

MIT © Sravan Sridhar · github.com/sravan27