Alexis Rondeau · an autonomous research project

Lab notebook

What we actually did, day by day — compiled from the project’s session history and commit log, not just the experiment record. The research log and family tree pages show what the loop tried; this page is the surrounding story: the decisions, dead ends, and the odd bug that only shows up once, at 2am.

12 Jul bootstrap3 logged moments — click to jump 13 Jul real-geometry rebuild8 logged moments — click to jump 14 Jul CFD calibration + rebrand7 logged moments — click to jump 16–17 Jul landing overhaul + real CFD flow7 logged moments — click to jump 17–23 July: no commits — the project sat idle for a week 24 Jul search-quality fixes8 logged moments — click to jump

Each band is one working stretch, sized by how much happened in it, not by literal duration — the ⋯ marks a real idle week. Ticks are logged moments below; click a band to jump there.

12 July 2026

Bootstrap — from nothing to a working Phase A pipeline in about ninety minutes

20:10–21:21

The project (then “framevo”) goes from empty repo to a working research loop in one sitting. A DXF-calibrated DroneAid 7-inch kit platform, a 14-gene genome including print material, a six-scenario portfolio with seeded Dryden turbulence, a GA with full lineage tracking, SQLite persistence with resume, and a Tufte-styled gallery with WebGL viewers — committed together as “Phase A complete,” co-authored by Claude Fable 5.

22:01

The patience/pivot mechanism is designed before the project has even run long enough to need it. Six generations without a ≥0.5% best-so-far improvement triggers a pivot: half the non-elite slots get bred from a tournament winner crossed with the most genetically distant still-decent candidate in the run’s history, mutation boosted, escalating to fully random far parents if the plateau survives another window. The threshold itself is grounded in run data gathered that evening: healthy improvement gaps run 1–4 generations; real plateaus coincide with population diversity collapsing below about 0.1.

22:37–22:56

The gallery is hardened for runs longer than a demo, then the day closes on a deliberate checkpoint. A density-adaptive progress chart and viewer-embedding caps go in so the report stays usable past a few hundred candidates. The last commit of the night is explicit about what’s coming: “parametric-primitive era complete before real-parts rebuild” — the genome so far deforms abstract primitive shapes, not a real drone. That rebuild is tomorrow’s job.

13 July 2026

The real-geometry rebuild — and the day the designer and narrator roles are born

10:10

The genome stops deforming shapes and starts morphing a real drone. It now bends the official TBS Source One V6 DXF plate outlines — real bolt holes, real cutouts — instead of abstract primitives. The first live headless-Claude “designer” round fires at generation 6 of the validating run, reasoning in plain aerodynamic language: one proposal, a “low-disk-loading cruiser,” bets that long, thick-section, waisted arms will cut induced power in storm and cold-headwind at the cost of stiffness margin.

~13:00

The new geometry immediately exposes a coupling the old primitives never had — and the narrator finds it before any human reads the code. Early candidates fail on “arm tongue bolts miss the main plate” and “arm root tongues collide,” and one lab-notebook note is blunt about a whole failed lineage: crossing plate size and arm length independently is “geometrically broken at the arm-plate joint regardless of material.”

~15:00

A screenshot-driven UI session turns up a real bug in one line. Iterating the 3D overlay’s default camera purely from before/after screenshots, a detail-card metric table renders with invisible text on the inverted dark band — no CSS rule explains it. The generated HTML was missing <!doctype html>: Chrome’s quirks-mode stylesheet silently blocks color inheritance into tables. One line fixed it.

15:13–16:28

A fast polish loop, verified live in the browser every round. Batches of screenshots — invalid-candidate overlays, inverted champion cards, pan and view-preset buttons — get fixed against a temporary local server (file:// can’t be scripted). One concrete miss: the new “front” view preset first showed the tail, not the nose — the yaw-to-view mapping had to be flipped before “front” actually faced the FPV camera forward.

16:35–16:51

A gut-check on the shapes themselves turns up the real gap of the day. Some plate sections look “pointy, fragile-looking” in the viewer; traced to the interactive blob decimating the whole deck to a 3200-face budget purely for display — a full-resolution render of the same plate is clean. While chasing that, Claude finds the thing that actually matters: arms had a structural check by this point, but plates had none at all.

~15:10

“We seem to again have lost 13 notes this round.” The narrator’s free-text JSON parsing keeps salvaging only partial results. Both narrator and designer move onto the claude -p CLI’s native --json-schema structured output, ending the malformed-JSON note losses for good — and picking up exact-model capture as a side effect.

17:54–19:52

Work pauses mid-task on a Claude Code session limit, right in the middle of building the plate hard-constraints Alexis had just asked for. It resumes about two hours later on a bare “continue” — the hard-constraints commit lands at 20:00, right on schedule after the reset.

19:52–20:00

Hard constraints land, specified exactly as the morning’s investigation had flagged them: plate web width ≥80% of stock, checked on the morphed outlines the same way arm tongue-bolt placement already was. A 300-genome random sample shows 30% of the raw gene space is now correctly rejected for web collapse; by 21:42 the check is already catching a live immigrant candidate: “plate web too thin (plate_main 1.51 mm, stock 1.90 mm).”

14 July 2026

CFD calibration finds the drag model was wrong by 2× — and the project becomes Airloom

00:02–00:46

The day opens mid-flight. A 30-generation run is already evolving under the previous night’s new battery-sag physics, seeded with a frog-inspiration file — the designer proposes an asymmetric “mid-leap” sweep and “webbed-foot” wide-thin arms once the search plateaus. In parallel, 12 OpenFOAM drag-calibration cases are queued and cfd-calibrate --jobs N is added so they solve concurrently — turning a projected half-day serial batch into an overnight job.

00:34

A real scaling problem gets fixed before it becomes a blocker. index.html had grown to 66 MB because every candidate’s 3D mesh was inlined directly into the page. Splitting meshes into lazy-loaded .mesh.js blobs drops it to 2.6 MB — removing an embed budget that would have made a 100-generation run too big to push to GitHub.

00:57

The project is renamed — carefully. “framevo” becomes “Airloom” (heirloom + air) at the display level first: gallery, lineage, glossary, README. The package and CLI stay framevo underneath for now, a deliberately staged rename to de-risk it before touching code.

01:43

The overnight calibration lands the biggest surprise of the project so far: the handbook drag model was wrong by roughly 2× at cruise tilt. Assembly interference turns out to be NEGATIVE — wake shielding and silhouette double-counting, −6% / −27% / −37% at 0°/20°/40° — and a contrasting genome comes back with nearly identical ratios, meaning the error is systematic, not gene-dependent. Applying the correction flips the robustness verdict from FRAGILE to STABLE and drops the champion’s own score from 8.13 to 6.21 Wh/km overnight, purely from fixing the model.

01:44

A near miss right behind it. The calibration commit had shipped its docs and tests but not aero.py itself — a failed git add on an ignored path had silently aborted staging mid-command, and a red test slipped past. Fixed a minute later, along with a note that under the corrected (lower) drag, the baseline essentially stops saturating in the storm scenario at all — expected, not a regression.

01:50–01:55

The gallery’s benchmark lines get re-derived under the new physics, and the rename finishes in one pass: src/framevosrc/airloom, 85 tests green, the GitHub repo moved to akaalias/airloom. A fresh run under the corrected model opens at generation 0 with 6.886 Wh/km — already dramatically below the old model’s 8.126 plateau.

02:52

A flight-replay tab ships, and one idea is deliberately cut. Champion flights across all six scenarios get re-simulated (fixed gust seeds give exact replays) into a 3D tab with a live HUD — speed, tilt, RPM, sagging pack voltage, a THRUST LIMITED flag. A weather-visualization overlay is prototyped alongside it and cut before shipping; the HUD alone carries the story. The real version of that idea would resurface two days later.

16 July 2026

The landing page leads with the result; a rejected decorative sketch becomes real CFD, by that evening

10:32–14:00

A small UX request quietly sets up the rest of the week. The single overlay button splits into “evolution” and a new “performance” view; baseline gets defined precisely as the first winning candidate of generation 0; every overlay view becomes a shareable deep link. Lazy-loading switches from native loading=lazy to an IntersectionObserver, specifically because Chromium prefetches lazy images in background tabs — which would have silently defeated lazy-loading on every shared link.

12:41

“The result is really the most interesting part for anyone not as obsessed about the process as I am.” That single request rebuilds the landing page around the champion and its score first, the full research log second — and cascades through the rest of the day: a shared viewer component library, live 3D candidate cards, an evolution-replay section, and a family tree later flipped so the newest generation renders on top, champion leading.

15:05–15:56

The sharpest dead end of the week, and the best recovery. Asked to revive “wind gust” lines on the weather views, two decorative attempts get rejected outright — “these are super duper weird… not like these random shitty strokes drawn on the background” — before Alexis asks directly whether the lines are simulating real airflow. They aren’t: only the free-stream direction was real. His answer is unambiguous: “we of course want real CFD streamlines.” airloom cfd-flow gets built the same day, reusing the calibration pipeline to solve real RANS flow over the champion’s assembly. First real streamlines render around 15:56 UTC.

17:53

A real production bug follows. The crosswind solve silently diverges around iteration 163 — pressure residuals never converge, continuity blows up, the container ends in a floating-point crash — and hangs the whole solve queue for roughly 1¾ hours before anyone notices. Fixed by hardening every flow case with a potentialFoam initialization pass and gentler relaxation factors.

18:30

A second, more conceptual bug: the atmosphere itself looked wrong. Posing the flow at the craft’s instantaneous replay attitude made the whole wind field tilt with it — “locked together unrealistically.” A first fix anchors the flow to the mean attitude instead (an acknowledged approximation); it’s superseded the same evening by solving several angles of attack around the mean and cross-fading live by the telemetry’s actual angle each frame, so the near field genuinely re-wraps as the craft pitches.

19:38–20:21

A second track running in parallel: can this actually be built? After confirming the champion’s 70 g frame mass and rendering printable SVG templates (“LOVE IT! They look fantastic.”), Alexis asks the load-bearing question: “our design’s arm holes match the plate holes? Like this could really be printed and assembled, correct?” Not yet — the bolt holes were still the stock pattern, unaware the sweep genes had rotated the arms off it. The fix re-cuts the arm-clamp holes into the actual placed-tongue positions, verified to 0.00 mm on all eight main-plate bolts. The validity checks are deliberately left seeing the old stock pattern, since feeding them the re-cut plates would have retroactively flipped 178 of the run’s 562 scored candidates’ validity.

19:13–23:30

The day closes on a share card, rejected and rebuilt, and a completed feature. An early share-image attempt is rejected hard for not matching the project’s own Tufte visual language, before converging on the final version: 84 real candidate silhouettes on bare paper, ink-only markers, regenerated fresh every run. By late evening, all six weather scenarios have their own quasi-steady CFD sweep — a feature that started as a rejected decorative sketch nine hours earlier.

24 July 2026

The 40-generation plateau gets a real diagnosis — twice in one day

morning

A finished 40-generation run reads as a plateau on the progress chart: 12% better than the baseline target, but flat for most of the back half. Rather than guess, the question gets answered against the actual database: run_20260714_015948, 562 candidates, 321 valid.

midday

Fitness turns out to be about 98% explained by frame mass alone. All six weather scenarios correlate above 0.99 with each other and with frame_mass; storm, which is always the worst-case scenario, carries roughly two-thirds of the fitness weight under the mean-plus-worst aggregation — so the elaborate six-scenario portfolio was behaving like a nearly one-dimensional “minimize mass” search. Separately, the champions turn out to be pinned exactly at the genome’s own artificial floor on four genes, not at the real structural limit — the box, not the physics, was stopping the search.

midday

A second finding: 43% of every evaluation in the run was invalid, wildly unevenly — immigrant candidates 90%, generation-0 seeds 73%, pivot breeding 60%, plain crossover 37%, the Claude designer only 10%. Almost all of it was pure geometry (tongue collisions, rotor overlaps, plate-too-thin-for-material) that doesn’t need a flight simulation to catch — and the designer’s own low rate turns out to be because it already runs every proposal through that same cheap geometry check before committing to it.

afternoon

Four changes land together, tested before touching the real run: the four floor-pinned gene bounds get widened; a repair/projection pass gives the GA’s own crossover, mutation and pivot operators the same cheap pre-screen the designer already had, bisecting an infeasible child back toward its parent instead of wasting the slot; blind immigrant sampling is replaced with resampling against that screen; and the pivot mechanism’s hypermutation is turned down from 3.0× to 1.6×, after the data shows pivot children had a worse invalid rate (60%) than plain crossover (37%) and never beat its best result.

afternoon

A real near-miss during testing, caught and fully reverted. A first sandboxed smoke test overwrites the project’s real published docs/ — the publish step mirrors results/ into docs/ unconditionally, regardless of a --results override, and only a full --root sandbox actually isolates it. Caught within the same exchange, fully restored via git checkout and git clean; the real run database (562 candidates) was never touched.

afternoon

The fix is verified against real physics before it touches the live run. A properly sandboxed end-to-end test shows crossover’s invalid rate drop from 37% to 0%, and every remaining failure across every operator is now a structural (flight-load) failure — the entire class of geometry/packing failures, 93% of the run’s historical invalid pool, is gone. The real run turns out to be fully resume-compatible (the genome-spec check only compares gene names, not bounds), so it resumes at generation 40 with its full 39-generation history intact rather than starting over. Generations 40–44 land at 86% valid against a historical average of 57%.

evening

Even with the fix landed, the chart still shows no quantum leaps — and the designer’s wildcard proposals keep scoring worse than the current best. The cause is a second, independent bug: the plateau detector compares each generation to a running best that itself creeps down every generation, so real, compounding progress (6.051→5.992 over 13 generations, about 1%) never crosses its 0.5% single-step bar — every designer round from generation 43 on fires as a “pivot” round, and the pivot prompt explicitly forbids refining the elites. Claude isn’t reasoning badly; it’s being told, every single generation, not to do the one thing that’s actually working — and its proposals dutifully go test PLA+ and ASA, materials the run’s own history already shows lose on mass.

evening

Both fixes land, checked against the real trajectory rather than guessed. min_rel_improvement drops from 0.5% to 0.15% — replayed against the run’s actual history, that turns a 13-generation stall reading (fully escalated, random-parent pivot) into a 3-generation one (a mild far-parent pivot, not full abandonment). The pivot prompt itself is softened: still mostly exploratory, but now explicitly permitted to spend one of its proposals pushing the current winning family further into newly-widened headroom instead of treating that headroom as another reason to abandon it. The loop restarts at generation 57 of a new 80-generation target, running now.

Compiled from git history and Claude Code session transcripts, 12–24 July 2026 — condensed for readability. The project’s own headless-Claude designer and narrator rounds are the loop’s research record, not conversations, and aren’t counted here as sessions. See the research log for the complete, machine-generated experiment record.

view on GitHub