Repository navigation
Wire calibration controls into create/update/read endpoints (inline JSON + controls_file CSV) #753
Description
Summary
Extend the calibration create, update, and read router endpoints to accept and return calibration controls — both as inline JSON in the request body and as an optional controls_file CSV upload.
Background
With the DB schema, view models, and validation in place, this issue wires everything together at the API layer. Controls should be manageable both inline (as part of the JSON payload) and via CSV upload, consistent with the existing classes_file pattern for class-based calibrations.
Proposed Behavior
Create (POST /api/v1/score-calibrations)
- Accept optional
controlsarray in theScoreCalibrationCreateJSON payload - Accept optional
controls_file(UploadFile, CSV) alongsidecalibration_json - CSV format: two columns —
variant(MaveDB URN or HGVS) andclinical_status(pathogenic|benign, case-insensitive) - If both JSON controls and
controls_fileare provided, return 422 - Run scope validation before persisting
Update (PATCH /api/v1/score-calibrations/{urn})
- Same as create: accept
controlsarray and/orcontrols_file - Replace semantics: submitted controls list replaces all existing controls for that calibration (consistent with how
functional_classificationsare handled)
Read (GET /api/v1/score-calibrations/{urn})
- Return
controlslist in the response (subject to existingprivateflag) - Return
diseaseandcontrols_not_phifields
CSV format for controls_file
- Columns:
variant(URN or HGVS nt/pro),clinical_status - Validation follows the same pattern as
validate_and_standardize_calibration_classes_dataframeinlib/validation/dataframe/calibration.py
Acceptance Criteria
-
POSTandPATCHendpoints acceptcontrolsin JSON payload -
POSTandPATCHendpoints acceptcontrols_fileCSV upload - Providing both JSON controls and
controls_filein the same request returns 422 -
GETreturnscontrols,disease, andcontrols_not_phifor authorized users - Controls are not visible in
GETresponses when the calibration is private and the requesting user lacks read access - CSV parsing validates columns, status values, and variant existence
- Replace semantics: updating with a new controls list replaces the old one atomically
- Empty
controlsarray clears all existing controls on update
Implementation Notes
- Follow the
classes_filepattern inrouters/score_calibrations.pyfor multipart upload handling controls_fileshould be optional: omitting it on update means "no change to existing controls"; sending an empty JSONcontrols: []means "clear all controls"- Add
controls_fileto the OpenAPI schema override dict alongsideclasses_filein the existing endpoint schemas - Wrap control persistence in a transaction so a validation failure mid-way leaves no partial state
Additional Considerations
List endpoint performance
The full controls list should be omitted from collection/list responses (e.g., GET /score-calibrations/me). Only the detail endpoint (GET /score-calibrations/{urn}) should include the full controls list. Consider returning a controlsCount: int in list responses to avoid large payloads.
Authorization
Controls must respect the calibration's existing permission model: write access is required to create or modify controls; read access is required to retrieve them. Apply the existing assert_permission / has_permission guards to control mutations the same way they are applied to calibration mutations. No new permission types are needed.
controls_not_phi reset on controls change
See the PHI gate issue (#752): when controls are replaced via an update, reset controls_not_phi to null so the submitter must re-acknowledge before republishing.
Activity
feat(calibration-controls): add view models for controls (#750)
feat(calibration-controls): validate controls belong to the score set (…
feat(calibration-controls): gate publishing on PHI acknowledgment (#752)
feat(calibration-controls): persist controls on create and modify (#753)
feat(calibration-controls): reset controls_not_phi when controls chan…
feat(calibration-controls): CSV validation with 1:1 HGVS resolution (#…
feat(calibration-controls): wire controls into create/update/read end…
feat(calibration-controls): report controlsCount on list responses (#753
feat(calibration-controls): validate controls belong to the score set (…
feat(calibration-controls): gate publishing on PHI acknowledgment (#752)
feat(calibration-controls): persist controls on create and modify (#753)
feat(calibration-controls): reset controls_not_phi when controls chan…
feat(calibration-controls): CSV validation with 1:1 HGVS resolution (#…
feat(calibration-controls): wire controls into create/update/read end…
feat(calibration-controls): report controlsCount on list responses (#753
fix(calibration-controls): re-enforce PHI gate on modify, not just pu…