From 87c477d232bd596212ecdeeaf0db041bae9b8a44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alexander=20K=C3=B6lnberger?=
<159939812+ProfRandom92@users.noreply.github.com>
Date: Tue, 19 May 2026 09:53:34 -0700
Subject: [PATCH] Add deterministic multi-family admissibility SVG renderer
---
.../multi_family_admissibility_curves.svg | 34 +++++
package.json | 3 +-
.../render_multi_family_admissibility_svg.py | 125 ++++++++++++++++++
tests/test_multi_family_svg_renderer.py | 47 +++++++
4 files changed, 208 insertions(+), 1 deletion(-)
create mode 100644 artifacts/multi_family_admissibility_curves.svg
create mode 100644 scripts/render_multi_family_admissibility_svg.py
create mode 100644 tests/test_multi_family_svg_renderer.py
diff --git a/artifacts/multi_family_admissibility_curves.svg b/artifacts/multi_family_admissibility_curves.svg
new file mode 100644
index 0000000..28b70a1
--- /dev/null
+++ b/artifacts/multi_family_admissibility_curves.svg
@@ -0,0 +1,34 @@
+
diff --git a/package.json b/package.json
index 9132b95..25894f4 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"layout": "python scripts/check_repo_layout.py",
"check": "npm run layout && npm run typecheck && npm run validate && npm run build && npm run test",
"generate:layered-admissibility": "python scripts/generate_layered_admissibility_artifact.py",
- "generate:multi-family-admissibility": "python scripts/generate_multi_family_admissibility_artifact.py"
+ "generate:multi-family-admissibility": "python scripts/generate_multi_family_admissibility_artifact.py",
+ "generate:multi-family-svg": "python scripts/render_multi_family_admissibility_svg.py"
}
}
diff --git a/scripts/render_multi_family_admissibility_svg.py b/scripts/render_multi_family_admissibility_svg.py
new file mode 100644
index 0000000..e7f28b1
--- /dev/null
+++ b/scripts/render_multi_family_admissibility_svg.py
@@ -0,0 +1,125 @@
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+INPUT_PATH = Path("artifacts/multi_family_admissibility_results.json")
+OUTPUT_PATH = Path("artifacts/multi_family_admissibility_curves.svg")
+
+WIDTH = 1000
+HEIGHT = 560
+MARGIN_LEFT = 90
+MARGIN_RIGHT = 40
+MARGIN_TOP = 70
+MARGIN_BOTTOM = 120
+
+TITLE = "Multi-Family Admissibility Degradation Curves"
+X_LABEL = "degradation level"
+Y_LABEL = "overall_admissibility_score"
+LEVELS: tuple[str, ...] = ("baseline", "mild", "moderate", "severe")
+PALETTE: tuple[str, ...] = (
+ "#0055aa",
+ "#aa5500",
+ "#117733",
+ "#882255",
+ "#44aa99",
+ "#cc6677",
+)
+
+
+def _fmt(value: float) -> str:
+ return f"{value:.3f}"
+
+
+def _level_from_fixture_id(fixture_id: str) -> str:
+ if "_mild_" in fixture_id:
+ return "mild"
+ if "_moderate_" in fixture_id:
+ return "moderate"
+ if "_degraded_" in fixture_id:
+ return "severe"
+ return "baseline"
+
+
+def render_svg(payload: dict) -> str:
+ families = sorted(payload["families"], key=lambda family: family["family"])
+
+ plot_width = WIDTH - MARGIN_LEFT - MARGIN_RIGHT
+ plot_height = HEIGHT - MARGIN_TOP - MARGIN_BOTTOM
+ plot_right = WIDTH - MARGIN_RIGHT
+ plot_bottom = HEIGHT - MARGIN_BOTTOM
+
+ x_by_level = {
+ level: MARGIN_LEFT + (plot_width * idx / (len(LEVELS) - 1))
+ for idx, level in enumerate(LEVELS)
+ }
+
+ elements: list[str] = [
+ f'")
+ return "\n".join(elements) + "\n"
+
+
+if __name__ == "__main__":
+ payload = json.loads(INPUT_PATH.read_text(encoding="utf-8"))
+ svg = render_svg(payload)
+ OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
+ OUTPUT_PATH.write_text(svg, encoding="utf-8")
diff --git a/tests/test_multi_family_svg_renderer.py b/tests/test_multi_family_svg_renderer.py
new file mode 100644
index 0000000..d2c1f0c
--- /dev/null
+++ b/tests/test_multi_family_svg_renderer.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+from scripts.render_multi_family_admissibility_svg import render_svg
+
+INPUT_PATH = Path("artifacts/multi_family_admissibility_results.json")
+SVG_PATH = Path("artifacts/multi_family_admissibility_curves.svg")
+
+
+
+def _render() -> str:
+ payload = json.loads(INPUT_PATH.read_text(encoding="utf-8"))
+ return render_svg(payload)
+
+
+
+def test_multi_family_svg_render_is_deterministic() -> None:
+ assert _render() == _render()
+
+
+
+def test_rendered_svg_matches_committed_artifact() -> None:
+ assert _render() == SVG_PATH.read_text(encoding="utf-8")
+
+
+
+def test_svg_contains_current_families() -> None:
+ output = _render()
+ assert "coding_workflow_pr_review" in output
+ assert "incident_response_page_triage" in output
+
+
+
+def test_svg_contains_degradation_levels() -> None:
+ output = _render()
+ for level in ("baseline", "mild", "moderate", "severe"):
+ assert f">{level}<" in output
+
+
+
+def test_svg_has_no_nondeterministic_fields() -> None:
+ output = _render().lower()
+ banned_tokens = ("timestamp", "date", "time", "random", "uuid", "id=")
+ for token in banned_tokens:
+ assert token not in output