008 — is the M1 pushable-block family decidable enough to carry M2's transfer curve, without being merely chaotic?
Status: NOT-TESTABLE (evaluated 2026-07-28) — the registered pre-fit clause fired at all
six gating cells and no arm was ever fit. See ## Result at the foot of this file. The four
difficulty knobs were frozen in the commit that registered this gate (24157ca), before any
transfer arm existed and before any calibration number was measured.
(Direct discharge of Gate 005's committed "What a STOP costs M2" clause
(005-anytime-transfer-metric.md, ~L346 and again ~L551), which handed the resolution to M1
as a world/budget design problem and named three levers. This gate freezes those levers as
concrete constants and tests whether they worked. It is a precondition, in the
Gate 006/007 sense — the decidability check computed before any arm is fit — and it does not
create a rung. It decides whether M2 may be built on this family at all.)
(Naming: per the 2026-07-28 convention, no new rung letter is minted. This is "M1's difficulty knobs (Gate 008)".)
Gate 004 (STOP): the self-calibrated test–retest noise floor NF came back 0.0 in every
cell — the full-budget few-shot fit converges to the same optimum regardless of fit-RNG, so
most goals were never decidable (11–14 of 48 on room). Gate 005 (STOP): the obvious fix —
score the fit trajectory rather than its endpoint — was pre-registered and failed.
The number that constrains this gate's design is Gate 005's own TIE_frac = 0.31 / 0.35 / 0.35. Those are bitwise float equalities read over the whole ladder K = {1,2,4,8,16,29}
(score_ladder, src/transfer.mojo:803). So ≥31% of goals tie one ES step in, while the
endpoint tied 100%.
Consequence: shortening FEW_ITERS cannot clear a tight tie bar on the walls family. It is
bounded above at ~0.31 by data already published. Gate 005's lever #2 is real but secondary;
the world-content knobs (K1/K2/K4) are what must carry the bar. Any design claiming the budget
knob alone suffices contradicts Gate 005's own numbers.
The second consequence is that the tie mechanism is not a budget artifact at all. It is
structural: BC_DIM = 18 carries 16 occupancy dims (typically ~[0, 0.15]) against 2 pose dims
(typically ~0.5 off) — BC_DIM = BC_BLOCKS + 2, src/sandbox.mojo:79-81. The MSE is dominated
by a two-dimensional positioning subproblem that every policy solves the same way.
Unchanged and load-bearing: POLICY_DIM = 294, SB_ACTIONS = 6, BC_BLOCK = 4,
BC_DIM = 18, FEW_N = 32, FEW_ALPHA0/1, FEW_SIGMA0/1, BUILD_*, SEL_K = 8,
SEL_POOL = 9. SB_ACTIONS/POLICY_DIM staying at 6/294 is deliberate: it keeps the .rep
format and every stored elite binary-compatible across the old and new worlds, which M2's
cross-world retain needs, and it makes "strict superset" a mechanically checkable property
rather than a slogan.
| symbol | SB_PUSH_OFF = 0, SB_PUSH_ON = 1; new POD field SandboxTask.push_mode: Int |
| lives in | src/sandbox.mojo (SandboxTask, sandbox_step) |
| current | does not exist; movement into a positive cell is permitted — "the avatar coexists with blocks", src/sandbox.mojo:255-256 |
| frozen | __init__ sets push_mode = SB_PUSH_OFF; M1 worlds set SB_PUSH_ON |
Under SB_PUSH_ON, a move into a positive cell pushes that cell one step in the move
direction if the destination is in-bounds and empty; otherwise the move is refused. Walls
(< 0) stay solid exactly as now. The SB_WALL pattern is kept honestly: dynamics parameters
already live on SandboxTask by design (src/sandbox.mojo:6), the default reproduces the old
dynamics bitwise, and no surrounding code changes.
Mechanism. A pushed block is positive, so _gravity_pass moves it and sandbox_bc counts
it. One differing action displaces a block, which changes terminal occupancy — the channel that
is currently absent.
| symbol | SB_SEED_BLOCKS = 12 |
| lives in | src/sandbox.mojo (world construction) |
| current | 0 pre-seeded blocks |
| frozen | 12, placed by the same variant-seeded LCG constants scatter already uses, only on cells directly above a wall or on the floor row, skipping the avatar start cell |
Mechanism. Without pre-seeded content a 12-iteration fit would have to paint before it
could push, putting the extension out of reach inside budget. Placing blocks only on supported
cells makes tick 0 a gravity fixed point, so the terminal arrangement is a direct function
of the push sequence rather than of a settling transient — the cleanest possible sensitivity
channel. On shelves, the wall rows r = 5 and r = 10 give genuine mid-air support, so a push
off a shelf produces a cascade.
| symbol | new FEW_ITERS_M1 = 12, SEL_FIT_ITERS_M1 = 11; doubling probe uses 24 |
| lives in | src/transfer.mojo |
| current | FEW_ITERS = 30 / SEL_FIT_ITERS = 29 — unchanged, not edited |
| frozen | 12 / 11 for M1 worlds |
Implementation constraint (contract-bearing). FEW_ITERS has 39 references across src/
and tests/. FEW_ITERS_M1 is a new constant used only by M1 worlds; editing FEW_ITERS
in place would break reproduction-contract clause 3 below.
Why 12 specifically, by rules fixed in advance rather than by measurement: (a) strictly above
the largest ladder rung (8) at which Gate 005 observed live variation, so it cannot be accused
of having been placed inside the informative band; (b) it keeps the ITE budget-honesty ledger
intact — SEL_POOL × SB_T = 576 trial ticks still cost strictly less than one ES iteration
(2 × FEW_N × SB_T = 4096), verified at src/transfer.mojo:499-500, so a selection win can
never be bought with ticks.
Why this is world design and not a metric knob — the clause has to hold up: it is frozen in
the registering commit; it is applied identically to every arm; and this gate fits no warm
arm, so there exists no warm-over-cold number against which it could have been tuned. The
forbidden version would be choosing FEW_ITERS after seeing which value maximizes the warm
margin. That is mechanically impossible here.
K4 — goal admission: the top-half-from-trivial rule (Gate 005's lever #3). World design, zero free parameters.
| symbol | CAL_POOL = 256, REF_CONST = 7, GOAL_ADMIT |
| lives in | the gate harness's goal generator (a sibling of gen_family_disjoint) |
| current | goals are any de-duplicated, repertoire-disjoint random-policy end-state |
| frozen | draw CAL_POOL = 256 candidates; compute each candidate's occupancy-only distance (BC dims 0..15) to the nearest of 8 reference policies; admit only candidates in the upper half by that distance; then apply the existing emap.contains de-duplication and disjointness filters |
The 8 references are zero-RNG and hand-free: the zero policy, plus 7 policies with a single output-bias slot set (always-up / down / left / right / paint / cycle / stay). They are the shared attractors — "do nothing", "walk into a wall", "paint in place" — the behaviours a 12-step fit falls into from any seed.
Mechanism. This is exactly Gate 005's "a continuous per-goal score that does not bottom out
on an attractor shared by all arms", implemented as goal-set design instead of score design:
the score stays byte-identical and the goals that are the attractor are removed instead.
There is no threshold to tune later — "upper half" is a rank rule, not a cutoff. The goal set is
fixed before any arm sees it, so it is symmetric across arms by construction. policy_score,
sandbox_bc, sandbox_cell_key, calculate_fitness and BC_DIM are untouched; the
contract below asserts empty diffs.
Why the score-design version is refused. The BC_DIM pose-share analysis above means
re-weighting or dropping the two pose dims would fix saturation in one line — and that is
exactly the forbidden move. It is a second metric change proposed after the first (Gate 005's)
returned STOP; it is unfalsifiable from the inside (any re-weighting can be justified
post-hoc); and it changes the number the consumer reads. The pose share is instead reported as
POSE_SHARE with an explicit no-promotion clause (Gate 007's RECOV precedent): it may not
become a bar in either direction once its value is known.
- No hand-authored sub-goal BC targets. The ROADMAP names "clear-a-path / stack-N-blocks / seal-a-region". This gate registers rollout-generated goals only. A curated target set is the single easiest place to smuggle per-task hand-staging into the family, and a hand-written "stack-N" BC vector is a symbolic target, not an emergent one. The names describe what the block world makes reachable; if hand-authored targets are ever wanted, that is a separate numbered gate.
- No change to
SB_ACTIONS. A dedicated push action is unnecessary (move-into-block pushes) and would breakPOLICY_DIMand.repcompatibility. - No change to the ES schedule beyond the K3 budget.
On the frozen M1 pushable-block family at the frozen few-shot budget FEW_ITERS_M1 = 12, with
an unchanged policy_score, the instrument has real resolution: two independent COLD fits
of the same held-out goal disagree by more than float dust on ≥95% of goals (NF > 0,
TIE_frac ≤ 0.05), and the instrument resolves a known-sign, arm-blind treatment
(cold@12 vs cold@24) far more often than it resolves pure fit-RNG
(SEP_2x − SEP_null ≥ 0.15), with a consistent sign (SIGN_2x ≥ 0.80) — so a later
warm-vs-cold comparison on this family is capable of returning "no".
Failing the tie/NF clause means the world extension did not desaturate the instrument and M2
must not be built on this family. Failing the sign/separation clause means the family
manufactured decidability out of chaos, which is the more dangerous outcome because it looks
like success.
Arm-blindness is structural, not a promise. This gate fits no warm arm and builds no
retrieval: no emap.nearest, emap.nearest_k, emap.select_uniform, or read of
emap.weights appears anywhere in its harness. That is grep-checkable (contract clause 4) and
it is what makes it impossible for any frozen value here to have been chosen to favour a warm
start.
The consumer is run_family_select (src/transfer.mojo:580) — M2's reader. This gate calls
a cold-only sibling of it; the fit call, the demo builder (make_demos) and the scoring call
are identical. Secondary consumers: Gate 003's banked P_a / τ / RAWPRIOR_SCR via the
N_dec ≥ 6 floor (see "Free evidence"), and the published MDE, which M2's own gate must
consume.
Primary statistics (definitions taken from the existing harness, not re-invented — the
NF / decidable_count machinery in tests/test_anytime_metric.mojo:733 and
tests/test_cbr_retain.mojo):
| stat | definition |
|---|---|
NF |
median_g |d_cold_a[g] − d_cold_b[g]| — two independent cold fits at different fit-RNG stream positions |
TIE_frac |
fraction of goals with d_cold_a[g] == d_cold_b[g] bitwise |
NF_rel |
NF / median_g d_cold_a[g] |
SEP_2x |
decidable_count(d_cold24, d_cold_a, d_cold_a, NF, ng) / ng — the known-sign, arm-blind treatment |
SIGN_2x |
among decidable goals, the fraction where cold@24 is strictly better |
SEP_null |
decidable_count(d_cold_a, d_cold_b, d_cold_a, NF, ng) / ng — the nuisance-matched null |
PROG |
median_g (d_ref[g] − d_cold_a[g]) / max(d_ref[g], EPS), d_ref[g] = best of the 8 constant-action references (zero RNG, zero fits) |
SENS_occ |
pre-fit occupancy sensitivity: fraction of R_SENS = 32 random action-sequence pairs whose terminal occupancy BCs differ, over T_SENS ticks (zero fits) |
POSE_SHARE |
reported diagnostic, no bar, no promotion |
MDE |
minimum detectable effect per cell — the published deliverable M2's gate must consume |
SENS_occ is measured in three matched cells per (world, seed), identical layout /
references / ticks:
| cell | what differs |
|---|---|
SENS_occ(M1) |
push_mode = ON, blocks seeded |
SENS_occ(blocks-only) |
push_mode = OFF, blocks seeded (diagnostic, no bar — decomposes K1 vs K2) |
SENS_occ(base) |
push_mode = OFF, no blocks — the family exactly as Gates 004/005 measured it |
Scored on the two designated M2 target worlds — push_room and push_scatter, both at
variant = 0 — across all three seeds: 6 gating cells. push_shelves and push_columns
are calibrated and reported (12 cells total) but do not gate: M2 never fits held-out goals
in a source world, so gating on cells the consumer does not read would be theatre.
NOT-TESTABLE — checked first, in this order; nothing below is scored if any trips:
- either reproduction-contract clause fails;
SENS_occ(M1) < 0.60orSENS_occ(M1) − SENS_occ(base) < 0.20in any gating cell — this is checked before any fit is run;PROGoutside[0.15, 0.85]in any gating cell (below ⇒ the family is too hard and every arm bottoms out on a ceiling, the mirror washout; above ⇒ goals are near-solved cold and there is no headroom for a warm start to occupy);- the harness references
emap.nearest/nearest_k/select_uniform/.weightsanywhere.
GO — every condition, all 6 gating cells:
NF > 0TIE_frac ≤ 0.05NF_rel ≥ DELTA_REL = 0.02(the relative floor is binding, not float dust)SEP_2x − SEP_null ≥ 0.15SIGN_2x ≥ 0.80
STOP (fires at ≥ 2 of 3 seeds):
TIE_frac > 0.05withNF = 0.0— the Gate 004 washout survived the extension;SEP_2x − SEP_null < 0.15— the instrument cannot resolve a doubled budget, so it is blind to any effect a warm start could plausibly produce;SIGN_2x < 0.60— it "decides" with near-random sign: dispersion without ordering, i.e. chaos wearing resolution's clothes.
PARTIAL: any GO condition holding at exactly 2 of 3 seeds on a gating world (seed splits are never rounded up), or one gating world clearing a condition 3/3 while the other does not. PARTIAL licenses M2 only on the worlds that individually cleared, and M2 must re-register its world list in its own gate. It does not license dropping goals, worlds, or seeds, nor aggregating.
Seeds 0, 1, 2 — three required, per the house rule; AND-across-seeds for GO, ≥2/3 for a STOP trigger. This is a claim about an instrument, and instruments must hold on every draw.
Each seed independently redraws every stochastic ingredient: the two source repertoire builds,
the CAL_POOL = 256 candidate goal policies (hence both the admitted goal set and the SENS
reference draws), and all three fit-RNG streams. Three independent goal-set draws, not
three reads of one.
Within a cell, the three fits are CRN-paired on one continuous fit-RNG stream, per goal, in
a frozen draw order. The SENS probe, the constant-action references, and the admission
filter's distance computation consume zero RNG and cannot move the stream:
seed(s) → build push_shelves rep → build push_columns rep [BUILD_* verbatim, .contains() only]
→ for w in [push_room, push_scatter, push_shelves, push_columns]:
SENS probe (3 matched cells, 0 draws)
constant-action reference distances (0 draws)
goal pool: 256 candidate draws → top-half admit → dedup → disjointness
for goal g: cold_a@12 → cold_b@12 → cold@24
Stream warning — Gate 005 was nearly voided by exactly this (005-…md, "One registered
detail that needed care"). The admission filter draws a fixed 256 candidates regardless of
how many are admitted, so the fit-stream position is stable within this gate — but it is
not the position Gates 004/005 fit at. Gate 008's numbers are therefore not comparable
to the published n_dec = 11/14/10, and no such comparison may be made. Bitwise reproduction
of those numbers is guaranteed instead by contract clause 3 (push_mode defaults to 0, so
test_cbr_retain / test_anytime_metric draw from unchanged streams).
The one that reads ~nothing if the knobs don't work: SENS_occ, then SEP_2x. If pushable
blocks plus seeded content do not make the terminal occupancy BC a sensitive function of the
action sequence, SENS_occ(M1) comes back near SENS_occ(base) and no fit is ever run —
the failure costs seconds, not minutes, the property that made Gate 006's ceiling clause pay
for itself on first use. If SENS passes but the fit still converges to a shared attractor,
SEP_2x reads ≈ 0: a doubled budget is invisible to the metric. Either way the "no" is
clean, cheap and unambiguous.
The one that could take the claim away — the nuisance-matched control: SEP_null and
SIGN_2x. Gate 007's lesson is that the control must be matched on the nuisance dimension.
Here the nuisance is dispersion: a chaotic world manufactures decidability without
resolution and would produce a beautiful NF > 0 / TIE_frac = 0.0 table that means nothing.
SEP_null is matched on everything — same world, same goals, same budget, same fit machinery,
same two cold fits — and differs only in carrying no treatment. SIGN_2x then asks whether
the decisions have a consistent direction or are coin flips.
The zero-RNG matched control on a pre-fit statistic: SENS_occ(base) is the family exactly
as Gates 004/005 measured it, with the same reference policies and the same ticks. The ≥ 0.20
delta is the load-bearing form of the precondition; the absolute ≥ 0.60 is the more guessable
of the two stated bars, and is recorded as such.
- Zero learning-core change. Empty
git diffonsrc/esper_evolution.mojo,src/memory.mojo,src/map_elites.mojo, theDomaintrait insrc/arc_io.mojo, andExamplePair/Taskinsrc/hope.mojo. - Zero metric change. Empty
git diffonpolicy_score,compose_score,sandbox_bc,sandbox_cell_key,calculate_fitness.BC_DIM == 18,POLICY_DIM == 294,SB_ACTIONS == 6asserted at runtime. - The extension is a true strict superset — mechanical proof.
./esper test cbr_retainand./esper test anytime_metricstill reproduce bitwise: Gate 004'sroomnumbersR1 = Rc = 1.0,NF = 0.0,n_dec = 11/14/10../esper test fit_tracedstill passes (0/294 differing floats). This makes "push_modedefaults OFF and nothing else moved" a checkable fact rather than a claim. - Arm-blindness.
grep -nE 'nearest|select_uniform|\.weights'over the harness returns nothing.
The fits stay single COLD fits at the frozen budget. Specifically, all of the following are scaffolding, and a pass obtained with any of them is a documented negative regardless of the raw number:
- Any post-hoc move of a frozen value:
push_mode,SB_SEED_BLOCKS = 12, the placement rule,FEW_ITERS_M1 = 12, the probe at 24,CAL_POOL = 256,REF_CONST = 7, the admission rule, the 8 constant-action references,R_SENS = 32,T_SENS,DELTA_REL = 0.02,N_DEC_MIN = 8,NUM_GOALS/NUM_GOALS_ESC, every bar above, the seed set. - No per-world or per-goal tuning of
FEW_N,FEW_ALPHA0/1,FEW_SIGMA0/1,grav_rate, or the wall variant. One schedule, every cell. - Raising
FEW_ITERS_M1mid-gate because the fit "under-fits"; and preserving the 30-step anneal rate under a 12-step budget is itself a design choice frozen here, not a mid-gate adjustment. - Any re-weighting, re-scaling, or dim-dropping of the BC — including dropping the two pose
dims — is a forbidden metric knob.
POSE_SHAREmay not be promoted to a bar in either direction. - No hand-authored goal BCs, no per-goal curation, no re-drawing a goal set that produced a
low
n_dec, no raisingCAL_POOLormax_triesto fish for goals. - No escalation beyond the inherited 24→48 schedule, and escalation stays driven by the endpoint decidable count exactly as in Gates 004/005.
- No best-of-seeds, no dropped seed, no dropped world, no mean-over-worlds when a per-cell condition fails.
SENS_occ(blocks-only)is a diagnostic and may not be promoted to a bar once its number is known.
The knobs are frozen in the commit that registers this gate — before any transfer arm exists and before any calibration number is measured.
- On STOP (the family is measurably saturated, or measurably chaotic), the knobs are not re-rollable. Re-tuning world or budget parameters after seeing a saturation number is precisely the post-hoc knob Gate 005 forbade. M2 is not built on the sandbox transfer family, and M5 gains a third publishable negative.
- On NOT-TESTABLE (the instrument never ran), there is exactly one re-roll, as Gate 009, with the complete screening table published.
The asymmetry follows the Gate 006→007 precedent: NOT-TESTABLE means the instrument never ran; STOP means it ran and answered. An unlimited re-roll budget would make this precondition unfalsifiable.
Gate 008 itself contributes zero. Gate 003 needs signed warm−cold margins per (world, seed) group; Gate 008 fits no warm arm, so it produces none. Said plainly rather than left to look like progress.
What it can fix is M2's arithmetic, which is why the held-out world count is a frozen knob:
| M2's held-out world count | groups | vs Gate 003's floor of 6 decidable groups |
|---|---|---|
1 (push_room only, Gate 004's shape) |
3 | impossible |
2 (push_room, push_scatter) |
6 | exactly the floor, zero slack — one undecidable cell sinks it |
3 (add a second (kind, variant) pair) |
9 | 3 groups of slack; needs 6/9 decidable |
So M2 must register ≥3 held-out (kind, variant) worlds. The layouts are already
parametric on variant (gen_walls_layout), so this costs a constant, not a build. Two further
registered asks on M2, both free: record the raw W1 prior per group so Gate 003's banked P_a /
τ = 0.150423175 / RAWPRIOR_SCR become scorable, and report per-group signed margins, not
only medians.
| component | cost |
|---|---|
pre-fit pass (SENS × 3 matched cells, references, admission) — 4 worlds × 3 seeds |
seconds |
| fits: 3 cold fits/goal × 24 goals × 4 worlds × 3 seeds at 12/12/24 iterations | ~4–6 min CPU |
| total | ~4–6 min CPU |
Cheaper than Gate 004's ~3 min per-arm count would suggest, because 48 fit-iterations per goal replaces 150, and no warm arms are fit.
Harness: tests/test_m1_calibration.mojo, default path ES-free (fast tier), fits behind an
argv flag (--fits, # suite-tier: full) — Gate 007's --arms pattern, which also keeps the
family-freezing commit provably arm-free.
- A GO licenses spending M2's budget; it licenses nothing about transfer. It says the instrument can return "no". It is not a signal about what M2 will find.
SEP_2xcalibrates resolution of a budget effect, not a transfer effect. If retained structure's effect is much smaller than a 2× budget difference, this is the single most likely cause of a later miss. No arm-blind control can calibrate the size of a transfer effect without fitting a warm arm — and fitting one here would destroy the structural guarantee that makes every frozen value in this gate credible. The effect-size question is pushed onto M2 as the registered, publishedMDE.- The
SENSdecomposition is extension-level, not factor-level in its gating form:SENS_occ(M1)vsSENS_occ(base)differs in both push and blocks. The third cell decomposes it, but it is non-gating. - This gate's goal sets are not M2's. The admission filter changes the draw. It counts as calibration, not prediction.
- GO ⇒ M1's frozen knobs are written into ROADMAP verbatim,
MDEis published per cell, and M2 may register its Gauntlet gate on this family — still bound by Gate 005's RAND-MATCHED structure-free control rule and by an M2-registered effect-size floor. - STOP ⇒ the family is measurably unsuitable. M2 is not built on the sandbox transfer family; the approach closes for a measured reason and the write-up (M5) gains a third publishable negative. No re-roll.
- NOT-TESTABLE ⇒ exactly one re-roll, as Gate 009, with the complete screening table published.
Five registered values could not be implemented as written. Every correction below was made
while building the harness, before a single fit was run and before --fits had ever been
invoked; the working tree contained no arm code when they were written. Each is recorded as a
forced reading — the registered text was unrealizable or absent, and in each case exactly one
implementation is consistent with the rest of the frozen spec. None of them is a post-hoc move of
a value against a seen number, which is what the freezing rule and the anti-stone-soup clause
forbid.
E1 — REF_CONST = 7 ⇒ REF_CONST = 6; "8 references" ⇒ 7 reference vectors.
K4 names seven single-bias constant-action policies "always-up / down / left / right / paint /
cycle / stay". There is no stay action: SB_ACTIONS = 6 (src/sandbox.mojo:40) is
up / down / left / right / paint / cycle-brush. Separately, the zero policy produces all-zero
logits, and policy_argmax (src/sandbox.mojo:~419) takes the first maximum, so the zero
policy is always-up. The reference set is therefore the zero policy plus one single-bias policy
per real action: 7 vectors, 6 distinct trajectories. The duplicate is inert — d_ref[g] is a
distance to the nearest reference, so a repeated member cannot change it. REF_CONST remains
hand-free and zero-RNG, which is the property K4 depends on.
E2 — T_SENS had no value. It is listed among the frozen constants (this file, "Anti-stone-soup
clause") but is never given a number. Frozen as T_SENS = SB_T = 64: the same tick budget every
scored rollout already uses. Any other value would introduce a genuinely new free parameter into a
gate whose whole claim is that its parameters were fixed in advance.
E3 — MDE had no formula. It is named a published deliverable that M2's gate must consume as
its effect-size floor, but no definition is given. Frozen as the threshold the registered
decidable_count already applies (tests/test_anytime_metric.mojo:343-344):
MDE = median_g max(NF, DELTA_REL · d_cold_a[g]), reported alongsideMDE_rel = MDE / median_g d_cold_a[g].
This introduces no new constant: it is NF and DELTA_REL = 0.02, both already frozen, combined
exactly as the decidability rule combines them. MDE is the smallest per-goal effect this
instrument can call.
E4 — the anneal rate needed derived endpoint constants. The anti-stone-soup clause freezes
"preserving the 30-step anneal rate under a 12-step budget". But fit_operator
(src/esper_evolution.mojo:349-350) derives its schedule as alpha_rate = log(alpha1/alpha0)/iters
— it anneals by fraction of the budget, not by absolute step. Passing iters = 12 with the
stock FEW_ALPHA0/1 and FEW_SIGMA0/1 would compress the whole 0.1→0.02 / 0.3→0.05 decay into 12
steps, a 2.5× faster anneal — the opposite of what is frozen. Reproduction-contract clause 1
forbids editing src/esper_evolution.mojo, so the rate can only be preserved by rescaling the
endpoints. Frozen as new derived constants in src/transfer.mojo, computed in code from the
already-frozen ones and never hand-typed:
FEW_ALPHA1_M1 = FEW_ALPHA0 * (FEW_ALPHA1/FEW_ALPHA0) ** (FEW_ITERS_M1 / FEW_ITERS) ~ 0.0525322
FEW_SIGMA1_M1 = FEW_SIGMA0 * (FEW_SIGMA1/FEW_SIGMA0) ** (FEW_ITERS_M1 / FEW_ITERS) ~ 0.1464844
FEW_ALPHA1_M1X2 = FEW_ALPHA0 * (FEW_ALPHA1/FEW_ALPHA0) ** (FEW_ITERS_M1X2 / FEW_ITERS) ~ 0.0275946
FEW_SIGMA1_M1X2 = FEW_SIGMA0 * (FEW_SIGMA1/FEW_SIGMA0) ** (FEW_ITERS_M1X2 / FEW_ITERS) ~ 0.0715455
With these, alpha(t) and sigma(t) are the same functions of t at 12 and at 24, so cold@24 is
a literal continuation of cold@12's schedule through its first 12 steps. That is what makes
SEP_2x / SIGN_2x a known-sign budget treatment rather than a schedule change — without it the
"doubled budget" arm would differ in two ways at once and SIGN_2x would be uninterpretable.
E5 — SENS_occ's "random action-sequence pairs" was undefined, and only one reading is
satisfiable. The metric is "the fraction of R_SENS = 32 random action-sequence pairs whose
terminal occupancy BCs differ", without saying how the two members of a pair relate. Frozen as:
one uniformly random action sequence of T_SENS ticks, paired with the same sequence with one
uniformly-chosen tick's action resampled — i.e. the pair differs in exactly one action. This is
the gate's own mechanism sentence for K1 ("One differing action displaces a block, which changes
terminal occupancy — the channel that is currently absent").
The alternative reading — two independently drawn sequences — is not merely different, it makes
the registered bar unsatisfiable by construction: two independent sequences diverge in the avatar's
whole paint trajectory, so SENS_occ would sit near 1.0 in the base cell as well as in M1, and
the registered SENS_occ(M1) − SENS_occ(base) ≥ 0.20 gap could never open regardless of whether the
knobs work. A reading under which the gate cannot fail or pass on its merits is not a reading.
This is the one erratum that is an interpretive call on a scored metric, and it is disclosed as
such. It is not self-serving: it is the stricter of the two readings (a one-action perturbation is
much harder to detect than two independent rollouts), and it is falsifiable — if SENS_occ(base)
comes back near 1.0 even under this definition, the instrument is saturated at the pre-fit stage and
the verdict is NOT-TESTABLE, which the harness must report rather than work around.
What did not change. No threshold, no bar, no seed, no world, no goal count, no
push_mode / SB_SEED_BLOCKS = 12 / placement rule / FEW_ITERS_M1 = 12 / probe-at-24 /
CAL_POOL = 256 / DELTA_REL = 0.02 / N_DEC_MIN = 8, and nothing in the GO, STOP, PARTIAL or
NOT-TESTABLE conditions. The reproduction contract and the arm-blindness clause are unchanged and
still bind.
E6 — SENS_occ's randomness source was contradictory in the registration, and is resolved by an
unregistered constant. The Seed plan says each seed "independently redraws every stochastic
ingredient", listing the CAL_POOL = 256 candidate draws and the SENS draws; twelve lines later
the frozen draw-order diagram says SENS probe (3 matched cells, 0 draws). Both cannot hold: a
probe over "random action-sequence pairs" that consumes zero global draws is unimplementable
from the global stream. The 0 draws clause is the load-bearing one (it is what makes the SENS
probe provably unable to move the fit stream, and the harness proves it mechanically), so it wins,
and the randomness comes from a local LCG — the same scatter LCG the world generator already
uses, seeded by
sens_seed_for(kind, variant, seed_idx)
= SENS_LCG_SEED_BASE + 7919·kind + 104729·variant + 1299709·seed_idx
SENS_LCG_SEED_BASE = 20260728
SENS_LCG_SEED_BASE was chosen at build time and was not registered, yet it directly determines
a scored number. That is exactly the exposure E5 was written to disclose, and the errata section
above wrongly claimed completeness ("Five registered values…", "no seed" changed) — this erratum
corrects that claim.
Because the constant is unregistered, it is screened rather than defended: re-running the six
gating cells with everything else frozen, over six alternative bases
(./esper run tests/test_m1_calibration.mojo --diag):
SENS_LCG_SEED_BASE |
cells clearing the 0.20 gap bar | worst gap |
|---|---|---|
| 1 | 1 / 6 | −0.094 |
| 12345 | 0 / 6 | −0.031 |
| 20260101 | 0 / 6 | −0.063 |
| 20260728 (chosen) | 0 / 6 | −0.094 |
| 99991 | 0 / 6 | −0.063 |
| 777777777 | 0 / 6 | −0.188 |
No base clears the bar on more than one of six cells; the chosen base is mid-pack, and base 1 is
strictly more favourable than the one used. The verdict does not depend on the choice.
Run: ./esper run tests/test_m1_calibration.mojo — the ES-free default path, seconds. The
registered pre-fit clause fired, so the --fits block never executed and the ~5 min of ES was
never spent. New code: K1 push_mode + K2 seed_blocks in src/sandbox.mojo, the derived M1
budget constants in src/transfer.mojo, and tests/test_m1_calibration.mojo.
| world | seed | SENS_occ(M1) |
SENS_occ(blocks-only) |
SENS_occ(base) |
gap | gating |
|---|---|---|---|---|---|---|
| push_room | 0 | 0.781 | 0.625 | 0.656 | +0.125 | yes |
| push_scatter | 0 | 0.781 | 0.750 | 0.875 | −0.094 | yes |
| push_room | 1 | 0.719 | 0.625 | 0.688 | +0.031 | yes |
| push_scatter | 1 | 0.813 | 0.781 | 0.781 | +0.031 | yes |
| push_room | 2 | 0.688 | 0.625 | 0.563 | +0.125 | yes |
| push_scatter | 2 | 0.750 | 0.688 | 0.688 | +0.063 | yes |
| push_shelves | 0 / 1 / 2 | 0.656 / 0.688 / 0.688 | 0.531 / 0.781 / 0.656 | 0.625 / 0.656 / 0.656 | +0.031 / +0.031 / +0.031 | no |
| push_columns | 0 / 1 / 2 | 0.688 / 0.594 / 0.656 | 0.719 / 0.625 / 0.594 | 0.625 / 0.656 / 0.625 | +0.063 / −0.063 / +0.031 | no |
SENS_occ(M1) − SENS_occ(base) ≥ 0.20 fails at 6 of 6 gating cells. By the registered clause
that is NOT-TESTABLE, checked and reported before any fit — which is what the ES-free path was
built to buy. The stream-integrity probe passed (the SENS path drew 0 from the fit stream), and the
reproduction contract holds in full (below).
Two honesty notes on the table. First, push_columns seed 1 reads SENS_occ(M1) = 0.594, under the
0.60 absolute bar — it is correctly non-gating, but a follow-up gate tempted to widen the world list
should know. Second, the absolute bar passed on the gating cells only by sampling luck:
R_SENS = 32 carries a per-cell standard error near ±0.09, and the --diag precision screen at
R = 2000 puts push_room's true SENS_occ(M1) at ≈0.58 — below 0.60 — at all three seeds. The
scored numbers remain the R = 32 ones (R_SENS is registered and is not re-chosen after the
fact), but the honest reading is that both bars were failing, not one.
K1 and K2 exist because Gate 004's NF = 0.0 was diagnosed as a world problem: terminal
occupancy supposedly barely depends on which actions were taken, so independently-seeded fits had
nothing to separate them. The probe says otherwise. The base cell — no seeded blocks, push OFF,
the family exactly as Gates 004/005 measured it — already flips terminal occupancy on 0.56–0.88
of one-action perturbations. A single differing move relocates the avatar, so every later paint
lands on a different cell.
That is not a paint artefact. Restricting the perturbed tick to a move action (--diag) leaves base
at 0.50–0.78. The world was never action-insensitive.
The knobs are also not inert — at R = 2000 the M1−base gap is positive in all six cells,
+0.018 to +0.038. The push channel is real and roughly 6× too small to reach the registered
bar. "K1/K2 add a channel to a world that was never missing one" is the accurate summary, and it is
a sharper result than "the knobs did nothing".
Consequence for the roadmap. World difficulty is not the binding constraint behind NF = 0.0.
The open question moves to fit/policy space: why do independently-seeded fits converge to the same
behaviour in a world that is demonstrably action-sensitive? No world knob can answer that, so the
sanctioned route is a new gate aimed at the fit, never nudging K1/K2 until the gap looks right.
| clause | check | result |
|---|---|---|
| 1 — zero learning-core change | git diff --stat on esper_evolution / memory / map_elites / hope / arc_io |
empty |
| 2 — zero metric change | per-function diff vs HEAD: sandbox_bc, sandbox_cell_key, sandbox_obs, policy_forward, policy_argmax, _gravity_pass, policy_score, compose_score |
all identical |
| 3 — bitwise reproduction | test_fit_traced, test_cbr_retain, test_anytime_metric vs pre-edit captures |
byte-identical |
| 4 — arm-blindness | grep -nE 'nearest|select_uniform|\.weights' tests/test_m1_calibration.mojo |
no matches |
Clause 3 is the one that makes "push_mode defaults OFF and nothing else moved" a fact: the
baselines were captured before any src/ edit, and cbr_retain still reproduces Gate 004's
published room numbers exactly (R1 = Rc = 1.0, NF = 0.0, escalated n_dec = 11 / 14 / 10).
The three "seeds" vary the action-sequence stream only: variant is hardcoded to 0, so all three
share one wall layout and one block placement per world. The registered Seed plan says each seed
redraws every stochastic ingredient. This does not threaten a negative verdict — the R = 2000
screen confirms the effect is real and tiny regardless — but it means the result is "2 worlds × 3
action-draws in 2 fixed layouts", not three independent world draws, and a successor gate should
pass variant = s (gen_walls_layout is already parametric) at no cost.
The --fits block below the pre-fit return is type-checked but has never executed. A follow-up
gate that runs it should expect first-run bugs that no compile can catch.