Adds the only legitimate BBB <-> MRI bridge in the platform — researcher
lane only. Fusion engine still excludes BBB as a diagnostic modality.
Modules:
- src/models/bbb_permeability_map.py: scalar BBB leakage score in [0,1]
with two modes. heuristic_proxy (default) reuses the 2D resnet18
Alzheimer classifier and computes 1 - P(NonDemented). dce_onnx loads
a real 4D DCE-MRI ONNX model from BBB_PERMEABILITY_DCE_PATH and
averages a normalised Ktrans map; raises a clear FileNotFoundError
with contract documentation when no artifact exists.
- src/research/drug_dose_adjuster.py: pure-function dose revision keyed
on (BBB intact?, drug BBB-permeable?). Permeable drugs see an
aggressive linear cut floored at 30%; non-permeable drugs see a mild
cut floored at 60%; intact BBB returns baseline unchanged. Unknown
drug permeability is treated as permeable (safer). Rationale always
includes the 'research suggestion, not medical advice' disclaimer.
API:
- POST /predict/bbb_permea…
feat(api): add POST /predict/eeg route (stub-able for demo)
- New experiments_router (prefix /experiments) hosts two endpoints:
GET /runs lists MLflow runs across all 3 experiments (bbb / eeg /
mri), POST /diff returns a side-by-side metric+param diff for two
given run ids.
- NEUROBRIDGE_DISABLE_MLFLOW=1 short-circuits both to empty
responses (no exception). Unknown run ids → 404 with detail.
- 5 new schemas: MLflowRunSummary, MLflowRunsResponse, RunDiffRequest,
RunDiffRow, RunDiffResponse.
- 2 new tests covering the empty-list and unknown-id paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api): POST /explain/eeg + /explain/mri — full-stack Track-1 coverage
- New explain_router with /explain prefix; symmetric with /predict/bbb
and reserves /explain/eeg, /explain/mri for future expansion.
- BBBExplainRequest carries the prediction snapshot + optional
user_question. top_features is required and must be non-empty
(Pydantic min_length=1 → 422 on empty).
- BBBExplainResponse: {rationale, source, model}. Always 200 because
the explainer's template fallback never raises.
- 1 new test: 200 + source='template' under NEUROBRIDGE_DISABLE_LLM=1
with full SHAP + calibration + drift payload.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api+frontend): MLflow provenance badge in decision card
- ModelProvenance schema (mlflow_run_id, model_version, train_date,
n_examples). BBBPredictResponse.provenance is always populated; failed
MLflow lookup degrades to None fields without breaking the response.
- _build_provenance() module-level cache: one MLflow query per worker.
NEUROBRIDGE_DISABLE_MLFLOW=1 short-circuits to None fields. n_examples
pulled per-request from model._neurobridge_train_stats.
- Streamlit decision card renders a one-line audit badge above the
label: run id (first 8 chars), model version, train date, n_examples.
- 1 new test: provenance field present in /predict/bbb body with the
fixture model (n_examples ≥ 1 from train stats).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api): drift z-score in /predict/bbb response
- WORKER_CONFIDENCE_DEQUE: collections.deque(maxlen=100), per-worker
rolling window of confidences; drift_z computed against train-time
median when ≥10 samples buffered AND model has _neurobridge_train_stats.
- BBBPredictResponse gains drift_z (float | None) and rolling_n (int).
- 2 new tests: drift_z/rolling_n always present in body; deque rolls
at 100 after 105 predictions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api): POST /pipeline/mri/diagnostics — pre/post ComBat KPIs + long-format rows
- Adds MRIDiagnosticsRequest/HarmonizationRow/MRIDiagnosticsResponse
schemas. The response carries the long-format rows plus 3 KPIs:
site_gap_pre, site_gap_post, reduction_factor (= pre/max(post,eps)).
- Site-gap is computed on the first feature's per-site means
(max - min). reduction_factor uses 1e-9 epsilon to avoid div-by-zero
when ComBat collapses the gap to numerical zero.
- Empty-volume input returns an empty rows list with zero KPIs (no
exception). FileNotFoundError → 404, KeyError → 400.
- 2 new tests: 200 happy path on the synthetic fixture (must pin
reduction_factor >= 1.0) and 404 on missing input_dir.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api): expose calibration bin in /predict/bbb response
- Adds CalibrationContext schema (threshold/precision/support).
- BBBPredictResponse gains optional calibration field; populated by
_matching_calibration_bin helper that picks the highest-threshold
bin whose threshold <= confidence.
- Returns None for legacy models without _neurobridge_calibration or
when confidence < lowest threshold (< 0.50).
- Extends existing 200-happy-path test with calibration assertions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api): POST /predict/bbb with prediction, uncertainty, SHAP top-k