# Coherence–growth replication: the plan, fixed before the run

Written on October 11, 2026, in the evening (Halifax), at Colson's request, before any of the new starts was run.

`python3 replication.py freeze` locks this plan. It writes the SHA-256 of this file, of replication.py, of every
script the analysis uses and of the saved results and runs it compares with into replication_lock.json, with the
time. `run` and `report` stop if any of them has changed since. Nothing is run on the new starts before the lock.

A toy model (two groups of phase oscillators, as in Memory in Motion). Whatever the result, it shows structure in
the model, not proof about anything beyond it.

## What led here (all on record, unchanged)

1. **The noticing** (Test 16, the long run at the threshold, starts 1 to 6): windows of 1,000 time units with
   higher coherence had slower growth. Noticed after the run, not tested.
2. **The coherence–growth test** (coherence_growth.txt; starts 7 to 12; both measures fixed before that run):
   - Same time, windows of 200 time units: +0.2763 (0.1044), below 0 in 1 of 6 starts: no clear link. The
     same-time idea did not hold (it leaned the other way).
   - Later: coherence now against the growth rate 200 to 500 time units later: −0.2061 (0.0186), below 0 in
     6 of 6: more coherence now, slower growth later.
3. **The earlier-growth check** (earlier_growth_check.txt). Exploratory: chosen after the test and run on the
   same saved runs. With the growth over the 500 time units before held fixed, the later link was −0.1610
   (0.0279) on starts 7 to 12 and −0.2223 (0.0389) on starts 1 to 6, below 0 in all twelve starts.

This run asks whether item 3 holds on starts that have never been run.

## Primary question

Does earlier coherence retain a negative association with later perturbation growth after controlling for
earlier growth?

## The new data

- **Starts 13 to 18**: random starting phases from seeds 12 to 17 and gap directions from (20261011, 12 to 17),
  as nudge_test.py derives them for every start. Never run at this size (N = 4,000 has used starts 1 to 12 only).
- **The model, exactly as before**, run by nudge_test.py's own code, imported unchanged (its SHA-256 is the one
  the page checks): two groups of N = 4,000 phase oscillators, natural rates spread evenly over a Lorentzian of
  width 1, coupling K = 1.90 inside each group and ε = 0.1 between them, no push; oscillators with natural rates
  beyond ±20 turn freely (they still count in the coherence); steps of 0.025 time units; settling 300 time units;
  then 6,000 time units.
- **The gap**: a second copy of the same moment with every pulled phase moved by a tiny random amount (rms 1e-7
  radians, overall timing unchanged), measured every 5 time units, the log of its growth noted, and put back to
  1e-7 in the direction it then points. The first copy is never touched.
- Run in pieces of about 4 minutes. Picking up after a pause changes digits only at the level of rounding; over
  thousands of time units the run then follows an equally valid path. That changes no rule here.
- All six starts are used. None is dropped, replaced or added.

## Measures, start by start

Over t = 2,000 to 6,000, in the 5-unit intervals the gap is measured on:

- **C(t)**: the untouched copy's coherence |z|, average of groups A and B, averaged over the interval.
- **G(t)**: the growth of the log of the gap over the interval.
- **g1(t) … g5(t)**: the growth rate in each of the five 100-unit windows that end with the interval (the 500 time
  units up to and including it; for the first intervals this reaches back to t = 1,505).
- **L = 200, 205, …, 500 time units** (61 lags). For each lag, every interval with t + L inside the span is used.

**Primary: the conditional coefficient.** For each start and lag, least squares:

    G(t + L) = a + b·C(t) + c1·g1(t) + c2·g2(t) + c3·g3(t) + c4·g4(t) + c5·g5(t) + error

The coefficient on C is reported on the correlation scale: the partial correlation of C(t) and G(t + L) with
g1 … g5 held fixed (both are freed of what the earlier growth predicts, then correlated). It has the same sign and
the same test as b, and sits on the same scale as the unadjusted correlation. Averaged over the 61 lags, it gives
one number per start. This is the earlier-growth check's main version, computed by its own code
(earlier_growth_check.py, imported unchanged).

**Unadjusted, for comparison:** the same without g1 … g5, a plain correlation: the coherence–growth test's later
measure exactly.

## Uncertainty: autocorrelation and overlap

Inside one start the 5-unit intervals follow each other closely, the 100-unit windows slide and overlap, and the 61
lags reuse the same stretch of the run. So nothing inside a start is treated as independent: no within-start error
bar or p-value is used anywhere. Each start gives one number, and the uncertainty comes only from the spread of the
six numbers. The six starts are independent: different random starting phases and gap directions, a model with no
noise, nothing shared between starts. Two error bars are computed:

- the six starts resampled 400 times (seed 20261015), as in every earlier part;
- the textbook standard error, SD (with n − 1) / √6.

With only six starts the resampled one runs about 9% small, so **the decision uses the larger of the two**. Also
printed, not used for the decision: t = average / textbook error bar, with 5 degrees of freedom, and its two-sided
p. (3 textbook error bars corresponds to p ≈ 0.03 with 5 degrees of freedom.)

## Decision rule (the primary measure, starts 13 to 18 only)

- **PASS (replicated):** the average of the six conditional coefficients is below 0 by more than 3 error bars.
- **FAIL, no clear link:** within 3 error bars of 0.
- **FAIL, reversed:** above 0 by more than 3 error bars.

No other lag range, window, adjustment, span or set of starts will be read as the result, and starts 13 to 18 are
not pooled with starts 1 to 12. The individual-start values and signs are reported whatever the decision.

## Also reported (fixed now, not used for the decision)

- The unadjusted later link on starts 13 to 18, read by the same rule (a replication of the test's later measure).
- From the earlier-growth check's code: the 200 time units before held fixed instead; a check on the check
  (another start's earlier growth held fixed: start 13's coherence and later growth with start 14's earlier growth
  held fixed, and so on, which shows how much holding five smooth series fixed moves the link by itself); the growth's
  own link (the growth rate over the 200 before against the growth rate 200 to 500 later); the link at every lag
  from 5 to 500, with and without the earlier growth held fixed; in the test's windows of 200,
  G(next window) = a + b·C + c·G (and two windows on), with scaled weights.
- From the test's code: the same-time correlation in windows of 200 (the idea that did not hold in the test), read
  by the test's own rule, and the long-run rate over t = 3,000 to 6,000 against Test 16's +0.0147 (0.0006), as a
  check that the new starts behave like the old ones (they agree if within 3 combined error bars).
- The same measures for starts 1 to 6 and 7 to 12, computed again by the same code; they must equal the saved
  results.

## Checks before the lock

- nudge_test.py is the copy the page carries (its SHA-256), and coherence_growth.py, earlier_growth_check.py,
  their saved results, outputs and figures, and the saved runs of starts 1 to 12 go into the lock as they are.
- Start 1, run by this code for 50 time units, repeats the long run exactly.
- The analysis, run on the saved starts 1 to 6 and 7 to 12, gives the saved numbers of the test and of the check
  exactly.
- No new data exist: no saved run, no run log, no progress files.

## What a result would mean

- **PASS:** in this toy model, on starts never used before, coherence carries information about growth 200 to 500
  time units later beyond what the 500 time units of earlier growth carry. A correlation in a noise-free model: no
  claim of cause or damping, nothing about systems beyond the model.
- **FAIL:** the exploratory result does not hold on new starts. It stays on record, labelled exploratory, with this
  result beside it.

Any change after the lock is a deviation: it will be written down beside the result with its reason, and the locked
analysis will still be reported. Nothing on the website changes until the result has been reviewed.

## Frozen settings

| setting | value |
| --- | --- |
| starts | 13 to 18 (seeds 12 to 17) |
| oscillators per group | 4,000 |
| K / ε / Lorentzian width | 1.90 / 0.1 / 1 |
| step / settling / run | 0.025 / 300 / 6,000 time units |
| gap / put back every / direction seed | 1e-7 radians / 5 time units / 20261011 |
| span measured | t = 2,000 to 6,000 |
| lags | 200 to 500 time units, steps of 5 (61) |
| earlier growth held fixed | five windows of 100 time units up to t |
| error bar | the larger of: resampled 400 times (seed 20261015); SD (n − 1) / √6 |
| decision | PASS if below 0 by more than 3 error bars |

## Outputs

replication.txt, replication.json, replication_lock.json, replication_runlog.json, sim_replication4000.npz, and the
figure screenshots/nudge-test-coherence-growth-replication.png. Earlier files are not touched.
