← All experiments

Field notes / Experiment guide

Does the opening-run effect survive a different growth clock?

A rule’s initial run of identical letters predicts boundary occupation after area adjustment. Does using current rather than early area change that association?

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.

The idea under test

Matched rule families with fixed composition should retain a positive effect if early-area conditioning is not creating it.

What we learned

The support gate fails: too few complete families survive. The registered effects are therefore not fitted or scored.

What this leaves open

Differential retention is the result here, not evidence for or against the effect. Lowering the gate after the run would change the test.

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

Does the leading run predict boundary occupation beyond the growth clock?

Registered 2026-10-16 21:14 +13:00, base c9811f56911ff4e7fd8cfe5e76cd5d461968265b, dirty shared workspace. No measurements of this cohort have been made.

Question and design

The fresh-leading-run study found a positive lead coefficient after controlling early area, but early area is a post-treatment variable and the mutation response is asymmetric. Does the association survive replacing early area with area at the actual measurement window? This is a descriptive growth-history audit, not a causal adjustment or a new explanation for kappa.

Generate 16 independent nine-letter suffixes using numpy default_rng(2026101607). Each family contains four 14-letter rules R^k L R^(4-k) SUFFIX, k=1..4. Thus length, total R count and all letters at indices >=5 are identical within family. Exclude any family containing a rule in the earlier fresh or mutant manifests. Four fresh patch seeds 202610160701..202610160704; probe 24 4096 (2^24 steps). These are fresh rules and starts; neither stationarity nor growth exponent is used to select the cohort. Moving the first L also changes its index: this design does not distinguish lead length from the position of that letter.

Primary window k=23, secondary k=21,22. Early area is end-of-window A18. For each rule, average logs across seeds that complete the target and early windows with B>0. Require >=3/4 seeds per rule. Report all escapes and exclusions. Primary gate: >=12 complete families, all four rules qualifying. Fit only those complete families; report selection by lead. Gate failure makes scientific predictions uninformative. Report between-seed sd alongside means.

Predictions fixed before measurement

Thresholds are design choices. Primary P1: in OLS ln kappa ~ spline(ln A23)+lead, the lead coefficient is positive with 95% family-bootstrap interval above zero and at least half its coefficient in ln kappa ~ spline(ln A18)+lead. Splines are linear hinges at 25/50/75% training quantiles, with a linear term and intercept. If the early coefficient is <=0, the expected effect has not replicated and P1 fails.

P2: adding lead to the current-area spline improves leave-one-family-out R2 by >=0.05, with lower 95% family-bootstrap interval above zero. R2 denominator is squared deviation from each fold's training mean. Knots are fit in each fold. Bootstrap 2000 draws, seed 2026101608; gain intervals resample out-of-fold loss contributions by family (uncertainty conditional on fitted folds).

Specificity/accounting, descriptive only: decompose the lead coefficient using ln kappa = ln(B/S) - ln(P/A), with exactly the same design matrix. Report current area + early area (linear) sensitivity, and all three windows. Never call this decomposition independent prediction. No intervention is justified by this audit.

Controls and reproducibility

Before ant analysis, calibrate coefficient recovery and zero added signal on synthetic responses in the exact spline model; verify the decomposition identity. There is no growth-exponent estimator in this experiment, so rotor/random-walk exponent calibration is not used. Run release tests. Spot-check four first-family specs on CPU against GPU, byte for byte, before the main GPU batch; GPU lanes=256, pool=4 GB, grid=4096. Record source/input hashes, exact commands and dirty state. Batch checkpoint .done is accepted only when recipe hashes match. Completed CSV windows are published under results; bulk CSV stays in dumps. No existing results are overwritten. All scripts run from the repo root under uv in WSL.

export UV_PROJECT_ENVIRONMENT=$HOME/.venvs/turmite UV_LINK_MODE=copy
uv run experiments/2026-10-16-kappa-growth-clock/scripts/sample.py
bash experiments/2026-10-16-kappa-growth-clock/scripts/run.sh
uv run experiments/2026-10-16-kappa-growth-clock/scripts/analyse.py
uv run --with nbconvert --with ipykernel --with nbformat jupyter nbconvert --to notebook --execute --inplace experiments/2026-10-16-kappa-growth-clock/notebook.ipynb

Related: ../2026-10-16-kappa-leadrun-fresh/README.md, ../../notes/kappa-mechanisms-2026-10-15.md. No literature claim is being made.

Results

UNINFORMATIVE: support gate failed. All three windows retain only 7/16 complete families versus the required 12. P1/P2 were not fitted or scored. There are 212 usable starts of 256 in each window; 40 miss A18 and four more miss the target. Overall 45 starts eventually escape, including one after a complete target window. No zero-boundary exclusions occur. Qualifying rules (>=3 starts) by lead 1/2/3/4: 16/9/15/13 out of 16 each. This is differential retention, not evidence for or against the lead effect.

Do not lower the gate or interpret a survivor-only fit as confirmation. A larger board could diagnose censoring, but this run does not identify highways or other growth regimes; no detector was run. Any follow-up must retain this cohort, preserve its failures and register its cap/grid before measurement.

Recipe: commands above, base c9811f5 (dirty source hashes in results/run-sources.sha256; frozen protocol in results/registration.md). results/seed_status.csv lists every exclusion; rule_means_k*.csv includes all 64 rules, with n=0 for absent usable starts. results/windows.csv publishes k=18..23; analysis.json records hashes, counts and estimator calibration. Seeds and parameters remain as registered. No effect uncertainty is reported because the gate stopped fitting; per-rule between-seed sd(log kappa) is in the CSV summaries where available.

All release tests passed, GPU probe tests 5/5 passed, and four CPU/GPU 2^24 trajectories are byte-identical. Synthetic planted slope 0.20 is recovered to roundoff; with correlated lead/area and family noise, 200 synthetic repeats have mean bias +0.000212 for both null and planted 0.15 slopes. The known area-only cross-validation gain is 0.0000231. These calibrate the instrument, not the ants. GPU batch: lanes=256, pool=4 GiB, grid=4096, 15.66 seconds, no requeues (descriptive timing, no CPU speed benchmark). The notebook is executed separately.

The full 256-spec CPU replay is byte-identical to the frozen GPU output (results/cpu-replay-check.txt). This also supplies a reproduction path without the GPU port, which was uncommitted shared work when this investigation ran: bash experiments/2026-10-16-kappa-growth-clock/scripts/replay_cpu.sh. If the GPU dump is absent, copy dumps/cpu-replay.csv to dumps/probe.csv inside this experiment before running analyse.py. The replay verifies the frozen digest before reporting success. scripts/check_replay.py verifies seven published analysis files byte for byte; batch resume verifies its recipe/digest.

Analysis notebook: notebook.ipynb

3 saved outputs · 3 code cells. Cells are not executed during publication. Download notebook

Question and why it matters

Does opening-run length predict late boundary occupation after adjusting for the area reached in that same window? Earlier area is a post-treatment variable and may leave growth-history confounding. See registration and results and mechanism context.

Assumptions and definitions

Kappa = (B/S)/(P/A), where B counts steps starting on visited boundary cells and P counts visited cells with an unvisited four-neighbour. All quantities use the probe's octave windows. Conditioning on area is descriptive and cannot estimate a causal direct effect. Constant composition does not distinguish leading-run length from first-L position. CPU/GPU equivalence is checked before the sweep.

Code
In [1]:
from pathlib import Path
import hashlib, json
SEED = 2026101608
root = Path.cwd().resolve()
while not (root / 'Cargo.toml').exists():
    if root == root.parent:
        raise RuntimeError('Repository root not found')
    root = root.parent
exp = root / 'experiments/2026-10-16-kappa-growth-clock'
paths = [exp / 'results' / s for s in ['analysis.json', 'cohort.csv', 'windows.csv', 'registration.md', 'spot-check.txt']]
for p in paths:
    assert p.is_file(), p
    print(str(p.relative_to(root)), hashlib.sha256(p.read_bytes()).hexdigest())
report = json.loads(paths[0].read_text())
print('Seed:', SEED, 'Simulation base commit:', report['git'])
print('Run commit:', (exp / 'results/run-commit.txt').read_text().strip())
print('Date: 2026-10-16 +13:00; exact raw/source hashes are in analysis.json and run-sources.sha256')
experiments/2026-10-16-kappa-growth-clock/results/analysis.json 7a1f4217c22346d6325c3566d08178305b2ea6dad4947bc6f427e5d829fbd74e
experiments/2026-10-16-kappa-growth-clock/results/cohort.csv 9bdf18c4493f1d549fd7d510b3572cdb7541273b863948c5df428b956fe7f848
experiments/2026-10-16-kappa-growth-clock/results/windows.csv c5df342a3bea1b6ce188b0c731f23a87edadb34f556a1186ad3d2484b9c08239
experiments/2026-10-16-kappa-growth-clock/results/registration.md 8e926fab77367d0c9221df239a2bc9d9dcb560ffe36781d7cbd3f2ab7a72c557
experiments/2026-10-16-kappa-growth-clock/results/spot-check.txt 2a85d93856130e93831452b6d751f0adf9f8337c5443d911da26d0b2e5d4abe3
Seed: 2026101608 Simulation base commit: c9811f56911ff4e7fd8cfe5e76cd5d461968265b
Run commit: c9811f56911ff4e7fd8cfe5e76cd5d461968265b
Date: 2026-10-16 +13:00; exact raw/source hashes are in analysis.json and run-sources.sha256

Data and method

Sixteen nine-letter suffixes each supply four 14-letter rules with leading runs 1..4; all rules in a family have equal composition. Four patch seeds per rule, 2^24 steps, grid 4096. Primary k=23, secondary k=21,22; early area is A18. No stationarity or exponent filtering. Require three completed seeds per rule and twelve complete families. OLS area controls use training-fitted spline hinges. Prediction uses leave-one-family-out folds. Uncertainty resamples whole families. The heavy computation lives in scripts/run.sh and scripts/analyse.py; this notebook reads only published results and makes no new estimates.

Code
In [2]:
print('Runs:', report['runs'], 'Escaped:', report['escaped'])
print((exp / 'results/spot-check.txt').read_text().strip())
print((exp / 'results/cpu-replay-check.txt').read_text().strip())
print(json.dumps(report['calibration'], indent=2))
print('Attrition:', report['status_counts'])
Runs: 256 Escaped: 45
Four specs byte-identical: probe/gpu_probe 24 4096
Full CPU replay: all 256 specs byte-identical to frozen GPU CSV
{
  "null_slope": 1.6004895062095795e-16,
  "planted_slope": 0.2000000000000002,
  "accounting_error": 0.0,
  "noisy_repetitions": 200,
  "noisy_null_mean": 0.00021200019296161492,
  "noisy_planted_mean": 0.1502120001929615,
  "known_null_cv_gain": 2.307788105654426e-05,
  "scope": "Exact spline coefficient and identity calibration; no exponent estimator used."
}
Attrition: {'k21': {'missing_early_window': 40, 'missing_target_window': 4, 'valid': 212}, 'k22': {'missing_early_window': 40, 'missing_target_window': 4, 'valid': 212}, 'k23': {'missing_early_window': 40, 'missing_target_window': 4, 'valid': 212}}

Results

The early and current slopes use the same response and rules, changing only the area-control window. P1 requires the current slope to retain half the early slope and have a positive interval. P2 requires gain >=0.05 and a positive interval.

Code
In [3]:
for r in report['windows']:
    print('Window', r['k'], 'families', r['complete_families'], 'retention', r['qualifying_by_lead'])
    if not r['gate_passed']:
        print(r['verdict']); continue
    print('Early slope %.4f %s; current %.4f %s' % (r['early_slope'], r['early_ci'], r['current_slope'], r['current_ci']))
    print('Held-out gain %.4f %s; P1 %s; P2 %s' % (r['gain'], r['gain_ci'], r['P1'], r['P2']))
    print('Accounting: boundary %.4f - edge fraction %.4f = kappa %.4f' % (r['boundary_log_slope'], r['edge_fraction_log_slope'], r['current_slope']))
    print('Both-area linear slope %.4f; median between-seed sd(log kappa) %.4f' % (r['both_area_linear_slope'], r['between_seed_sd_median']))
Window 21 families 7 retention {'1': 16, '2': 9, '3': 15, '4': 13}
UNINFORMATIVE: complete-family support gate failed
Window 22 families 7 retention {'1': 16, '2': 9, '3': 15, '4': 13}
UNINFORMATIVE: complete-family support gate failed
Window 23 families 7 retention {'1': 16, '2': 9, '3': 15, '4': 13}
UNINFORMATIVE: complete-family support gate failed

These tables show whether the registered association survives a different growth-clock control. They do not separate cause from response to growth history.

Final verdict: UNINFORMATIVE. All three windows retain seven complete families, below the registered twelve-family gate. P1/P2 were not fitted or scored. Of 256 starts, 45 eventually escape; 40 miss the early window and four more miss the targets. The 212 valid starts do not supply balanced families. This does not support or reject the lead association.

Caveats and controls

Synthetic exact-spline and correlated-noise controls calibrate the regression; the coefficient decomposition is an identity. CPU/GPU outputs are compared byte for byte on all 256 specs and release tests recorded. The cohort has only sixteen independent suffix families and uses a shorter horizon than the previous 2^27 study. Area and perimeter are measured on the response trajectories; neither is an independent causal control. Gain intervals condition on fitted folds. Support failure means uninformative, and failed thresholds remain failed.

What this changes / next steps

Read the frozen primary verdict in results/analysis.json together with the final README interpretation. If current-area adjustment removes the association, early area alone was insufficient at this horizon; if it survives, test transport with independent pre-window predictors before interventions. Longer-horizon and fixed-area replication are needed in either case.

Open questions: how much is survivor selection, which field history matters, and can first-L position be separated from opening-run length?

Read the dated lab log

Lab notebook

2026-10-16 21:14 (+13:00) · c9811f5 · intent

User requested a fresh experiment. Test whether the leading-run association survives contemporaneous area adjustment, using new paired-suffix families and fresh seeds. Registration is in README.md. Keep work isolated because the shared tree contains ongoing GPU and ribbon work.

2026-10-16 21:14 (+13:00) · c9811f5 · assumption

The current CPU/GPU probe implements the same octave window definition. Verify four specs byte-for-byte before trusting the GPU batch. Conditioning on current area remains post-treatment and cannot identify a direct causal lead effect.

2026-10-16 21:14 (+13:00) · c9811f5 · decision

Use constant length/composition families instead of independent random rules. Choose leads 1..4 because the prior study lost many high-lead rules; do not filter stationarity here. Record retention rather than silently changing the cohort.

2026-10-16 21:18 (+13:00) · c9811f5 · observation

bash experiments/2026-10-16-kappa-growth-clock/scripts/run.sh completed. results/release-tests.log passes, gpu-tests.log has 5/5 passes, and spot-check.txt records four byte-identical CPU/GPU trajectories. The GPU batch has no pool requeues (results/gpu.json). Synthetic controls from uv run experiments/2026-10-16-kappa-growth-clock/scripts/calibrate.py recover the planted coefficient; finite-noise mean bias is +0.000212 over 200 repeats (results/calibration.json).

2026-10-16 21:18 (+13:00) · c9811f5 · observation

uv run experiments/2026-10-16-kappa-growth-clock/scripts/analyse.py yields 7/16 complete families in all three windows; support threshold is 12. results/analysis.json and seed_status.csv: 45/256 eventual escapes, 40 missing early windows, four further missing target windows, 212 usable starts. rule_means_k23.csv: qualifying rule counts 16/9/15/13 by lead. No models fit.

2026-10-16 21:18 (+13:00) · c9811f5 · surprise, interpretation

Restricting lead to 1..4 did not preserve balanced support. Lead 2 loses most rules here, unlike a monotone high-lead attrition story. This does not diagnose highways: the instrument only records board escape. The complete-family gate prevents an unplanned survivor analysis. Growth-clock confounding remains open.

2026-10-16 21:18 (+13:00) · c9811f5 · decision

Close as UNINFORMATIVE. Keep the cohort and threshold fixed; do not expand the board or replace families after seeing attrition. Publish all seed statuses, including rules with no usable starts. Next candidate is a separately registered censoring audit on this same cohort. Finish notebook execution and deterministic rerun checks before committing the final record.

2026-10-16 21:21 (+13:00) · 9af869a · deviation

First replay comparison failed because another investigation committed to the shared branch between analysis runs, changing the report's ambient HEAD field. No scientific decision changes. Pin that provenance field to run-commit.txt; the analysis source is separately SHA-256 pinned. Rerun analysis and require byte-identical outputs before closing. Preserve unrelated staged/working changes.

2026-10-16 21:23 (+13:00) · 9af869a · observation

bash experiments/2026-10-16-kappa-growth-clock/scripts/replay_cpu.sh reproduces the entire 256-spec GPU CSV byte for byte (results/cpu-replay-check.txt). uv run experiments/2026-10-16-kappa-growth-clock/scripts/check_replay.py now preserves all seven published outputs byte for byte (results/replay-check.txt). Batch resume verifies its recipe and raw digest, then skips computation.

2026-10-16 21:24 (+13:00) · 916d2f4 · decision

Closed: registered support gate failed; P1/P2 remain untested. Notebook executed top to bottom against committed inputs using the README nbconvert command (results/notebook-check.log). Analysis replay still matches after commit. README, executed notebook and JSON agree. No Rust instrument or dependency was changed by this experiment. Retain fresh cohort for a prospectively registered censoring follow-up; no additional runs are launched in this session.

2026-10-16-kappa-growth-clock · Source revision ba38590b33e3

Original source ↗ · Input hashes

Introductions summarize the evidence; the expandable record preserves the original predictions, methods and caveats. Figures and notebooks are published as saved. Publication runs no simulations or notebook cells.