Factor Recombination Ladder
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.
On this page
Results at a glance 7
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.
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 condition | seen-IID | format shift | recombination holdout |
|---|---|---|---|
| frozen base | 0% | 0% | 0% |
| trace-trained | 80.6% | 63.9% | 8.3% |
| labelled-trace-trained | 80.6% | 72.2% | 8.3% |
| no-trace-trained | 33.3% | 25% | 10% |
| shuffled-trace-trained | 27.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.
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.
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 evaluation | seen-IID | format shift |
|---|---|---|
| correct trace | 80.6% | 63.9% |
| trace removed | 16.7% | 19.4% |
| trace shuffled | 0% | 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.
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.
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 family | trace-trained | labelled-trace-trained | no-trace-trained |
|---|---|---|---|
| sorted_tuple_affine | 33.3% | 33.3% | 50% |
| sorted_contains_count | 8.3% | 0% | 0% |
| length_contains_code | 0% | 0% | 0% |
| modulo_sum_label | 0% | 0% | 0% |
| tuple_branch_label | 0% | 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.
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.
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 combination | Trace ladder |
|---|---|
| aggregation | 4.2% |
| arithmetic | 8.3% |
| branching | 0% |
| modulo | 0% |
| ordering | 20.8% |
| sequence_iteration | 8.3% |
| string_format | 2.1% |
| string_match | 4.2% |
| string_normalization | 8.3% |
| tuple_access | 16.7% |
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.
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.
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 variant | Seen-combination IID | Format shift | Recombination holdout |
|---|---|---|---|
| Full labelled prompt | 80.6% | 72.2% | 8.3% |
| Labels removed | 75% | 69.4% | 5% |
| No trace prompt | 22.2% | 16.7% | 8.3% |
| Shuffled trace prompt | 13.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.
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).
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 condition | Visible tests | Hidden tests |
|---|---|---|
| Frozen trace | 0% | 0% |
| Trace ladder | 80.6% | 83.3% |
| No-trace ladder | 33.3% | 36.1% |
| Shuffled-trace ladder | 27.8% | 30.6% |
| Labelled trace ladder | 80.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.
How to read
Each bar is one way of training the model; height is the training time in seconds (shorter is cheaper).
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 condition | Runtime (s) |
|---|---|
| Trace ladder | 426 |
| No-trace ladder | 438 |
| Shuffled-trace ladder | 420 |
| Labelled trace ladder | 422 |
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:
large_artifacts/factor_recombination_ladder/models/
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/dataTrain adapters:
python experiments/factor_recombination_ladder/scripts/run_training.py --suite allRun final evaluations:
python experiments/factor_recombination_ladder/scripts/run_final_evaluations.py --suite allGenerate report:
python experiments/factor_recombination_ladder/scripts/make_report.pyReport
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
| Condition | Seen-Combination IID | Format Shift | Recombination Holdout |
|---|---|---|---|
| Frozen trace | 0.0% (0/36) | 0.0% (0/36) | 0.0% (0/60) |
| Trace ladder | 80.6% (29/36) | 63.9% (23/36) | 8.3% (5/60) |
| No-trace ladder | 33.3% (12/36) | 25.0% (9/36) | 10.0% (6/60) |
| Shuffled-trace ladder | 27.8% (10/36) | 30.6% (11/36) | 8.3% (5/60) |
| Factor-labelled trace ladder | 80.6% (29/36) | 72.2% (26/36) | 8.3% (5/60) |
Prompt Ablations
| Condition | Seen-Combination IID | Format Shift | Recombination Holdout |
|---|---|---|---|
| Trace ladder | 80.6% (29/36) | 63.9% (23/36) | 8.3% (5/60) |
| Trace ladder, no trace prompt | 16.7% (6/36) | 19.4% (7/36) | 8.3% (5/60) |
| Trace ladder, shuffled trace prompt | 0.0% (0/36) | 2.8% (1/36) | 6.7% (4/60) |
| Factor-labelled trace ladder | 80.6% (29/36) | 72.2% (26/36) | 8.3% (5/60) |
| Labelled adapter, labels removed | 75.0% (27/36) | 69.4% (25/36) | 5.0% (3/60) |
| Labelled adapter, no trace prompt | 22.2% (8/36) | 16.7% (6/36) | 8.3% (5/60) |
| Labelled adapter, shuffled trace prompt | 13.9% (5/36) | 8.3% (3/36) | 6.7% (4/60) |
Recombination Holdout By Family
| Family | Trace ladder | Factor-labelled trace ladder | No-trace ladder | Shuffled-trace ladder |
|---|---|---|---|---|
| length_contains_code | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) |
| modulo_sum_label | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) |
| sorted_contains_count | 8.3% (1/12) | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) |
| sorted_tuple_affine | 33.3% (4/12) | 33.3% (4/12) | 50.0% (6/12) | 41.7% (5/12) |
| tuple_branch_label | 0.0% (0/12) | 8.3% (1/12) | 0.0% (0/12) | 0.0% (0/12) |
Trace Ladder Holdout By Factor
| Factor | repair@1 |
|---|---|
| aggregation | 4.2% (1/24) |
| arithmetic | 8.3% (4/48) |
| branching | 0.0% (0/36) |
| length | 0.0% (0/12) |
| modulo | 0.0% (0/12) |
| ordering | 20.8% (5/24) |
| sequence_iteration | 8.3% (1/12) |
| string_format | 2.1% (1/48) |
| string_match | 4.2% (1/24) |
| string_normalization | 8.3% (1/12) |
| tuple_access | 16.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
experiments/factor_recombination_ladder/figures/final_repair_by_condition_split.pngexperiments/factor_recombination_ladder/figures/recombination_holdout_by_family.png
Artifact Layout
- Compact artifacts:
experiments/factor_recombination_ladder/. - Large artifacts:
large_artifacts/factor_recombination_ladder/. - Dataset manifest:
experiments/factor_recombination_ladder/data/dataset_manifest.json. - Evaluation manifest:
experiments/factor_recombination_ladder/reports/final/final_evaluation_jobs.json.
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.pywith seed20260621. The first two build attempts caught and fixed generator issues before any dataset was accepted:
sum_thresholdcould reuse[1, 1]across visible and hidden cases for one parameter draw.modulo_shiftcould 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+modulobranching+tuple_accesslength+string_matchordering+string_matchordering+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-Instructrevision488639f1ff808d1d3d0ba301aef8c11461451ec5. 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 seed9173.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.csvreports/final_results_by_family.csvreports/final_results_by_factor.csv
Core repair@1 results:
| Condition | Seen-IID | Format shift | Recombination holdout |
|---|---|---|---|
| Frozen trace | 0.0% (0/36) | 0.0% (0/36) | 0.0% (0/60) |
| Trace ladder | 80.6% (29/36) | 63.9% (23/36) | 8.3% (5/60) |
| No-trace ladder | 33.3% (12/36) | 25.0% (9/36) | 10.0% (6/60) |
| Shuffled-trace ladder | 27.8% (10/36) | 30.6% (11/36) | 8.3% (5/60) |
| Factor-labelled trace ladder | 80.6% (29/36) | 72.2% (26/36) | 8.3% (5/60) |
Prompt ablation results:
| Condition | Seen-IID | Format shift | Recombination holdout |
|---|---|---|---|
| Trace ladder, no trace prompt | 16.7% (6/36) | 19.4% (7/36) | 8.3% (5/60) |
| Trace ladder, shuffled trace prompt | 0.0% (0/36) | 2.8% (1/36) | 6.7% (4/60) |
| Labelled adapter, labels removed | 75.0% (27/36) | 69.4% (25/36) | 5.0% (3/60) |
| Labelled adapter, no trace prompt | 22.2% (8/36) | 16.7% (6/36) | 8.3% (5/60) |
| Labelled adapter, shuffled trace prompt | 13.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
- Generated final markdown report:
reports/factor_recombination_ladder_report.md. Generated figures:
Verified artifact split:
- compact experiment directory: about 14 MB.
- large artifact directory: about 5.2 GB.
- no
.safetensors,.bin,.pt, or.pthfiles were present inexperiments/factor_recombination_ladder/.
- Final status: complete.
Figures 2
Data files 4
Result tables and metrics copied from the experiment folder — preview inline or open the raw file.
reports/final_results.csv12 kBreports/final_results_by_factor.csv37 kBreports/final_results_by_family.csv30 kBreports/final/final_evaluation_jobs.json41 kB
Reproduce
Run steps are documented inside the experiment folder (README and scripts).

