Skip to content

feat: aggregation-safe mutation generation + balanced K/R charge variants - #50

Merged
cschanhniem merged 2 commits into
mainfrom
feat/aggregation-safe-mutations
Jun 28, 2026
Merged

cschanhniem merged 2 commits into
mainfrom
feat/aggregation-safe-mutations

Conversation

@cschanhniem

Copy link
Copy Markdown
Collaborator

Summary

Closes the divergence between generator, scorer, and QC layers — all three now use the same VILMFW-run-≥4 aggregation threshold:

  • generate_aggregation_safe_double_variants(): filters double substitutions that would create hydrophobic runs ≥4 residues. Previously, the generator could produce sequences that synthesis_feasibility_score() immediately penalised — now they're filtered at the source. Attempt budget raised to 50× to handle hydrophobic seeds.
  • generate_balanced_charge_variants(): generates both K and R replacements at each polar (S/T/N/Q) position. Old generate_charge_enhanced_variants() randomly picked one; now both are generated so the scoring pipeline can select the better GRAVY/selectivity profile automatically (K KD=−3.9, R KD=−4.5).
  • generate_all_variants(): updated to use the new safe functions by default; old functions preserved for backward compatibility.
  • SynthQC.aggregation_propensity_score: float: continuous [0,1] aggregation score added to SynthQC dataclass and to_dict(), from physchem.aggregation_propensity(). Provides gradient information alongside the existing boolean aggregation_risk flag — operators can now distinguish score 0.14 (one run-of-4) from 0.70 (run-of-8) rather than seeing both as a generic boolean True.
  • _max_hydrophobic_run() helper and _AGG_HYDROPHOBIC constant added to template_mutator.py, explicitly matching AGG_HYDROPHOBIC in physchem.py.

Test plan

  • tests/test_aggregation_safe_mutations.py: 33 new tests covering _max_hydrophobic_run(), generate_aggregation_safe_double_variants(), generate_balanced_charge_variants(), generate_all_variants() no-run guarantee, and SynthQC.aggregation_propensity_score
  • Full suite: 1124 → 1157 tests, all passing
  • ruff check src tests: clean
  • No changes to scoring formulas or AUROC (generator is upstream of scoring)
  • Backward compatibility: generate_double_substitution_variants() and generate_charge_enhanced_variants() still exported and tested

🤖 Generated with Claude Code

…ants + SynthQC continuous agg score

Generator, scorer, and QC now use the same aggregation threshold (VILMFW run >= 4) consistently:

- generate_aggregation_safe_double_variants(): filters double substitutions that would create
  hydrophobic runs >= 4 before they enter the candidate pool, preventing the generator from
  producing sequences immediately penalised by synthesis_feasibility_score()
- generate_balanced_charge_variants(): generates both K and R replacements at each S/T/N/Q
  position, giving the pipeline twice as many charge-enhanced options to rank by selectivity
  (K KD=-3.9 vs R KD=-4.5 differ in GRAVY; scoring picks the best one per seed profile)
- generate_all_variants() now uses both new functions; old functions preserved for compat
- SynthQC.aggregation_propensity_score: float [0,1] field added to SynthQC dataclass and
  to_dict(), providing continuous gradient information alongside aggregation_risk boolean
- _max_hydrophobic_run() helper; _AGG_HYDROPHOBIC constant matching physchem.py

33 new tests; 1124 -> 1157 total passing
HIGH: Single-substitution variants now filtered in generate_all_variants() with
_max_hydrophobic_run(v) < 4, same as double-substitution path. A seed with run=3
and adjacent A/Y (conservative aliphatic group members) could produce run=4 singles;
added test with KVLLAK borderline seed to verify the filter catches KVLLLK.

MEDIUM: Import _AGG_HYDROPHOBIC from physchem.AGG_HYDROPHOBIC instead of duplicating
the constant — single source of truth, cross-module consistency guaranteed by the import
rather than a manual comment. Fixed aggregation_propensity() docstring: "Ramp: 0.0 at
run=4" corrected to "0.20 at run=4" (formula (max_run-3)/5.0 gives 0.20, not 0.0).

LOW: generate_balanced_charge_variants() n_samples parameter renamed to n_positions for
API clarity (n_samples caps total output in other generators; here it caps positions
targeted, yielding up to 2×n_positions sequences). Added deprecation note to
generate_charge_enhanced_variants(). Fixed trivial test assertion in
test_generates_both_k_and_r_per_position to use direct variant lookup rather than
fallback any() clauses that always passed.

1157 → 1158 tests
@cschanhniem
cschanhniem merged commit 551308f into main Jun 28, 2026
3 checks passed
@cschanhniem
cschanhniem deleted the feat/aggregation-safe-mutations branch June 28, 2026 07:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant