Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions configs/metric_polarity_registry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Metric Polarity Registry",
"description": "Defines whether each metric improves when higher or lower.",
"pipeline_metrics": {
"auroc": {"polarity": "higher_is_better", "description": "Area under ROC curve"},
"auprc": {"polarity": "higher_is_better", "description": "Area under precision-recall curve"},
"recall_at_10": {"polarity": "higher_is_better", "description": "Recall at top 10"},
"recall_at_20": {"polarity": "higher_is_better", "description": "Recall at top 20"},
"precision_at_10": {"polarity": "higher_is_better", "description": "Precision at top 10"},
"enrichment_factor": {"polarity": "higher_is_better", "description": "Enrichment over random"},
"delta": {"polarity": "depends", "description": "Improvement over baseline — check context"},
"disagreement": {"polarity": "lower_is_better", "description": "Model disagreement score"},
"charge_bias": {"polarity": "lower_is_better", "description": "Charge dominance in score"}
},
"simulation_metrics": {
"bacterial_binding": {"polarity": "higher_is_better", "description": "Membrane binding score"},
"selectivity_ratio": {"polarity": "higher_is_better", "description": "Bacterial vs mammalian selectivity"},
"helix_weight": {"polarity": "higher_is_better", "description": "Helical propensity weight"},
"non_helical": {"polarity": "lower_is_better", "description": "Non-helical flag (0=helical)"},
"uncertainty": {"polarity": "lower_is_better", "description": "Simulation uncertainty score"}
},
"safety_metrics": {
"safety": {"polarity": "higher_is_better", "description": "Safety score"},
"rich_selectivity": {"polarity": "higher_is_better", "description": "Selectivity composite"},
"hemolysis_risk": {"polarity": "lower_is_better", "description": "Predicted hemolysis risk"},
"toxicity_count": {"polarity": "lower_is_better", "description": "Number of toxic candidates"}
}
}
52 changes: 52 additions & 0 deletions tests/test_metric_polarity_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Tests for metric polarity registry."""
import json
from pathlib import Path


def _registry():
return json.loads(Path("configs/metric_polarity_registry.json").read_text())


def test_file_exists():
assert Path("configs/metric_polarity_registry.json").exists()


def test_is_valid_json():
data = _registry()
assert "pipeline_metrics" in data
assert "simulation_metrics" in data
assert "safety_metrics" in data


def test_auroc_is_higher_better():
data = _registry()
assert data["pipeline_metrics"]["auroc"]["polarity"] == "higher_is_better"


def test_disagreement_is_lower_better():
data = _registry()
assert data["pipeline_metrics"]["disagreement"]["polarity"] == "lower_is_better"


def test_all_metrics_have_description():
data = _registry()
for category in data.values():
if isinstance(category, dict):
for name, info in category.items():
assert "description" in info, f"{name} missing description"
assert "polarity" in info, f"{name} missing polarity"


def test_polarity_values():
data = _registry()
valid = {"higher_is_better", "lower_is_better", "depends"}
for category in data.values():
if isinstance(category, dict):
for name, info in category.items():
assert info["polarity"] in valid, f"{name} has invalid polarity: {info['polarity']}"


def test_known_metric_count():
data = _registry()
total = sum(len(cat) for cat in data.values() if isinstance(cat, dict))
assert total >= 10
Loading