HF Space deployment needs every showcase path to work without external
data. Five artifacts are gitignored (model binaries, RAG index, derived
fixtures) so they have to be (re)generated at image-build time.
- scripts/seed_demo_artifacts.py: idempotent generator for
data/processed/mri_dl_2d/best_model.pt (random resnet18 4-class),
data/processed/mri_model.onnx (dynamic-D/H/W ONNX biased to 'abnormal'),
data/processed/eeg_clf.joblib (synthetic-separable RandomForest),
data/external_rag/index/rag_index.pkl (4-chunk synthetic clinical
TF-IDF index), and tests/fixtures/mri_sample/subject_0_axial.png
(axial slice from the bundled NIfTI). Each step is a no-op when the
artifact already exists.
- Dockerfile.hf: COPY scripts/, RUN seed_demo_artifacts.py after the
pipeline + FAISS-index build steps. Keeps Dockerfile (HF
auto-discovered name) byte-identical to Dockerfile.hf.
- docker-entrypoint.sh: re-run the seed script on container start so a
mounted-volume deploy can re-s…
fix(demo): wire every showcase path end-to-end with auto-resolved artifacts
Goal: every endpoint and every Streamlit tab must work in a 2-minute
hackathon demo without requiring the demoer to fetch external data.
Code fixes:
- src/api/routes.py + src/agents/tools.py: fix two stale references —
bbb_model.load (not load_model) and bbb_model.predict_with_proba (not
predict_one); also corrects the agent-side default BBB artifact path
from .pkl to .joblib so the auto-resolve in adjust_drug_dose works.
- src/api/routes.py: replace hard-coded _AGENT_DEFAULT_MODEL = google/
gemini-2.0-flash-exp:free (now 404 on OpenRouter) with a fallback
chain probed at orchestrator-build time. Picks the first model that
returns a non-404/429 ping. Override via NEUROBRIDGE_AGENT_MODEL
(single id) or NEUROBRIDGE_AGENT_MODEL_CHAIN (csv).
- src/llm/explainer.py: prepend openai/gpt-oss-20b:free (verified 2026-
05-02) to the explainer fallback chain so /explain/* doesn't fall
back to the deterministic template when free-tier ids churn.
- src/frontend/app.py: drop the en…
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)
Adds network-gated live test that skips without OPENROUTER_API_KEY (and
without the BBB model artifact, since explainer.py auto-loads .env at
import time). Adds /diag/agent diagnostic endpoint reporting key presence,
agent model, RAG index status, and registered tool names.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(api): POST /agent/run endpoint (orchestrator + RAG, stub-injectable)
One-shot in-container probe to diagnose why /explain/* falls back
to template on HF Space. Shows key presence (length + 12-char prefix
only — never full secret), kill-switch state, and an 8-token probe
against the chain's first model. Surfaces 401/429/CONN errors as
JSON so deployment issues can be diagnosed without container shell
or HF logs API access.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(api): GET /experiments/runs + POST /experiments/diff (Track 5)
- 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>
fix(schemas): silence Pydantic protected-namespace warning on ModelProvenance
The model_version field in T2's ModelProvenance triggers Pydantic v2's
"model_*" protected-namespace UserWarning. Our DoD gate runs
pytest -W error::UserWarning, which would escalate this to a hard
error during T4 close-out. Set protected_namespaces=() on this single
schema to keep the field name as designed without weakening the gate.
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