# Check of the slow-drift hold (H2) before any lock: plan

Written October 13, 2026, about 12:00 Halifax, before anything in it was run. Nothing here is locked, and no
experiment is run. It checks one part of the revised design in hold_vs_pulse_revised.md (section 4, H2) on old starts.

## Why

Colson chose H2 ("correct only the slow drift") and asked that, before any lock, "the slow-drift controller achieves a
sustained historical coherence difference over the registered blocks", that "the sham adequately controls for
cumulative intervention effort, including displacement magnitude and frequency", that the analysis "separately reports
achieved historical coherence, cumulative intervention effort, and subsequent growth", and: "Run the revised checks on
old starts only. No fresh experimental starts, no experimental lock, and no publication yet." "If either measurement or
the slow-drift intervention remains infeasible, present a simpler alternative rather than forcing the design through."

This check measures history and effort only. No gap is carried and no growth is measured, so "subsequent growth" is
not part of it; the coherence left after release is reported on its own.

## What stays fixed

- Old starts 13 to 18 only (seeds 12 to 17), with new moments. No fresh start is touched.
- Nothing is written to ../cause-test-2026-10-12, ../cause-explore-2026-10-12, ../nudge-test-2026-10-10 or
  ../coherence-growth-2026-10-11. The cause test's 16 locked files are checked against cause_lock.json before every
  piece and after the check, and both folders' files are fingerprinted before and after.
- prelock_checks_plan.md is not edited. Its feasibility result (both ±25% holds NOT FEASIBLE) stays on record.
- Draws: (20261013, 5, seed) for this check's moments and (20261013, 6, seed, moment, hold length) for its sham signs.

## The hold (H2)

Each group g has its own target. R_g^none(t) is the untouched run's coherence of group g at time t, and its target base
m_g(t) is the mean of R_g^none over t − 24, ..., t (the past 25 units). The target is (1 + 0.25) m_g(t) for up and
(1 − 0.25) m_g(t) for down.

- **First kick, at T − H.** Each group of up and down is set to its target, from the untouched state, by the checked
  hold's kick: Δθ_j = a_g sin(ψ_g − θ_j) for every pulled oscillator j, with a_g solved as before (scan |a| = π/512 to
  π/2 on the side that moves toward the goal, then halve the interval to 10⁻¹²; within a relative 10⁻⁶).
- **Later kicks, every 5 units to T.** b_g is the branch's own mean of R_g over the past 25 units, using only its
  samples since T − H (6 samples at the second kick, 25 from the sixth on; the value just before the kick is the last).
  Each kick aims at goal_g = R_g × (target_g / b_g)^λ, R_g being the branch's value just before the kick. So a branch
  whose recent average sits 10% below its target is raised by a factor 1.1^λ, whatever its fast swings are doing.
  This form never asks for a negative coherence and asks for no change when the average is on target.
- λ is the one number to fix. It is chosen on old starts 13 to 15 by the rule below and confirmed on 16 to 18.
- 101 kicks for the 500-unit hold, 21 for the 100-unit hold, the last at T; untouched after T. If a kick cannot be
  solved, or is outside its band (below), that hold of that moment stops and is not carried out. Nothing is clipped
  or replaced.

## The sham

The sham kicks at exactly the same times as up and down. At each kick and in each group, its oscillators are ranked
by sin²(ψ_g − θ_j) and taken in pairs of neighbours, and the cause test's draw decides which one of each pair moves
forward and which back (ct.paired_signs, unchanged, with the same draws), so the sham's first-order effect on
coherence cancels. In the draft, every sham oscillator moved by the root mean square of up's and down's sizes. That
matches Σ Δθ², but not Σ |Δθ| or the largest move when up's and down's sizes differ, as they can at the first kick.
So here the pairs take up's size |a_up| and down's size |a_down| in turn down the ranking (the starting one switching
at every kick). The sham's moves are then a mix of up's and down's sizes, so its Σ Δθ², its Σ |Δθ|, its largest move
and its kick count all match the mean of up's and down's.

## Moments

Ten per start: T = 2,000 + o + 350 m (m = 0 to 9), o a multiple of 5 from 0 to 345 drawn once per start from
(20261013, 5, seed). If o equals the first check's o for that start, the next draw from the same generator is taken.
Each base run is run again (it must reproduce its saved run exactly, as these six did in the first check) and keeps
the untouched state at T − 500 and T − 100.

## Stages

1. **Base runs**, starts 13 to 18.
2. **Choosing λ**, on old starts 13 to 15 (30 moments): both hold lengths, nothing after T. The candidates are
   λ = 0.05, 0.10 and 0.20, run one at a time in that order. The first that meets F1, F2, F3a, F3b, F4a and F4c below
   for the 500-unit hold is chosen, and no later candidate is run. (The 100-unit hold uses the same λ; its numbers are
   reported.) If none meets them, H2 is not feasible at ±25%: the confirmation is not run, and the result goes to
   Colson with a simpler alternative. The run code applies this rule itself.
3. **Confirmation**, on old starts 16 to 18 (30 moments), with the chosen λ: both hold lengths, then untouched to
   T + 500.

## Definitions

c(t) = (R_A + R_B) / 2. For a hold of length H, M = the mean of c over t = T − H, ..., T − 1 (as in the first check).
A_up = (M_up − M_none) / (0.25 M_none), A_down = (M_none − M_down) / (0.25 M_none), A_sham = (M_sham − M_none) /
(0.25 M_none). The registered blocks are the 100-unit blocks of the hold, five for H = 500 and one for H = 100. In
block b, against the target base m = (m_A + m_B) / 2: up's fraction u_b = (mean c_up / mean m − 1) / 0.25, down's
fraction d_b = (1 − mean c_down / mean m) / 0.25, and the up–down difference as a fraction of the planned one,
s_b = (u_b + d_b) / 2 = (mean c_up − mean c_down) / (0.5 × mean m).

## Criteria

For each set of 30 moments and each hold length:

| | criterion | |
|---|---|---|
| F1, kicks as specified | every kick of up, down and sham carried out as specified in at least 29 of the 30 moments, and every start keeps at least 5 of its 10. The first kick of up and down lands within 1.225 to 1.275 (up) or 0.725 to 0.775 (down) × m_g(T − H); every later kick within a relative 10⁻⁵ of its goal; every sham kick within 0.95 to 1.05 × its own R_g before the kick | blocking |
| F2, history achieved | unchanged: in at least 90% of the moments carried out, both A_up and A_down between 0.75 and 1.25; the mean of each over the moments between 0.85 and 1.15 | blocking |
| F3a, the difference sustained | in at least 90% of the moments carried out, every registered block keeps at least a quarter of the planned up–down difference: s_b ≥ 0.25 | blocking |
| F3b, held evenly | in every registered block, the mean over the moments of u_b and of d_b between 0.75 and 1.25 | blocking |
| F4a, sham effort | in every moment carried out, the sham's Σ Δθ² over the hold between 0.8 and 1.2 × the mean of up's and down's | blocking |
| F4c, sham displacement | in every moment carried out, the sham's Σ \|Δθ\| over the hold between 0.8 and 1.2 × the mean of up's and down's; and the sham kicks at every kick time of up and down, and only then | blocking |
| F4b, sham history | the mean of A_sham over the moments between −0.25 and +0.25 | reported; a failure is flagged |
| the draft's standard | the share of moments in which every u_b and d_b lies between 0.5 and 1.5; and the first check's F3 (25-unit blocks) | reported |

**Why F3 is not the draft's per-arm standard.** The draft said evenness "would be judged over 100-unit blocks, against
the target". Worked through before this check, that standard fails a controller that works as intended. H2 leaves fast
swings free by design. In the untouched runs, 100-unit block means of c swing about their local level with an SD of
about 0.0029 (section 2 of hold_vs_pulse_revised.md), against a planned change of about 0.0065 for one arm, and the
target base carries the untouched run's own swings. So one arm's single block would be expected to swing by roughly
±0.4 of the planned change, and all ten blocks of up and down staying within ±0.5 would happen in only a minority of
moments. Two quantities avoid this. The up–down difference shares the target, so its swings cancel; only the two
branches' own swings remain, roughly ±0.25 of the planned difference per block. F3a sets its floor three such swings
below the plan, so a moment fails if the difference has really been lost in a block, not because a block swung.
Averaging over the 30 moments removes most of the swings, so F3b judges each arm's evenness block by block on the
average. The draft's standard is still reported.

## The verdict

- **The 500-unit hold under H2 is FEASIBLE at ±25%** if the confirmation meets F1, F2, F3a, F3b, F4a and F4c. If a
  criterion is not met, or no λ is chosen, it is NOT FEASIBLE as specified.
- The 100-unit hold is judged by the same criteria on the confirmation, separately.
- Either way, the result goes to Colson. A NOT FEASIBLE result comes with a simpler alternative, which is not run.
  No criterion or candidate is changed after results are seen.

## Reported separately

1. **History**: M by arm, A_up, A_down, A_sham, ΔM = (M_up − M_down) / 2 against the planned change and the natural
   spread of H-unit history means, the block fractions u_b, d_b and s_b, and each arm's ratio to its target just
   before each kick.
2. **Effort**: the number of kicks; Σ Δθ², Σ |Δθ| and the largest |Δθ| by arm; the first kick's share; the median
   later kick; each kick's sham-to-arms ratio; against the first check's pinned hold and against one pulse.
3. **After release** (confirmation only): mean c over (T, T + 200] and (T + 200, T + 500] minus untouched, per unit of
   the planned change, by arm. No growth is measured.

## Running

- A dry run on old start 1 (seed 0, 700 units, one moment at T = 600, 50 units after, λ = 0.10), written to
  dryruns/. It checks the base run in pieces against ct.base_run and the saved run; that a hold asking for no change
  (λ = 0, no first change) follows the untouched run; the target base and the branch's average against a direct
  computation; and the sham's matching. Its numbers count toward nothing and are disclosed in the results.
- Then foreground pieces, one at a time, each under `timeout -k 10 285 python3 -B hold_check.py run`: seven workers,
  no task begun after 120 seconds into a piece, nothing left running between pieces. One piece of base runs, about
  three pieces per candidate λ, and about five for the confirmation: about 30 to 45 minutes in all.
- Working files go to generated-artifacts/cause-prelock-2026-10-13/hold_check/ (git ignores it). The plan, the run
  log, the results and the dry run stay here.
