You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Case constraints currently live in two unconnected places: toolchain/mfc/case_validator.py (~2,400 lines, Python, runs at case load) and the m_checker*.fpp files (Fortran @:PROHIBIT, runs at startup). Most constraints exist on only one side. Two consequences observed during the 2026-06 refactoring series:
Drift: where both sides do check the same thing, they were written independently and can disagree (value sets, error text).
Proposal
A declarative constraint layer in the parameter registry (predicates over parameter values: requires/prohibits/implies/range-with-condition), from which the generator emits BOTH the Python validation calls and the Fortran @:PROHIBIT lines (into the per-target m_checker structure, via a generated include like the other twelve-plus files).
Not all 2,400 Python lines are declarative — complex multi-parameter physics checks stay hand-written on whichever side needs them. The goal is the (large) mechanical subset: the same residue-classification method that converted the MPI broadcast lists (#1552) applies — classify every existing check, generate the generable, keep the rest with a ! manual: annotation.
Execution sketch
Step 1 (investigation, the bulk of the work): classify every self.prohibit(...) in case_validator.py and every @:PROHIBIT in m_checker*.fpp into generable/manual + which side(s) it currently exists on. The classification doc is the deliverable that scopes everything after.
Step 2: constraint schema in definitions.py + generate_checks_fpp(target) + the Python consumption path; TDD per constraint class.
Step 3: equivalence: existing checks must survive (set comparison of emitted PROHIBIT conditions vs the hand-written ones they replace); NEW Fortran-side coverage (the previously Python-only constraints) is a deliberate behavior tightening — listed explicitly in the PR.
Effort: large (the classification is hundreds of constraints). Risk: moderate — mitigated by doing it in slices (one constraint family per PR).
Closes the class behind #1571's reachability and gives every future constraint two enforcement points for one definition.
Motivation
Case constraints currently live in two unconnected places:
toolchain/mfc/case_validator.py(~2,400 lines, Python, runs at case load) and them_checker*.fppfiles (Fortran@:PROHIBIT, runs at startup). Most constraints exist on only one side. Two consequences observed during the 2026-06 refactoring series:case_validator.py:577). A hand-written namelist (or any non-toolchain driver) reaches Fortran code paths the validator believes impossible — which is exactly why the dead hypoelastic solver blocks deleted in Phase-3: Riemann hot-path decomposition into shared GPU device helpers #1572 were a live hazard, and why HLL hyperelastic wave-speed branch reads shear moduli that only the hypoelastic path initializes #1571's uninitialized-G path is reachable at all.Proposal
A declarative constraint layer in the parameter registry (predicates over parameter values: requires/prohibits/implies/range-with-condition), from which the generator emits BOTH the Python validation calls and the Fortran
@:PROHIBITlines (into the per-targetm_checkerstructure, via a generated include like the other twelve-plus files).Not all 2,400 Python lines are declarative — complex multi-parameter physics checks stay hand-written on whichever side needs them. The goal is the (large) mechanical subset: the same residue-classification method that converted the MPI broadcast lists (#1552) applies — classify every existing check, generate the generable, keep the rest with a
! manual:annotation.Execution sketch
self.prohibit(...)in case_validator.py and every@:PROHIBITin m_checker*.fpp into generable/manual + which side(s) it currently exists on. The classification doc is the deliverable that scopes everything after.definitions.py+generate_checks_fpp(target)+ the Python consumption path; TDD per constraint class.Closes the class behind #1571's reachability and gives every future constraint two enforcement points for one definition.