Drop7 Research
lifetime-objective

The data factory, and the switch that was left off

support-onlyevidence: none: no retained result of its ownteacher

Replays many games and labels every visited position with its remaining lifetime, producing training data for the rest of the family.

Replay a great many games and write down every position they passed through, each one labelled with how many moves that game still had left. This approach produces no result of its own; it is the data other approaches in this family learn from.

support-onlyevidence: none: no retained resultteacherreads hidden values or the future — a teacher, never a policy

Why a label like that is worth having

The obvious training target is score. Score in this game mode is a poor target: it is dominated by a flat 17,000-point bonus, it is heavy-tailed, and there is exactly one label per game. Remaining lifetime is the same quantity with the noise taken out — final score and moves survived correlate at r = 0.9995 (finding-01), and it gives one label per move instead of one per game.

The intuition: seven answers per position, and only one of them written down

Here is one real position from the rules engine. Seven columns are legal and the next disc is a . Two of the seven possibilities:

the position
drop into the second column

A three-wave chain worth 155 points. The board ends the move with two fewer discs on it than it started, even after adding one: this is the kind of move that keeps a game alive.

the same position
drop into the rightmost column

Nothing happens. No clear, no reveal, no points, and the board is one disc fuller. Same position, same disc, and a completely different future.

A model that is going to choose a column has to tell those apart. The repository's most repeated failure is a model trained only on the move that was actually played and then asked, at play time, to rank the six it never saw — the sibling trap. The obvious fix is data that contains all seven.

This generator can write all seven, and the corpus that was actually made contains one. That is the single most important fact about this approach and it is on the record.

How it works

  1. Play whole games with the repository's own searches and write, for every move, a fixed-width record: the public board before the move, the visible next disc, how many drops remain before the next rise, which columns were legal, which one was played, how many discs cleared and how many gray discs were revealed, and the labels, which are how many moves and how many rises that game still had ahead of it.
  2. Mix the behaviour rather than branching at each position. The generator was run four times with searches of one, two, three and four moves of look-ahead, each injecting a small fraction of deliberately random legal moves. Positions a strong policy never reaches — crowded, nearly-dead boards — come from the weak arm; positions near where the real policy plays come from the strong arm.
  3. Optionally, write the panel. A second record type stores, for a sampled position, the resolved board and immediate effects of every legal column under the same randomness. This is the successor-closed data the benchmark contract asks for.
  4. Keep training and evaluation seeds apart by construction. The generator refuses to run outside its lease, and evaluation seeds live under a different prefix entirely.

What happened

There is no retained result for this approach. It has no row in the experiment index, no entry in the ledger and no finding document of its own. What is recorded is what it produced and who consumed it.

The corpus exists and was used. Four training blocks were leased and opened — 65,536 games at two moves of look-ahead, 16,384 at one, 4,096 at three and 768 at four, with deliberately-random move fractions of 8%, 15%, 5% and 3% respectively (lease-map). The resulting state files are the training data behind the learned leaf, whose result is retained, and behind the afterstate net, whose outcome is not recorded anywhere.

The all-sibling panel was built and left switched off. An independent read-only review of the working tree (reconciliation-01) found that the panel is gated behind an option that defaults to disabled, that every corpus summary from the four training blocks records zero panel records, that only a 16-game smoke run ever produced a panel file, and that the reader used by the model trained on this data contains no panel reader at all. So the capability was deliberately built and the corpus that was consumed holds one row per played move, not one row per legal column. Coverage of alternatives comes instead from behaviour mixing: a column that one arm avoids appears in the data as a column another arm played, in a different game, which is not the same thing as having the alternatives at the same position.

A lease collision was caught and the data destroyed rather than filtered. The first corpus run was sized in games and its end address was not checked against the allocation table, so it overlapped the scenario-minting range by 4,096 seeds. Both ranges are development data, so no protected seed was touched and no qualification claim is affected, but positions minted for a benchmark could have appeared in the training data for a model later graded on that benchmark. The contaminated corpus, 1,029,206 records, was destroyed rather than filtered, and regenerating it from a clean range cost 103 seconds (lease-map, incident of 2026-08-20).

The record, and what it does not contain

Sources. The generator's own source comments; the seed allocation table lease-map; and the read-only working-tree review reconciliation-01 §"Sibling coverage". There is no result record, no preregistration and no finding document for this approach, and none is implied by the existence of the files.

Record shapes, from the source. The per-move record carries the 49 public cells, the next disc, the moves remaining before the rise, the legal-column mask, the chosen column, moves-to-death and rises-to-death as labels, clears and reveals for that move, the behaviour depth, a flag for whether the move was a deliberate random deviation, a censored-game flag, occupancy, the move index and the game seed. The panel record additionally carries the resolved afterstate and immediate effects of every legal column at a sampled position.

Common random numbers come for free in this design: the engine derives its reveal randomness from the game seed and the number of moves played, which are identical across the siblings of one position, so the panel compares columns under the same luck without any extra machinery.

Leases. SEEDLEASE-A52 blocks 0xa52000000xa520ffff (depth 2), 0xa52100000xa5213fff (depth 1), 0xa52140000xa5214fff (depth 3) and 0xa52150000xa52152ff (depth 4), all with the training role. Once read these can never become confirmation evidence. Withdrawn: 0xa51d90000xa51dcfff, the destroyed first attempt.

What is not established. Nothing here is evidence that any policy is stronger. This approach produced no games under a benchmark tier, no paired comparison, and no bound of any kind.

What this taught us, and what is still open

  • A capability that ships disabled is not a capability. The panel record is the exact thing six of this repository's seventeen failed learned models are recorded as having lacked, and it was present in the generator and off in every run that mattered. It is worth checking, for any corpus, what was actually written rather than what the writer supports.
  • Behaviour mixing is not successor closure. Both give a model variety; only one gives it the alternatives at a position it will actually be asked about. The planner distillation work later built a corpus that does have full sibling coverage — 108,462 labelled columns with zero gaps, and found that closing this gap, on its own, was not enough to beat the reference search.
  • Sizing a seed range in games rather than addresses is a real hazard, and the recorded process change — print the arithmetic and check it against the allocation table before launch — came from this approach's own incident.
  • Still open: whether re-running the generator with the panel enabled, on a fresh training lease, would produce data worth the disk it costs. Nothing here answers that, and the later distillation result is a reason to be cautious rather than optimistic.

PanelRecordV2 (--panel2): sibling panels with CRN continuation outcomes

Added 2026-08-23 for EX-20260823-sol-corpus-and-offline-gate-4d3d86e4 (P-SOL-v1, stage G0). The v1 record layouts and code paths are untouched; with the flag absent the generator's state and panel output is byte-identical to the pre-change binary (gated against a pristine build from git HEAD in runs/RUN-20260823T215500Z-sol/g0/gates.log).

The technical record

Record layout — 992 bytes per root, fixed stride. A 96-byte header (version 0x0200, sequential seed-order recordId, originSeed for split bookkeeping only, moveIndex, root next disc / moves-to-rise / legal mask, behaviour chosenColumn, fair-D4 referenceColumn computed only when recordId % 16 == 0 else 255, engineId 0=D1 / 1=D2 / 2=D3 N7M6, K, H, panelFlags bit0 = reference computed bit1 = ε-root, the 49-cell root board, 24 zero pad) followed by seven 128-byte sibling slots: resolved one-step afterstate (afterBoard, afterNextDisc, afterMovesToRise, survived, legal, clears/reveals/max-depth, i32 afterScoreDelta — same true-tape semantics as the v1 panel), then u8 contLifetime[K], u8 contDeathRise[K] (0 = censored at H, else rise bin 1–12), then u32 contClearsTotal, u32 contRevealsTotal, zero pad to 128. Illegal columns keep their slot, fully zeroed.

Implementation completion, not a protocol change. The design's per-sibling table left everything after contDeathRise[K] as pad. Per the work-package instruction, the layout was completed so each legal sibling carries every continuation summary the labels need: the KM hazard-vector inputs (per-rise survival counts over K) and the restricted-mean lifetime sum are derivable exactly from contLifetime/contDeathRise (censoring is type I at fixed H, so the KM restricted mean equals the mean capped lifetime), the censor count is #{deathRise == 0}, and the clears/reveals totals over the K continuations occupy 8 bytes of the former pad. Consequence: K ≤ 30 (the design said "K ≤ 32 supported"; this experiment uses K = 6 and K = 16).

CRN continuation tapes never see the seed. Continuations run in the canonical (mirror-normalized) orientation of the public root. The tape seed for continuation j is mix32(FNV1a(canonical board, next disc, moves-to-rise) ^ 0x50534f4c ^ (j+1)·0x9e3779b9), and move ordinal t of a continuation reseeds its own Mulberry32 stream via mix32(tapeSeed ^ 0x434f4e54 ^ (t+1)·0x85ebca6b), so cascade length cannot desynchronize siblings and alignment is by continuation move ordinal. The same tape serves all 7 siblings and every engine. Because the tape and the engines are pure functions of the canonical root, mirror invariance of the labels is exact (gate C), and regenerating a recordId reproduces byte-identical labels (gate B). This differs deliberately from the design text's Hash(originSeed, moveIndex, j): the frozen lease record (SL-20260823T215000Z-a5216000) and the work-package instruction both fix tapes to public root hashes with dedicated domains, never the seed, which also makes the labels a pure function of the deployable information boundary.

Engines. D1/D2 are the frozen parameterized fair search at depths 1/2 (5 strata, work 3,200,000, cache 60,000); D3 N7M6 is the C0 arm exactly as retained in runs/RUN-A525-reveal/d3-n7-m6.json (depth 3, N=7, M=6, work 51,084,852, cache 87,025). All three run through a faithful copy of reveal-sampling/search.cpp's FactoredSearch (whose gate B proved the M=1 collapse is bit-identical to the single-knob search).

Lifetime semantics. contLifetime counts moves survived from the root, the sibling placement being the first move: 0 if that placement is immediately terminal, H if alive at the horizon (then contDeathRise = 0, censored); otherwise contDeathRise = min(12, rises completed at death + 1).

Root sampling. The grid is every --panel-stride-th move from --panel2-start (design: stride 4 from move 8); --panel2-roots R keeps R evenly spaced grid roots per game (floor((i+0.5)·n/R); R = 1 keeps the median grid root — the disclosed G0 ladder rule producing one root per behaviour game), 0 keeps all. Output is written in seed order with deterministic recordIds for any thread count.

Readers and gates. approaches/lifetime-objective/p-sol/panel2_reader.py (numpy reader + KM helpers), check_panel2.py (legality/layout gate), ladder.py (within-root Kendall τ between engines with cluster bootstrap by origin, seed 0xb0071eaf).

Source files