Field notes / Experiment guide
The ant that stopped growing a blob
RLRLLL looks like a compact chaotic grower for billions of steps, then begins sweeping columns. What changes at that late transition?
New to these ants? Start here.
An ant moves on a grid of coloured squares. Each colour tells it to turn left (L) or right (R). It advances that square to the next colour, then steps forward. A rule such as RLR is the list of turns, starting at colour zero. On a blank grid the same rule always makes the same trajectory.
Territory means every cell visited so far. Its boundary consists of visited cells with an unvisited neighbour. A highway is a repeating pattern of motion that carries the ant away. A tether means repeated returns to a small home region.
Growing like the cube root of time means taking eight times as many steps to double a linear size. The rotor walker is a comparison model that follows and rotates arrows stored on cells. A seed makes a random starting pattern reproducible; the ant itself can still move deterministically.
We distinguish c, the chance of discovering a cell per boundary step, from kappa (κ), time at the boundary normalized by perimeter divided by area. Explaining their values is harder than using them to account for growth.
A closer look

The idea under test
A local signature combining geometry and growth efficiency might distinguish the new phase and recur in other unexplained escapes.
What we learned
The signature separates the known phases of RLRLLL. Its column sweep leaves a repeating three-colour wake, but the proposed shared global geometry in other escapes fails the registered test.
What this leaves open
This is one deterministic blank-grid trajectory. Describing the sweep does not explain its trigger, and global board escape does not reveal local anatomy.
Read the evidence and reproduction recipe ↗
Inside the experiment
Methods, registered predictions, exact commands and saved analysis. These are the working research documents; expand them for the detail behind the introduction.
Methods and original experiment record
g1-ribbon-breakout
Migrated legacy investigation (2026-10-14). Its files used to sit in the flat data/ directory (and calib/, occ/, snaps/, dumps*, knock* where listed) with the label prefix below; experiments/_migration/map.tsv gives the exact old -> new path of every file. This stub was generated from file names and script docstrings. It is not the original write-up: the question, timestamped hypotheses, commands and results are in notes/ (mainly notes/frontier-results.md, notes/frontier-status.md, notes/research-frontier*.md; search for the label), and the producing command is usually in the script docstring or a run_*.sh here.
Old labels / prefixes: g1
Scripts
scripts/g1_breakout_stats.py: dependencies = ["polars", "numpy"]scripts/g1_stats.py: G1 analysis of experiments/2026-10-13-g1-ribbon-breakout/results/g1_ribbon.csv (made by examples/ribbon_trace.rs). Predictions: notes/research-frontier-2026-10-
Results
3 entries in results/ (1 are .log/.done markers); csv/json/txt outputs, *_stats.txt hold the summaries quoted in the notes.
2026-10-15 21:22 NZDT: survivor comparison registration
Base commit da88e61b690507526ba4e2a2c017d9c7941beb91; existing dirty work is unrelated. Before computing the comparison: use every chunk CSV with a sibling .done in h1e10 and h1e11, separately (not the historical 240-rule subset). Escape means stop=escaped and empty period; no claim of infinite-time nonperiodicity. All runs are deterministic blank-board starts, no random seed.
Structural signature S: in complete 1M-step G1 windows, steps/new cell <8 AND axis-aligned new-cell box aspect >=20. Predict >=90% of the previously defined breakout windows (steps/new cell <10) satisfy S; <=5% of preceding complete fine windows satisfy S. Calibration: a synthetic 40-by-10000 slab at 4 steps/cell passes; a square at the same efficiency and a thin slow slab fail. This is a window-box signature, not a measurement of individual stroke width.
Transfer prediction T: >=75% of no-highway escapes in EACH completed census have whole-history box aspect >=2. This deliberately weaker census proxy tests whether elongated territory is shared; it cannot validate S in another rule. Compare against escaped recognised highways and budget survivors. Report all rules, dimensions and prior-decade expansion ratios where available. RLRLLL is a budget survivor at 1e10, so its later escape belongs to the 1e11 cohort. No new multi-billion-step simulations are needed for this archival comparison.
Recipe: uv run experiments/2026-10-13-g1-ribbon-breakout/scripts/compare_survivors.py under WSL with UV_PROJECT_ENVIRONMENT=$HOME/.venvs/turmite UV_LINK_MODE=copy. Outputs: results/survivor_comparison.json and results/survivor_geometry.csv. Input SHA-256 hashes and script hash are stored in the JSON. Re-run must give identical bytes. Historical generator: examples/ribbon_trace.rs (command in notes/research-frontier-2026-10-13-pm.md G1); census: src/bin/sweep_lean.rs, blank board, grid 32768, budgets 1e10/1e11, original logs beside chunks.
2026-10-15 archival outcome
S held: 281/298 complete breakout windows (94.3%), 0/676 preceding windows. Median efficiency 4.022 steps/new cell; median transverse window box 54 cells; the old <=12 prediction still fails (0/298). Partial final window excluded. T failed: 0/37 h1e10 and 0/3 h1e11 no-highway escapes have global aspect >=2. The completed h1e11 cohort is 324, not the historical 240 or planned 732. Its three no-highway escapes are RLLLLRRL, RLLLLRLRRL, RLLLRLRLLL; max-extent expansion relative to 1e10 is 1.1691, 2.1892, 8.5065. RLRLLL is in h1e10/chunk_29.csv (3377 x 3250), and in h1e11/chunk_27.txt without a completed CSV row. Its later evidence is the G1 trace, not a completed h1e11 census record. Full per-rule comparisons and input hashes are in outputs.
Interpretation: the efficient narrow-window signature is descriptive evidence for RLRLLL's phase switch, not an independently discovered mechanism. Global aspect does not identify local ribbons: even recognised highways usually have nearly square whole-history boxes at board escape. No shared local mechanism has been established for the other survivors. Need local-window traces and moving-frame recurrence tests, on larger boards, to distinguish parallel strokes from periodic translation. No new simulations or causal claims. Timestamp correction: registration's 21:22 was an estimated time; actual clock was 21:19 after the first analysis. Tool order establishes registration before run.
2026-10-16: paper figure and recovered wake archive
Presentation work, base commit c9811f56911ff4e7fd8cfe5e76cd5d461968265b.
Recovered the original note and exporter from worktree-g1-builder-structure
(c82030e), and compact extracts/draft from worktree-paper-figure-proposals
(b7c55f9 plus its untracked files). The exporter is now
examples/g1_ribbon_breakout_builder_dump.rs (dynamics unchanged). Historical
paths in the recovered note refer to that old worktree; current commands follow.
Raw dumps are retained in this experiment's ignored dumps/. Their SHA-256
hashes match the recovered extract manifest. No new long ant run was needed.
From the repository root in WSL, after setting
export UV_PROJECT_ENVIRONMENT=$HOME/.venvs/turmite UV_LINK_MODE=copy:
# Long regeneration, if raw dumps are absent: run in the background.
nohup bash experiments/2026-10-13-g1-ribbon-breakout/scripts/g1_builder_run.sh > experiments/2026-10-13-g1-ribbon-breakout/results/g1_regenerate.log 2>&1 &
# Fast archival extraction (writes only this experiment's results):
uv run experiments/2026-10-13-g1-ribbon-breakout/scripts/g1_wake_extract.py experiments/2026-10-13-g1-ribbon-breakout/dumps
uv run research-outputs/cube-root-growth-paper/late_switch_figure.py
typst compile --root . research-outputs/cube-root-growth-paper/main.typ research-outputs/cube-root-growth-paper/main.pdf
# Optional PDF rendering/byte-repeat verification; pypdfium2 version is recorded:
uv run --with pypdfium2==5.14.0 experiments/2026-10-13-g1-ribbon-breakout/scripts/verify_figure.py
Compact results are g1_wake_extract.json, g1_wake_crop_*.csv,
g1_wake_shape_*.csv, and g1_sweep_trace_*.csv. The paper script reads only
results, never raw dumps. Output PDF/PNG and late_switch_numbers.json live in
research-outputs/cube-root-growth-paper/fig/; that JSON hashes source and inputs.
No randomness: one blank-board RLRLLL trajectory, 32768 board; 400,000-step
windows at 12.8 and 12.9 billion steps. Wake snapshots are at each window's END;
trace sample 0 is the position after the first step of each window (an offset of
one step relative to the displayed elapsed-time origin, negligible here).
Reproduced comparisons: L=6400/8610, predicted d|x|²/dt=0.864883/0.835453, measured 0.862245/0.832701. Use the original analysis's strict symmetric +/-20,000,000-step window (39 samples), OLS slope of |x|, times 2|x(t0)|. The draft used an alternative x² fit and an asymmetric endpoint inclusion; we restored the original reported method. This is an archival consistency check, not a changed scientific estimator or new evidence for a scaling law. The wake figure uses the first 48 rows of the 36x80 extract, square cells, unvisited white. Full extracted-wake lag-3 agreement is 0.994327/0.994538. No between-seed uncertainty is estimable from this trajectory.
Validation: the compact CSVs regenerate byte-identically; raw hashes match.
check_builder_dump.py checks all sampled trajectory states and ALL wake bytes
against an independent obvious ant loop for all 28 rules of lengths 2--4,
2000 steps each; results/builder_oracle_check.log records success. Build the
exporter with cargo build --release --example g1_ribbon_breakout_builder_dump.
The full cargo test --release suite passed (results/figure_release_tests.log).
No instrument change; no new rotor calibration. The shareable notebook adds a
results-only figure section, executed via the command in
scripts/update_figure_notebook.py; execution log results/figure_notebook.log.
Analysis notebook: notebook.ipynb
4 saved outputs · 3 code cells. Cells are not executed during publication. Download notebook
Question and why it matters
Does RLRLLL share a measurable escape structure with census survivors? See README.md and ../../notes/open-questions-hypotheses.md. # Assumptions and definitions Blank starts are deterministic (no random seed). Census extents cover whole history; G1 extents cover new cells per window. Only completed chunks enter cohorts. Windows are correlated. # Provenance, data and method The JSON records every input SHA-256, base commit, recipe and producing script hash. No heavy simulation runs here.
Code
from pathlib import Path
import json
root = next(p for p in [Path.cwd(), *Path.cwd().parents] if (p / 'Cargo.toml').exists())
p = root / 'experiments/2026-10-13-g1-ribbon-breakout/results/survivor_comparison.json'
d = json.loads(p.read_text())
print('Base commit:', d['base_commit'], 'Registration:', d['registration'], 'Seed:', d['seed'])
for path, digest in d['input_sha256'].items():
print(path, digest)
print('Trace:', d['trace'])
print('Census:', d['census'])
print('Transfer passed:', d['transfer_prediction_pass'])
Results
S passes in 281/298 complete breakout windows and 0/676 preceding windows. This distinguishes the already known phases; it does not establish a mechanism. Zero of 37 earlier and 3 later no-highway escapes satisfy global aspect >=2. This fails T; it does not test their local ribbon geometry. # Caveats and controls Synthetic efficient slab passes, square and slow slab fail. Historical <=12-cell prediction fails (0/298). Thresholds use historical knowledge. Partial final window excluded; no window-based uncertainty. Later census only 324 completed rules, RLRLLL later row absent. Square-board censoring limits global geometry. # What this changes / next steps A reproducible local signature exists for RLRLLL. Shared local anatomy remains open. Record local windows for all three later escapes with larger-board and recognised-highway controls; apply S unchanged and test moving-frame recurrence.
Archival figure: question and assumptions (2026-10-16)
Can one figure show the late efficiency switch, the period-3 wake and the quantitative sweep check? This is a presentation of existing measurements, not a new experiment. See README.md and ../../notes/g1-builder-structure-2026-10-14.md. One deterministic blank-board RLRLLL trajectory; no random seed, no independent replication. Wake snapshots are taken after each 400,000-step dump.
Code
from pathlib import Path
import hashlib, json, subprocess
import numpy as np
import polars as pl
import matplotlib.pyplot as plt
ROOT = next(p for p in [Path.cwd(), *Path.cwd().parents] if (p / 'Cargo.toml').is_file())
G1 = ROOT / 'experiments/2026-10-13-g1-ribbon-breakout/results'
names = ['g1_ribbon.csv', 'g1_wake_extract.json', 'g1_wake_crop_12800000000.csv', 'g1_sweep_trace_12800000000.csv']
print('commit:', subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=ROOT, text=True).strip())
print('section date: 2026-10-16 NZDT; seed: none (deterministic blank board)')
for name in names:
print(name, hashlib.sha256((G1 / name).read_bytes()).hexdigest())
ext = json.loads((G1 / 'g1_wake_extract.json').read_text())['dumps']
Data, method and results
Original simulation: recovered examples/g1_ribbon_breakout_builder_dump.rs.
scripts/g1_wake_extract.py makes these compact results; the notebook reads
only committed results. The original post-hoc check fits |x| in a strict
±20,000,000-step window around each dump, then multiplies by 2|x(t0)|.
The model uses 3 columns per 12L steps, hence d|x|²/dt = |x|/(2L).
Code
d = pl.read_csv(G1 / 'g1_ribbon.csv').filter(pl.col('t_end') > 12_000_000_000)
rows = []
for t0 in (12_800_000_000, 12_900_000_000):
e = ext[str(t0)]
w = d.filter((pl.col('t_end') - t0).abs() < 20_000_000)
t, x = w['t_end'].to_numpy(), np.abs(w['x'].to_numpy())
pred = (abs(e['x_start']) + abs(e['x_end'])) / (4 * e['L_traj'])
measured = 2 * np.interp(t0, t, x) * np.polyfit(t - t0, x, 1)[0]
rows.append({'t0': t0, 'L': e['L_traj'], 'predicted': pred, 'measured': measured, 'windows': w.height})
print(pl.DataFrame(rows))
e = ext['12800000000']
crop = pl.read_csv(G1 / 'g1_wake_crop_12800000000.csv')['colour'].to_numpy().reshape(80, 36)[:48]
from matplotlib.colors import ListedColormap
palette = ['#e3e3e3', '#1fa187', '#e8a33d', '#7a3b8f', '#5fb3d9', '#8c6d31', '#ffffff']
fig, ax = plt.subplots(figsize=(2, 2.8))
ax.imshow(np.where(crop == 255, 6, crop), cmap=ListedColormap(palette), vmin=0, vmax=6, origin='lower', interpolation='nearest')
ax.set_title('Actual period-3 wake crop'); ax.set_axis_off(); plt.show()
Caveats, controls and next steps
The wake has a strong three-column repeat, and the two local rates agree with the sweep picture. These observations do not explain period 3 or the trigger. The two heights and positions come from one trajectory; this is not an independent test of L proportional to |x|, and no between-seed error bar is available. Exporter trajectories and all wake bytes were checked against an independent obvious ant loop for all 28 rule strings of lengths 2–4; the Rust release suite is a separate simulator check. No estimator changed, so no new rotor calibration is implied. See results/builder_oracle_check.log. Next: obtain a third sweep-height sample and investigate the switching trigger.
Read the dated lab log
G1 lab notebook
2026-10-15 21:22 (+13:00) · da88e61 · intent
User requested RLRLLL anatomy and comparison with other escaped-without-highway survivors. Read Q8, frontier G1 and its withdrawal before analysis. Register S and T in README before computing; reuse existing traces and all completed chunks.
2026-10-15 21:22 (+13:00) · da88e61 · assumption
Census extents are whole-history bounding boxes (verified in sweep_lean source), not local ribbon thickness. A failed transfer proxy cannot refute local ribbons. Blank starts are deterministic; rules, not windows, are the sampling units.
2026-10-15 21:20 (+13:00) · da88e61 · deviation
Timestamp correction: the registration and initial entries say 21:22, entered from an estimated clock; actual tool clock after analysis was 21:19. Registration was written before running compare_survivors.py, as tool order records. Keep the original text intact. No new trajectory simulations were run. WSL required a sandbox escalation after E_ACCESSDENIED; the approved retry succeeded.
2026-10-15 21:20 (+13:00) · da88e61 · observation
Command: uv run experiments/2026-10-13-g1-ribbon-breakout/scripts/compare_survivors.py. Outputs: results/survivor_comparison.json, results/survivor_geometry.csv. Complete fine windows: 974; breakout 298, preceding 676. S passes in 94.2953% of breakout and 0% preceding windows. Median steps/new cell 4.022; transverse new-cell box median 54; none <=12. First breakout window ends 12677000000. The historical 299-window count includes the partial final window excluded here. Census: h1e10 has 807 rules (732 budget, 38 highway, 37 no-highway escapes); h1e11 has 324 completed rules (317 budget, 4 highway, 3 no-highway escapes). Zero of 37 and zero of 3 no-highway escapes have aspect >=2. Transfer T fails in both cohorts. Median aspects are 1.000031 and 1.002050 respectively. Later escapes: RLLLLRRL, RLLLLRLRRL, RLLLRLRLLL. Their maximum-extent expansion from 1e10 is 1.1691, 2.1892, 8.5065 respectively (not a rate or local thickness). RLRLLL is h1e10/chunk_29.csv: budget, 3377 x 3250 at 1e10. It is listed in h1e11/chunk_27.txt but has no completed CSV row; its escape comes from G1.
2026-10-15 21:20 (+13:00) · da88e61 · dead-end
T is falsified. Whole-history box aspect is a poor transfer instrument: even 37 of 38 earlier recognised highways fail aspect>=2. Stopping on a square board and pre-existing territory confound this proxy. It cannot classify local ribbons or rule out repeated strokes that together fill a square box. The original G1 <=12-cell prediction remains failed; efficiency is not periodicity.
2026-10-15 21:20 (+13:00) · da88e61 · interpretation
S separates the two already known RLRLLL phases descriptively; thresholds were chosen with historical G1 summaries in view, so this is not independent discovery or a causal test. Window counts are correlated, no window-based confidence interval. Other survivors share board escape but do not share elongated whole-history boxes. Their local mechanism is unmeasured. No evidence here establishes a surface wave, a repeat period, or an asymptotic universality class.
2026-10-15 21:20 (+13:00) · da88e61 · decision
Close archival comparison with failed T reported. Next discriminating measurement: record equal-duration local windows for all three later escapes on a larger board, plus pre-onset and recognised-highway controls; apply S unchanged, add moving-frame tape/field recurrence to distinguish parallel strokes from periodic translation. Do not treat absent unfinished chunks as budget survivors or merge decades as iid.
2026-10-15 21:23 (+13:00) · da88e61 · observation
Verification: second analysis run produced identical SHA-256 for both outputs: JSON f0fcadf227826de070f3c19d22b07c1cfe3b411d3e66dda433597a9607e300a4; CSV 6cad1fdcb8e15e297572ec7777b05cd9fdbc7f4be7028f3b436be25113c7c507. Shareable notebook executed top to bottom via uv run --with nbconvert --with ipykernel --with nbformat jupyter nbconvert --to notebook --execute --inplace experiments/2026-10-13-g1-ribbon-breakout/notebook.ipynb. cargo test --release passed; log results/comparison_tests.log. No dependencies changed. New results are pending commit because the user did not request one; notebook reads only results paths, which should be committed together.
2026-10-16 21:09 NZDT · c9811f5 · intent
User requested a three-part paper figure: switch, period-3 wake, and predicted versus measured d|x|²/dt. Recovered an existing draft and compact extracts from worktree-paper-figure-proposals (b7c55f9 plus untracked files); original exporter, raw dumps and hypothesis note from worktree-g1-builder-structure (c82030e). Use archival inputs, verify hashes and extract reproduction before plotting. No new physical hypothesis, estimator or simulation measurement is proposed.
2026-10-16 21:16 NZDT · c9811f5 · observation
Raw dump SHA-256 hashes matched the archived manifest. g1_wake_extract.py reproduced every recovered compact CSV byte-for-byte. The original scaling analysis uses strict +/-20M windows and the slope of |x| times 2|x(t0)|; the draft used a different fit. Restored the original method, reproducing 0.862245 and 0.832701 (39 samples each) versus 0.864883 and 0.835453 predicted. Commands and outputs: README and paper fig/late_switch_numbers.json. Independent exporter check passed all 28 rules of lengths 2--4, including all wake bytes; cargo test --release passed. See results/*check.log and figure_release_tests.log. First check attempted length-1 rules, correctly rejected by Rule parsing; test domain corrected to valid rule lengths. The first plot build needed a Polars integer-index cast; initial Typst caption needed spaced math identifiers. Both corrected. Notebook execution passed.
2026-10-16 21:16 NZDT · c9811f5 · decision
Recovered originals instead of starting the proposed new simulation. Cropped the displayed wake to 36x48 square cells and added the sweep trace to panel b; caption distinguishes snapshot end time from trajectory start. PDF page 28 visually checked: complete figure and caption, no clipping. Two local rates remain post-hoc same-trajectory consistency checks, without seed error bars. Intent timestamp 21:09 was approximate; actual first tool clock was 21:08:56.
2026-10-16 21:21 NZDT · c6b5053 · observation
Archive and reproduction tools committed in c6b5053. Verified raw hashes, byte-identical re-extraction, and byte-identical PDF/PNG on repeat: results/ figure_verification.json (renderer pypdfium2 5.14.0). Figure is on manuscript page 28. Final legend includes all six states because boundary defects include states 0--2; amended prose from exact periodicity/only 3--5 to strong periodicity and dominance by 3--5, matching the measured 0.994 agreement. Notebook rerun against committed results. No full unrelated-figure rebuild was needed.
2026-10-16 21:19:04 NZDT · c6b5053 · decision
Closing status: figure, caption, audit recovery, rebuild hook and shareable notebook complete; final rendered page inspected, verification passed. The previous 21:21 heading was an estimate written ahead of the clock; actual clock at this closing entry is 21:19:04. Next figure proposals remain unimplemented.
2026-10-17 17:37 (+13:00) · b7c55f9 · intent
Build paper figure item 4 (notes/paper-figure-proposals-2026-10-16.md): RLRLLL column-sweeper figure (steps per new cell with the switch; period-3 wake crop; predicted vs measured d|x|^2/dt). No new simulation; reuse g1_ribbon.csv and the two existing builder_dump trajectories (1.28e10, 1.29e10).
2026-10-17 17:37 (+13:00) · b7c55f9 · decision
Dumps (38 MB each, gitignored, only in sibling worktree g1-builder-structure at 18b49fc) are not read by the figure. New scripts/g1_wake_extract.py is their only reader and writes a small committed extract (g1_wake_extract.json, g1_wake_{shape,crop}
2026-10-17 17:37 (+13:00) · b7c55f9 · deviation
The original data/g1_builder_*.py analysis scripts were never ported (flagged "absent from checkout" in the paper audit table); g1_wake_extract.py supersedes the parts used here. Also restored examples/builder_dump.rs and notes/g1-builder-structure-2026-10-14.md from commit 18b49fc; the example builds under cargo --release (checked, no API drift). cargo test --release not rerun: no Rust source changed.
2026-10-17 17:37 (+13:00) · b7c55f9 · observation
Reproduced from the extract: switch t = 1.2677e10 (g1_stats.py rule); L = 6,400 / 8,610; |x| = 11,070 / 14,386; predicted d|x|^2/dt = |x|/(2L) = 0.865 / 0.835; measured (polyfit of x^2 vs t over 40 fine 1e6-step windows within +-2e7 of each dump) 0.860 / 0.832, matching the paper's 0.86,0.84 vs 0.86,0.83. Wake colours 3,4,5 each ~0.33; lag-3 column agreement 0.994, lags 1,2,4,5 < 0.003. The earlier g1 note's 0.862/0.833 used a slightly different window; difference in the third decimal.
2026-10-17 17:37 (+13:00) · b7c55f9 · interpretation
Panel d is a consistency check, not a test of L ~ |x|: both L values come from one trajectory (n = 1 run, no replicates). The figure caption and main.typ say so. Trigger of the switch and the origin of period 3 remain unexplained.
2026-10-17 17:37 (+13:00) · b7c55f9 · observation
Figure inserted in main.typ (sec:late-switch, Figure 16) and registered in rebuild_figures.py (SCRIPTS and INPUTS). typst compile succeeds; figure checked at final width in the compiled PDF. The full rebuild_figures.py was not run (it regenerates every figure); only late_switch_figure.py was run.
2026-10-19 (+13:00) · merge · deviation
The 2026-10-17 17:37 entries above come from worktree-paper-figure-proposals (b7c55f9) and describe the same figure as the 2026-10-16 entries from main (c9811f5/c6b5053), built independently. Main's version is kept in the tree: exporter renamed examples/g1_ribbon_breakout_builder_dump.rs (the branch's builder_dump.rs is not carried over), 36x80 crop, results/figure_verification.json. The two extractions agree on L, |x| and the predicted and measured d|x|^2/dt (0.865/0.835 vs 0.860/0.832 in the branch's polyfit; the main-line restored the original strict +-2e7 window: 0.862245/0.832701). Branch-side differences (x^2 polyfit, 48-row crop) are superseded.