Wet-lab feedback loop

Architecture for Waves 2-4 — how wet-lab measurements flow into the platform, calibrate predictions, and close the dry/wet loop.

The pipe at a glance

   Wet-lab bench                    Platform
   ────────────                     ────────
   SPR / BLI Kd  ─────────────┐
   Flow cytometry %           │
   Cytotoxicity E:T            │     ┌──────────────────────────┐
   Yield mg/L                  ├───▶ │  POST /api/v1/wet-lab/    │
   Tonic readouts              │     │       measurements        │
   Stability Tm                │     │  (single or /batch)       │
   ─────────────              ┘      └──────────┬───────────────┘
                                                │
                                                ▼
                                ┌──────────────────────────────┐
                                │  wet_lab_measurements (DB)   │
                                │  - antibody_id               │
                                │  - measurement_type          │
                                │  - value / unit / assay      │
                                │  - batch_id / measured_at    │
                                └──────────┬───────────────────┘
                                           │
                                           ▼
                                ┌──────────────────────────────┐
                                │  Wave 2 calibration runner    │
                                │  (pipeline.tools.calibration) │
                                │  Fits per (score × wet-lab    │
                                │  type) corrector — linear,    │
                                │  isotonic, or Platt scaling   │
                                └──────────┬───────────────────┘
                                           │
                                           ▼
                                ┌──────────────────────────────┐
                                │  score_calibrations (DB)     │
                                │  - score_id, wet_lab_type    │
                                │  - method + parameters_json  │
                                │  - n_samples + ρ + RMSE      │
                                └──────────┬───────────────────┘
                                           │
                                           ▼
                                ┌──────────────────────────────┐
                                │  Calibrated score surface    │
                                │  - /candidates shows         │
                                │    corrected values + raw    │
                                │  - /docs/scoring-audit V4    │
                                │    reports per-score ρ to    │
                                │    measurement              │
                                │  - Wave 3 internal models    │
                                │    train on (raw, wet-lab)   │
                                │    pairs                     │
                                └──────────────────────────────┘

Every observation at the bench has exactly one place it lands: the wet_lab_measurements table. Calibration runs read from there, fit per-score correctors, and store parameters in score_calibrations. The platform then surfaces both the raw prediction and the calibrated correction so researchers can see the delta.

What's needed from each wet-lab batch
FieldRequiredExampleWhy
antibody_idyes37Pairs measurement to a platform candidate.
measurement_typeyesKd_SPR_nMStandardized type string — used as the join key for calibration.
valueyes12.4The measurement itself.
unityesnMRequired for unit-aware comparison across batches.
assay_methodrecommendedSPR / Biacore 8KDifferent assays correlate differently; calibration can stratify by method.
batch_idrecommendedBCMA-batch-2026-06-14Tracks the wet-lab campaign for traceability + re-fit triggers.
measured_atrecommended2026-06-14T09:30:00ZISO timestamp — needed to detect drift over time.
notesoptionaloutlier — possible aggregationAnything that helps future-you re-interpret the row.
Canonical measurement-type vocabulary

Keep types as `name_method_unit` so the platform can auto-match wet-lab columns to in-silico scores at calibration time.

measurement_typeMaps to in-silico score
Kd_SPR_nMipTM / ensemble_iptm (rank against)
Kd_BLI_nMipTM / ensemble_iptm
expression_yield_mg_per_Lablang_avg / TAP composite
tm_DSF_celsiustm_prediction / ddg_thermompnn
aggregation_SEC_pct_HMWaggregation_score / tap_psh
tonic_signal_flow_pcttonic_clustering_risk
cytotoxicity_E_T_5_1_pct_killingcar_score + composite
surface_expression_MFIcar_score component (expression)
cross_reactivity_TACI_BLI_nMselectivity
cyno_binding_BLI_nMxspecies_cyno_iptm
fcrn_binding_SPR_pH6_nMfcrn_binding
Three waves of calibration

Wave 2 — Linear / isotonic correction

Once 10-20 (in-silico, wet-lab) pairs exist per type, the calibration runner fits a per-score linear corrector and an isotonic regression backup. Outputs: corrected score column + Spearman ρ + RMSE diagnostic. Storage: score_calibrations table.

Wave 3 — Internal predictor training

Once 50+ pairs exist, train an internal model that beats the corrected public-tool score on this specific assay. Stored as a versioned model alongside its training cohort id. Architecture: ESM-2 embeddings → small MLP head, or whatever rank-correlates best. Triggers automatic re-evaluation against the latest wet-lab batch.

Wave 4 — Foundation-model fine-tune

Once 200+ pairs cover the full design space, fine-tune ProteinMPNN / RFantibody on internal sequence + wet-lab label pairs. Gated on Modal self-host (Spec 3 S.1) — these models need GPU. Output: a fine-tuned design model that proposes candidates already shifted toward the wet-lab-validated subspace.

API surface (live now)
EndpointPurpose
POST /api/v1/wet-lab/measurementsSingle measurement ingest
POST /api/v1/wet-lab/measurements/batchBatch ingest from a CSV / pipeline export
GET /api/v1/wet-lab/measurementsList recent measurements, optional type filter
GET /api/v1/wet-lab/measurements/candidate/{id}All measurements for one candidate
GET /api/v1/wet-lab/coverageHow many candidates have which measurement types
GET /api/v1/wet-lab/calibrationsLatest fitted correctors per (score, wet-lab type)
GET /api/v1/wet-lab/healthPipe sanity check — confirms tables exist
Current status

✅ Tables created (wet_lab_measurements + score_calibrations)

✅ Ingest + retrieval API live (7 endpoints above)

✅ Wave 2 calibration runner shipped (pipeline.tools.calibration.refit_all)

⏳ Awaiting first wet-lab batch — coverage is 0 measurements / 0 candidates today

🔒 Wave 4 (foundation-model fine-tune) is gated on Modal self-host