Research log Small Model Experimentation
GitHub

Factor Recombination Ladder

Finished2026-06-21imported · line ZBenchmark GeneralizationGitHub ↗
Models master each fix but cannot blend skills

The one idea you need

Each bug fix pairs two skills the model already knows, say sorting and counting. Trained on hundreds of such pairings, it aces every pair it practiced. But hand it a fresh combination of two familiar skills, and it can no longer fix the code.

The question

If a model learns to fix broken code by combining skills, can it handle a fresh pairing of two skills it already knows but never saw combined?

What we found

No. Trained on worked solutions, the model fixed about 81% of bugs when two skills were paired the way it saw in training, but only 8 to 10% when the same familiar skills were paired in a new way. Adding skill labels lifted some familiar cases yet moved that wall not at all. It learns each pairing, not how to recombine skills.

Why it matters

If you fine-tune a small model to repair code or solve tasks, cover every skill combination you actually need in the training data. Do not count on it to bridge to unseen pairings of skills it already knows.

Bugs fixed on familiar skill pairings81%two skills paired the way training showed them
Bugs fixed on brand-new skill pairings8-10%familiar skills combined in a way unseen in training
Fixing from prompting alone, no fine-tuning0%the same worked examples placed only in the prompt
Fixing after hiding the worked solution at test time81% → 17%shows the model reads the solution, not just its format
On this page
  1. Results at a glance
  2. Overview
  3. Report
    1. Question
    2. Design
    3. Overall Results
    4. Prompt Ablations
    5. Recombination Holdout By Family
    6. Trace Ladder Holdout By Factor
    7. Readout
    8. Figures
    9. Artifact Layout
  4. Experiment log
  5. Figures
  6. Data files
  7. Reproduce
  8. Related

Results at a glance 7

Fixing familiar bugs versus brand-new skill combinations

How to read

Each cluster is one training setup; three bars show the share of bugs fixed (taller is better) on familiar pairings, the same bugs reworded, and brand-new skill combinations.

0%25%50%75%100%frozen basefrozen base0%0%0%trace-trainedtrace-trained80.6%63.9%8.3%labelled-trace-trainedlabelled-trace-trained80.6%72.2%8.3%no-trace-trainedno-trace-trained33.3%25%10%shuffled-trace-trainedshuffled-trace-trained27.8%30.6%8.3%

Takeaway → Brand-new-combination bars stay tiny, about 8 to 10% for every trained setup, while familiar bars reach 64 to 81%. Recombining known skills is a hard wall.

Data table
training conditionseen-IIDformat shiftrecombination holdout
frozen base0%0%0%
trace-trained80.6%63.9%8.3%
labelled-trace-trained80.6%72.2%8.3%
no-trace-trained33.3%25%10%
shuffled-trace-trained27.8%30.6%8.3%

Numbers from reports/final_results.csv

Technical framing

Repair success by training condition and evaluation split — Trace training lifts seen and format-shifted repair to 64-81%, but held-out factor recombination stays near 8-10% for every condition.

What happens when the worked solution is taken away at test time

How to read

Bars show the share of bugs fixed (taller is better) when the model is given its correct worked solution, none at all, or a scrambled one, for familiar bugs and the same bugs reworded.

0%25%50%75%100%correct tracecorrect trace80.6%63.9%trace removedtrace removed16.7%19.4%trace shuffledtrace shuffled0%2.8%

Takeaway → Fixing collapses from 64 to 81% toward zero once the worked solution is removed or scrambled, proving the model genuinely reads it.

Data table
prompt condition at evaluationseen-IIDformat shift
correct trace80.6%63.9%
trace removed16.7%19.4%
trace shuffled0%2.8%

Numbers from reports/final_results.csv

Technical framing

Trace-trained adapter with traces removed or shuffled at test time — The trace-trained adapter collapses without its correct trace, so the model is genuinely reading trace content, not ignoring it.

Which brand-new problem types ever get fixed

How to read

Each cluster is one brand-new problem type unseen in training; bars show the share fixed (taller is better) for three ways of training the model.

0%20%40%60%sorted_tuple_affinesorted_tuple_affine33.3%33.3%50%sorted_contains_countsorted_contains_count8.3%0%0%length_contains_codelength_contains_code0%0%0%modulo_sum_labelmodulo_sum_label0%0%0%tuple_branch_labeltuple_branch_label0%8.3%0%

Takeaway → Only one problem type reaches 33 to 50%; two others barely register near 8%, and the rest sit at zero, so nearly every novel skill combination is never solved.

Data table
held-out factor-pair familytrace-trainedlabelled-trace-trainedno-trace-trained
sorted_tuple_affine33.3%33.3%50%
sorted_contains_count8.3%0%0%
length_contains_code0%0%0%
modulo_sum_label0%0%0%
tuple_branch_label0%8.3%0%

Numbers from reports/final_results_by_family.csv

Technical framing

Recombination holdout by held-out bug family — Almost all holdout success comes from one family (sorted_tuple_affine); most novel factor pairings never succeed.

Which individual skills carry over into new combinations

How to read

Each bar is one skill appearing inside a brand-new combination; height is the share of those bugs fixed (taller is better) by the worked-solution-trained model.

0%10%20%30%aggregationaggregation4.2%arithmeticarithmetic8.3%branchingbranching0%modulomodulo0%orderingordering20.8%sequence_iterationsequence_iteration8.3%string_formatstring_format2.1%string_matchstring_match4.2%string_normalizationstring_normalization8.3%tuple_accesstuple_access16.7%

Takeaway → Most skills sit at or near zero; only ordering (about 21%) and tuple handling (about 17%) show any carryover into unfamiliar pairings.

Data table
Factor appearing in held-out combinationTrace ladder
aggregation4.2%
arithmetic8.3%
branching0%
modulo0%
ordering20.8%
sequence_iteration8.3%
string_format2.1%
string_match4.2%
string_normalization8.3%
tuple_access16.7%

Numbers from reports/factor_recombination_ladder_report.md (Trace Ladder Holdout By Factor table; length factor at 0.0% omitted for the 10-category limit)

Technical framing

Recombination holdout by shared factor (trace-trained adapter) — Held-out recombination stays near zero for most factors; only ordering and tuple_access show any transfer.

Do the extra skill labels matter, or the worked solution?

How to read

Each cluster is a different test-time prompt; three bars show the share fixed (taller is better) on familiar bugs, reworded bugs, and brand-new combinations.

0%25%50%75%100%Full labelled promptFull labelled prompt80.6%72.2%8.3%Labels removedLabels removed75%69.4%5%No trace promptNo trace prompt22.2%16.7%8.3%Shuffled trace promptShuffled trace prompt13.9%8.3%6.7%

Takeaway → Stripping the skill labels barely hurts (81% to 75%), but removing the worked solution collapses familiar fixing to about 22%. The worked solution does the work.

Data table
Test-time prompt variantSeen-combination IIDFormat shiftRecombination holdout
Full labelled prompt80.6%72.2%8.3%
Labels removed75%69.4%5%
No trace prompt22.2%16.7%8.3%
Shuffled trace prompt13.9%8.3%6.7%

Numbers from reports/factor_recombination_ladder_report.md (Prompt Ablations table)

Technical framing

Factor-labelled adapter: removing labels barely hurts, removing traces collapses it — Stripping factor labels costs only ~3-6 points, so the adapter leans on trace content, not the labels themselves.

Do the fixes pass hidden checks, not just the visible ones?

How to read

Each cluster is one way of training the model; paired bars show the pass rate on the checks the model was shown versus hidden checks it never saw (taller is better).

0%25%50%75%100%Frozen traceFrozen trace0%0%Trace ladderTrace ladder80.6%83.3%No-trace ladderNo-trace ladder33.3%36.1%Shuffled-trace ladderShuffled-trace ladder27.8%30.6%Labelled trace ladderLabelled trace ladder80.6%80.6%

Takeaway → Hidden-check pass rates match or slightly beat the visible ones, so successful fixes are genuine, not gaming the checks in view.

Data table
Training conditionVisible testsHidden tests
Frozen trace0%0%
Trace ladder80.6%83.3%
No-trace ladder33.3%36.1%
Shuffled-trace ladder27.8%30.6%
Labelled trace ladder80.6%80.6%

Numbers from reports/final_results.csv

Technical framing

Visible vs hidden test pass rate on seen combinations — Hidden-test pass rates match or slightly exceed visible ones, so successful repairs are not overfitting the shown tests.

Training cost is nearly identical across methods

How to read

Each bar is one way of training the model; height is the training time in seconds (shorter is cheaper).

0200400600Trace ladderTrace ladder426No-trace ladderNo-trace ladder438Shuffled-trace ladderShuffled-trace ladder420Labelled trace ladderLabelled trace ladder422

Takeaway → All four methods take about seven minutes, so the large accuracy gaps come from the worked-solution content, not from extra compute.

Data table
Training conditionRuntime (s)
Trace ladder426
No-trace ladder438
Shuffled-trace ladder420
Labelled trace ladder422

Numbers from reports/training/training_jobs.json

Technical framing

LoRA training cost per condition — All four adapters cost about seven minutes to train, so the big accuracy gaps come from trace content, not compute.

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

The experiment found a sharp split between in-distribution repair learning and held-out factor recombination. Correct trace training worked well on seen factor combinations: 80.6% seen-IID repair and 63.9% format-shift repair. Factor labels improved format shift to 72.2%, but did not improve recombination holdout. Recombination holdout stayed low across trained conditions: trace 8.3%, labelled trace 8.3%, no-trace 10.0%, shuffled-trace 8.3%. Prompt ablations showed the trace content is behaviorally important: removing or shuffling traces collapsed seen/format performance for trace-trained adapters. Main readout: this ladder supports trace-conditioned template/mechanism learning, but not robust transfer to held-out factor-pair recombination. … Read the full result →

Overview

Standalone experiment package for testing whether trace-conditioned repair learns reusable factor recombination, rather than only learning seen rule templates.

Result

The experiment found a sharp split between in-distribution repair learning and held-out factor recombination.

  • Correct trace training worked well on seen factor combinations: 80.6% seen-IID repair and 63.9% format-shift repair.
  • Factor labels improved format shift to 72.2%, but did not improve recombination holdout.
  • Recombination holdout stayed low across trained conditions: trace 8.3%, labelled trace 8.3%, no-trace 10.0%, shuffled-trace 8.3%.
  • Prompt ablations showed the trace content is behaviorally important: removing or shuffling traces collapsed seen/format performance for trace-trained adapters.
  • Main readout: this ladder supports trace-conditioned template/mechanism learning, but not robust transfer to held-out factor-pair recombination.

Primary report:

  • reports/factor_recombination_ladder_report.md

Layout

  • configs/experiment.json: fixed design, model, and hyperparameter settings.
  • data/: generated JSONL datasets and dataset manifest.
  • scripts/: dataset generation, LoRA training runner, final evaluation runner, and report generator.
  • reports/: training manifests, final evaluation JSON, CSV summaries, and markdown report.
  • figures/: generated plots.
  • logs/experiment_log.md: chronological run log.

Large model artifacts are intentionally outside this directory:

The compact experiment directory contains scripts, logs, data, reports, and figures only. Adapter weights and training checkpoints are separated so this directory can be downloaded without multi-GB model files.

Core Commands

Build data:

python experiments/factor_recombination_ladder/scripts/build_ladder_dataset.py \
  --output-dir experiments/factor_recombination_ladder/data

Train adapters:

python experiments/factor_recombination_ladder/scripts/run_training.py --suite all

Run final evaluations:

python experiments/factor_recombination_ladder/scripts/run_final_evaluations.py --suite all

Generate report:

python experiments/factor_recombination_ladder/scripts/make_report.py

Report

Rendered from reports/factor_recombination_ladder_report.md

Question

Can trace-conditioned repair learn reusable factor recombination when specific factor-pair cells are held out from training?

Design

  • The training set contains 12 seen rule families with 240 total records per condition.
  • The recombination split contains five held-out factor-pair cells absent from training.
  • Core conditions compare frozen trace prompting, aligned trace training, no-trace training, shuffled-trace training, and factor-labelled trace training.
  • Prompt ablations test whether trained trace adapters depend on trace content and factor labels at inference time.
  • Checkpoints and adapter weights are stored outside this experiment directory under large_artifacts/factor_recombination_ladder/models/.

Overall Results

ConditionSeen-Combination IIDFormat ShiftRecombination Holdout
Frozen trace0.0% (0/36)0.0% (0/36)0.0% (0/60)
Trace ladder80.6% (29/36)63.9% (23/36)8.3% (5/60)
No-trace ladder33.3% (12/36)25.0% (9/36)10.0% (6/60)
Shuffled-trace ladder27.8% (10/36)30.6% (11/36)8.3% (5/60)
Factor-labelled trace ladder80.6% (29/36)72.2% (26/36)8.3% (5/60)

Prompt Ablations

ConditionSeen-Combination IIDFormat ShiftRecombination Holdout
Trace ladder80.6% (29/36)63.9% (23/36)8.3% (5/60)
Trace ladder, no trace prompt16.7% (6/36)19.4% (7/36)8.3% (5/60)
Trace ladder, shuffled trace prompt0.0% (0/36)2.8% (1/36)6.7% (4/60)
Factor-labelled trace ladder80.6% (29/36)72.2% (26/36)8.3% (5/60)
Labelled adapter, labels removed75.0% (27/36)69.4% (25/36)5.0% (3/60)
Labelled adapter, no trace prompt22.2% (8/36)16.7% (6/36)8.3% (5/60)
Labelled adapter, shuffled trace prompt13.9% (5/36)8.3% (3/36)6.7% (4/60)

Recombination Holdout By Family

FamilyTrace ladderFactor-labelled trace ladderNo-trace ladderShuffled-trace ladder
length_contains_code0.0% (0/12)0.0% (0/12)0.0% (0/12)0.0% (0/12)
modulo_sum_label0.0% (0/12)0.0% (0/12)0.0% (0/12)0.0% (0/12)
sorted_contains_count8.3% (1/12)0.0% (0/12)0.0% (0/12)0.0% (0/12)
sorted_tuple_affine33.3% (4/12)33.3% (4/12)50.0% (6/12)41.7% (5/12)
tuple_branch_label0.0% (0/12)8.3% (1/12)0.0% (0/12)0.0% (0/12)

Trace Ladder Holdout By Factor

Factorrepair@1
aggregation4.2% (1/24)
arithmetic8.3% (4/48)
branching0.0% (0/36)
length0.0% (0/12)
modulo0.0% (0/12)
ordering20.8% (5/24)
sequence_iteration8.3% (1/12)
string_format2.1% (1/48)
string_match4.2% (1/24)
string_normalization8.3% (1/12)
tuple_access16.7% (4/24)

Readout

  • Best core recombination result: No-trace ladder at 10.0% (6/60).
  • Factor labels delta on recombination: trace 8.3% (5/60) vs labelled trace 8.3% (5/60).

Figures

Artifact Layout

Experiment log 6

Show the running log (6 entries, 2026-06-21)

2026-06-21

  • Created standalone experiment directory at experiments/factor_recombination_ladder/.
  • Created large-artifact directory at large_artifacts/factor_recombination_ladder/models/.
  • Defined the central question: can trace-conditioned repair learn reusable factor recombination when specific factor-pair cells are held out from training?
  • Planned a factor-balanced ladder:

    • 12 seen training rule families, 20 records each, 240 total records per training condition.
    • 5 recombination holdout families, each withholding one factor pair absent from training.
    • Three evaluation splits: seen-combination IID, format-shifted seen combinations, and recombination holdout.
    • Trace, no-trace, shuffled-trace, and factor-labelled trace training conditions.
  • Implemented scripts/build_ladder_dataset.py.

    • The builder writes normal and factor-labelled train/eval JSONL files.
    • Each generated record is validated before writing:

      • the wrong implementation fails visible tests,
      • the target corrective diff applies,
      • the target implementation passes visible and hidden tests,
      • hidden inputs are disjoint from visible inputs.

Next step: build and validate the dataset.

Dataset Build

  • Ran scripts/build_ladder_dataset.py with seed 20260621.
  • The first two build attempts caught and fixed generator issues before any dataset was accepted:

    • sum_threshold could reuse [1, 1] across visible and hidden cases for one parameter draw.
    • modulo_shift could reuse a scalar hidden input that also appeared in visible cases.
  • Both templates were patched so hidden inputs are selected disjointly from visible inputs.
  • Completed dataset generation and validation.
  • Wrote 1,020 total JSONL records across normal and labelled variants:

    • repair_train_ladder: 240 records, 12 seen rule families x 20.
    • repair_train_ladder_labelled: 240 records, same examples with factor labels prepended to the failing trace.
    • repair_val_seen_iid: 36 records, 12 seen rule families x 3.
    • repair_val_format_shift: 36 records, 12 seen rule families x 3.
    • repair_val_recombination_holdout: 60 records, 5 held-out recombination families x 12.
    • labelled variants for each evaluation split.
  • Confirmed held-out factor pairs are absent from training:

    • aggregation+modulo
    • branching+tuple_access
    • length+string_match
    • ordering+string_match
    • ordering+tuple_access
  • Manifest reports leaked_heldout_pairs: [].
  • Compact experiment directory size after dataset build: about 5.4 MB.
  • large_artifacts/factor_recombination_ladder/ remains empty before training.

Next step: train four LoRA adapters: trace ladder, no-trace ladder, shuffled-trace ladder, and factor-labelled trace ladder.

Training

  • Ran scripts/run_training.py --suite all.
  • Trained four LoRA adapters from Qwen/Qwen2.5-Coder-3B-Instruct revision 488639f1ff808d1d3d0ba301aef8c11461451ec5.
  • Shared hyperparameters:

    • max sequence length: 3072
    • epochs: 3
    • learning rate: 1.5e-4
    • LoRA rank/alpha/dropout: 32/64/0.05
    • gradient accumulation: 8
    • eval/save interval: 30 steps
  • Adapters trained:

    • ladder_trace_lora: normal traces.
    • ladder_no_trace_lora: no trace in prompt.
    • ladder_shuffled_trace_lora: traces shuffled by seed 9173.
    • labelled_trace_lora: normal traces with factor labels prepended.
  • Stored all adapters and checkpoints outside the compact experiment directory under large_artifacts/factor_recombination_ladder/models/.
  • Training console log: run_logs/training_console.log.
  • Training manifest: reports/training/training_jobs.json.
  • End-of-training loss pattern:

    • trace and labelled-trace adapters learned much lower training loss than no-trace and shuffled-trace controls.
    • held-out validation loss remained substantially higher than seen-format validation for all conditions.

Next step: run the full 30-job final evaluation matrix.

Final Evaluation

  • Ran scripts/run_final_evaluations.py --suite all.
  • Completed all 30 planned final evaluation jobs:

    • 5 core conditions x 3 splits.
    • 5 prompt ablation conditions x 3 splits.
  • Final evaluation console log: run_logs/final_evaluation_console.log.
  • Final evaluation manifest: reports/final/final_evaluation_jobs.json.
  • Machine-readable summaries:

    • reports/final_results.csv
    • reports/final_results_by_family.csv
    • reports/final_results_by_factor.csv

Core repair@1 results:

ConditionSeen-IIDFormat shiftRecombination holdout
Frozen trace0.0% (0/36)0.0% (0/36)0.0% (0/60)
Trace ladder80.6% (29/36)63.9% (23/36)8.3% (5/60)
No-trace ladder33.3% (12/36)25.0% (9/36)10.0% (6/60)
Shuffled-trace ladder27.8% (10/36)30.6% (11/36)8.3% (5/60)
Factor-labelled trace ladder80.6% (29/36)72.2% (26/36)8.3% (5/60)

Prompt ablation results:

ConditionSeen-IIDFormat shiftRecombination holdout
Trace ladder, no trace prompt16.7% (6/36)19.4% (7/36)8.3% (5/60)
Trace ladder, shuffled trace prompt0.0% (0/36)2.8% (1/36)6.7% (4/60)
Labelled adapter, labels removed75.0% (27/36)69.4% (25/36)5.0% (3/60)
Labelled adapter, no trace prompt22.2% (8/36)16.7% (6/36)8.3% (5/60)
Labelled adapter, shuffled trace prompt13.9% (5/36)8.3% (3/36)6.7% (4/60)

Recombination holdout by family showed the small number of successes concentrated in sorted_tuple_affine; three of five held-out families were at or near zero across all trained conditions.

Interpretation

  • Correct trace supervision has a large effect on seen-combination repair and format-shift repair.
  • Shuffled traces and no-trace prompts substantially degrade seen and format-shift performance, so the trace content is behaviorally important.
  • Factor labels help format shift, and most of that benefit remains when labels are removed at inference time, suggesting labels improve training organization more than acting as a required runtime token.
  • The key negative result is stable: trace supervision did not produce robust transfer to unseen factor-pair recombinations in this setup.
  • Best core recombination score was the no-trace ladder at 10.0% (6/60), only one example above trace and labelled-trace at 8.3% (5/60).
  • This experiment should be treated as evidence that the next most useful direction is not more trace decoration, but an intervention that directly trains or searches over factor recombination.

Wrap-Up

Figures 2

final repair by condition split
final repair by condition split · figures/
recombination holdout by family
recombination holdout by family · figures/

Data files 4

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

Reproduce

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

Browse the experiment folder on GitHub ↗