Research / the eye
Notebook 02
The first experiment's pilot got its senses served on a plate: nineteen tidy, hand-engineered numbers. Real systems don't get that gift: they get pixels. This experiment closes the gap. A 28,000-parameter convolutional network watches raw game frames and paints what it understands (every ship, every laser, the black hole) live, while the game plays. Then it gets squeezed into 8-bit integers, and you get to try to tell the difference. Perception and policy: the two halves of an autonomy stack, both small enough to read.
Same rules as the pilot's notebook: the plain story reads on its own; ▸ FOR THE LEARNERS rebuilds the machinery from first principles for any scientifically curious reader (this experiment is the more physical of the two, all sampling, resolution, and dynamic range); ▸ FOR THE DATA SCIENTISTS is the working notebook, with references to go deeper.
01 · The film: two and a half minutes, silent by design
What you're watching: the same eye at different ages, growing up on camera. It opens as a newborn (random weights, painting its favorite ship everywhere) and learns in the order every version of this net learns: first that almost everything is background, then the hole (biggest, easiest), then all five classes as a coarse heat map, then real silhouettes once the second half of the net joins (the decoder, whose job is painting answers back onto every pixel), and finally the finished eye, converged, noise-proof, and squeezed into 8-bit integers you get to try to tell from the original. The footage is a duel it never saw during training, and the era labels carry the actual training clock: the entire education, newborn to converged, is about five minutes on a laptop.
One note on where the footage comes from, in two halves. Everything the finished eye paints comes from the exact frozen file of numbers this project ships, run by a reference program short enough to read (chapter 07): the converged duel, the noisy feed, and the float-versus-int8 alternation (at most six pixels of 61,440 differ; try to spot the swap). The infancy segments can't come from that file (it has no memory of being young), so they come from re-running the training recipe from the same starting seed (a starting number that makes the randomness repeatable; chapter 03 explains) and photographing it growing up; their scores track the shipped run closely, but they are a re-run, not the original.
02 · The eye
The pilot's brain was 6,220 numbers; the eye is about 28,000. Big enough to see, still small enough to print. It's a convolutional network: instead of looking at all 61,440 pixels at once, it sweeps small learned patterns across the image, the same trick your visual cortex opens with. Feed it a raw 320×192 frame and it answers, for every single pixel: background, interceptor, fighter, laser, or hole.
The two ships get told apart by shape, not color: the classes were designed so the narrow dart and the broad wedge differ in silhouette, and the test set proves the net isn't just color-matching. The black hole's glowing halo is deliberately labeled background: the eye learns that only the dark disk at the center kills you. The glow is scenery.
Start with what convolution is, because you've been using it for years: every blur, sharpen, and edge-detect filter in a photo editor is a tiny grid of numbers (a kernel, here 3×3) slid across the image, multiplying and summing at every stop. A convolutional layer is a bank of such filters with one upgrade: the numbers in the grid are learned, not chosen. Two properties follow. It's shift-invariant (move the ship left and its response moves left, automatically), which is exactly the right assumption to build into vision. And it's local: each output sees only a small patch, but stacking layers grows that patch: the receptive field, the amount of image that can influence one output. Each layer also runs many filters at once, producing channels: at every position, not one number but a short list of learned local descriptors ("edge here," "glow here," "bright-against-dark here"). Between layers sits a nonlinearity: ReLU, max(0, x), a hinge that lets evidence accumulate without canceling (negative evidence is dropped rather than subtracted, so features can only pile up). Without it the whole stack would collapse into one big fixed filter.
Stride is downsampling: a stride-2 layer computes its output at every second position, so the map shrinks by half, like a thumbnail. This trunk strides three times, so its deepest map lives at 1/8 resolution: each position there summarizes an 8×8 neighborhood (and, through the stacked filters, sees far wider). That pyramid (sharp edges at the bottom, coarse "what is this region" at the top) is the standard shape of a vision network; your own visual system opens with the same architecture. Hold onto the 1/8 number: chapters 04 and 05 are both about what that shrinking costs.
Do the parameter bookkeeping like chapter 02 of the pilot's notebook: a 3×3 filter bank from Cin channels to Cout costs 9·Cin·Cout + Cout numbers. The trunk's six layers (3→8→16→16→24→24→32) total 19,344; the decoder that paints answers back at full resolution adds ~8,500; about 28,000 all in. One more term you'll meet: batch normalization ("BN") re-centers and re-scales each channel during training to keep the arithmetic well-behaved. And because that correction is just a multiply and an add, at export it folds into the neighboring filter weights and vanishes (a scale and shift after a linear filter is just a different linear filter, so the two merge into one). The shipped net has no BN; it trained with it and absorbed it. Three more parts you'll see in the deep dive's parts list: a 1×1 conv mixes the channel list at a single position (no spatial reach, a per-pixel re-blend); an average-pool shrinks a map by averaging small blocks; a nearest-neighbor upsample grows one by copying each value into a 2×2 block. And its "no concat, no attention" just means none of the channel-stacking or big-model machinery. Every operation on the list is arithmetic at this level.
Finally the task itself: segmentation means per-pixel classification. The output isn't one label for the image but a full-resolution map of 5 scores per pixel (per-pixel logits; the argmax at each pixel paints the overlay). The same classifier machinery as ever, asked everywhere at once. You can now read the deep dive.
A deliberately boring fully-convolutional net, designed backward from the small set of operations a cheap integer chip can run. The ops allow-list is the real spec: 3×3 conv, 1×1 conv, stride-2 conv, 4×4 average-pool, ×2 nearest-neighbor upsample, elementwise add, ReLU. Nothing else: no concat, no attention, no fancy resize. BN trains and folds at export.
| fact | value |
|---|---|
| input | 320×192 RGB (16:9 field + 6-px letterbox) |
| trunk | 3→8→16→16→24→24→32, all 3×3, strides 1/2/1/2/1/2 (→ /8) |
| decoder | 3 × (×2 NN-upsample + additive 1×1 skip + 3×3 conv), 32→16→12→8 + 1×1 head (the skips are chapter 05's story) |
| parameters | 28,126 training / 27,970 with BN folded |
| classes | background · interceptor · fighter · laser · hole (+ ignore: thrust flames) |
| output | 5 logit planes at 320×192; argmax = the overlay |
Class-map decisions that mattered: hulls differ in silhouette so the interceptor/fighter split can't lean on color alone; the hole class is the hard event-horizon disk only (the glow is background: labeling the glow would teach the net a soft, ambiguous boundary); thrust flames are ignore-class 255, excluded from the loss, because they're transient decoration neither background nor ship. Small design choices like these are where segmentation projects are quietly won or lost.
03 · The labels
Vision projects usually die in labeling: humans drawing boxes, arguing over edges, at dollars per image. This one has a loophole: the game draws its own answers. The lab's renderer draws every entity twice from the same geometry: once shaded into the pretty frame, once flat into an answer sheet where each pixel carries its true class. No labelers, no label review, no licensing. The only human check is looking at a contact sheet to confirm the renderer itself draws correctly. And "a million" undersells it: 2,857 training frames × 61,440 labeled pixels is about 175 million labels, free.
The training diet is seeded and synthetic (random legal scenes, plus about a third from real recorded duels, for realistic orbits and firefights), and one entire recorded duel was locked away untouched. That held-out duel is the film in chapter 01. One scope note: "the game" throughout this page is the lab's faithful re-rendering of it: same physics, same geometry, drawn at 320×192. Pointing the eye at captures from the shipped engine itself is a future experiment.
Unlike the pilot (reinforcement learning, no answer key), the eye is trained supervised: inputs paired with ground-truth targets, adjust the weights to shrink the error. Here the error is one number: across all 61,440 pixels, how far the five scores sit from piling their weight on the true class. Training walks all 28,000 weights downhill on that number, exactly as in the pilot's notebook (the field's word for it is the loss). Everything therefore hangs on where the targets come from and whether you can trust them. Here the renderer is the labeler: the pretty frame and the answer sheet are two drawings of the same underlying scene geometry, so the labels are pixel-perfect by construction. There is no label noise in this experiment at all, which is exactly what makes it a clean teaching instrument: every error you'll meet in chapters 04–05 is genuinely the model's.
The discipline vocabulary: the train / validation / test split exists because a model must be judged on data it never fit ("validation" steers design choices; "test" is touched last, once). Leakage is any path by which test information sneaks into training: the silent killer of machine-learning results, the equivalent of grading students on the exact questions they rehearsed. The defense here is structural: every scene is generated from a seed (a starting number that makes the randomness exactly repeatable), and the splits draw from disjoint seed blocks, non-overlapping by construction rather than by careful bookkeeping. Plus one whole recorded duel held out untouched, because random scenes can't test what correlated, duel-shaped sequences test.
The catch you should be asking about: synthetic data is too clean. A net trained on noiseless renders can learn to depend on that cleanliness. Chapter 05 of the pilot's notebook called this training against a lie. The counter is domain randomization, encountered there as theory and used here for real: every training frame gets randomly jittered brightness, color balance, and sensor-style grain, so the net has to learn objects, not exact pixel values. Train in every weather. A separate, deliberately harsher stress set probes robustness beyond the training jitter: the final exam is harder than the homework, on purpose.
Generator recipe: seeded random scenes (ships anywhere legal, 0–8 lasers in flight, 5% dead ships, varied star clutter) mixed ~30% with frames from recorded self-play replays, which contribute the correlations random placement can't: real orbits, close passes, laser exchanges. Splits are disjoint seed blocks (block starts: train 1,000,000 / val 2,000,000 / test 3,000,000); episode seed_005 is fully held out and is what the demo and the film replay. Each split ships as one compressed npz plus a manifest recording every seed. Any shard is bit-reproducible.
Train-time photometric augmentation (label-preserving only): brightness gain ±15%, DC bias ±0.08, per-channel gain ±10%, Gaussian noise up to σ=8/255. The fixed stress set (its own seed) pushes harder: ±20%, ±0.12, σ=12/255. Geometry is never augmented: the renderer can just draw more geometry, which is cleaner than warping labels.
Scale: 2,857 train / 400 val frames proved sufficient. With perfect labels and a 28k-parameter model, data efficiency is not the fight it usually is. Dataset generation, training end to end (both stages, next chapters), and export together run in well under ten minutes on a laptop, all from one seed.
04 · The traps
Training ran in two stages: first a coarse net giving one verdict per 8×8 tile, then the decoder that paints every pixel. Both traps bit the coarse stage. The first version trained on small cropped tiles and aced them: 99.9% accurate. Run on full frames, it saw nothing. It called every pixel background. Not degraded: blind. The second trap was quieter: the way tiles were being labeled made the 3-pixel lasers mathematically invisible. Most laser tiles didn't count as laser at all, so the net was being taught to ignore them.
Both traps share a moral the pilot's notebook already taught once: the test you pass must be the test you'll face. The training views weren't the deployment views, and the score was measuring the wrong world. Fix the world (train on full frames, label tiles by what's present in them) and the same architecture that was blind sees everything.
Trap one is a boundary bug with a satisfying explanation. A filter sliding near the edge of a small, isolated tile runs out of image, so the missing pixels are invented as zeros (zero-padding), and every output near a border is computed partly against synthetic blackness. On a 32×32 tile, with a filter stack whose receptive field is wider than the tile, effectively every output is a border output: the net learned the statistics of padded crops. Run the same weights across a full frame and the padding vanishes (real neighbors everywhere), and the cues the net had leaned on simply never occur. It learned faces from passport photos and was then shown a crowd. The trained-on view and the deployed view were two different worlds that happened to share pixels.
Trap two is a sampling error, the phenomenon physicists know as aliasing: a signal narrower than your sampling grid slips between the samples. The coarse first-stage net (next chapter) makes one decision per 8×8 tile, and each tile was initially labeled by its center pixel's class. A laser is a 3×3-pixel spark, nine pixels: the chance one of them sits exactly on that sparse lattice of center pixels is about one in seven (9 of 64). So six of seven laser tiles were labeled "background" while visibly containing a laser, and the net did exactly what it was taught: ignore lasers. No amount of training fixes a labeling scheme that erases the class. The fix is correct sampling too: label each tile by the rarest class present anywhere in it (an "is it in there at all?" test, not a point sample), which guarantees every object lights at least one tile.
The meta-lesson generalizes far past machine learning: both traps produced excellent scores. Nothing inside the training loop can warn you that the benchmark measures the wrong thing: the 99.9% was real, on a test set built with the same flaw. The only defense is an end-to-end check under deployment conditions, which is why every stage of this project gates on full-frame, held-out evaluation before proceeding. A great score on the wrong test is the most expensive kind of success.
Lesson one, verbatim from the notebook: patches ≠ full frames. Training classified isolated 32×32 patches (99.9% val accuracy); run fully convolutionally, the model collapsed to all-background. Isolated patches zero-pad every conv at their borders; full-frame windows see real neighbors; and the trunk's receptive field exceeds 32 px, so the two views are not equivalent: the patch statistics the net fit don't exist in deployment. Fix: dense-coarse training on full frames, identical architecture, one decision per stride-8 cell against a coarse label grid.
Lesson two: label cells by presence, not center pixel. Center-pixel labeling makes a 3×3-px laser land on the stride-8 center lattice ~1 time in 7 (9/64): undetectable by construction, no amount of training fixes a label scheme that erases the class. Cells are labeled by the rarest class present in the tile (priority: laser > ships > hole > background), guaranteeing every entity lights ≥1 cell. The coarse stage then gates on per-class recall (of the cells of a class that exist, how many the net catches), not overall accuracy: overall accuracy is 92% background and lies fluently.
Result after both fixes, still at 1/8 resolution: 99.6% cell accuracy, worst class 96.2%. That coarse "heatmap" stage shipped as milestone 1 and survives in the demo as a view mode. Watching the net see in 8-pixel tiles makes the next chapter's problem visceral.
05 · The plateau
Getting from "one verdict per 8×8 tile" to "a verdict for every pixel" stalled hard. The upgrade path (let the net paint at full resolution by scaling its coarse understanding back up) plateaued at a score of about 0.59 on the small objects, no matter how long it trained. The reason is plain arithmetic: after the squint down to 1/8 resolution, the information about exactly which pixel an 18-pixel ship hull covers is gone. The net knew what was there and roughly where; it could not know where the edges were.
The fix cost 1,180 parameters, four percent of the model. Give the decoder shortcut wires from the trunk's earlier, sharper layers, so full-resolution edge detail flows directly to the painting stage instead of dying in the squeeze. The small-object score jumped from 0.585 to 0.973. On objects that small, a one-pixel halo of error is the whole score.
First, the metric, because every number here uses it: IoU (intersection-over-union) for a class is overlap ÷ union of the predicted and true pixel sets. 1.0 is perfect, and it punishes painting too much and painting too little symmetrically. Small objects make IoU brutal: misdraw an 18-pixel hull by a 1-pixel ring and you lose tens of points, because that ring is a large fraction of a small area. That's the whole plateau in one sentence: an 8× upscale can only place edges to within ±4 pixels, and ±4 on an 18-pixel object caps IoU near 0.6. The decoder wasn't undertrained. It was information-limited. Once downsampling threw the fine positions away, no amount of training could conjure them back: you can't unshred the page by studying the shreds harder.
The fix is the field's standard answer, worth knowing by name: skip connections. The sharp spatial detail isn't gone from the network: the early layers still run at full and half resolution; it's only missing from the deepest map. So the decoder, at each 2× upscale, adds in a lightly-transformed copy of the matching-resolution early layer: coarse meaning arriving from above, crisp location wired in from the side. This is the U-Net idea, the backbone of a decade of segmentation work (medical imaging especially). One engineering nuance from this lab: the skips are additive (plain elementwise addition, not the textbook's channel-stacking), chosen deliberately because an add stays trivial in 8-bit integer arithmetic (chapter 06) while stacking complicates it. Design for the cheap chip before you shrink to fit it.
Second theme of the chapter: class weighting, the knob for imbalanced data. Lasers are a few thousandths of the pixels, so an unweighted loss barely notices losing them; weighting laser errors up makes the net eager: high recall (it misses almost nothing) at lower precision (it paints lasers a bit generously, about 2× fat). That trade is one knob on one curve, and where to sit on it is a product decision, not a math one: in a live demo, a missed laser reads as blindness while a slightly fat laser reads as glow. The lab chose recall, on purpose, and wrote the reason down. Chapter 06's calibration decision rhymes with this one. (Two training names you'll see in the deep dive: AdamW is the pilot notebook's Adam optimizer with a standard tidy-up, and a cosine schedule just eases the step size down along a smooth curve as training finishes.)
Lesson four: the no-skip decoder (NN-upsample + 3×3 stacks from the /8 map alone) plateaued at val IoU ~0.585 interceptor / ~0.60 laser across a wide LR/schedule sweep: a ±1-px ring on an 18-px hull costs exactly the missing IoU; the failure is in representation, not optimization. Additive 1×1-projected skips from trunk stages at /4, /2, /1 (+1,180 params) took min-class val IoU 0.585 → 0.973. Additive rather than concat keeps the decoder int8-clean: elementwise adds requantize to the sum tensor's scale; no concat means no scale-reconciliation across channel groups.
Lesson three: inverse-sqrt class-frequency weights put laser at precision 0.46 / recall 0.99 on held-out (≈2× spatial bloom); softer cbrt weights traded to precision 0.62 / recall 0.90. Rejected, because a missed laser reads worse in the demo than a confidence-dimmed bloom, and the real precision fix is the per-pixel decoder anyway (post-skip laser: val IoU 0.998).
Final dense numbers (milestone 2, worst class = interceptor): val min IoU 0.9733, held-out episode 0.9652, stress set 0.9653. Gates were per-class IoU 0.70 on validation, 0.60 on the held-out episode, 0.50 on the stress set; all cleared with margin. Training: dense stage inits from the coarse stage's weights (~70 s), then 14 epochs AdamW + cosine, ~4 min total on a laptop, seed 20260708 end to end.
06 · Eight bits
The trained net thinks in 32-bit floating point. Cheap silicon thinks in 8-bit integers. Quantization is the conversion. And it's a bargain: a quarter the memory, integer math instead of floating point, and if you do it right, nobody can tell. The film's alternating segment is that claim, live: float and int8, at most six pixels different out of 61,440 on its worst frame. Measured over the entire 741-frame held-out duel, the two disagree on 586 pixels of 45.5 million, and 333 of the frames match to the last pixel.
The one real decision hiding in "do it right" made the best story in the project. Standard practice says: when choosing each signal's numeric range, clip the rarest, brightest extremes. Outliers waste your precious 256 levels. Here, standard practice failed one class: the lasers. On these clean synthetic frames the rare bright spikes aren't noise: they are the lasers. Clip them and the eye goes blind to exactly the thing it fought hardest to see. Keep the full range and everything passes. Know your signal before you trust a heuristic about it.
Quantization is rounding with a plan. Every weight and every activation gets mapped from smooth floating-point numbers onto 256 integer levels (int8) by a scale factor: choose a full-scale F for each signal and code it as round(127·x/F). Choosing F is the entire game, and it's the same dilemma as setting recording levels for audio: set the level too low and quiet detail is lost in coarse steps; too high and the loud peaks clip. Weights are known exactly at export, so each output channel gets its own perfect scale (per-channel). Activations depend on the input, so their ranges are estimated empirically, by streaming calibration frames through the float net and recording the extremes each signal actually reaches. The arithmetic then runs int8 × int8 with the sums accumulated in int32 (a wide running total, so nothing overflows partway through), after which each sum is requantized: re-leveled back onto the 256-step scale, one precomputed multiplier per channel. Everything is symmetric around zero (no offset terms anywhere), which is what kept chapter 05's additive skips trivial: integer adds, one shared rescale.
The calibration decision deserves a slower telling. The textbook heuristic sets each activation's F at the 99.9th percentile of what calibration observed: "don't waste your 256 levels on freak outliers," which on photographs (sensor noise, sun glints) is usually right. On these synthetic frames it is precisely wrong, and the reason is the shape of the signal: the images are nearly binary (flat dark space, a few small bright objects), and the laser-detecting channels fire rarely and hard. Their top 0.1% of activations isn't a noise tail. It is the signal. Clip it and you amputate the laser detector. Max calibration (F = the true observed maximum, clip nothing) spends a little resolution everywhere to keep the spikes, and here that cost is absorbable. Laser accuracy under percentile clipping: fails the gate. Under max: identical to float. Know the shape of your signal before you trust anyone's heuristic about it.
Why is such a crude scheme sufficient (round the finished net, no retraining; the field calls it PTQ, post-training quantization)? Margin. A well-trained classifier's decisions sit far from its decision boundaries, and int8's worst-case rounding (~0.4%) nudges the scores far less than the typical winner's lead. When PTQ isn't enough (huge models, more aggressive formats), the field retrains with the rounding simulated inside the training loop (QAT, quantization-aware training). Rule of thumb worth exporting: try the cheap thing first and measure per class. Aggregate accuracy hides exactly the small, rare classes that clipping kills.
Scheme: symmetric per-out-channel int8 weights; symmetric per-tensor activations; int32 bias and accumulators; no zero-points anywhere; per-channel requantize multipliers recorded in the export (a hardware target swaps them for fixed-point multiplier+shift pairs). Additive skips requantize to the sum tensor's scale: plain integer adds. The integer path is defined end to end in integer arithmetic, which makes it bit-exact reproducible on any platform: the bundle's verifier (next chapter) checks the integer path byte-for-byte, not approximately.
Lesson five: 99.9-percentile activation calibration failed the int8 gate on the small classes (laser int8-vs-float IoU 0.963, below the 0.98 gate): the rare bright activations a percentile clips are the lasers. Max calibration passed everything, laser IoU vs float = 1.000. On near-binary synthetic frames there is no outlier noise to trim; clipping only destroys signal. The percentile constant now sits in the code at 100.0 with the lesson documented above it.
Acceptance, measured: ≥99.99% per-pixel argmax agreement vs float; per-class IoU vs float ≥0.99 (gate 0.98); over the full 741-frame held-out episode, int8 and float disagree on 586 of 45.5M pixels (0.79 per frame, worst frame 6, and 333 frames bit-identical). PTQ only. No QAT needed at these margins.
07 · The handoff
The experiment's product isn't a demo. It's a frozen bundle: the trained numbers (float and int8), a reference implementation of the math in plain code short enough to read, and a set of golden vectors (known inputs with their exact recorded outputs). Anyone porting the eye to new hardware re-implements the arithmetic on their target, runs the same inputs, and checks against the goldens. One command, one dependency, pass or fail.
Two properties make the folder trustworthy. It's relocatable: copy it anywhere and it still verifies; it doesn't need the lab. And it's reproducible: the entire experiment re-runs from one seed, dataset through training through export, and lands on the same file, bit for bit. The chapter-01 film honors the same contract: every painted pixel you watched came from this folder through the reference implementation, not from the training framework.
The bundle is a contract, and its enforcement mechanism is old and beautiful: golden vectors, recorded inputs with their exact recorded outputs. The reference implementation (a few hundred lines of plain array arithmetic) is the executable spec: not a description of the computation but the computation itself, short enough to read in one sitting. Anyone porting the eye to new hardware re-implements the arithmetic however they like, feeds it the same eight inputs, and compares against the goldens. Match, and the port is correct by the contract's definition. No argument about methodology required. It's the logic of a checksum, or of the old standard kilogram: correctness defined as agreement with a fixed reference artifact, not as anyone's opinion.
What ML adds is a subtlety about tolerances, worth internalizing. The float gate can't demand bit-for-bit equality: adding the same list of numbers in a different order legitimately changes the last decimal place, and different hardware sums in different orders. So the float spec says "within 1e-4, and all 61,440 pixel decisions must agree." The int8 gate is stricter than the float one: because chapter 06 defined the integer path entirely in integer arithmetic, there is no order-of-addition ambiguity. The correct output is one specific string of bytes, compared byte for byte. That determinism isn't luck; it was purchased back in chapter 05 (additive skips) before quantization ever ran: adds keep the whole path in whole numbers, and whole-number arithmetic has exactly one right answer.
The reproducibility claim is the other half. One seed drives scene generation, splits, initialization, and training order, and re-running the whole pipeline lands on the same shipped file, bit for bit, on the same machine and software stack: floating-point training is only bit-repeatable on the platform that ran it, which is why the bundle's gates, not its bits, are the cross-platform contract. That still makes the experiment falsifiable end to end (every number in this notebook can be regenerated, or caught wrong), which is rarer in machine learning than it has any right to be (nondeterministic training, undocumented data filtering, and "the checkpoint we happened to keep" are endemic). And note where the notebook deliberately stops: the bundle says what a port must compute, never how. No target, no toolchain, no vendor. Any student with a microcontroller, an FPGA, or a GPU shader can port the eye and prove their port against the same goldens. The two experiments on this site are the two halves of an autonomy stack: a policy that decides (the pilot) and perception that sees (the eye), each shipped as a folder of checkable arithmetic.
Bundle contents: frozen float + int8 models (dense JSON: plain arrays, no framework), a pure-numpy reference forward (~200 lines, numpy is the verifier's only dependency), eight seeded golden vectors, and a one-command verifier. Verification ladder, in order: float gate: recomputed logits within 1e-4 of goldens (measured deviation ~2.4e-05) and 100% per-pixel argmax agreement; int8 gate: the integer path reproduces stored outputs bit-exactly (int8 weights, int32 accumulators: deterministic on any platform), plus ≥99% argmax agreement vs float and per-class IoU ≥0.98 vs float. Float first, always: quantization error is only meaningful against a float reference you've already proven.
Relocatable: copy the directory anywhere, run the verifier from a bare copy. Pass. Reproducible: the full pipeline (generate → train coarse → train dense → export → quantize → bundle) re-run from seed 20260708 reproduces the bundle bit-for-bit on the same platform and stack (cross-platform, the verification gates are the contract; the film's era clips come from such a same-seed re-run, instrumented for snapshots; its metrics track the shipped run without bit-matching it). A downstream port replaces the reference forward with its own implementation and runs the same script against the same goldens; nothing flows back upstream. The consumer is described only as what it is from here: a hardware port, on whatever tiny accelerator it targets.
08 · If you remember five things
"The renderer is the labeler: 175 million perfect labels, free."
"99.9% in the lab, blind in the field: the test wasn't the deployment."
"The outliers the textbook said to clip were the lasers."
"Float vs int8: six pixels in 61,440, on the worst frame. You cannot tell."
"What ships is a folder anyone can check."