STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_requirements_schema_completeness.py
Go to the documentation of this file.
1"""Every requirement key Layer 1 reads must be DECLARED in DesignRequirementsConfig.
2
3A pydantic model silently DROPS unknown keys. So a key the optimizer reads but the schema
4does not declare cannot be set at all: `PUT /api/config` returns 200 and discards it, a YAML
5carrying it loads without it, and the value the optimizer uses is always its hardcoded
6fallback. Four such keys even had labelled controls in the Configuration editor, so the UI
7offered knobs that did nothing.
8
9Sixteen keys were in that state when this test was written (2026-09-14), including
10`max_chamber_length_m`, the throat-area search bounds, and the whole injector ring-geometry
11group. This test fails if anyone adds a seventeenth.
12
13The reverse direction is deliberately NOT checked: a declared field with no reader is
14harmless (it may be read by Layer 2/3, the frontend, or a future consumer).
15"""
16from __future__ import annotations
17
18import re
19from pathlib import Path
20
21import pytest
22
23from engine.pipeline.config_schemas import DesignRequirementsConfig
24
25LAYER1 = Path(__file__).resolve().parent.parent / "engine/optimizer/layers/layer1_static_optimization.py"
26
27# Keys read from `requirements` that are NOT design requirements and are supplied by the
28# caller at runtime instead. Keep this list short and justified.
29RUNTIME_ONLY: set[str] = set()
30
31READ_PATTERNS = (
32 r'_requirement_float\‍(\s*requirements,\s*["\']([A-Za-z0-9_]+)["\']',
33 r'_requirement_bool\‍(\s*requirements,\s*["\']([A-Za-z0-9_]+)["\']',
34 r'_requirement_int\‍(\s*requirements,\s*["\']([A-Za-z0-9_]+)["\']',
35 r'requirements\.get\‍(\s*["\']([A-Za-z0-9_]+)["\']',
36 r'_req_lookup\‍(\s*requirements,\s*["\']([A-Za-z0-9_]+)["\']',
37)
38
39
40def _keys_layer1_reads() -> set[str]:
41 src = LAYER1.read_text(encoding="utf-8")
42 keys: set[str] = set()
43 for pat in READ_PATTERNS:
44 keys |= set(re.findall(pat, src))
45 return keys - RUNTIME_ONLY
46
47
49 declared = set(DesignRequirementsConfig.model_fields)
50 missing = sorted(_keys_layer1_reads() - declared)
51 assert not missing, (
52 "Layer 1 reads these requirement keys but DesignRequirementsConfig does not declare "
53 "them, so pydantic silently drops them and they can never be set:\n "
54 + "\n ".join(missing)
55 + "\n\nAdd each as `Optional[...] = Field(default=None, ...)` whose description states "
56 "the optimizer's fallback, and make sure any raw `requirements.get(k, default)` "
57 "reader is None-safe -- once declared the key arrives present-with-value-None, so "
58 "`.get(k, default)` stops firing and `int(None)` / `float(None)` raises."
59 )
60
61
63 """Guard the guard: if the regexes stop matching, the test above passes vacuously."""
64 found = _keys_layer1_reads()
65 assert len(found) > 80, f"only found {len(found)} requirement reads - the scan is broken"
66 for anchor in ("optimal_of_ratio", "min_Lstar", "W_MOM"):
67 assert anchor in found, f"scan missed a known requirement key: {anchor}"
68
69
70@pytest.mark.parametrize("key", [
71 "layer1_enforce_ring_geometry",
72 "layer1_impingement_Ld_min",
73 "layer1_impingement_Ld_max",
74 "max_chamber_length_m",
75])
77 """These four were readable-but-unsettable and are the reason this test exists."""
78 assert key in DesignRequirementsConfig.model_fields
79 val = True if key == "layer1_enforce_ring_geometry" else 6.0
80 cfg = DesignRequirementsConfig(**{key: val})
81 assert getattr(cfg, key) == val, f"{key} did not survive construction"