1"""Every requirement key Layer 1 reads must be DECLARED in DesignRequirementsConfig.
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.
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.
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).
16from __future__
import annotations
19from pathlib
import Path
25LAYER1 = Path(__file__).resolve().parent.parent /
"engine/optimizer/layers/layer1_static_optimization.py"
29RUNTIME_ONLY: set[str] = set()
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_]+)["\']',
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
49 declared = set(DesignRequirementsConfig.model_fields)
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 "
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."
63 """Guard the guard: if the regexes stop matching, the test above passes vacuously."""
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}"
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",
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
81 assert getattr(cfg, key) == val, f
"{key} did not survive construction"
set[str] _keys_layer1_reads()
test_every_key_layer1_reads_is_declared()
test_the_scan_actually_finds_keys()
test_previously_undeclared_keys_now_round_trip(key)