Validation & testing
Copy page
Nizhal validates sync with adversarial emulation — not only happy-path unit tests.
Chaos suite (pnpm chaos)
Section titled “Chaos suite (pnpm chaos)”apps/emulation runs 19 scenarios against a real createNizhalServer + N createNizhalClient instances with failure injectors:
- Network partition / delayed push
- Server restart mid-outbox
- Dropped realtime (SYNC-5 —
pull.intervalMsconverges) - Garbage cursor (
cursorReset) - Poison mutation dead-letter + cascade-cancel
- Revoked membership eviction
- Concurrent POS inventory races
- Credit-ledger balance fold invariants
Default DB: PGlite. Set NEON_URL for managed Postgres.
Current status: 19/19 PASS on PGlite (see rfcs/RFC-004-findings.md).
Offline-first matrix
Section titled “Offline-first matrix”research/phase2/offline-first-testing-and-transports.md defines a 30-scenario matrix covering transports (web↔mobile), persistence drivers, and tenancy edge cases. Scenarios map to TS harness rows in apps/emulation.
Oracles
Section titled “Oracles”- Convergence —
assertInvariantsdiffs all clients vs server row sets (strips TanStack metadata + timestamp columns) - Exactly-once — replay entire outbox twice → byte-identical server state
- No poison wedge — queue drains after deterministic failure
What is verified today
Section titled “What is verified today”| Area | Evidence |
|---|---|
| Multi-device web | live-e2e, emulation harness |
| op-sqlite on device | apps/op-sqlite-probe iOS simulator |
| Managed Postgres | NEON_URL chaos + neon-smoke |
| CF realtime | packages/server/examples/cf-e2e-smoke.ts |
| RN native WS + fetch | @nizhal/react-native README path |
What is not headless in Node
Section titled “What is not headless in Node”op-sqlite JSI — native only. Emulation uses wa-sqlite WASM / node:sqlite for the same persistence code paths; literal op-sqlite binary requires simulator/device (RFC-004 scope split).
Run locally
Section titled “Run locally”pnpm install && pnpm build && pnpm test && pnpm chaosUnit tests (~64+) stay in pnpm test; chaos is heavier and separate.