Skip to content

feat: add selectivity_proxy — cytotoxicity risk detector for Stage 2 (#47) - #47

Merged
cschanhniem merged 2 commits into
mainfrom
feat/selectivity-proxy
Jun 28, 2026
Merged

cschanhniem merged 2 commits into
mainfrom
feat/selectivity-proxy

Conversation

@cschanhniem

Copy link
Copy Markdown
Collaborator

Summary

  • New selectivity_proxy feature in compute_features(): heuristic [0,1] score predicting likelihood of selective bacterial killing without mammalian cytotoxicity. Based on net charge (pH 7.4) and GRAVY — the two physicochemical axes most correlated with cytotoxicity in literature (Dathe & Wieprecht 1999 BBA; Shai 2002 BBA).
  • HIGH_CYTOTOX_RISK informational flag in presynth QC (SynthQC.cytotox_risk): fires when selectivity_proxy < 0.5. Appended after synthesis difficulty is computed (does not inflate LOW→MODERATE→HIGH rating). Flag text includes specific assay instructions (HC50/MTS).
  • Vendor handling note in order_generator.py _HANDLING_MAP: cytotox-flagged candidates get "Include mammalian cytotox assay (HC50/MTS); reduce MIC conc if cytotox" in synthesis_order.csv.
  • Scientific validation: SEED-004 (FLPLIGRVLSGIL, temporin-like, GRAVY=+1.81, charge=+1.0) is correctly flagged — consistent with known hemolytic profile of hydrophobic short temporins (Carotenuto et al. 2008, J Med Chem 51:2279–2287). All other 7 seeds correctly pass (selective window).
  • Discovery probability update: Stage 2 (Therapeutic Index) improved to ~40–55% (from ~38–52%); combined "breaking news" probability updated to ~24–45% (from ~22–43%). AUROC corrected to 0.811 throughout the document.
  • Makefile ci target comment corrected from "814-test suite" to "1044-test suite".
  • Fix pre-existing lint error: unused import pytest in tests/test_order_generator.py.

Test plan

  • 37 new tests in tests/test_selectivity_proxy.py covering: charge edge cases (0, 1, 2, 7, 8, 12, negative), GRAVY edge cases (negative, 0, 0.5, 0.75, 1.0, >1.0), combined cases, compute_features() output key, presynth QC flag presence/absence, to_dict() fields, order generator handling map
  • 1081 total tests pass (pre-push hook confirmed)
  • Lint clean (ruff)
  • AUROC validation: make validate-scoring → 0.811 STRONG (confirmed before this PR)
  • SEED-004 flagged as HIGH_CYTOTOX_RISK (correct per literature)
  • SEED-001 through SEED-003, SEED-005 through SEED-008: NOT flagged (correct)

🤖 Generated with Claude Code

Addresses Stage 2 (Therapeutic Index) failure mode previously invisible
to the pipeline. Peptides with charge <+2 or GRAVY >0.5 often fail
mammalian cytotoxicity assays even when MIC is excellent.

Changes:
- physchem.py: new selectivity_proxy(charge, gravy) function [0,1];
  added to compute_features() output dict
- presynth_check.py: SynthQC gains selectivity_proxy float + cytotox_risk bool;
  HIGH_CYTOTOX_RISK informational flag (appended after difficulty is set)
- order_generator.py: HIGH_CYTOTOX_RISK entry in _HANDLING_MAP with
  mammalian assay instructions (HC50/MTS)
- Makefile: fix stale "814-test suite" comment to "1044-test suite"
- docs/DISCOVERY_PREDICTION.md: Stage 2 updated to ~40-55% (+2-3 pp);
  combined probability updated to ~24-45% (up from ~22-43%)

SEED-004 (temporin-like, GRAVY=+1.81, charge=+1.0) is correctly flagged
HIGH_CYTOTOX_RISK — consistent with known hemolytic profile of hydrophobic
short temporins (Carotenuto et al. 2008, J Med Chem).
37 new tests (1081 total). AUROC confirmed 0.811. Lint clean.
…y, imports, defaults

- presynth_check.py: move selectivity_proxy imports to module level (was deferred;
  deferred imports are justified only to break circular dependencies, which do not
  exist here). Use physchem.net_charge_at_ph74() for consistency with compute_features()
  so the selectivity_proxy value is identical in both the feature dict and QC report.
  The old _net_charge_at_ph() included terminal groups/Cys/Tyr producing a ~0.2 offset
  that would give divergent cytotox verdicts for the same sequence.
- SynthQC.selectivity_proxy default changed from 1.0 to 0.0 (conservative: assume
  cytotoxic until check_sequence() fills the field; 1.0 = safe default is misleading
  for a risk field)
- physchem.py docstring: "optimum: +3 to +7" → "+2 to +7" (code awards full score
  starting at charge=2.0; the prior text contradicted the implementation and the test)
- test_selectivity_proxy.py: add boundary test (selectivity_proxy=0.50 exactly must NOT
  trigger cytotox_risk since predicate is strict <0.5)
- Makefile: update echo to "1081-test suite" → "1082-test suite" (38 new tests total)
@cschanhniem
cschanhniem merged commit 3c31b0c into main Jun 28, 2026
2 checks passed
cschanhniem added a commit that referenced this pull request Jun 28, 2026
* docs: update METHODS.md to reflect all v0.2.x scoring changes

- Section 4.1: expand activity-likeness formula to show all 7 terms (length, charge
  density at pH 7.4, hydrophobic fraction, aromatic bonus, amphipathicity, helix bonus
  weight 0.03, cross-term) with ceiling 0.97; note charge_density_ph74 preference
- Section 4.2: add μH > 0.55 risk signal (Dathe 1999); update charge_density column
  to charge_density_ph74 with fallback note; tabulate all 6 risk signals with increments
- Section 4.3: add proline penalty threshold (>15% → −0.10, DKP/Fmoc deprotection
  mechanism); tabulate aggregation penalty with ramp details
- New Section 4.3b: serum stability score — protease site density model for trypsin
  (×2), chymotrypsin (×1), elastase (×0.5); score formula and literature basis
- New Section 5.2: pilot panel selection — pilot_priority formula, cytotox_penalty
  for HIGH_CYTOTOX_RISK tier (proxy < 0.5), net selectivity swing +0.055
- Section 8: add retrospective AUROC 0.8164; table of v0.2.x PRs #47-54 with impact
- Section 10: expand references from 4 to 17; add all citations used in scoring code

* docs: fix 4 HIGH issues in synthesis feasibility table (code review PR #55)

- Rename 'Long cysteine repeat run' → 'Long homo-repeat run (any AA)'; fix deduction
  from −0.15 to −0.10 flat (code: synthesis.py repeat_run >= 5 → score -= 0.10)
- Fix cysteine fraction threshold from 0.15 to 0.20; fix deduction from scaled formula
  to −0.15 flat (code: cys > 0.20 → score -= 0.15)
- Fix aggregation propensity trigger from >0.2 to >0.0; fix formula from
  0.20×(prop−0.2)/0.8 to min(agg×0.25, 0.20) — linear ramp from zero, capped −0.20
- Add missing length penalties: length>30 (up to −0.40 ramp), length<8 (−0.30 flat)
  — the length>30 penalty is the largest single deduction possible; its absence from
  docs was a material omission
- Fix 'five risk signals' → 'six' in safety score prose (μH signal added in PR #53)
- Fix version header: 0.1.0 → 0.2.x with PR range note
- Fix activity score ceiling: clarify it is the arithmetic maximum of weight sum (0.97),
  not an explicit min() cap — the code applies clamp01() which caps at 1.0
cschanhniem added a commit that referenced this pull request Jun 28, 2026
* docs: update METHODS.md version tag and annotate 7-seed synthesis pool expansion

The methods document was last updated for PRs #47-54. Since then the synthesis
pool was expanded from 5 to 7 scaffold families (SEED-006 through SEED-009 in
expansion PRs; SEED-001 re-entered in PR #72 via face_segregation_bonus).

Changes:
- Version line: "PRs #47-54" → "PRs #47-78"
- Generation section: added blockquote note distinguishing the initial 5-seed
  benchmark run (383 variants, 87-candidate eval set, AUROC 0.8420) from the
  current 7-seed synthesis pool (100 candidates)
- No scoring formulas or benchmark numbers changed

* docs: fix AUROC attribution in METHODS.md 7-seed note

AUROC 0.8420 was achieved in PR #72 (face_segregation_bonus), not in the
initial 5-seed benchmark generation run. Clarify that the generation section
describes the initial corpus and the AUROC figure reflects scoring improvements
through PR #72. Also note that the 87-sequence eval set was finalized in PR #66.
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