Fly Worker

a QA fuzzer you can plug any policy into
FlyWire v783 Β· 138,639 neurons Β· 0 LLM calls

It plays your game,
finds the bugs,
and loses to noise.

A fuzzer that attaches to a browser game with no cooperation from it β€” synthetic keys in, framebuffer out β€” finds where the game breaks, and replays every finding exactly. What generates the input is a swappable policy.

One of those policies is a real fruit-fly connectome: 138,639 neurons running as a spiking network in this page, steering read from descending neurons with no correction. We measured it against random noise on the same budget. It loses. That table is on this page rather than hidden, because the framework outlives any policy plugged into it.

Scroll
138,639
neurons stepped in your browser
0
LLM calls Β· every rule deterministic
12/12
findings replay to the exact pixel
0.03%
of the brain, cut, kills the steering
The workbench

Watch it work.

Pick a workplace. GTA1 has no interface to speak of, so the fly drives it with synthetic key events and we intercept the WebGL framebuffer to see the screen. Yours takes any HTML game you drop in. Then swap the policy underneath and watch the same framework behave differently.

Workplace

β€” 0f Starting
Steering0
Thrust0
Descending0Hz
Left eye
Right eye
Policy β€” what generates the input

Brain

real anatomical coordinates
Optic Central Sensory Descending Projection
Watch activity spread from the optic lobes through the central brain into the descending neurons.
Cutting 40 neurons out of 138,639 β€” 0.03% β€” drops steering to zero. Implementations that script their steering survive this test. This one does not.

Staff

Each hire downloads the connectome and goes through training β€” flashing light into each eye to find that individual's steering neurons.
On shift
0m
Bugs
0
Spikes
0
Runs
0
The output

Every finding replays to the exact pixel.

The game is deterministic given a seed and an input sequence, so storing the inputs is enough to bring a bug back. The hardest thing in QA β€” "cannot reproduce" β€” stops existing. Press Replay on any finding, or export the whole session as a single self-contained report.

Findings

Nothing yet. The fly is working.

Policies, measured

24,000 frames each, lab game
PolicyCoverage Β· rangeSymptom types
The fly loses. It covers 42% of the map where smoothed noise covers 61% β€” the ranges do not overlap β€” and it hits fewer symptom types per run than either noise policy. We publish this because the product is the framework, not the policy.

Bug count is a fake metric. "Straight ahead" leads on count β€” 95 findings, every one of them the same freeze. Coverage and symptom diversity are what matter.

Does the connectome add anything on top of noise? We put it to the framework. Fly + noise covers 53% (49–56); the same noise sequence with the fly term removed covers 56% (52–63) β€” a paired control, identical seeds. The connectome costs 3 points of coverage and buys 0.4 symptom types, both inside the spread. It adds nothing we can measure.

These numbers reproduce. A single run of a random policy swings between 55% and 78%, so a single measurement is worthless. The noise is seeded and averaged over repeats; node policy_bench.mjs prints this table.

Reproduce

Pick a finding to replay
The lab game is deterministic given seed + input sequence. Storing the inputs reproduces any bug exactly. The hardest thing in real QA β€” a bug that won't reproduce β€” stops existing.
Verified 12/12 exact matches
The product is the framework. It reads the screen, injects input, watches for symptoms, and stores the input sequence so any finding replays exactly. It attaches to games that expose no interface at all β€” GTA1 here is driven by synthetic key events with the WebGL framebuffer intercepted.

That claim is only true if it attaches to a game we have never seen, so you can test it: open the Yours workplace above and drop any HTML game in. It loads into a same-origin frame, takes arrow keys and WASD, and runs the same detectors. What does not work is written down too β€” cross-origin URLs, DOM-only games, tainted canvases, and exact replay outside the Lab.

What generates the input is a swappable policy, and one of them is a real fruit-fly connectome β€” 138,639 neurons, steering read from descending neurons with no correction. We measured it against noise on the same budget. It loses. That result is on this page rather than hidden, because a framework outlives any policy plugged into it.

Getting that result right took three tries, and the middle one was wrong in our favour. Our first answer was that the connectome adds nothing to noise (βˆ’3%p). Then a reader watched the fly on this page and said it was driving in circles. It was: a residual +0.044 bias left the fly turning a 40px circle on a 320Γ—240 board. One adaptation constant fixed it, the fly went 42% β†’ 50%, and the paired control flipped sign β€” +11.4%p, t = 4.63. That is a real number, and stopping there would have let us announce that the connectome beats noise.

So we built the control that separates information from amplitude: show the brain a completely different board and drive this one with its output. Same amplitude, same temporal structure, no relationship to the screen. The blindfolded fly scores 66% against the seeing fly's 62% β€” indistinguishable (βˆ’3.2%p, t = 0.98). What the connectome supplies is steering amplitude, not sight. The first answer was right; its reasoning was not.
Who actually steers, in each implementation
abgunaydin/webgpu-fly β€” its limitations file states plainly: "the connectome does not walk the fly." 20.3M edges reach the body as one scalar plus a turn bias, scaling a hand-written sin(t Γ— 10 Hz) tripod gait.

Xenova/fruit-fly-simulation β€” line one of the decoder reads "Engineered rate decoder"; the README says the movements are "illustrative, not validated predictions of fly behavior."

snedea/flybrain β€” README claims "Behavior is not scripted", but the steering code clamps the brain to Β±0.05 and computes heading with atan2. Its own comment: "Steering is primarily handled by behavioral biases." The clamp exists "to prevent worker noise from causing spinning."

nftechie/doomfly β€” the furthest anyone has taken this. 166,700 neurons, 25.6M connections, plus dopamine plasticity: damage drives a 200 ms aversive pulse into two PPL101 cells and rewrites 4,184 KCβ†’MBON11 weights during play. Its README opens with "Status: live experimental training, not demonstrated learned survival. The current v6 candidate failed its visual, conditioning and survival validation gates." Steering is clip((DNp20_R βˆ’ DNp20_L) Γ— .12, βˆ’6, 6), which the author calls "engineered controller assignments, not established natural motor functions." We measured DNp20 in our own model: left/right separation 0.18 Hz, against 0.889 for the channels we find statistically. There is one DNp20 per side β€” too few to read.

Nobody has done it. Even with reinforcement learning. The honest ones say so.
Why it fails β€” the signal dies before it arrives
We went after this properly, got it wrong once, and measured our way out. Both versions are here because the wrong one was on this page for a while.

What we used to say. Flies see motion, not brightness, so we fed ON/OFF temporal contrast into L1 (ON) and L2 (OFF). L1 125Hz β†’ Mi1 0.08Hz β€” ON pathway dead; L2 125Hz β†’ Tm1 26.0Hz β€” OFF pathway fine. We concluded that the ON pathway relies on sign inversion through inhibition, that our model has no baseline firing to inhibit, and that T4 therefore never fires β€” and that the deeper cause was uniform time constants, since T4/T5 direction selectivity comes from neuron-specific timing.

Both halves were wrong. We gave the model per-neuron membrane time constants and tried five configurations. T4 stayed at 0.00 Hz in every one. Then we counted the wiring directly instead of reasoning about it:
T4: 47,625 incoming connections β€” from L1: 0, from L2: 0, from medulla: 24,045
T4 receives nothing from L1 or L2. Our explanation had been describing a pathway that does not exist in this connectome.

What is actually wrong. Firing rates along the chain:
optic nerve 31Hz β†’ L1Β·L2 21Hz β†’ medulla 2.6Hz β†’ T4's own inputs 0.56Hz β†’ T4 0.00Hz
Roughly 10Γ— attenuation per stage. It is not timing, it is gain: one synaptic weight of 0.44 cannot carry a signal through five stages to threshold.

And raising the gain makes the fly worse. T4 does wake up β€” 0.00 β†’ 4.32 Hz at WSYN = 6 β€” but so does everything else, and steering is a left/right ratio, so saturating both channels erases it. Measured on the same bench, fly policy, 3 reps:
WSYNT4Map coverage
0.44 (shipped)0.00 Hz42%
1.50.43 Hz34%
4.02.84 Hz25%
So we kept 0.44. A prettier firing rate is not a better policy, and we only publish the policy number. Every figure here comes from wiring.mjs, chain.mjs, tau_test.mjs and gain.mjs in the repo.
So why is it useful
A QA fuzzer does not need goal-seeking. It needs tireless exploration at a cost that lets you run it for hours β€” which rules out an LLM in the loop. A connectome gives you structured, non-deterministic input at zero inference cost, forever. What it does not give you is an advantage over noise: we measured that, and the table above is the result.

The lab game has four bugs planted in it. The detector does not know where they are; it only watches for symptoms.

Not reaching the goal is a limit of the model. Spinning in a corner was our bug. Residual bias and saturation in the steering signal kept the fly circling in one place. Retuning adaptation and gain against map coverage β€” not against goal-seeking β€” took it from 16 visited cells to 30 and from 8.3 spins to 1.9.

The second problem was that a wedged fly never recovers β€” a 6000-frame run covered less ground than a 750-frame one. So when the detector reports stuck, no-progress or frozen, the shift ends and a new one starts. The finding is still logged; this is what a real fuzzer does. Same budget, 24,000 frames, averaged over three repeats: 9% β†’ 37% coverage, 5 runs β†’ 53, 10 findings β†’ 53.

We also tried randomising the starting position, the way fuzzers randomise initial state. It measured worse β€” some seeds start inside a small dead end β€” so we dropped it. (That comparison predates the deduplication fix below, so we quote no number for it.)
The four planted bugs