Fly Worker

A QA fuzzer for browser games. One of its policies is a real fly brain.
FlyWire v783 Β· 138,639 neurons Β· 2.7M connections Β· 0 LLM calls

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

Findings

Nothing yet. The fly is working.

Policies, measured

24,000 frames each, lab game
PolicyCoverage Β· rangeSymptom types
The fly loses. It reaches a third of the map where smoothed noise reaches two thirds, 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.

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.
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 β€” wiring without dynamics
We went after this properly. Flies see motion, not brightness, so we fed ON/OFF temporal contrast into the anatomically correct cells β€” L1 for ON, L2 for OFF.

L1 125Hz β†’ Mi1 0.08Hz, Tm3 0.00Hz, Mi4 0.00Hz β€” ON pathway dead.
L2 125Hz β†’ Tm1 26.0Hz, Tm2 15.5Hz, Tm4 21.0Hz β€” OFF pathway fine.

The fly's ON pathway works by sign inversion through inhibition: L1 inhibits Mi1, Mi1 inverts again. Our model has no baseline firing, so inhibiting a silent neuron does nothing. T4, which needs ON input, never fires.

Adding tonic drive woke HS cells from 0 to 6.7 Hz β€” but direction selectivity stayed at zero. Doubling the visual connectome (2.7M β†’ 5.9M edges) left T4 at 0.0 Hz.

The real reason: T4/T5 direction selectivity comes from neuron-specific timing β€” Mi9 slow, Mi1/Tm3 fast, Mi4 delayed inhibition. Our model gives every neuron the same Ο„m = 20 ms, Ο„syn = 5 ms. The connectome gives you wiring, not dynamics. No amount of better input fixes that.
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