The brain
Measured: MaleCNS v1.0
The connectome is the male Drosophila melanogaster central nervous system reconstructed by Janelia's FlyEM team from electron microscopy. We keep every entry with an assigned superclass, 166,700 neurons, and every released edge between them, 25,582,938 directed connections. Each edge's sign comes from the predicted neurotransmitter of its source (acetylcholine positive; GABA, glutamate and histamine negative; ambiguous cells kept positive and counted). Nothing is pruned.
Engineered: the kernel
The network runs as leaky integrate-and-fire neurons at 0.1 ms steps, 50 ms of neural time per observation, in a small C++ kernel vendored from fly-wirehead and stonkfly. The phone's screen, captured at 90 × 160, drives 3,335 R1–R6 photoreceptors by brightness and 811 R8 cells by colour. That is the entire sensory channel.
| wirehead reports | ours | |
|---|---|---|
| neurons / directed edges | 166,700 / 25,582,938 | 166,700 / 25,582,938 |
| R1–R6 / R8 inputs | 3,335 / 811 | 3,335 / 811 |
| plastic KC→MBON07/11 edges | 7,835 | 7,835 |
| control, 200 ms white: PAM11 spikes | 0 | 0 |
| stimulated (20 mV into 15 PAM11): PAM11 spikes | 261 | 261 (87.0 Hz per cell) |
| plastic edges changed after the stimulated 200 ms | 3,087 | 3,087 |
| video-linked reward == manual pulse (spike hash) | yes | yes |
Also measured, not in wirehead's report: the control run changed 1,768 plastic edges on its own. The centred rule moves weights whenever KC and DAN rates deviate from baseline, so "edges moved" is not a reward signal by itself; the number to show is the difference against a matched control, which was 3,095 edges here.
| timing, Mac M1 Pro | |
|---|---|
| graph prepare (import + compile) | 19 s |
| engine load (graph + circuits + kernel build cached) | 2.6 s |
| one 50 ms observation, median of 20 | 0.282 s (min 0.271, max 0.303) |
| real-time factor | 0.18× |
| peak RSS | 0.95 GB |
So on the Mac the fly lives about 5.6× slower than wall-clock. For the show that is fine: the loop advances 50 ms of neural time per observation and we report simulated time, as wirehead does.
| timing, Linux box (AMD Ryzen 7 9800X3D, g++ 13) | |
|---|---|
| graph prepare, including the 1.1 GB download | ~60 s |
| engine load | 1.3 s |
| one 50 ms observation, median of 20 | 0.1689 s (min 0.0653, max 0.1758) |
| real-time factor | 0.3× |
| peak RSS | 0.96 GB |
The kernel is single-threaded CPU code; the GPU is not used. The box is 1.7× faster than the Mac per observation.
Engineered: reward and readout
Reward and aversive cells come from wirehead's circuit.identify: the 15 cells typed
PAM11 and the 2 typed PPL101 in MaleCNS v1.0, with the 7,835 KC→MBON07/11 edges as the
plastic set. Unchanged.
The Spin readout is ours. Candidates were every descending neuron within two hops of MBON07/MBON11 (549 cells at two hops, only 3 at one hop). Rates under a static frame, 1 s of neural time after a 2 s settle, mean per cell:
| type | white | black | reels | noise | no reward / reward (reels, 1 s) |
|---|---|---|---|---|---|
| DNa02 (2) | 19.5 | 10.5 | 11.0 | 12.5 | 10.5 / 13.5 |
| DNa03 (2) | 36.0 | 23.0 | 17.0 | 27.5 | 18.0 / 25.5 |
| DNp32 (2) | 154.0 | 154.5 | 155.0 | 156.5 | 155.0 / 155.0 |
| DNp29 (2) | 38.0 | 38.5 | 40.0 | 39.0 | 40.5 / 40.0 |
| DNp62 (2) | 9.0 | 9.0 | 10.0 | 10.5 | 10.5 / 10.0 |
| MN9 (2) | 14.5 | 24.0 | 16.0 | 20.5 | 21.5 / 15.0 |
| DNa13 (4) | 2.0 | 0 | 0.5 | 0.2 | 2.0 / 0.5 |
| DNp09, DNa15, DNp42 (2 each) | 0 | 0 | 0 | 0 | 0 / 0 |
DNp32 and DNp29 are pinned regardless of input or reward: no decision in them. DNp09, DNa15 and DNp42 never fire. DNa02 + DNa03 vary with the frame and rise with the reward current, so those four cells are the readout. Their body IDs:
| type | bodyId | index |
|---|---|---|
| DNa02 | 10360 | 332 |
| DNa03 | 10975 | 902 |
| DNa03 | 519624 | 130282 |
| DNa02 | 523769 | 131957 |
Reward (PAM11):
| type | bodyId | index |
|---|---|---|
| PAM11 | 114661 | 86107 |
| PAM11 | 119763 | 89566 |
| PAM11 | 137539 | 100417 |
| PAM11 | 138822 | 101105 |
| PAM11 | 139706 | 101542 |
| PAM11 | 145749 | 104512 |
| PAM11 | 147857 | 105465 |
| PAM11 | 157016 | 109038 |
| PAM11 | 204930 | 119647 |
| PAM11 | 215931 | 121077 |
| PAM11 | 224500 | 121901 |
| PAM11 | 238644 | 122768 |
| PAM11 | 273182 | 123824 |
| PAM11 | 319321 | 124499 |
| PAM11 | 520616 | 130852 |
Aversive (PPL101):
| type | bodyId | index |
|---|---|---|
| PPL101 | 11327 | 1235 |
| PPL101 | 11900 | 1774 |
observe(frame, duration_ms, reward_mv=0, aversive_mv=0) returns wirehead's telemetry
plus readout_hz, spin, reward_mv, aversive_mv and memory.l1_drift. Spin fires
when the readout's mean rate over the observation is ≥ SPIN_THRESHOLD_HZ (20 Hz) and
at least SPIN_REFRACTORY_MS (2,000 ms of neural time) have passed since the last one.
Both are engineered starting points; S04 measures the resulting spin rate and adjusts.
configuration() returns every engineered number and every cell for the page.
Learned: the plasticity rule
The only weights that change are the 7,835 Kenyon-cell-to-MBON07/11 edges. The rule is a baseline-centred anti-Hebbian eligibility model adapted from Huang, Luo et al. 2024 (doi:10.1038/s41586-024-07819-w) by stonkfly: Kenyon-cell activity leaves an eligibility trace, PAM11 activity gates it, and each edge's efficacy drifts within bounds and decays back over half an hour. The page reports how many edges differ from baseline and the L1 drift, live. Applying this rule to this reconstruction is a hypothesis, not a result.
Measured: the network is bistable
Same graph, same checksums, same 200 ms of white input from the same 1.5 s conditioning:
| Mac (clang 16, arm64) | Linux (g++ 13, x86_64) | |
|---|---|---|
| control PAM11 spikes | 0 | 0 |
| stimulated PAM11 spikes | 261 | 270 |
| KC spikes in the stimulated 200 ms | 1,823 | 5 |
| plastic edges changed | 3,087 | 5 |
| total spikes, control 200 ms | 252,777 | 162,921 |
The reward current does the same thing on both (PAM11 silent without it, 90 Hz with
it), but the rest of the network is in a different state. The cause is not the compiler
alone: the network is bistable. From a cold start it sits in a low state (23k spikes
per 50 ms, Kenyon cells silent); under white light it ignites into a high state (~50k,
Kenyon cells at ~4,000 spikes per 500 ms) and stays there afterwards. On the Mac
ignition happens within the 1.5 s of conditioning; on the Linux build it happens at
about 1.8 s (measured: KC spikes per 500 ms chunk 16, 14, 13, then 3,979), so the assay's
200 ms window lands before it and the plasticity rule, which needs Kenyon-cell
eligibility, has nothing to move. Floating-point differences between the two builds
(FMA contraction on arm64 by default) shift the trajectory of a chaotic network enough to
move that moment.
Consequences, applied in S04: the loop keeps the white light on until the Kenyon cells have ignited rather than for a fixed 1.5 s, and the reward / no-reward / frozen controls are always compared on the same machine and build. Exact spike hashes are reproducible on one machine (the tests check that) and not across machines.