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
The single largest bug class found during the 2026-06 refactoring series (#1550-#1572) was mirror drift: a parameter or type member added or removed on one side of a manual mirror without its counterpart. The starkest instance was #1562 — fourteen parameters registered in the toolchain whose Fortran type members had been removed a year earlier; setting any of them in a case file passed validation and then crashed the namelist read with a misleading datatype error.
The registry (toolchain/mfc/params/definitions.py) and the derived types (src/common/m_derived_types.fpp) are maintained by hand on both sides, with nothing checking they agree. #1553 fixed the current instances; nothing prevents recurrence.
Proposal
A build-time audit, run by the same ninja-tracked custom command that already generates the parameter includes (so it costs nothing extra to wire), that:
Parses the struct-member declarations from m_derived_types.fpp for every type backing an indexed parameter family (fluid_pp, patch_icpp, bub_pp, lag_params, chem_params, ...).
Asserts every registered member name + Fortran type class (REAL/INT/LOG/STR) exists in the corresponding derived type, and that every namelist-bound member of those types is registered.
Fails the build with a named, two-sided diff on any mismatch ("registered but not in type: ...", "namelist-bound member not registered: ...").
Execution sketch
A new toolchain/mfc/params/generators/type_audit.py (~150 lines): a line-level Fortran declaration parser scoped to the known type blocks (the codebase's declaration style is uniform enough; the broadcast generator already does similar member-walking).
Wire into cmake_gen.py after generation; unit tests in params_tests/ with deliberately broken fixtures (member removed, member added, kind mismatch).
Effort: small (one toolchain file + tests). Risk: low — it only ever fails builds that would mis-run anyway.
Part of the structural theme proven by the series: make invariants structural, not disciplinary. Companion proposals: the registry-driven defaults and the validator/checker unification.
Motivation
The single largest bug class found during the 2026-06 refactoring series (#1550-#1572) was mirror drift: a parameter or type member added or removed on one side of a manual mirror without its counterpart. The starkest instance was #1562 — fourteen parameters registered in the toolchain whose Fortran type members had been removed a year earlier; setting any of them in a case file passed validation and then crashed the namelist read with a misleading datatype error.
The registry (
toolchain/mfc/params/definitions.py) and the derived types (src/common/m_derived_types.fpp) are maintained by hand on both sides, with nothing checking they agree. #1553 fixed the current instances; nothing prevents recurrence.Proposal
A build-time audit, run by the same ninja-tracked custom command that already generates the parameter includes (so it costs nothing extra to wire), that:
m_derived_types.fppfor every type backing an indexed parameter family (fluid_pp,patch_icpp,bub_pp,lag_params,chem_params, ...).Execution sketch
toolchain/mfc/params/generators/type_audit.py(~150 lines): a line-level Fortran declaration parser scoped to the known type blocks (the codebase's declaration style is uniform enough; the broadcast generator already does similar member-walking).cmake_gen.pyafter generation; unit tests inparams_tests/with deliberately broken fixtures (member removed, member added, kind mismatch).Part of the structural theme proven by the series: make invariants structural, not disciplinary. Companion proposals: the registry-driven defaults and the validator/checker unification.