Browser-based multi-client convergence fuzzing for collaborative, local-first, and offline-first applications.
ReplicaFuzz is an experimental local falsification harness that asks one question: after several real browser clients act under adverse schedules, do their application-defined canonical states converge and still match the semantic model?
This alpha is intentionally smaller than a product. It launches isolated Chromium contexts with Playwright, drives semantic actions through a six-method adapter, generates schedules from a seed with fast-check, minimizes failures by replaying candidate schedules, and emits a short JSON + Markdown counterexample.
The core targets are synthetic micro-apps that make the harness testable. A separate external adapter now exercises unmodified Etherpad 3.3.2 and records a minimized post-reconnect UI-readiness failure. One production application is evidence of portability, not broad vendor-neutral coverage.
npm install --save-dev replicafuzz@alpha
npx playwright install chromium
npx replicafuzz smokeNode 22 or newer is required. The package runs locally and does not require an account or hosted service.
pnpm install
pnpm exec playwright install chromium
pnpm demoThe demo plants a disclosed WebSocket message-loss mutant. Its generated replay looks like this:
Seed 10000, replay path ddmin/3:5,0:2
5 steps -> 1 step
1. client 1 increments by 1
FAIL semantic-model: canonical value differs from accepted semantic total 1
Artifacts land under output/playwright/. The checked-in example is
examples/websocket-drop-first-outbound.md.
- Two to five clients are separate Playwright
BrowserContexts, not simulated objects or tabs sharing storage. - WebSocket, Server-Sent Events + HTTP, and REST polling exercise three distinct inbound transport shapes. A fourth polling + localStorage fixture measures adapter integration.
- A fifth target uses the external
yjspackage with a small local WebSocket relay to exercise real CRDT merge and reconnect behavior. Its UI, relay, and adapter remain purpose-built, so it is not presented as a production- application integration. - The external Etherpad adapter drives the unmodified upstream browser UI, observes canonical text, collaboration revision, and native pending-commit state, and supports real browser disconnect/reconnect, reload, death, and relaunch. Its three-step reconnect counterexample reproduced 5/5 locally.
- Offline and reconnect use
BrowserContext.setOffline; reload usesPage.reload; client death closes the page and relaunch creates a new page in the same context. - The runner observes the browser app through semantic actions, canonical snapshots, application-defined quiescence, and invariants.
- Schedules and action values are generated by fast-check from an integer seed. Replay-driven delta debugging is used for shrinking because browser timing can invalidate purely structural shrinks.
- The 20 fault-gate cases are explicit implementation mutants, not naturally discovered production bugs.
- Delay, single-message drop, and clock skew are fixture-level transport/lifecycle controls. They are not claims of arbitrary TCP packet control.
- The fixtures use a local in-process server, no authentication, and no service worker. Remote queues and third-party infrastructure are outside this proof.
# Type checks and tests
pnpm check
pnpm test
pnpm test:browser
# One minimized counterexample
pnpm demo
# All 20 disclosed mutants
pnpm replicafuzz fault-suite
# Baseline resilience gap not covered by the fixture's happy-path test
pnpm replicafuzz novel
# Independent PR-size timing run
pnpm campaign
# Re-run a saved failure exactly
pnpm replicafuzz replay output/playwright/faults/websocket-drop-first-outbound.json
# Recompute the gate report locally
pnpm proof
# Against a separately running Etherpad 3.3.2 source build
ETHERPAD_ORIGIN=http://127.0.0.1:9001 pnpm test:etherpad
ETHERPAD_ORIGIN=http://127.0.0.1:9001 pnpm proof:etherpad -- --runs 10Node 22 or newer and pnpm are required. The browser install is local Playwright state; no account or external service is needed after dependency installation.
An application adapter supplies:
interface SyncAdapter {
reset(options): Promise<void>;
launch(clientId, options): Promise<ClientHandle>;
relaunch(client, options): Promise<void>;
act(client, semanticAction): Promise<void>;
canonicalSnapshot(client): Promise<CanonicalSnapshot | null>;
waitForQuiescence(clients, timeoutMs?): Promise<void>;
assertInvariants(clients): Promise<InvariantFailure[]>;
control(client, faultOrLifecycleStep, options): Promise<void>;
close(clients): Promise<void>;
}The proof keeps reset/launch, action, observation, quiescence, invariant, and
fault responsibilities explicit. See docs/adapter-guide.md
and docs/architecture.md.
pnpm proof writes outputs/replicafuzz-proof-report.{json,md} for the original
synthetic gates. pnpm proof:etherpad writes the separate unfamiliar-app proof
and human-readable minimized replay. Etherpad materially strengthens the
portability and actionable-failure evidence, but one local default deployment
still does not establish broad production validation.
src/ runner, adapter contract, CLI, generation, shrink, replay
fixtures/ local browser apps and fixture server
integrations/ external application adapters and setup boundaries
tests/ core, existing-test baseline, and fourth-app integration
examples/ checked-in minimal replay
evidence/ integration timing record
docs/ architecture, adapter, metrics, and limitations
outputs/ final local proof report (generated)
output/playwright/ ephemeral browser replay artifacts (ignored)
ReplicaFuzz is an experimental alpha, not a hosted service or production certification. The code is MIT licensed. The current evidence proves the harness against disclosed local fixtures, one external sync library, and one unfamiliar production application under a local default configuration. It does not establish broad production portability, maintainer-confirmed upstream bug status, or customer impact.