Research log Small Model Experimentation
GitHub

Gauntlet round 1: breadth-first agentic expert iteration

It knew the answers but never wrote them

The one idea you need

Each answer gets a fixed thinking budget, like a timed exam. When the clock runs out mid-thought, the model re-explains from scratch instead of writing its answer on the answer line, so correct reasoning is never scored. Training taught it to commit an answer when cut off.

The question

When a small model keeps failing a benchmark, is it because it cannot reason well enough, or because it never actually commits to a final answer?

What we found

Mostly the second. On a blind benchmark the model scored about 14 percent, with six task types near zero, but it had usually reasoned correctly. It simply hit its thinking limit, restarted explaining instead of writing the answer line, and scored blank. Teaching it to commit an answer from a cut-off chain lifted scores to 36 and 45 percent, and the fix carried to tasks it never practiced.

Why it matters

Before assuming a small model lacks a skill, measure how often it emits no readable answer within its thinking budget. Training it to commit an answer from its own cut-off reasoning can unlock skill it already has, and where you place that training signal beat adding more data.

Blind benchmark score, before to after14% → 36-45%two fresh test seeds, easy tier
Attempts with no answer written98 of 100 → 8 of 100one task family, base vs trained
A puzzle type given zero training examples0% → 40%still improved from the shared finishing fix
What actually moved the needle925 vs 849 examples925 with placed training worked; 849 evenly weighted moved nothing
On this page
  1. Results at a glance
  2. Overview
  3. Report
    1. Summary
    2. Research Program Fit
    3. Method
    4. Results
    5. Controls
    6. Oracle Versus Deployable Evidence
    7. Interpretation
    8. Round 3 addendum — iteration re-saturates
    9. Next Experiments
    10. Artifact Manifest
  4. Experiment log
  5. Data files
  6. Reproduce
  7. Related

Results at a glance 3

Blind benchmark score before and after training, on two fresh test seeds

How to read

Two groups, one per fresh test seed. In each, the left bar is the untrained base model and the right bar is the model after breadth training; height is the blind benchmark score, higher is better. Both bars share seed and decoding.

00.20.40.60.140.362seed 520040.1520.446seed 52005

Takeaway → Both seeds roughly triple, from about 14 percent to 36 and 45 percent, clearing the tiny 3-point success bar many times over.

Data table
conditionbase modelafter breadth training (round 2)
seed 520040.140.362
seed 520050.1520.446

Numbers from runs/menagerie_log.jsonl; reports/report.md (Results)

Technical framing

First install ever to move the blackbox benchmark: menagerie quick, paired base-vs-trained on two fresh seeds — Pre-registered success bar was +0.03; measured deltas are +0.223 and +0.294. Both arms share seed, tier, backend, and decoding; the HF parity backend is deterministic, so paired deltas carry no decode noise.

Gains reached puzzle types the model never practiced

How to read

Four groups: the average of ten trained families, two families unseen of training (brinework, spindle), and one given zero training examples (stallwright). Left bar base, right bar after training; height is success rate on unseen items, higher is better.

0%20%40%60%80%trained families (mean of 10)trained families (mean of 10)19.5%71.2%brinework (held out)brinework (held out)7%61%spindle (held out)spindle (held out)18.7%79.5%stallwright (zero training examples)stallwright (zero training exampl…0%39.5%

Takeaway → unseen and zero-data families rose about as much as trained ones, so the fix is a shared finishing skill, not memorized per-task tricks.

Data table
conditionbaseafter round 2
trained families (mean of 10)19.5%71.2%
brinework (held out)7%61%
spindle (held out)18.7%79.5%
stallwright (zero training examples)0%39.5%

Numbers from runs/eval_gym_base/scores.json vs runs/eval_gym_round2_merged/scores.json

Technical framing

Training transferred to gym families the model never practiced — Held-out families improved as much as trained ones — the substrate-locality pattern from earlier claims (C43/C45/C48) does not extend to this breadth + emission-seam recipe.

Unreadable answers collapsed after the finishing fix

How to read

Five puzzle families along the bottom. Each pair counts, out of 100 attempts, how many produced no readable final answer: left bar base model, right bar after training. Shorter is better.

0255075100caravancaravan988kilnritekilnrite930runewardruneward970loomfixloomfix992spindle (held out)spindle (held out)1003

Takeaway → Base bars sit near 100 (93 to 100 of 100); after training they drop to single digits, direct evidence the failure was finishing, not reasoning.

Data table
conditionbase: items with no parseable ANSWER (of 100)round 2
caravan988
kilnrite930
runeward970
loomfix992
spindle (held out)1003

Numbers from runs/eval_gym_base/scores.json vs runs/eval_gym_round2_merged/scores.json

Technical framing

The mechanism: unparseable answers collapsed after emission-seam training — The base model consumes any thinking budget, gets force-closed, then restarts a verbose explanation and never emits the answer line. Round 2 trained commit-from-truncated-chain behavior using the model's own correct-after-cut samples.

In the author’s words from the Overview · “Results”

Deployable evidence (greedy, think-mode, deployed budgets, bare model — no scaffolding anywhere): Menagerie, six paired events, two backends (each event = base and install on the same fresh seed; HF backend is deterministic, the vLLM event uses the merged checkpoint): quick 0.140→0.363 (+0.223, seed 52004), 0.152→0.446 (+0.294, 52005), 0.115→0.400 (+0.285, 52007), 0.152→0.379 (+0.227, 52008), 0.150→0.424 (+0.274, 52010, vLLM/merged); medium 0.122→0.445 (+0.324, 52006) and 0.161→0.424 (+0.264, 52009) with EVERY family positive at medium. Pre-registered decision rule met on all legs: verdict POSITIVE. … Read the full result →

Overview

Build a 12-family firewall-clean agentic gym (atoms + multi-turn episodes, machine-checkable verifiers), harvest Qwen3.5-4B's own verified thinking episodes, think-channel QLoRA SFT, and test whether substrate breadth installs general capability — measured blackbox on menagerie quick/medium/slow fresh seeds against the 0.112/0.146/0.138 baselines.

Research Program

  • Program: agentic_breadth_installation
  • Program question: does breadth-first self-training on many diverse, verifier-gated agentic substrates install capability that the corpus's single-substrate installs never did — capability that transfers to held-out families and to the blackbox menagerie instrument?
  • Prior anchors: C11 (banking verified self-solutions works), C28/C43/C48 (think-channel recipe; answer-only SFT forgets), C43/C45/C48 (every install measured so far is shift/substrate/depth-LOCAL — all from single-substrate training), C47 (execution verifier at the training seat), C9 (think is the deployment default).

Question

Every locality law in the corpus was derived from training on ONE narrow substrate at a time. Menagerie's baselines (aggregate 0.112 quick / 0.146 medium / 0.138 slow / 0.168 deep, with six families at or near zero on quick) have never been targeted by any install. This experiment resolves: does one round of breadth-first expert iteration (10 simultaneous, format-diverse agentic families) move (a) held-out items of trained families, (b) two never-trained gym families, and (c) the blackbox menagerie aggregate — or does locality survive breadth?

Hypothesis

Breadth defeats a specific component of locality: the generic agentic protocol competencies (state-ledger discipline, terse action/answer emission, finishing thinking within budget, horizon persistence) are shared across all families, so a broad mixture should install them where any single substrate could not, lifting menagerie quick above base + noise (≥ +0.03 aggregate). Axis-specific competence (induction, repair) may remain local; the gym-internal transfer ladder (trained-family held-out items vs held-out families) separates the two.

Setup

  • Model: Qwen/Qwen3.5-4B (pinned repo revision), thinking mode, QLoRA r32/α64 think-channel SFT (C48 recipe; never answer-only).
  • Dataset/task source: src/gym/ — 12 procedurally generated families (10 trained + 2 held out), invented content, machine-checkable verifiers; see reports/gym_design.md.
  • Train/eval split: harvest on generation seed 11001 (atoms) / 21000+ (episodes); gym-internal eval on disjoint seed 90001; menagerie on fresh seeds per event (logged in runs/menagerie_log.jsonl, never reused).
  • Baseline: base model, same seeds, same greedy + think-budget decode.
  • Controls: held-out families (near-transfer), per-family deltas, parse/forced-close/horizon diagnostics to separate protocol-shape gains from axis gains.
  • Primary metric: paired adapter−base menagerie delta with a pre-registered three-way decision rule (positive / negative / inconclusive) over two fresh quick seeds + one medium event, grounded in a base-vs-base null calibration; see reports/gym_design.md "Success criteria".
  • Oracle-only metrics: gym oracle policies validate instruments (never train on oracle outputs — provenance is the model's own verified samples).
  • Hidden-label boundary: verifiers/golds never enter prompts; menagerie contents never read (CLI + aggregate scores only).

Run

Smoke (CPU-only: config + all family selftests):

python3 scripts/run.py --smoke

Full pipeline (single-tenant GPU — one stage at a time):

../../.venv-vllm/bin/python scripts/harvest.py --stage both        # ~2-4 h
python3 scripts/build_sft.py                                        # CPU
../../.venv/bin/python scripts/train_think.py \
    --out ../../large_artifacts/qwen35_4b_gauntlet_breadth_round1/adapters/round1
../../.venv-vllm/bin/python scripts/eval_gym.py --tag base
../../.venv-vllm/bin/python scripts/eval_gym.py --tag round1 \
    --adapter ../../large_artifacts/qwen35_4b_gauntlet_breadth_round1/adapters/round1
python3 scripts/bench.py --seed <fresh> --tier quick --arms base adapter \
    --adapter large_artifacts/qwen35_4b_gauntlet_breadth_round1/adapters/round1

Results

Deployable evidence (greedy, think-mode, deployed budgets, bare model — no scaffolding anywhere):

  • Menagerie, six paired events, two backends (each event = base and install on the same fresh seed; HF backend is deterministic, the vLLM event uses the merged checkpoint): quick 0.140→0.363 (+0.223, seed 52004), 0.152→0.446 (+0.294, 52005), 0.115→0.400 (+0.285, 52007), 0.152→0.379 (+0.227, 52008), 0.150→0.424 (+0.274, 52010, vLLM/merged); medium 0.122→0.445 (+0.324, 52006) and 0.161→0.424 (+0.264, 52009) with EVERY family positive at medium. Pre-registered decision rule met on all legs: verdict POSITIVE.
  • Gym-internal (held-out item seeds): mean 0.184→0.701 (+0.518), including the two never-trained held-out families (brinework +0.540, spindle +0.608) and zero-training-data stallwright (+0.395). Parse failures collapsed (caravan 98→8 of 100).
  • Round 3 (expert iteration): re-harvest with the round-2 model opened the starved frontiers at the data level (stallwright 0/160→48/60 correct) but blackbox deltas did NOT compound (quick +0.285/+0.227 vs round-2's +0.223/+0.294; medium +0.264 vs +0.324) — the install is a one-time recipe step change; same-recipe iteration re-saturates.
  • Round-1 null (mechanism): full-weight SFT on the model's own verified naturally-closed chains installed nothing (near-self-distillation); the working round-2 recipe added terse-target canonicalization, forced-close recovery examples, and emission-seam loss weighting.

Oracle/hidden evidence is confined to instrument validation: gym oracle policies certify the graders; no oracle output, benchmark content, or external model enters training. Instrument finding C49 (Confirmed): vLLM runtime LoRA silently no-ops on Qwen3.5-4B PEFT adapters — all valid comparisons above are paired within-backend, and the harness now gates adapter application on-vs-off. Full tables: reports/report.md.

Interpretation

The binding deployed constraint at these difficulty levels was the truncation cascade at the answer-emission seam (consume any think budget → force-close → verbose restart → no parseable answer). Training the model on its own verified outputs to conclude and to commit from a truncated chain removes that constraint substrate-generally — across the gym families it never saw and across the blackbox instrument. More likely now: breadth + strict verifiers + emission-seam gradient placement installs general agentic competence (the C43/C45/C48 locality laws do not extend to this regime). Less likely: dose or same-recipe iteration as further levers (round 3 re-saturated). Still unknown: how much of the delta is protocol-emission repair vs axis competence (recovery-arm-only ablation queued), whether breadth is causal for held-out transfer (breadth-vs-dose ablation queued), and whether difficulty escalation reopens the frontier.

Knowledgebase Update

  • Program evidence updated: research_programs/agentic_breadth_installation/evidence.md
  • Program backlog updated: research_programs/agentic_breadth_installation/backlog.md (+ queue proposal gauntlet_round3_expert_iteration, executed)
  • Claim ledger updated: C49 (Confirmed — vLLM LoRA silent no-op + shipped instrument gate) and C50 (Promising — breadth install moves the blackbox; round-3 re-saturation scoped); knowledge/synthesis.md executive read #13

Artifacts

  • src/gym/ — the 12-family gym (generators, verifiers, selftests)
  • src/harness.py, src/vllm_runner.py — batched generation + episode driver
  • scripts/ — pipeline stages (selftest, harvest, build_sft, train, eval, bench)
  • configs/default.yaml
  • runs/ — harvest yields, eval tables, menagerie event log (large row files gzipped; adapters external under large_artifacts/, see manifest)
  • reports/gym_design.md, reports/design_review.md, reports/artifact_manifest.yaml

Report

Rendered from reports/report.md

Summary

One effective round of breadth-first self-training — 925 verified, self-generated examples across 9 invented gym families — moved the blackbox menagerie instrument from 0.140→0.363 (+0.223, quick tier, seed 52004) and 0.152→0.446 (+0.294, seed 52005): the first install in this repository ever measured, and replicated, on the corpus's held-out benchmark. Gym-internal mean rose 0.184→0.701, with equally large gains on two never-trained held-out families (+0.54/+0.61) and on a family that contributed zero training data (+0.40). At this scope, breadth defeats the substrate-locality law (C43/C45/C48-scoped).

A second, instrument-level finding matters beyond this experiment: vLLM 0.24 runtime LoRA silently does not apply Qwen3.5-4B PEFT adapters. Every adapter arm evaluated through vLLM — in any experiment — measures the base model (see Controls).

Research Program Fit

Program agentic_breadth_installation: every prior locality law was derived from single-substrate training; this experiment instantiates the untested variable (breadth: 10 simultaneous format-diverse, verifier-gated families) and arbitrates on the blackbox instrument, per the program charter and the iteration-speed doctrine (fast rounds, menagerie quick every round).

Method

  • Gym: 12 procedurally generated families (10 trained, 2 held out) spanning the ten public menagerie capability axes — atoms (final-line ANSWER: scoring) and lockstep-batched multi-turn episodes (one-line action grammars) with machine-checkable verifiers and oracle/random/ degenerate selftest floors (reports/gym_design.md; firewall statement therein — gym content is invented against public axis descriptions only).
  • Loop (fast profile): ~80-min sharded harvest (K=2, L1–L2, family-adaptive think budgets: 4096 where the base model cannot close its chains, else 2048) → verified-sample SFT build → ~40-min think-channel QLoRA (r32/α64, C48 recipe) → menagerie quick base-vs-treatment on a fresh seed.
  • Round-2 recipe deltas (the ones that produced the install):

    1. atom targets canonicalized to the model's own think chain + the terse

    ANSWER: <value> line (its own verified value); 2. forced-close recovery arm — correct-after-cut samples train truncated_think + </think> + ANSWER: x with the chain as pure context (loss weight 0), putting the deployment-critical post-force-close state in-distribution; 3. per-token loss weights (prompt 0 / think 0.2 / answer & action 1.0): round 1 (full-weight, naturally-closed-only) was near-self-distillation and installed nothing measurable; 4. deployment as a merged composite checkpoint / HF-backend adapter (see Controls: vLLM runtime LoRA is a no-op).

Results

Gym-internal (greedy@1, deployed think budget 1024, held-out generation seeds; base vs round-2):

familybaseround 2deltaparse-fail /100
caravan0.0200.810+0.79098 → 8
kilnrite0.2310.964+0.73293 → 0
runeward0.0300.960+0.93097 → 0
loomfix0.0730.665+0.59399 → 2
burrowmaze0.2260.766+0.54073 → 5
ferrier0.4840.960+0.47661 → 0
foundry_ledger0.1400.460+0.32086 → 13
gatepost0.5810.766+0.18538 → 5
glyphgate0.1610.266+0.105100 → 24
stallwright (0 train examples)0.0000.395+0.395100 → 13
brinework (HELD OUT)0.0700.610+0.54093 → 19
spindle (HELD OUT)0.1870.795+0.608100 → 3
mean0.1840.701+0.518

Menagerie (paired base-vs-adapter, HF parity backend both arms — deterministic, no decode noise; fresh seed per event, aggregate scores only):

eventtierbaseadapterdelta
seed 52004quick0.13960.3625+0.2229
seed 52005quick0.15210.4458+0.2938
seed 52006medium0.12170.4453+0.3237

Medium (multi-turn episodes + L3/L4 atoms) confirms with EVERY family positive, including axes flat on quick: mirage +0.600, siftstack +0.700, chronicle +0.700, toolsmith +0.383, lockpick +0.200, sirens +0.200, warren +0.200, menders +0.100, rites +0.100, stockade +0.053. The pre-registered three-leg decision rule (two positive quick seeds with mean ≥ +0.03; medium ≥ +0.02) is met at 8–16× its bars: verdict POSITIVE.

Per-family quick deltas (seed 52004): chronicle +0.750, siftstack +0.625, toolsmith +0.354 (→1.000), mirage +0.250, lockpick/rites/warren +0.125, menders 0.000, sirens 0.000, stockade −0.125.

Controls

  • Same-seed pairing + deterministic backend: all valid menagerie deltas are within the HF parity backend on one seed; vLLM numbers are never mixed in. A vLLM base-base-adapter event (seed 52001) measured the same-seed decode-nondeterminism spread at ~±0.03 aggregate — and, retrospectively, its "adapter" arm was the base model (below).
  • The vLLM LoRA no-op: two different trained adapters produced 1200/1200 byte-identical gym-eval generations; an in-process on-vs-off probe (same engine, same prompts, greedy) gave token-identical outputs. Mechanism: adapter tensors are base_model.model.model.layers.*, the served composite keeps text layers under model.language_model.layers.*; vLLM matches nothing silently. The repo's earlier zero-adapter "plumbing test" cannot catch this by construction. Codified with the required on-vs-off gate in docs/vllm_inference.md; merged-composite deployment implemented in scripts/merge_adapter.py. Menagerie's --adapter (vLLM path) is presumed equally affected; its --model-id guard also rejects local checkpoint paths (README documents checkpoint runs) — both flagged for maintainer action.
  • Transfer-vs-leakage signature: menagerie gains concentrate on trained axes; axes without training signal stay flat (menders, sirens) or dip (stockade — whose gym analogue was harvest-starved). Held-out gym families move as much as trained ones. Gym content was authored under the benchmark firewall (no menagerie contents ever read).
  • Lucky-guess gate (C28): small-answer-domain items require ≥3/K correct samples before entering SFT; episode turns require verifier-accepted actions (action_ok); at most 2 samples/item and 2 rollouts/instance.

Oracle Versus Deployable Evidence

All headline numbers are deployable: greedy, think-mode, deployed budgets, no scaffolding, bare model (adapter or merged). Oracle policies validated the gym instruments only; no oracle output, no benchmark content, and no external model enters training — provenance is exclusively the model's own execution-verified samples.

Interpretation

  • The binding deployment constraint at these difficulty levels was the truncation cascade at the answer-emission seam: the model consumes any budget, is force-closed, then restarts a verbose explanation and never emits a parseable answer. Training the model — on its own verified outputs — to conclude and to commit from a truncated chain removes that constraint generally: across formats, across gym families it never saw, and across the blackbox benchmark.
  • Breadth + emission-seam supervision installs something substrate-general; the C43/C45/C48 locality laws do not extend to this regime. Whether the remaining gap (menagerie ceiling; glyphgate/loomfix/stallwright frontiers) yields to iterated rounds is the program's next question.
  • Methodologically: gradient signal placement beat dose. 925 examples with weighted loss moved the blackbox instrument where 849 at full weight moved nothing.

Round 3 addendum — iteration re-saturates

Re-harvesting with the round-2 model opened the frontier at the data level (stallwright 0/160 → 48/60 correct at L1; glyphgate L1 2/80 → 60/60; 2,276 new examples, all families represented) — but blackbox gains did NOT compound: quick +0.285/+0.227 (seeds 52007/52008) vs round-2's +0.223/+0.294; medium +0.264 (seed 52009) vs +0.324; gym-internal +0.019. The install is a one-time step change from the recipe, stable at +0.22..+0.32 across five paired events; same-recipe expert iteration re-saturates (C11's coverage-boundedness, one level up).

Next Experiments

  • Difficulty escalation as the frontier lever (L3–L4 mass, harder gym generators, longer horizons) — same-recipe rounds are exhausted.
  • Recovery-arm-only ablation to split emission-seam repair from axis competence; breadth-vs-matched-dose single-family ablation (is breadth causal for the held-out-family transfer?).
  • slow/deep-tier confirmation events; vLLM-path restoration (merged checkpoints through menagerie once the --model-id guard is resolved).

Artifact Manifest

reports/artifact_manifest.yaml lists the adapter + merged checkpoint under large_artifacts/ (regenerable end-to-end from seeds in configs) and the gzipped harvest/eval row files under runs/.

Experiment log 7

Show the running log (7 entries, 2026-07-09 → 10)

Scaffold

Created as a new experiment scaffold (program: agentic_breadth_installation).

2026-07-09 — gym built, design reviewed, round-1 harvest launched

  • Designed the 12-family gym (10 trained + 2 held-out) against the public menagerie axis descriptions only; family module contract in reports/gym_design.md. All 12 families implemented with generators, verifiers, oracle/random policies, selftests: oracle 1.0 everywhere, degenerate/random floors <= 0.15 (runeward's 0.25 constant-IMPOSSIBLE floor documented, gate <= 0.30).
  • Pipeline: src/harness.py (batched atoms + lockstep episode driver over the template src/vllm_runner.py), scripts/harvest.py (per-family sharded, resumable), scripts/build_sft.py (verified + naturally-closed + terse-answer filter, lucky-guess gate, action_ok gate, per-item/rollout caps, (level,kind) round-robin family cap), scripts/train_think.py (C48 think-channel QLoRA recipe, revision-pinned), scripts/eval_gym.py, scripts/bench.py (fresh-seed enforcement, aggregate-only storage, null-calibration support).
  • Smoke harvest 1 (think 2048, 240 atom gens, 72 rollouts): keeper rate 0.146; five families at zero. Diagnosis: (a) terminal-marker pollution — the runner generates through <|im_end|>; gym parsers kept the literal marker, so word/glyph/list answers and ALL episode actions failed (mechanism lens verified: stripping markers raises correct 40->94/240); (b) at think 2048 the model solves hard items in-think, force-closes while double-checking, and the stage-2 answer restarts an explanation truncated before ANSWER.
  • Three-lens adversarial design review (reports/design_review.md): all three lenses sound_with_fixes; every must-fix applied pre-GPU (marker stripping + selftest enforcement, lucky-guess answer_domain gate, last_action_ok turn gate, round-robin family cap, pre-registration reconciliation, null calibration + three-way decision rule, yield-gate fallback).
  • Smoke harvest 2 (think 4096, fixed parsers): atom keeper rate 0.146 -> 0.433; episodes from 0.00 success everywhere to 0.50-1.00 in most cells (ferrier 1.00 with zero forced closes). Remaining thin: glyphgate atoms 0.08, loomfix atoms 0.08, stallwright atoms 0.00 (the model never concludes its optimization deliberation even at 4096 — matches the public stockade floor; yield gate will handle).
  • Launched the full round-1 harvest (~8.5 h projected) — then KILLED it ~35 min in on user direction: iteration speed is the research budget; a multi-hour-to-first-feedback loop wastes a 44-second instrument. Doctrine codified in gym_design.md ("Iteration doctrine") and the program charter.
  • Cut over to the fast profile (configs/fast.yaml): atoms 40/40 L1-L2 K=2 with family-adaptive think budgets (4096 only for slow-closing families), episodes 16/level K=2; harvest ~80 min; menagerie quick base-vs-adapter every round on a fresh seed. Full profile reserved for decision rounds. Fast harvest running under runs/harvest_round1_fast/.

2026-07-10 — round 1 fast: FLAT on both instruments; mechanism diagnosed

  • Fast harvest yields: 849 SFT examples across 9/10 families (stallwright 0 — never closes optimization deliberation even at 4096; pre-registered starved-family handling). Atom targets canonicalized to terse ANSWER: <value> after the filter audit showed the ≤96-token answer filter rejecting the model's verbose-but-correct answers wholesale.
  • Training required length-bucketed batching (random batching padded to ~max_length: 60 s/step -> mixed 10-50 s/step).
  • First menagerie event ever recorded for an install (quick, seed 52001, arms base/base/adapter): base0 0.1156, base1 0.1500, adapter 0.1271 — FLAT inside the same-seed null spread. NULL CALIBRATION KEY FINDING: base-vs-base same-seed spread is ~0.034 (three base realizations 0.116 / 0.150 / 0.171) — ~3x the published cross-backend 0.011; single quick arms only detect large effects. Seven of ten families are hard-zero in all arms; quick variance lives entirely in toolsmith/warren.
  • Gym-internal eval (greedy, think 1024, held-out seeds): base mean 0.184 vs adapter 0.187 — flat even in-distribution, held-out families flat, and the dominant failure UNCHANGED: parse_fail ~90/100 atoms in most families (the forced-close cascade; e.g. caravan 98/100 -> 95/100).
  • MECHANISM READ: round-1 training was near-self-distillation — loss 0.27 -> 0.20; ~1,400 own-text think tokens per example carry ~zero gradient and the ~10 tokens encoding the new behavior (terse ANSWER) are diluted AND conditioned on a naturally-completed chain, a state deployment rarely reaches at budget 1024 (the naturally-closed-only filter excluded the deployment-critical post-force-close state entirely).
  • ROUND 2 (same harvest, sharper signal): (a) forced-close recovery arm — 76 correct-after-cut samples train truncated_think + </think> + terse ANSWER with think-as-context (weight 0); (b) per-token loss weights (prompt 0 / think 0.2 / close+answer 1.0, echo-QLoRA precedent); (c) bs4/ga4. 925 examples (467 atom / 76 recovery / 382 episode turns). Primary readout: does gym parse_fail collapse; then a fresh-seed quick event.

2026-07-10 (cont.) — vLLM runtime LoRA is a SILENT NO-OP; rounds 1-2 were never measured

  • Round-2 gym-eval came back BYTE-IDENTICAL to round-1's (1200/1200 identical generations from two different adapters, sha-identical row files) — a behavioral impossibility that unmasked the real bug: vLLM 0.24 runtime LoRA silently does not apply Qwen3.5-4B PEFT adapters. In-process probe (same engine, same prompts, greedy, lora_request on vs off): token-identical outputs. Mechanism: adapter tensors are named base_model.model.model. layers.* but the served composite keeps text layers under model.language_model.layers.*; vLLM's mapping matches nothing, no error. ALL adapter arms so far (gym-evals and menagerie events at seeds 52001/52002) actually measured the BASE model. Codified in docs/vllm_inference.md with the on-vs-off behavioral gate; menagerie's --adapter flag is presumed equally affected (same vLLM path) — merged checkpoints via --model-id are the verified deployment.
  • Fix: scripts/merge_adapter.py merges LoRA deltas into the FULL COMPOSITE checkpoint by explicit name mapping (a text-only merge_and_unload checkpoint does not load — vLLM's Qwen3.5 class requires the composite config); runner gains model_override; bench gains a merged arm.
  • Merged round-2 probe on training items: the trained recovery behavior IS installed and visible (immediate terse ANSWER: <value> after a force-closed chain, where base emits a verbose re-explanation). Rounds 1-2 "flat" results were measurement artifacts, not nulls.

2026-07-10 (cont.) — REAL round-2 results: gym +0.52, MENAGERIE QUICK +0.22

  • Gym-internal (greedy, think 1024, held-out seeds; merged deployment): mean 0.184 -> 0.701 (+0.518). Parse failures collapsed (caravan 98/100 -> 8/100; kilnrite/runeward/loomfix -> ~0). BREADTH TRANSFERS IN-GYM: held-out never-trained families brinework +0.540 and spindle +0.608; harvest-starved stallwright (zero training examples) 0.000 -> 0.395 by pure transfer.
  • Menagerie --model-id guard rejects local checkpoint paths (string-prefix one-model check) despite the README documenting checkpoint runs — instrument bug flagged for the user; worked around via the HF parity backend (--backend qwen), where PEFT adapters genuinely apply and base-vs- adapter on the same seed is deterministic and noise-free.
  • FIRST VALID BLACKBOX EVENT (quick, seed 52004, HF backend both arms): base 0.1396 -> adapter 0.3625, DELTA +0.2229 — 7x the pre-registered +0.03 bar. Per-family deltas align with trained axes (chronicle +0.750, siftstack +0.625, toolsmith +0.354 to 1.000, mirage +0.250, lockpick/rites/ warren +0.125) while untrained/starved axes stay flat or dip (menders 0, sirens 0, stockade -0.125) — the signature of genuine transfer, not leakage. Replication (quick seed 52005) + medium confirmation (seed 52006) running per the decision rule.
  • Replication landed: quick seed 52005 base 0.1521 -> adapter 0.4458 (+0.2938). MEDIUM CONFIRMED (seed 52006, --max-batch 12 dodged the fla-kernel fault): base 0.1217 -> adapter 0.4453 (+0.3237), EVERY family positive incl. mirage +0.600, siftstack +0.700, chronicle +0.700, lockpick +0.200. Decision rule met on all three legs: VERDICT POSITIVE. C50 updated. Round 3 (configs/round3.yaml: fresh seed namespace, mass shifted to L2-L3, L3 episodes opened, harvest with the round-2 merged model, train from base on the rounds-union) launches next.

2026-07-10 (cont.) — round 3: frontier opens at harvest, blackbox does NOT compound

  • Round-3 harvest with the round-2 merged model transformed yields: the previously-unharvestable stallwright went 0/160 correct -> 48/60 at L1 (answering via the trained commit-from-truncated-chain behavior); glyphgate L1 2/80 -> 60/60. Dataset: 2,276 new examples (825 atom / 477 recovery / 974 episode turns), all 10 families represented.
  • Round-3 adapter (trained from BASE on the 3,201-example rounds-union; bs1/ga16 after a transient 'device not ready' CUDA fault — the same fault class that required --max-batch 12 on medium benches): quick +0.2854 (seed 52007) and +0.2271 (52008) vs round-2's +0.2229/+0.2938; medium +0.2637 (52009) vs +0.3237 (52006); gym-internal mean 0.701 -> 0.721 (+0.019; glyphgate +0.089, gatepost +0.129, but held-out spindle -0.124).
  • VERDICT: the install is a one-time STEP CHANGE from the recipe (emission-seam repair + breadth), holding a stable +0.22..+0.32 plateau across five paired events — but same-recipe expert iteration RE-SATURATES (C11's coverage-boundedness reappears at the recipe frontier). Next levers: difficulty escalation (L3-L4 mass, harder generators, longer horizons) and the pre-registered ablations, not more same-recipe rounds. C50 updated.

2026-07-10 (cont.) — menagerie maintenance (user-authorized) + cross-backend replication

  • Fixed the two instrument issues from C49 (user-authorized harness edits; families/ never read): (a) run.py --model-id now accepts local checkpoint directories config-verified against the pinned Qwen3.5-4B architecture (model_type + hidden/layers/vocab fingerprint), matching the documented checkpoint-run interface; (b) the vLLM backend now runs an on-vs-off LoRA application probe at engine start and ABORTS with a C49 message when the adapter has no effect (verified live: the round-2 adapter trips the gate with the correct remediation text; suite bench-validate stays green).
  • First VALID vLLM-backend paired event (quick, seed 52010, merged round-3 checkpoint via --model-id): base 0.1500 -> 0.4235, +0.2735 — cross-backend replication of the HF-measured install (+0.223..+0.294).

Data files 9

Result tables and metrics copied from the experiment folder — preview inline or open the raw file.

Reproduce

Smoke test

python3 scripts/run.py --smoke

Full run

see README Run section (staged pipeline; single-tenant GPU)

Run steps are documented inside the experiment folder (README and scripts).

Browse the experiment folder on GitHub ↗