Stop asking a friend to hop on a call

Every developer who has built a chat, a game, or a call knows the ritual: open two browsers, sign into two accounts, message a colleague — "can you join for a second? I need to test something." And every regression tool you might automate that with compares a page against yesterday's copy of itself, which catches what changed and never what only one kind of user sees.

Parallax is the friend who always picks up. Point it at a URL. It opens seven isolated browser contexts against the same commit at the same instant — each changing exactly one property from a baseline (role, language, theme, viewport) — and reads the disagreement. The derivation rule is fixed; the vocabulary is yours: declare any role with a rank, any BCP 47 locale (direction is derived, so a Hebrew witness gets the RTL mirror checks), any viewport — each adds one witness, never a cross-product. When the promise needs several people, it is the several people: two live players of one game, three WebRTC peers with audio genuinely travelling between them, a sender and a receiver of one message, a session that stays open while its authority is revoked.

No stored screenshots. No golden files. No selectors. The finding is the disagreement — so the first sweep of a site it has never seen still has something to say.

The whole job, autonomously (Taskmaster)

You hand it a URL and a credentials file. It:

  1. Finds the sign-in surface itself — on a production Arabic chat app, that was a panel with no <form> element, rendered after hydration, beside three buttons of which two don't take credentials. It signed in as two roles anyway.
  2. Discovers routes and controls breadth-first, honouring a written deny-list ("delete" covers every delete button; every exclusion is logged in the feed for audit).
  3. Decides which axes the application even supports — a monolingual app is never judged on translation; the gate says not applicable and why.
  4. Witnesses all seven contexts concurrently, composes a live mosaic wall, retains the CDP screencast as published motion clips.
  5. Judges measured-first, model-last: deterministic geometry/contrast/i18n probes decide measurements; Gemini judges only what cannot be computed.
  6. Plays declared protocols with its own sessions — a seven-step game verified from both boards before each next step — and listens to declared audiences: after pressing mute, who still hears the audio, and who chose silence and must not be reported?
  7. Emits failing Playwright specs and opens the pull request — one commit per finding. Here is a real one.

Three findings a diff cannot produce

A control that only exists on desktop — swept the-internet.herokuapp.com (nobody built it for Parallax): 26 findings, first run. Verified by hand: 20 actionable controls off-screen at 360px, zero at 768px. The page never changed; only two witnesses disagreeing can see it.

A game that ends for the winner alone — the demo fleet serves the same game at two pixel-identical routes; on one, the loser is still told it's their turn. The engine's own ledger reads: broke at step 7 of 7 — samir should have seen it but it never appeared.

A mute button that mutes nothing — a real WebRTC mesh; one route updates the button and never touches the outgoing track. Two listeners still hear her; the third muted his own speaker and is correctly not reported — the sensor measures audio energy, because a muted sender, a deafened listener and a working call all have tracks.

A detection rate means nothing without an error rate

Seven demo applications declare their own planted defects in code, including two clean controls with nothing planted — anything found there is, by definition, an error the tool made.

17 / 17 found · 0 missed · 0 false positives — graded in CI on every push 18 / 18 generated specs fail as assertions — none skipped, none passing 2,572 ms measured revocation window on an already-open session (OWASP ASVS V3 names this control; there is no standard automated verifier) 457 automated tests

Run it yourself, right now, on any public URL: perallax.mlki.app/run.html — the sweep runs on Cloud Run's background thread and the page re-attaches if you leave and come back. Finished sweeps are mirrored to Cloud Storage, so a saved run link keeps working even after the demo's single instance restarts.

Technologies

  • Gemini 3.7 Flash (Vertex AI, GenAI SDK): judges the composed seven-tile wall; behind --propose-scenarios, proposes relational/capability tests from observed evidence only — every proposal passes the same validator as hand-written declarations.
  • gemini-embedding-001 (Vertex): semantic equivalence of changed text, cosine ≥ 0.90 — replaced a hash comparison that scored correct and wrong translations in overlapping bands.
  • Cloud Translation v2: translates the baseline into the variant locale so comparison is same-language.
  • Gemma 4 26B A4B (Vertex, or self-hosted via PARALLAX_GEMMA_URL): names the shared cause behind repeated findings — a language judgement, never a measurement.
  • Cloud Text-to-Speech (Chirp3-HD): narrates the demo film, aligned to timestamps the recorder observed.
  • Cloud Run (us-central1, one instance): serves console + sweep API; Cloud Build → Artifact Registry deploys it. Python/Playwright/Chromium underneath; specs emitted as TypeScript.
  • Cloud Storage: every finished run is mirrored file by file through the runtime service account — status, feed, mosaics, and specs are read back from the mirror by instances that never ran them.

Findings & learnings

  • The gate that grades you must be un-gameable by you. My arena fixture broke at step 2 for an unrelated reason and the gate still counted its step-7 plant as found — kind+axis+route wasn't identity. Plants can now require a phrase their finding must contain.
  • Prose is not structure. The axis gate once believed our own console had a language switcher because a finding card mentioned Arabic. Controls are switchers by their short labels, not by sentences about them.
  • CDP screencasts were being thrown away after deciding settle-time. They now ship as per-surface motion WebPs — and Gemini accepts video natively, so a temporal lens (hover, scroll, animation jank) is the designed next step: the footage ships today, the lens doesn't yet. Every limit like this is written in the README, not implied away.
  • The demo must be the product. The film is one uncut browser session: a URL pasted into the deployed service on camera, findings produced live, and the pull request opened by the sweep — because a screenshot of a pull request instead of the pull request would be exactly the substitution this project argues against.

Individual entry. Everything above is reproducible from the repo README (parallax.toml + one command), and the graded figures are produced by the same workflow CI runs on every push.

Built With

  • artifact-registry
  • chromium
  • cloud-build
  • cloud-run
  • cloud-translation
  • gemini
  • gemma
  • google-genai-sdk
  • playwright
  • python
  • text-to-speech
  • typescript
  • vertex-ai
  • webrtc
Share this project:

Updates

Submission history