Feature-Factorized Rule Diversity
The one idea you need
Imagine teaching an apprentice to fix broken programs by drilling repairs. You can drill single tricks, drill combined tricks, or split the same practice time between both. Then test on bug types never drilled. Which practice diet best prepares them for genuinely new combinations?
The question
Does splitting practice between single-skill and combined-skill repairs help a small model fix brand-new bug combinations better than drilling either kind of practice alone?
What we found
No. All three practice diets fixed only about 1 in 5 brand-new bug combinations, so mixing bought nothing over drilling either kind alone. What actually mattered was showing worked, step-by-step repair reasoning during training: strip it out and success collapsed to about 1 in 30. And most of that thin transfer came from a single lucky bug family, not broad skill.
Why it matters
When fine-tuning small models to reach unseen combinations, spend effort on including step-by-step worked solutions, not on balancing which skill mixtures you cover. And check transfer family-by-family, since one easy family can inflate an otherwise flat average.
On this page
Results at a glance 6
How to read
Grouped bars show how often each training recipe fixes bugs across three tests: familiar single-skill, familiar combined-skill, and brand-new combinations. Taller is better; the flat gray bar is the untrained model.
Takeaway → On the brand-new-combination test all three trained recipes sit at nearly equal low height, so mixing practice adds no transfer over either recipe alone.
Data table
| evaluation split | frozen (no adapter) | singleton factors, trace | composite factors, trace | mixed factors, trace |
|---|---|---|---|---|
| singleton IID | 0% | 85% | 10% | 57.5% |
| composite IID | 0% | 22.2% | 91.7% | 69.4% |
| recombination holdout | 0% | 20% | 23.3% | 21.7% |
Numbers from reports/final_results.csv
Technical framing
Repair success by training coverage and eval split — Each coverage recipe masters its own distribution, but all three land at ~20-23% on held-out recombinations — mixing buys no extra transfer.
How to read
Bars show repair success on brand-new bug combinations across five setups that keep, remove, or scramble the step-by-step worked reasoning during practice or at solving time. Taller is better.
Takeaway → Only the setup keeping intact reasoning throughout rises; every removed or scrambled version drops to near zero, so the reasoning is essential.
Data table
| control condition | repair@1 |
|---|---|
| trace train + trace prompt | 21.7% |
| no-trace train | 3.3% |
| shuffled-trace train | 6.7% |
| trace adapter, no-trace prompt | 0% |
| trace adapter, shuffled-trace prompt | 1.7% |
Numbers from reports/final_results.csv
Technical framing
Aligned traces are necessary: mixed-coverage controls on recombination holdout — Removing or corrupting traces at train or eval time collapses recombination repair from 21.7% to near zero.
How to read
For each of five brand-new bug families, grouped bars show repair success under the three practice recipes, one color per recipe. Taller is better.
Takeaway → Only the sorted-join family reaches full height for every recipe while the other four stay near the floor, so transfer is confined to one family.
Data table
| held-out bug family | singleton factors, trace | composite factors, trace | mixed factors, trace |
|---|---|---|---|
| contains+length code | 0% | 0% | 0% |
| parity offset | 0% | 0% | 0% |
| sorted join | 100% | 100% | 100% |
| sum parity shift | 0% | 16.7% | 8.3% |
| tuple max label | 0% | 0% | 0% |
Numbers from reports/final_results_by_family.csv
Technical framing
Recombination transfer is concentrated in one family — All the apparent recombination transfer comes from the sorted-join family (12/12 for every adapter); the other four families stay near zero.
How to read
Grouped bars compare one trained model tested with intact, removed, or scrambled worked reasoning, across familiar single-skill, familiar combined-skill, and brand-new tests. Taller is better.
Takeaway → Removing or scrambling the reasoning at solving time flattens every group to near zero, so the reasoning must accompany the actual problem.
Data table
| Evaluation split | Mixed trace adapter, trace prompt | Same adapter, no-trace prompt | Same adapter, shuffled-trace prompt |
|---|---|---|---|
| Singleton IID | 57.5% | 5% | 5% |
| Composite IID | 69.4% | 13.9% | 8.3% |
| Recombination holdout | 21.7% | 0% | 1.7% |
Technical framing
Traces must also be present at evaluation time, not just in training — Removing or shuffling the trace at eval time collapses the trained mixed adapter to near zero on every split.
How to read
Bars show the mixed-diet model's repair success on brand-new combinations, one bar per underlying skill involved, sorted from highest to lowest. Taller is better.
Takeaway → A few skills reach full height while most sit near the floor, so the model's transfer is narrow and skill-specific rather than general.
Data table
| Primitive factor in held-out rule | Mixed factors, trace (recombination holdout) |
|---|---|
| sequence_iteration | 100% |
| sorting | 100% |
| string_normalization | 100% |
| string_format | 33.3% |
| aggregation | 4.2% |
| modulo | 4.2% |
| arithmetic | 2.1% |
| branching | 2.1% |
| string_match | 0% |
| tuple_access | 0% |
Technical framing
Mixed adapter's holdout transfer is confined to a few primitive factors — Three factors transfer perfectly while most sit near zero; the length factor (0.0%, omitted) also fails, so transfer is factor-specific.
How to read
Paired bars per training recipe: one for how often the code fix is well-formed and applies cleanly, one for how often it passes the hidden tests. Taller is better.
Takeaway → The 'applies cleanly' bar is near full for every recipe while 'passes tests' stays low, so failures come from misunderstanding the rule, not formatting.
Data table
| Training condition | Patch applies cleanly | Hidden tests pass |
|---|---|---|
| Singleton factors, trace | 100% | 20% |
| Composite factors, trace | 100% | 23.3% |
| Mixed factors, trace | 100% | 21.7% |
| Mixed, no trace | 96.7% | 3.3% |
| Mixed, shuffled trace | 100% | 6.7% |
Technical framing
Holdout failures are semantic, not formatting: patches apply but tests fail — Every condition emits well-formed, applicable patches on the holdout, so the 20-point gap to hidden-test pass is pure rule misunderstanding.
In the author’s words from the Overview
The best recombination score was the composite-trace adapter at 14/60; mixed trace reached 13/60 and mostly transferred only the sorted_join_holdout family.
Overview
Standalone experiment package for testing whether trace-conditioned repair transfer is driven more by isolated primitive factor coverage, analogous multi-factor composition coverage, or a fixed-budget mixture of both.
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.
Final Report
- Main report:
reports/feature_factorized_rule_diversity_report.md - Detailed log:
logs/experiment_log.md - Final results CSV:
reports/final_results.csv - Final evaluation manifest:
reports/final/final_evaluation_jobs.json
Key readout: aligned trace supervision is necessary, but fixed-budget mixed factor coverage did not improve broad recombination. The best recombination score was the composite-trace adapter at 14/60; mixed trace reached 13/60 and mostly transferred only the sorted_join_holdout family.
Large model artifacts are intentionally outside this directory:
large_artifacts/feature_factorized_rule_diversity/models/
Core Commands
Build data:
python experiments/feature_factorized_rule_diversity/scripts/build_factorized_dataset.py \
--output-dir experiments/feature_factorized_rule_diversity/dataTrain adapters:
python experiments/feature_factorized_rule_diversity/scripts/run_training.py --suite allRun final evaluations:
python experiments/feature_factorized_rule_diversity/scripts/run_final_evaluations.py --suite allGenerate report:
python experiments/feature_factorized_rule_diversity/scripts/make_report.pyReport
Rendered from reports/feature_factorized_rule_diversity_report.md
Question
Does held-out rule repair improve more when training examples cover isolated primitive factors, analogous multi-factor compositions, or a fixed-budget mixture of both?
Design
- Three trace-trained adapters use the same 240-record budget: singleton factors only, composite factors only, and a mixed singleton/composite allocation.
- Two controls use the mixed allocation with traces removed or trace outputs shuffled during training.
- Final evaluation uses singleton IID, composite IID, and recombination holdout splits.
- Checkpoints and adapter weights are stored outside this experiment directory under
large_artifacts/feature_factorized_rule_diversity/models/.
Overall Results
| Condition | Singleton IID | Composite IID | Recombination Holdout |
|---|---|---|---|
| Frozen trace | 0.0% (0/40) | 0.0% (0/36) | 0.0% (0/60) |
| Singleton factors, trace | 85.0% (34/40) | 22.2% (8/36) | 20.0% (12/60) |
| Composite factors, trace | 10.0% (4/40) | 91.7% (33/36) | 23.3% (14/60) |
| Mixed factors, trace | 57.5% (23/40) | 69.4% (25/36) | 21.7% (13/60) |
| Mixed factors, no trace train/eval | 5.0% (2/40) | 16.7% (6/36) | 3.3% (2/60) |
| Mixed factors, shuffled trace train | 5.0% (2/40) | 13.9% (5/36) | 6.7% (4/60) |
Prompt Ablations
| Condition | Singleton IID | Composite IID | Recombination Holdout |
|---|---|---|---|
| Mixed factors, trace | 57.5% (23/40) | 69.4% (25/36) | 21.7% (13/60) |
| Mixed trace adapter, no trace prompt | 5.0% (2/40) | 13.9% (5/36) | 0.0% (0/60) |
| Mixed trace adapter, shuffled trace prompt | 5.0% (2/40) | 8.3% (3/36) | 1.7% (1/60) |
Recombination Holdout By Family
| Family | Singleton factors, trace | Composite factors, trace | Mixed factors, trace |
|---|---|---|---|
| contains_length_code_holdout | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) |
| parity_offset_holdout | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) |
| sorted_join_holdout | 100.0% (12/12) | 100.0% (12/12) | 100.0% (12/12) |
| sum_parity_shift_holdout | 0.0% (0/12) | 16.7% (2/12) | 8.3% (1/12) |
| tuple_max_label_holdout | 0.0% (0/12) | 0.0% (0/12) | 0.0% (0/12) |
Mixed Trace Holdout By Factor
| Factor | repair@1 |
|---|---|
| aggregation | 4.2% (1/24) |
| arithmetic | 2.1% (1/48) |
| branching | 2.1% (1/48) |
| length | 0.0% (0/12) |
| modulo | 4.2% (1/24) |
| sequence_iteration | 100.0% (12/12) |
| sorting | 100.0% (12/12) |
| string_format | 33.3% (12/36) |
| string_match | 0.0% (0/12) |
| string_normalization | 100.0% (12/12) |
| tuple_access | 0.0% (0/12) |
Readout
- Best core recombination result: Composite factors, trace at 23.3% (14/60).
- Mixed trace vs controls on recombination: trace 21.7%, no trace 3.3%, shuffled-trace train 6.7%.
Figures
experiments/feature_factorized_rule_diversity/figures/final_repair_by_condition_split.pngexperiments/feature_factorized_rule_diversity/figures/recombination_holdout_by_family.png
Artifact Layout
- Compact artifacts:
experiments/feature_factorized_rule_diversity/. - Large artifacts:
large_artifacts/feature_factorized_rule_diversity/. - Dataset manifest:
experiments/feature_factorized_rule_diversity/data/dataset_manifest.json. - Evaluation manifest:
experiments/feature_factorized_rule_diversity/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/feature_factorized_rule_diversity/. - Created large-artifact directory at
large_artifacts/feature_factorized_rule_diversity/models/. - Defined the central question: compare fixed-budget primitive factor coverage, analogous composition coverage, and a mixed allocation for trace-conditioned held-out recombination repair.
Implemented
scripts/build_factorized_dataset.py.- The builder writes three 240-record training sets.
- It writes three evaluation splits: singleton IID, composite IID, and recombination holdout.
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,
- visible expected outputs appear in the failing trace.
- Implemented
scripts/eval_factorized.pywith summary outputs by split, family, and factor tag. - Implemented
scripts/run_training.pyso all adapter training jobs and hyperparameters are captured inreports/training/training_jobs.json. - Implemented
scripts/run_final_evaluations.pyfor the full final evaluation matrix. - Implemented
scripts/make_report.pyfor CSV summaries, plots, markdown report, and large-artifact manifest refresh.
Next step: build and validate the dataset, then train the five planned adapters.
Dataset Build Pass 1
- Started dataset generation with full pytest validation.
- Interrupted after the run remained silent for too long during the first split.
- Diagnosis: validation was active, but the builder had no progress logging. The test template also used a looped pytest test, which can hide later visible counterexamples after the first failure.
Fix applied:
- converted generated tests to
pytest.mark.parametrizecases, - added per-family progress logging to stderr.
- converted generated tests to
Dataset Build Pass 2
- Completed dataset generation and validation.
Wrote 856 total records:
train_singletons: 240 records, 10 singleton families x 24 records.train_composites: 240 records, 6 composite families x 40 records.train_mixed: 240 records, 8 mixed families x 30 records.val_singleton_iid: 40 records.val_composite_iid: 36 records.val_recombination_holdout: 60 records, 5 held-out recombination families x 12 records.
- Confirmed compact experiment directory size after dataset build: about 13 MB.
- Confirmed
large_artifacts/feature_factorized_rule_diversity/remains empty before training.
Next step: train five LoRA adapters: singleton trace, composite trace, mixed trace, mixed no-trace, and mixed shuffled-trace.
Training
- Completed all five planned LoRA training jobs.
- Training jobs and exact commands are recorded in
reports/training/training_jobs.json. - Console output is recorded in
run_logs/training_console.log. Adapter directories:
large_artifacts/feature_factorized_rule_diversity/models/singletons_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/composites_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/mixed_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/mixed_no_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/mixed_shuffled_trace_lora
- Approximate adapter directory size after training: 1.3 GB each.
Final checkpoint eval losses:
- singleton trace on singleton IID: about 0.0071.
- composite trace on composite IID: about 0.0018.
- mixed trace on recombination holdout: about 0.0886.
- mixed no-trace on recombination holdout: about 0.2108.
- mixed shuffled-trace on recombination holdout: about 0.1782.
Next step: run final generation evaluations for frozen baseline, trace adapters, controls, and prompt ablations.
Final Generation Evaluation
- Completed the full 24-job final evaluation suite.
- Final evaluation jobs and result paths are recorded in
reports/final/final_evaluation_jobs.json. - Console output is recorded in
run_logs/final_evaluation_console.log. Generated CSV summaries:
reports/final_results.csvreports/final_results_by_family.csvreports/final_results_by_factor.csv
Generated report and figures:
reports/feature_factorized_rule_diversity_report.mdfigures/final_repair_by_condition_split.pngfigures/recombination_holdout_by_family.png
Core repair@1 results:
| Condition | Singleton IID | Composite IID | Recombination Holdout |
|---|---|---|---|
| Frozen trace | 0/40 | 0/36 | 0/60 |
| Singleton factors, trace | 34/40 | 8/36 | 12/60 |
| Composite factors, trace | 4/40 | 33/36 | 14/60 |
| Mixed factors, trace | 23/40 | 25/36 | 13/60 |
| Mixed factors, no trace train/eval | 2/40 | 6/36 | 2/60 |
| Mixed factors, shuffled trace train | 2/40 | 5/36 | 4/60 |
Prompt ablations for the mixed trace adapter:
| Prompt condition | Singleton IID | Composite IID | Recombination Holdout |
|---|---|---|---|
| Normal aligned trace prompt | 23/40 | 25/36 | 13/60 |
| No-trace prompt | 2/40 | 5/36 | 0/60 |
| Shuffled-trace prompt | 2/40 | 3/36 | 1/60 |
Recombination holdout family pattern for the three main trace adapters:
| Family | Singleton trace | Composite trace | Mixed trace |
|---|---|---|---|
| contains_length_code_holdout | 0/12 | 0/12 | 0/12 |
| parity_offset_holdout | 0/12 | 0/12 | 0/12 |
| sorted_join_holdout | 12/12 | 12/12 | 12/12 |
| sum_parity_shift_holdout | 0/12 | 2/12 | 1/12 |
| tuple_max_label_holdout | 0/12 | 0/12 | 0/12 |
Interpretation:
- The strongest in-distribution behavior is narrow specialization: singleton trace is best on singleton IID, and composite trace is best on composite IID.
- The fixed-budget mixed trace adapter improves breadth relative to single-domain adapters, but it does not improve the recombination holdout. It reaches 13/60, slightly below composite trace at 14/60 and only slightly above singleton trace at 12/60.
- The apparent recombination success is mostly not broad recombination. All three trace adapters solve
sorted_join_holdoutperfectly, but they fail three of five holdout families completely. Composite trace gets only 2/12 onsum_parity_shift_holdout; mixed trace gets only 1/12. - Aligned traces are clearly important. Removing traces during training collapses mixed performance to 2/40, 6/36, and 2/60. Shuffling training traces also collapses to 2/40, 5/36, and 4/60.
- The aligned mixed trace adapter is also highly dependent on the inference prompt contract. With no trace prompt it drops to 2/40, 5/36, and 0/60. With shuffled trace prompts it drops to 2/40, 3/36, and 1/60.
Decision readout:
- This experiment does not support simple fixed-budget mixing as the next scaling direction for broad recombination.
- The most useful positive signal is that aligned traces carry real supervision. The most important failure is that traces and examples do not yet teach reusable factor abstractions for length/string-match/tuple/modulo recombinations.
- The next experiment should preserve aligned trace supervision, but change the data design toward factor-balanced recombination coverage and trace consistency diagnostics instead of simply mixing singleton and composite examples.
Artifact Verification
- Compact experiment directory:
experiments/feature_factorized_rule_diversity/, about 19 MB after reports and figures. - Large artifact directory:
large_artifacts/feature_factorized_rule_diversity/, about 6.4 GB total. Adapter/checkpoint directories are intentionally outside the compact experiment package:
large_artifacts/feature_factorized_rule_diversity/models/singletons_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/composites_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/mixed_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/mixed_no_trace_loralarge_artifacts/feature_factorized_rule_diversity/models/mixed_shuffled_trace_lora
- Large artifact manifest refreshed at
large_artifacts_manifest.md.
Figures 2
Data files 4
Result tables and metrics copied from the experiment folder — preview inline or open the raw file.
reports/final_results.csv8.8 kBreports/final_results_by_factor.csv24 kBreports/final_results_by_family.csv15 kBreports/final/final_evaluation_jobs.json34 kB
Reproduce
Run steps are documented inside the experiment folder (README and scripts).

