Skip to content

Move input-only checks to case_validator, delete dead params_tests, enforce the split - #1717

Open
sbryngelson wants to merge 10 commits into
masterfrom
move-input-checks-to-python
Open

Move input-only checks to case_validator, delete dead params_tests, enforce the split#1717
sbryngelson wants to merge 10 commits into
masterfrom
move-input-checks-to-python

Conversation

@sbryngelson

@sbryngelson sbryngelson commented Aug 9, 2026

Copy link
Copy Markdown
Member

Description

Three related changes. Net −1,363 lines (409 added, 1,772 removed).

1. Move input-only checks out of Fortran

case_validator.py and src/simulation/m_checker.fpp had drifted into double entry — reactive_burn (#1670) added nine constraints to both, in the same PR.

Check Status
reactive_burn num_fluids / gamma / pi_inf / qv new in Python
chemistry operator-split sub-stepping (4) new in Python
synthetic-turbulence forcing zones (3) new in Python (check_synthetic_turbulence)
many_ib_patch_parallelism requires ib new in Python
bf_spatial_support 2D-only new in Python
dt <= 0, ib_state_wrt, chemistry + bubbles_euler/qbmm already in Python — Fortran duplicate dropped
particle_cloud%packing_method (2), muscl_order/int_comp already in Python — Fortran duplicate dropped

src/simulation/m_checker.fpp: 225 → 113 lines. s_check_inputs_time_stepping, s_check_inputs_particle_clouds, and s_check_inputs_synthetic_turbulence are gone entirely, along with the now-unused m_helper_basic import and muscl_order_first_order.

Fortran defaults are materialized where an unset value is meaningful. chem_params%reaction_substeps{,_max} and fluid_pp(i)%qv default to 0, so unset is treated as 0. gamma/pi_inf default to the dflt_real sentinel, which f_approx_equal reports as equal, so the comparison is skipped when either is unset. check_synthetic_turbulence loops d = 1..num_dims to match the Fortran, so trailing components of a lower-dimensional case stay optional.

nv_uvm_igr_temps_on_gpu deliberately stays in Fortran. Its default is 3 and the check is == 3 .and. igr_iter_solver == 2, so it fires precisely when the user has not set the parameter. In Python an unset value reads as None and the check would silently never fire — moving it would look like a migration and act like a deletion. It is also inside #ifdef __NVCOMPILER_GPU_UNIFIED_MEM.

What remains in Fortran depends on state unavailable at validation time: MPI decomposition (s_check_total_cells, s_check_inputs_fft), per-rank m/n/p (WENO/MUSCL stencils), compiler conditionals (s_check_amd, rdma_mpi), and num_species, which Cantera fills in at runtime.

2. Delete the params_tests CLI island — −1,651 lines

coverage.py, inventory.py, mutation_tests.py, negative_tests.py, runner.py, snapshot.py. Together they collect zero pytest tests. Every one is imported only by runner.py, which nothing imports and which appears in no workflow, script, doc, or CMake file. Its whole history is incidental edits from unrelated feature PRs — #1713 had to update mutation_tests.py to drop model_eqns = 4 earlier today.

It could not be promoted as-is: negative_tests decides whether the right error fired with a matches >= len(key_terms) * 0.5 substring heuristic, and runner verify needs a data/ baseline that is gitignored. The sibling test_*.py files, which supply all 171 real tests in the package, are untouched.

3. Enforce the split — check_checker_input_constraints

New check in lint_source.py. A @:PROHIBIT in src/**/m_checker*.fpp is allowed only inside a subroutine listed in RUNTIME_CHECKER_SUBROUTINES, or on a line marked ! lint: runtime-check <reason>. Otherwise it fails with a pointer to case_validator.py.

This is what stops the next feature PR from re-creating the double entry this one removes.

Type of change

  • Refactor

Testing

  • ./mfc.sh precheck — all 7 stages pass (full pytest suite + all 155 example cases), run repeatedly including via the pre-commit hook
  • Built pre_process / simulation / post_process — clean, no new warnings
  • ./mfc.sh test --percent 4 — 24 passed, 0 failed, on both commits
  • New toolchain/mfc/test_case_validator.py32 tests, every migrated check in both directions
  • Lint rule verified both ways: passes on the tree, and rejects an injected input-only @:PROHIBIT with the right message; the ! lint: runtime-check escape hatch suppresses it
  • check_synthetic_turbulence verified against the real examples/2D_synthetic_turbulence case — accepts it, and rejects it once synth_L(1,2) is removed

case_validator.py had no pytest coverage of its constraint checks, and validating the example cases only exercises configurations meant to pass, so a check that stopped firing would go unnoticed. That matters more now that these have no Fortran backstop. Reverting case_validator.py fails 15 of the original 24 tests; the 9 that survive are exactly those covering checks that already existed in Python.

Checklist

  • I added or updated tests for new behavior
  • I updated documentation if user-facing behavior changed

physics_constraints.md / case_constraints.md are generated from case_validator.py at docs-build time. A PHYSICS_DOCS entry was added for check_synthetic_turbulencelint_docs.py caught its absence, which is the doc-coverage gate working as intended.

GPU changes (expand if you modified src/simulation/)

Validation-only; no kernel, data-movement, or numerics changes. The one GPU-conditional check (nv_uvm_igr_temps_on_gpu, under #ifdef __NVCOMPILER_GPU_UNIFIED_MEM) is deliberately left in place, and s_check_inputs_nvidia_uvm is on the lint rule's runtime allowlist.

The Python validator and src/simulation/m_checker.fpp had drifted into
double entry: reactive_burn (#1670) added nine constraints to both in the
same PR, and ib_state_wrt, chemistry+bubbles_euler, and dt <= 0 were each
enforced twice.

Delete the Fortran copies of the checks that depend only on input
parameters, and complete their Python counterparts:

  - reactive_burn num_fluids / gamma / pi_inf / qv pairing (new in Python)
  - chemistry operator-split sub-stepping, 4 checks (new in Python)
  - many_ib_patch_parallelism requires ib (new in Python)
  - bf_spatial_support 2D-only (new in Python)
  - dt <= 0, ib_state_wrt, chemistry + bubbles_euler/qbmm (already in
    Python; drop the Fortran duplicates)

s_check_inputs_time_stepping had no remaining body and is removed.

Fortran defaults are materialized where an unset value is meaningful:
chem_params%reaction_substeps{,_max} and fluid_pp(i)%qv all default to 0,
so Python treats unset as 0 to match. gamma and pi_inf default to the
dflt_real sentinel, which f_approx_equal reports as equal, so Python
skips the comparison when either is unset.

nv_uvm_igr_temps_on_gpu stays in Fortran. Its default is 3 and the check
is "== 3 .and. igr_iter_solver == 2", so it fires precisely when the user
has not set the parameter; in Python an unset value reads as None and the
check would never fire. It is also inside #ifdef
__NVCOMPILER_GPU_UNIFIED_MEM, which the validator cannot see.

The remaining Fortran checks depend on runtime or compiler state that is
unavailable at validation time: MPI decomposition (s_check_total_cells,
s_check_inputs_fft), per-rank m/n/p (WENO/MUSCL stencil widths), and
compiler conditionals (s_check_amd, rdma_mpi).

Add toolchain/mfc/test_case_validator.py. case_validator.py had no pytest
coverage of its constraint checks, and validating the example cases only
exercises configurations meant to pass, so a check that stopped firing
would go unnoticed -- which now matters more, since these no longer have
a Fortran backstop. Reverting case_validator.py fails 15 of the 24 tests.

src/simulation/m_checker.fpp: 225 -> 162 lines.
Copilot AI lite review requested due to automatic review settings August 9, 2026 19:24
…plit

Three follow-ons to the previous commit, which moved the input-only
simulation checks into case_validator.

Migrate the last input-only Fortran checks
------------------------------------------
  - particle_cloud packing_method (2 checks) and the muscl_order/int_comp
    check were already duplicated in case_validator; drop the Fortran.
  - synthetic-turbulence forcing zones (3 checks) had no Python
    counterpart; add check_synthetic_turbulence, covering
    num_turbulent_sources bounds and per-zone turb_pos / synth_L over
    d = 1..num_dims, matching the Fortran loop so trailing components of a
    lower-dimensional case stay optional.

s_check_inputs_particle_clouds and s_check_inputs_synthetic_turbulence
are removed along with their call sites, and m_helper_basic and
muscl_order_first_order are no longer used by m_checker.

src/simulation/m_checker.fpp: 162 -> 113 lines (225 before this branch).

Delete the params_tests CLI island
----------------------------------
coverage.py, inventory.py, mutation_tests.py, negative_tests.py,
runner.py, and snapshot.py: 1651 lines that collect zero pytest tests.
Each is imported only by runner.py, which nothing imports and which
appears in no workflow, script, doc, or CMake file. Its entire history is
incidental edits from unrelated feature PRs -- #1713 had to update
mutation_tests.py to drop model_eqns = 4 earlier today.

It could not be promoted as-is: negative_tests decides whether the right
error fired with a "half the key terms appear" substring heuristic, and
runner verify needs a data/ baseline that is gitignored. The sibling
test_*.py files, which supply all 171 real tests in the package, stay.

Enforce the split going forward
-------------------------------
Add check_checker_input_constraints to lint_source. A @:PROHIBIT in
src/**/m_checker*.fpp is allowed only inside a subroutine listed in
RUNTIME_CHECKER_SUBROUTINES -- the ones that depend on the MPI
decomposition, per-rank grid extents, the active compiler, or a
Cantera-populated value -- or on a line marked
"! lint: runtime-check <reason>".

This is what stops the next feature PR from re-creating the double entry
this branch removed: reactive_burn added nine constraints to both
languages in a single PR.
@sbryngelson sbryngelson changed the title Move input-only simulation checks from Fortran to case_validator Move input-only checks to case_validator, delete dead params_tests, enforce the split Aug 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Moves input-parameter-only simulation constraints out of Fortran m_checker*.fpp and into toolchain/mfc/case_validator.py, reducing duplicate logic and enforcing rules earlier (before binaries run).

Changes:

  • Added Python-side constraint checks for synthetic turbulence, chemistry substepping, reactive-burn fluid pairing, IB/body-force flags, and removed matching Fortran duplicates.
  • Added a dedicated unit test module covering the migrated Python-only constraints.
  • Added a source-lint rule to prevent reintroducing input-only @:PROHIBIT constraints into Fortran checker files; removed the old params test “safety net” tooling.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
toolchain/mfc/test_case_validator.py New unit tests for migrated Python-only constraint checks.
toolchain/mfc/params_tests/snapshot.py Removed legacy snapshot-based validation regression tooling.
toolchain/mfc/params_tests/runner.py Removed CLI runner for legacy params test tooling.
toolchain/mfc/params_tests/negative_tests.py Removed legacy negative-test generator (superseded by new unit tests).
toolchain/mfc/params_tests/mutation_tests.py Removed legacy mutation test tool.
toolchain/mfc/params_tests/inventory.py Removed parameter inventory export tool.
toolchain/mfc/params_tests/coverage.py Removed constraint coverage analysis tool.
toolchain/mfc/params_tests/init.py Updated package docstring to reflect remaining test purpose.
toolchain/mfc/params_tests/.gitignore Removed ignores for deleted generated “data/” outputs.
toolchain/mfc/lint_source.py Added lint guard to keep input-only constraints out of Fortran m_checker*.fpp.
toolchain/mfc/case_validator.py Added/expanded Python checks replacing the removed Fortran counterparts.
src/simulation/m_checker.fpp Removed input-only @:PROHIBIT checks and dead subroutines now enforced in Python.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +82 to +89
def errors_for(self, params) -> str:
"""Return all simulation-stage validation errors for params, joined."""
validator = CaseValidator(dict(params))
try:
validator.validate("simulation")
except Exception as exc: # CaseConstraintError
return str(exc)
return ""
Comment thread toolchain/mfc/test_case_validator.py Outdated
Comment on lines +91 to +99
def assertRejects(self, params, expected: str):
"""params must fail validation with expected in the message."""
errors = self.errors_for(params)
self.assertIn(expected, errors)

def assertAccepts(self, params, unexpected: str):
"""params must not trip the check identified by unexpected."""
errors = self.errors_for(params)
self.assertNotIn(unexpected, errors)
Every ./mfc.sh run called ensure_vscode_settings(), which edited
.vscode/settings.json in the user's checkout whether or not they use VS
Code. It did so by string surgery -- rfind("}"), then splice in a block
and guess whether a comma is needed -- on a file that is hand-maintained,
committed, and legally contains comments, so a malformed result was a
plausible outcome.

Remove toolchain/mfc/ide.py entirely. Its two functions,
ensure_vscode_settings and update_vscode_settings, were near-duplicates
of each other, called from main.py (every invocation) and from
generate --json-schema respectively.

Also drop generate_vscode_settings() from json_schema_gen.py: a third
copy of the same settings blob, called by nothing, and disagreeing with
ide.py on both the fileMatch patterns and the schema URL.

.vscode/settings.json keeps all 32 of its settings, including the
json.schemas/yaml.schemas association -- it is a useful set of defaults
for anyone working on MFC. The block is now plain committed config rather
than a region the toolchain rewrites, so the "auto-generated, do not
edit" markers are replaced with a comment pointing at ./mfc.sh generate,
which still writes toolchain/mfc-case-schema.json.
user_guide.py: 710 -> 315 lines.

interactive_mode (~145 lines)
  ./mfc.sh interactive presented a numbered menu whose seven handlers each
  shelled back out to ./mfc.sh new/validate/build/run/test/clean. The
  command is removed from the CLI schema, main.py, and the README.

Tips (~78 lines)
  A class of five contextual hint methods. Only after_build_failure was
  ever called (twice, from build.py); after_case_error, after_test_failure,
  after_run_failure, and suggest_validate had no callers at all.

Markdown help scraper (~173 lines)
  MARKDOWN_HELP_FILES, _extract_markdown_section, _load_markdown_help, and
  _generate_markdown_help re-read docs/documentation/*.md at runtime,
  stripped Doxygen syntax with regexes, and re-rendered four topics (gpu,
  batch, debugging, performance) in the terminal -- a second, lossy
  presentation of pages that already exist on the docs site.

With those four topics gone, HELP_TOPICS held a single dynamic entry, so
the topic-dispatch layer (print_topic_help, print_help_topics, and the
`topic` positional on the help command) collapses into print_clusters_help.
./mfc.sh help now prints the cluster table directly, through the same
Panel it always rendered in.

Kept: the cluster table itself, which derives from toolchain/modules and
so cannot go stale, and print_help / print_command_help, which back
./mfc.sh --help and ./mfc.sh <command> --help.
The cluster listing existed twice: a hand-written coloured menu in
toolchain/bootstrap/modules.sh, shown by ./mfc.sh load, and 163 lines of
Python in user_guide.py that re-derived the same list from
toolchain/modules for ./mfc.sh help.

Keep the shell menu and delete the Python. That removes CLUSTER_ORGS,
SLUG_ORG_OVERRIDE, SLUG_NAME_OVERRIDE, ORG_ORDER, ORG_COLORS (which mapped
all eight organisations to "yellow"), _parse_modules_file,
_get_cluster_short_name, _generate_clusters_content, and
print_clusters_help. The cluster table was the only content ./mfc.sh help
had left, so the help command goes with it.

user_guide.py: 315 -> 144 lines (710 at the start of this branch).

Fix the drift the second copy had been masking. The menu offered Summit,
which was decommissioned and has no entry in toolchain/modules, so
selecting it loaded nothing; and it omitted Phoenix IFX (pifx) and Santis
(san), both of which have module sets that users could not discover.

Add check_cluster_menu_slugs to lint_source so the hand-written menu
cannot drift again: the slugs it advertises must match the cluster
definitions in toolchain/modules, in both directions. Module-list lines
(<slug>-{all,cpu,gpu}[-unload]) are excluded -- p-gpu-unload is an unload
list, not a cluster.
Three places still offered Summit as a machine you could target:

  - modules.sh show_help listed "Summit (s)". This was a second, staler
    copy of the cluster list inside the same file -- it also omitted
    Tuolumne, Santis, Phoenix IFX, Anvil, HiPerGator, and Turing. Replace
    the list with a pointer to the interactive menu so the file holds one
    list, the one check_cluster_menu_slugs already validates.

  - running.md's "Example Runs" passed -c summit. For ./mfc.sh run, -c
    names a batch template in toolchain/templates, and summit.mako does
    not exist, so the documented command could not have worked. Point it
    at Frontier.

  - running.md described LSF as "e.g., Summit". LSF support stands; drop
    the example.

Historical references are deliberately kept: the V100 weak-scaling
results and figure in expectedPerformance.md, the gallery entries in
docs/index.html recording where each simulation ran, the allocation
acknowledgement and scaling record in the README, and the search
keywords. Those describe what was done, not what users can target.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Claude Code Review

Head SHA: 21ca34b

Files changed:

  • 24
  • .vscode/settings.json
  • README.md
  • docs/documentation/running.md
  • docs/documentation/troubleshooting.md
  • src/simulation/m_checker.fpp
  • toolchain/bootstrap/modules.sh
  • toolchain/main.py
  • toolchain/mfc/args.py
  • toolchain/mfc/build.py
  • toolchain/mfc/case_validator.py

Findings:

  • Lost validation: rburn%ta/fluid_pp(1)%cv constraint dropped, not migrated. src/simulation/m_checker.fpp had two @:PROHIBIT checks removed (reactive_burn .and. rburn%ta < 0._wp and reactive_burn .and. rburn%ta > 0._wp .and. fluid_pp(1)%cv <= 0._wp, the latter guarding against a silently-disabled Arrhenius factor). The PR's own design (toolchain/mfc/lint_source.py's new check_checker_input_constraints) requires such input-only constraints to move to toolchain/mfc/case_validator.py, and this PR does migrate several sibling reactive_burn checks there (num_fluids, gamma, pi_inf, qv — see check_reactive_burn in the diff, plus matching tests in TestReactiveBurnFluidPairing). No equivalent rburn%ta/cv check was added to case_validator.py, and no test covers it. Since the Fortran check is now gone and nothing in Python replaces it, a case with reactive_burn = T, rburn%ta > 0, and fluid_pp(1)%cv <= 0 (or an unset/sentinel cv) will now pass validation and silently disable the Arrhenius ignition factor at runtime.
  • Lost validation: muscl_order/int_comp constraint dropped, not migrated. src/simulation/m_checker.fpp's s_check_inputs_muscl had @:PROHIBIT(muscl_order == muscl_order_first_order .and. int_comp > 0, ...) removed (and the now-unused muscl_order_first_order import dropped from the use m_constants line), which previously prevented running with int_comp > 0 and muscl_order = 1 — a combination that leaves the reconstruction workspace uninitialized. This is a pure input-parameter constraint (not grid/MPI/compiler dependent), so per this PR's own migration pattern it belongs in case_validator.py, but no int_comp/muscl_order check was added there, and no test covers it. Cases with this invalid combination will now pass validation and hit uninitialized reconstruction data.

errors_for caught bare Exception and returned str(exc), so a regression in
the validator that raised KeyError or TypeError would be stringified and
could satisfy an assertion instead of failing the test. Catch only
CaseConstraintError; anything else propagates.

assertAccepts checked that one message was absent, which a case that broke
for an unrelated reason would still satisfy. It now asserts full validity
(no violations at all) and takes only the params. Every call site already
uses a fully valid configuration, verified individually, so no test needed
relaxing to accommodate the stronger form.

assertRejects gained a check that validation failed at all, so a case that
is wrongly accepted reports "expected validation to fail with X" rather
than the less obvious "X not found in ''".

Verified the new assertions catch what the old ones missed: injecting a
KeyError into CaseValidator.validate now errors the test instead of
passing; assertAccepts on a fixture with an unrelated violation (dt <= 0)
now fails; assertRejects on a case that validates cleanly now fails.

The 2D synthetic-turbulence z-component test folded into
test_accepts_fully_specified_zone -- with assertAccepts asserting full
validity, accepting a fixture that sets only d = 1, 2 is itself the proof
that turb_pos(1,3) and synth_L(1,3) are not required. 32 -> 31 tests.
@sbryngelson

Copy link
Copy Markdown
Member Author

Thanks — went through all four findings. Two were valid and are fixed in 94b8565; two are false positives, with evidence below.

Fixed — Copilot, test_case_validator.py

errors_for caught bare Exception. Correct, and the consequence was real: a regression raising KeyError would be stringified and could satisfy an assertion. Now catches only CaseConstraintError; anything else propagates.

assertAccepts only checked one message was absent. Also correct — a case broken for an unrelated reason would still pass. It now asserts full validity (no violations at all) and takes only params. I checked every call site individually first; all seven were already fully valid configurations, so nothing had to be relaxed to accommodate the stronger form.

assertRejects also gained an explicit "did it fail at all" check, so a wrongly-accepted case now reports expected validation to fail with X instead of X not found in ''.

Verified the new assertions catch what the old ones missed:

  • injecting a KeyError into CaseValidator.validate → test now errors (previously would have passed)
  • assertAccepts on a fixture with an unrelated violation (dt <= 0) → now fails
  • assertRejects on a case that validates cleanly → now fails

Not a defect — Claude review, "lost validation" ×2

Both checks were already in case_validator.py on master before this PR. They were among the nine reactive_burn / MUSCL constraints that existed in both languages — which is the duplication this PR removes. Only the Fortran copy was deleted; the Python side is untouched by this diff.

Claim Where it lives on master
rburn%ta / fluid_pp(1)%cv case_validator.py:1571 onward, in check_reactive_burn
muscl_order / int_comp case_validator.py:431

git diff master...HEAD -- toolchain/mfc/case_validator.py contains no +/- line touching rburn%ta, %cv, or int_comp.

Confirmed by running the validator on this branch:

rburn%ta < 0                          -> CAUGHT
rburn%ta > 0 with fluid_pp(1)%cv = 0  -> CAUGHT
rburn%ta > 0 with cv unset            -> CAUGHT
muscl_order = 1 with int_comp = 1     -> CAUGHT

Message for the second: reactive_burn with rburn%ta > 0 requires fluid_pp(1)%cv > 0 (the reactant temperature needs a physical heat capacity; cv = 0 silently disables the Arrhenius factor) — the exact constraint the review reported as dropped.

Worth noting these two are only covered by check_reactive_burn / check_interface_compression, not by the new tests, since they predate this PR. Happy to add cases for them if that's wanted, though it widens the scope past the migration.

Self-review of this branch found that three checks I moved to Python are
weaker than the Fortran they replaced, all from the same cause: Python's
`is not None` / `_is_numeric` guards no-op on an absent key, while the
deleted Fortran compared against the dflt_real / dflt_int sentinels, so an
unset parameter was itself a violation. Each turned a startup abort into a
silently wrong run.

  - reactive_burn now requires both fluid_pp(1)%{gamma,pi_inf} and
    fluid_pp(2)%{gamma,pi_inf} to be set. Previously, omitting fluid 2's
    EOS was accepted and the product phase ran with gamma = pi_inf =
    dflt_real = -1e6, a negative stiffened-gas EOS. The earlier reasoning
    only covered both-unset, where f_approx_equal(dflt, dflt) is true.
  - reactive_burn now requires num_fluids and model_eqns to be set, not
    merely correct-if-present. Omitting both was accepted outright.
  - dt is required whenever stepping is not CFL-driven. The adap_dt
    exemption had no counterpart in the Fortran, which checked
    `if (.not. cfl_dt) dt <= 0` regardless. Cases that genuinely need no
    dt use cfl_adap_dt (2D_lagrange_rising_bubble), which is unaffected.

Four tests cover the gaps; all four fail against the previous validator.
TestTimeStepPositivity became TestTimeStep, since it previously only
exercised a rule that predates this branch.

lint_source.py fixes, all in code this branch added:

  - The runtime-check marker was consumed by the next physical line, so a
    blank line or Fypp directive between it and the @:PROHIBIT silently
    dropped the exemption. It now persists until the next @:PROHIBIT.
  - The subroutine regex accepted only impure/pure, so `recursive
    subroutine` reported "at module scope" and told the developer to add
    `None` to the allowlist. It now accepts the full prefix set and gives
    scope-appropriate advice.
  - s_check_inputs_weno and s_check_inputs_muscl left the allowlist. They
    mix runtime and input-only checks -- the muscl_order/int_comp check
    this branch deletes lived in one of them -- so allowlisting the
    subroutines would have let a replacement back in unnoticed. Their six
    grid-extent checks now carry explicit markers instead, and an
    int_comp-style addition to either is caught.
  - check_cluster_menu_slugs keyed on the literal strings "Select a
    system:" and "read u_c", so rewording the prompt disabled it and
    editing the read broke precheck repo-wide. It now keys on explicit
    cluster-menu-begin/end markers, tolerates rewording, still catches
    slug drift, and fails loudly if the markers go missing.

Also drops HELP_TOPICS from commands.py and the help_topics field from
CLISchema: 25 lines describing five help topics that no longer exist and
that nothing reads, left behind when the help system was removed.
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.20%. Comparing base (ae4b4c4) to head (ea5dca3).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1717      +/-   ##
==========================================
- Coverage   61.21%   61.20%   -0.01%     
==========================================
  Files          84       84              
  Lines       21601    21572      -29     
  Branches     3195     3192       -3     
==========================================
- Hits        13223    13204      -19     
+ Misses       6209     6202       -7     
+ Partials     2169     2166       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…alidator

Master's s_check_inputs_hll_non_conservative and s_check_inputs_hypo_branch are the double entry this branch removes: nearly all of their PROHIBITs already exist verbatim in case_validator.py. Dropped both, and migrated the four that had no Python counterpart (HLL Method 2 3D cylindrical, alt_soundspeed with HLL in 2D axisymmetric and 3D cylindrical, alt_soundspeed with HLLD without hypoelasticity), with tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants