Skip to content

Conversation

@sbryngelson
Copy link
Member

@sbryngelson sbryngelson commented Jan 31, 2026

User description

PR Type

Enhancement, Tests, Documentation

Description

Major Quality of Life Improvements for MFC Toolchain

  • Centralized Parameter System: Consolidated ~3,300 MFC case parameters into unified registry with descriptions, constraints, and dependencies (params/definitions.py, params/descriptions.py)

  • Enhanced CLI Architecture: Refactored argument parsing with declarative schema-based command definitions, auto-generated argparse parsers, and shell completion support (cli/schema.py, cli/argparse_gen.py, cli/completion_gen.py)

  • Improved User Experience: Added interactive user guide with topic-based help system, contextual tips, and first-time user onboarding (user_guide.py, completion.py)

  • Case Template System: New case template generator with built-in minimal templates and example-based case creation (init.py)

  • Parameter Discovery: New CLI command for searching and exploring parameters with filtering and statistics (params_cmd.py)

  • Enhanced Validation: Comprehensive physics constraint validation for bubbles, patches, time stepping, and acoustic sources with improved error reporting (case_validator.py)

  • Build System Improvements: Added progress bars, streaming output, and detailed error reporting with contextual hints (build.py)

  • Test Infrastructure: Comprehensive parameter validation test suite including negative tests, mutation testing, snapshot regression testing, and coverage analysis (params_tests/ module)

  • Documentation Generation: Auto-generated CLI reference and parameter documentation from schema definitions (cli/docs_gen.py, params/generators/docs_gen.py)

  • Code Quality: Fixed formatting issues across example cases and benchmarks (PEP 8 compliance for imports and comments)

Diagram Walkthrough

flowchart LR
  A["Parameter Registry<br/>definitions.py<br/>descriptions.py"] -->|"loads"| B["Case Validator<br/>Enhanced Constraints"]
  A -->|"powers"| C["Parameter Search<br/>params_cmd.py"]
  D["CLI Schema<br/>schema.py"] -->|"generates"| E["Argparse Parser<br/>argparse_gen.py"]
  D -->|"generates"| F["Shell Completions<br/>completion_gen.py"]
  D -->|"generates"| G["CLI Docs<br/>docs_gen.py"]
  E -->|"used by"| H["Enhanced Args<br/>args.py"]
  H -->|"provides"| I["User Guide<br/>user_guide.py"]
  J["Build System<br/>build.py"] -->|"reports"| I
  B -->|"tested by"| K["Test Suite<br/>negative/mutation/<br/>snapshot/coverage"]
  L["Case Templates<br/>init.py"] -->|"creates"| M["New Cases"]
Loading

File Walkthrough

Relevant files
Enhancement
15 files
descriptions.py
Centralized parameter descriptions and documentation system

toolchain/mfc/params/descriptions.py

  • New file providing centralized parameter descriptions for ~3,300 MFC
    case parameters
  • Includes manual descriptions dictionary extracted from documentation
  • Implements pattern-based auto-generation for indexed parameters (e.g.,
    patch_icpp(N)%geometry)
  • Provides fallback naming convention inference for undocumented
    parameters
+552/-0 
case_dicts.py
Migrate parameter definitions to central registry               

toolchain/mfc/run/case_dicts.py

  • Refactored to load parameter definitions from central registry instead
    of hardcoded dictionaries
  • Replaced ~500 lines of manual parameter type definitions with dynamic
    loading via _load_from_registry()
  • Updated CASE_OPTIMIZATION to derive from registry metadata instead of
    hardcoded list
  • Added comprehensive docstrings to ParamType enum and utility functions
+61/-523
commands.py
Unified CLI command definitions and schema                             

toolchain/mfc/cli/commands.py

  • New file defining all MFC CLI commands as a single source of truth
  • Includes 20+ commands (build, run, test, clean, validate, new, params,
    etc.) with full argument specifications
  • Defines common argument sets, command aliases, and help topics
  • Provides structured schema for generating argparse parsers,
    completions, and documentation
+1003/-0
case_validator.py
Enhanced case validation with physics constraints               

toolchain/mfc/case_validator.py

  • Added check_parameter_types() to validate logical parameters are 'T'
    or 'F'
  • Enhanced check_bubbles_euler() with validation for bubble physics
    parameters (R0ref, p0ref, viscosities, surface tension)
  • Added check_patch_physics() to validate initial condition constraints
    (positive pressure, valid volume fractions, positive dimensions)
  • Improved check_time_stepping() to handle multiple time stepping modes
    (CFL-based, adaptive, fixed)
  • Enhanced check_acoustic_source() with physics validation (positive
    frequency, wavelength, gaussian parameters)
  • Added _is_numeric() helper and _format_errors() for better error
    reporting with hints
+257/-20
definitions.py
Consolidated parameter definitions module with constraint and
dependency support

toolchain/mfc/params/definitions.py

  • New file consolidating ~3,300 parameter definitions into a single
    compact module using loops instead of a definitions/ directory
  • Defines parameter constraints (choices, min/max values) and
    dependencies (requires/recommends relationships)
  • Implements _load() function that registers all parameters across
    COMMON, PRE_PROCESS, SIMULATION, and POST_PROCESS stages
  • Supports indexed parameters for patches, fluids, boundary conditions,
    acoustic sources, probes, and other multi-instance configurations
+394/-0 
user_guide.py
New user guide with enhanced help and interactive onboarding system

toolchain/mfc/user_guide.py

  • New comprehensive user guide module providing enhanced help system
    with Rich formatting
  • Implements topic-based help system covering GPU configuration, cluster
    setup, batch jobs, and debugging
  • Provides contextual tips after build failures, case errors, test
    failures, and run failures
  • Includes onboarding for first-time users with welcome message and
    interactive menu-driven interface
+594/-0 
init.py
New case template generator with built-in and example-based templates

toolchain/mfc/init.py

  • New case template generator module for creating new case files from
    built-in or example templates
  • Provides three built-in minimal templates: 1D_minimal, 2D_minimal, and
    3D_minimal with documented parameters
  • Implements create_case() function to generate new cases from templates
    or copy from examples directory
  • Includes list_templates() to display available templates and
    get_available_templates() for programmatic access
+500/-0 
args.py
Refactored argument parsing with centralized CLI schema and enhanced
help

toolchain/mfc/args.py

  • Refactored argument parsing to use auto-generated parsers from
    centralized CLI schema instead of manual argparse setup
  • Added enhanced help output with print_help(), print_command_help(),
    and topic-based help system integration
  • Implemented _handle_enhanced_help() to provide rich formatting before
    argparse help
  • Deferred test case loading to avoid slow startup for non-test commands
  • Added support for command aliases and improved help for first-time
    users
+106/-151
build.py
Enhanced build system with progress bars and improved error reporting

toolchain/mfc/build.py

  • Added progress bar visualization for build process with ninja/make
    output parsing using regex patterns
  • Implemented _run_build_with_progress() function supporting streaming
    mode (-v) and interactive progress bars
  • Added _show_build_error() to display detailed error information from
    captured subprocess output
  • Enhanced configure, build, and install steps with status indicators
    (✓/✗), timing information, and contextual error tips
  • Improved verbosity levels: default (progress bar), -v (streaming),
    -vv+ (full compiler output)
+339/-7 
completion_gen.py
New shell completion generator for bash and zsh from CLI schema

toolchain/mfc/cli/completion_gen.py

  • New module generating bash and zsh shell completion scripts from CLI
    schema
  • Implements generate_bash_completion() and generate_zsh_completion()
    functions for auto-generated completions
  • Supports completion for commands, options, positional arguments, and
    file types (Python, YAML, pack files)
  • Handles command aliases, mutually exclusive groups, and common
    argument sets in completion generation
+353/-0 
argparse_gen.py
New argparse generator from declarative CLI schema             

toolchain/mfc/cli/argparse_gen.py

  • New module generating argparse parsers from declarative CLI schema
    definitions
  • Implements generate_parser() to convert schema into complete
    ArgumentParser with subcommands and argument groups
  • Handles MFCConfig boolean pair arguments (--flag/--no-flag)
    dynamically from dataclass fields
  • Supports positional arguments, common argument sets, mutually
    exclusive groups, and nested subcommands
+226/-0 
params_cmd.py
Parameter search and discovery CLI command                             

toolchain/mfc/params_cmd.py

  • New module providing CLI command for searching and exploring ~3,300
    MFC case parameters
  • Implements parameter search with filtering by type and collapsing of
    indexed parameters
  • Displays parameter statistics, families, and descriptions with
    configurable output formats
  • Includes helper functions for pattern matching, result formatting, and
    alternative suggestions
+330/-0 
test.py
Enhanced test reporting and failure feedback                         

toolchain/mfc/test/test.py

  • Enhanced test output formatting with improved progress display showing
    test names prominently
  • Added test duration tracking and comprehensive summary report with
    visual panel formatting
  • Implemented real-time failure feedback with error type detection and
    helpful hints
  • Added failed_tests tracking and _print_test_summary() function for
    detailed failure reporting
+136/-18
completion.py
Shell completion installation and management                         

toolchain/mfc/completion.py

  • New module for shell completion installation and management
  • Implements auto-detection and installation for bash and zsh shells
  • Manages completion script installation to
    ~/.local/share/mfc/completions/
  • Provides status checking, uninstall, and RC file configuration
+220/-0 
schema.py
CLI schema dataclass definitions                                                 

toolchain/mfc/cli/schema.py

  • New module defining dataclasses for CLI schema (single source of
    truth)
  • Implements Argument, Positional, Command, CommonArgumentSet, and
    CLISchema dataclasses
  • Defines enums for ArgAction and CompletionType with completion
    configuration
  • Provides helper methods for command lookup and argument flag
    generation
+204/-0 
Formatting
7 files
case.py
Fix comment formatting in example case                                     

examples/2D_shearlayer/case.py

  • Fixed comment formatting from #' to # ' for consistency with Python
    style guidelines
+4/-4     
case.py
Fix import statement formatting                                                   

examples/1D_bubblescreen/case.py

  • Split multi-import statement into separate lines for PEP 8 compliance
+2/-1     
case.py
Code formatting improvement for import statements               

examples/nD_perfect_reactor/case.py

  • Minor formatting change: split import json, argparse into separate
    lines for PEP 8 compliance
+2/-1     
case.py
Code formatting and style improvements                                     

benchmarks/5eq_rk3_weno3_hllc/case.py

  • Reformatted import statements to follow PEP 8 (one import per line)
  • Converted multi-line comments from ## to single # for consistency
+9/-7     
case.py
Comment style normalization                                                           

examples/2D_axisym_shockwatercavity/case.py

  • Converted multi-line comments from ## to single # for consistency
+6/-6     
case.py
Comment style normalization                                                           

examples/2D_ibm_steady_shock/case.py

  • Converted multi-line comment from ## to single # for consistency
+1/-1     
export.py
Import statement formatting                                                           

examples/scaling/export.py

  • Reformatted import statements to follow PEP 8 (one import per line)
+5/-1     
Tests
6 files
negative_tests.py
Negative test case generator for validator constraints     

toolchain/mfc/params_tests/negative_tests.py

  • New test module generating negative test cases that intentionally
    violate validator constraints
  • Defines BASE_CASE with valid parameters and ConstraintTest dataclass
    for test specification
  • Implements generate_constraint_tests() covering simulation domain,
    model equations, time stepping, WENO, boundary conditions, and
    acoustic source constraints
  • Provides run_constraint_tests() and print_test_report() for validation
    and reporting
+358/-0 
mutation_tests.py
Mutation testing for validator coverage analysis                 

toolchain/mfc/params_tests/mutation_tests.py

  • New module for mutation testing that systematically mutates valid
    parameters to verify validator coverage
  • Defines MUTATIONS dictionary with invalid values for ~40 parameters
    across numeric, boolean, physics, and numerics categories
  • Implements mutation application and validation checking with result
    tracking
  • Provides comprehensive reporting on catch rates and missed mutations
    by parameter
+279/-0 
snapshot.py
Validation snapshot tool for regression testing                   

toolchain/mfc/params_tests/snapshot.py

  • New module for capturing and comparing validation snapshots of example
    cases for regression testing
  • Implements CaseSnapshot and ValidationResult dataclasses for storing
    validation state
  • Provides functions to load case parameters, validate across stages,
    and save/load snapshots to JSON
  • Includes comparison logic to detect changes in validation behavior
    across refactoring
+301/-0 
coverage.py
Constraint coverage analysis tool                                               

toolchain/mfc/params_tests/coverage.py

  • New module analyzing constraint coverage by parsing case_validator.py
    AST
  • Extracts all self.prohibit() calls and maps them to validation stages
  • Generates coverage reports showing constraints per method and stage
  • Provides JSON export and console reporting of coverage metrics
+278/-0 
runner.py
Test safety net runner and orchestrator                                   

toolchain/mfc/params_tests/runner.py

  • New main entry point for building and verifying parameter validation
    test suite
  • Implements build_safety_net() to capture parameter inventory,
    validation snapshots, and constraint coverage
  • Provides verify_safety_net() to detect unintended validation behavior
    changes
  • Includes CLI interface supporting build, verify, summary, and report
    generation commands
+258/-0 
inventory.py
Parameter inventory export and analysis                                   

toolchain/mfc/params_tests/inventory.py

  • New module exporting parameter inventory with types and validation
    stages
  • Implements export_parameter_inventory() categorizing parameters by
    stage and type
  • Extracts dynamic parameter patterns with normalization and example
    tracking
  • Provides JSON export and console summary reporting of parameter
    metadata
+176/-0 
Documentation
2 files
docs_gen.py
CLI documentation generator from schema                                   

toolchain/mfc/cli/docs_gen.py

  • New module generating markdown CLI reference documentation from schema
    definitions
  • Formats command sections with usage, arguments, options tables,
    examples, and subcommands
  • Organizes commands by category (core, utility, development, CI, other)
  • Generates quick reference tables and common options documentation
+322/-0 
docs_gen.py
Parameter documentation generator                                               

toolchain/mfc/params/generators/docs_gen.py

  • New module generating markdown documentation for all MFC case
    parameters
  • Organizes parameters by family with descriptions, types, and
    constraints
  • Generates table of contents and detailed family sections with pattern
    grouping for large families
  • Includes command-line reference examples and footer with CLI search
    instructions
+234/-0 
Additional files
74 files
docs.yml +1/-1     
lint-toolchain.yml +3/-0     
settings.json +21/-9   
CMakeLists.txt +1/-1     
README.md +46/-0   
case.py +3/-1     
case.py +3/-1     
case.py +3/-1     
case.py +3/-1     
authors.md +2/-0     
case.md +5/-1     
cli-reference.md +667/-0 
docker.md +2/-0     
expectedPerformance.md +2/-0     
getting-started.md +40/-0   
gpuParallelization.md +2/-0     
papers.md +2/-0     
parameters.md +1000/-0
readme.md +29/-18 
references.md +2/-0     
running.md +2/-0     
testing.md +2/-0     
troubleshooting.md +151/-0 
visualization.md +2/-0     
examples.sh +1/-1     
index.html +1/-1     
plot.py +3/-3     
case.py +1/-1     
case.py +3/-1     
case.py +2/-1     
case.py +2/-1     
case.py +2/-1     
case.py +2/-1     
case.py +2/-1     
case.py +6/-4     
casefile.py +8/-5     
case.py +2/-2     
case.py +9/-7     
case.py +2/-1     
case.py +2/-1     
case.py +6/-4     
case.py +2/-2     
case.py +6/-6     
case.py +6/-6     
analyze.py +2/-1     
case.py +7/-3     
mfc.sh +22/-5   
format.sh +53/-19 
format_python.sh +6/-1     
lint.sh +1/-1     
python.sh +235/-4 
_mfc +449/-0 
mfc.bash +191/-0 
main.py +60/-11 
mfc-case-schema.json +24427/-0
case.py +37/-7   
clean.py +22/-0   
__init__.py +37/-0   
common.py +26/-1   
gen_case_constraints_docs.py +1/-0     
generate.py +116/-0 
ide.py +136/-0 
__init__.py +10/-0   
__init__.py +5/-0     
case_dicts_gen.py +46/-0   
json_schema_gen.py +128/-0 
registry.py +52/-0   
schema.py +88/-0   
validate.py +148/-0 
__init__.py +8/-0     
input.py +20/-5   
run.py +29/-1   
validate.py +58/-0   
pyproject.toml +1/-1     

CodeAnt-AI Description

Central registry for case parameters, comprehensive CLI schema, and interactive build/test UX

What Changed

  • Case parameter metadata moved to a centralized registry with human-friendly descriptions and pattern-based auto-generation; parameter-type maps are now loaded from that registry so all ~3,300 parameters are sourced from one place.
  • New CLI schema file defines all commands/options in a single source: build, run, test, clean, validate, new (case templates), params (search/explore), completion (install/uninstall/status), generate, and several helper commands; this enables auto-generated parsers, completions, and docs.
  • Build and install now show interactive progress (progress bar or streaming [X/Y] output depending on verbosity/TTY), present captured CMake/compiler output in formatted panels on failure, and print concise success/failure indicators.
  • Added a validate command to perform pre-flight case validation without building, and a clean command to remove build artifacts.
  • New "params" CLI lets users search, filter by type, list families, and view descriptions for parameters; also adds utilities for generating JSON schema and other param-derived artifacts.
  • New case/template command to create cases from built-in or example templates and list available templates.
  • CLI now supports debug logging flag and completion installation commands to improve discoverability and first-time user onboarding.

Impact

✅ Clearer build errors and compiler output for faster debugging
✅ Shorter time to find and understand case parameters
✅ Shorter onboarding to create and run new cases via templates and shell completion

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • New Features

    • Major CLI expansion (many new commands), init templates, installable Bash/Zsh completions, and IDE helpers.
  • Documentation

    • Added CLI reference, full parameter reference (~3,400 entries), troubleshooting, getting-started, reorganized docs hub, README toolchain guide, and many doc pages.
  • Improvements

    • Richer build/run/test progress and summaries, enhanced parameter validation with suggestions, validation snapshots and testing tooling, shell completion generation.
  • Chores

    • CI/lint updates, formatter change, widespread cosmetic formatting and tooling scripts.

✏️ Tip: You can customize this high-level summary in your review settings.

sbryngelson and others added 30 commits January 27, 2026 20:34
- Add validate command for pre-flight case validation without building
- Add clean command implementation (was previously missing)
- Show detailed CMake/compiler errors on build failure with formatted panels
- Add build progress indicators (Configuring/Building/Installing status)
- Display human-readable test names prominently in test output
- Add real-time test failure feedback with helpful hints
- Enhanced case validator error messages with suggestions
- Add --debug-log flag for troubleshooting
- Create troubleshooting documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Test Summary:
- Rich panel with formatted pass/fail/skip counts
- Total test duration display
- Failed test details with UUIDs and error types
- Helpful "Next Steps" suggestions for failures

Case Template Generator (./mfc.sh init):
- Create new cases from built-in templates (1D/2D/3D_minimal)
- Copy from any example with --template example:<name>
- List available templates with --list
- Well-documented case files with clear parameter sections

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…oarding

- Add ./mfc.sh completion command to install shell tab-completion
  - Installs to ~/.local/share/mfc/completions/ (works across MFC clones)
  - Automatically configures ~/.bashrc or ~/.zshrc
  - Supports install/uninstall/status subcommands

- Add enhanced help output with Rich formatting
- Add contextual tips after build/test failures
- Add interactive menu mode (./mfc.sh interactive)
- Add welcome message for first-time users with getting started guide
- Add bash and zsh completion scripts
- Update README with toolchain features documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused Text import from rich.text
- Add pylint disable for too-many-locals in test()
- Add pylint disable for too-many-arguments in _print_test_summary()
- Rename failed_tests param to failed_test_list to avoid shadowing
- Prefix unused skipped_cases param with underscore
- Add pylint disable for global-statement in setup_debug_logging()

Lint score: 10.00/10

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Enhanced subcommand help (./mfc.sh build --help):
   - Shows Rich-formatted header with command description
   - Displays practical examples with explanations
   - Lists key options in easy-to-read format
   - Still shows full argparse options below

2. Topic-based help (./mfc.sh help <topic>):
   - gpu: GPU configuration, OpenACC/OpenMP, troubleshooting
   - clusters: HPC cluster setup (Phoenix, Frontier, etc.)
   - batch: Batch job submission options and examples
   - debugging: Debug logging, validation, common issues

3. Command aliases for faster typing:
   - b = build
   - r = run
   - t = test
   - v = validate
   - c = clean

4. Consistent --help behavior:
   - ./mfc.sh --help now shows enhanced help (same as ./mfc.sh)
   - Aliases shown in command table

Updated bash/zsh completion scripts to support new commands.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The 'load' command must be sourced to set environment variables in the
current shell. Running it directly (./mfc.sh load) now shows a clear
error message with the correct usage:

  source ./mfc.sh load -c p -m g

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Unicode progress bar during first-time pip package installation
  Shows "│████████░░░░░░░░░░░░│ 53% (37 pkgs, 1m23s)" in terminals
  Falls back to milestone updates when output is piped

- Defer list_cases() call in args.py until test command is actually used
  Previously generated all ~200 test cases on every startup

- Make pyrometheus and cantera imports lazy in run/input.py
  These heavy chemistry packages are now only imported when needed

These changes fix the apparent "hang" on first run where pip install
showed no progress, and significantly speed up startup time for
non-test commands.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Progress bar now tracks three phases: resolving (0-60%),
  building wheels (60-80%), and installing (80-100%)
- Add "Starting..." message in mfc.sh for immediate user feedback
- Non-TTY mode now shows phase transitions (building, installing)
- Better status messages showing current operation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Display the currently processing package (collecting, downloading, or
building) on a second line below the progress bar. The display updates
in real-time as pip processes each package.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use lazy imports in main.py to defer loading heavy modules
- Remove heavy imports from args.py (run.run, build, test.cases)
- Hardcode target names and template names to avoid import chain
- Import test.cases only when running test command

This reduces startup time from ~1.4s to ~1.0s by avoiding loading
mako, pygments, and other heavy dependencies until they're needed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
uv is a blazing fast Python package installer (10-100x faster than pip).
When uv is detected, use it for package installation (~7 seconds vs
several minutes with pip). Falls back to pip with progress bar when
uv is not available.

Users can install uv with: pip install uv

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of requiring users to manually install uv, automatically
bootstrap it in the venv using pip. This gives all users the speed
benefit of uv (~23 seconds for fresh install vs several minutes
with pip alone).

The bootstrap process:
1. Create venv
2. Install uv via pip (~2-3 seconds)
3. Use uv to install all ~70 packages (~7 seconds)

Falls back to pip with progress bar if uv installation fails.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The exact number of packages varies, so just say "Installing Python
packages" without specifying a count.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of hiding uv's output, show its native progress display when
running in an interactive terminal. This lets users see what's happening
during installation instead of appearing to hang.

For non-interactive (CI) environments, output is still captured for logs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
On HPC systems where cache and venv are on different filesystems,
uv's hardlink attempts fail and fall back to copying. Setting
UV_LINK_MODE=copy skips the failed hardlink attempts, reducing
overhead and eliminating the warning message.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove early exit for 'init' command in mfc.sh that prevented help
  from showing
- Fix _handle_enhanced_help to properly show both enhanced help and
  argparse help for all subcommands
- Add subparser map to print argparse help for specific commands

Now ./mfc.sh init --help (and other subcommands) properly show help.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Make build imports lazy in case.py and run/input.py to break circular
import chains that were exposed by the lazy import optimizations in
main.py and args.py.

- case.py: lazy import build in get_inp() and get_fpp()
- run/input.py: lazy import build in generate_inp(), validate_constraints(),
  and clean()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Pass --help through to Python for bash-handled commands (clean, lint,
  format, load, spelling) so enhanced help is shown
- Add missing commands to COMMANDS dict in user_guide.py:
  bench, completion, lint, format, spelling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use argparse's built-in aliases= parameter instead of separate parsers
for command aliases (b, r, t, v, c). This ensures aliases inherit all
arguments from their parent commands.

Previously, ./mfc.sh t would fail because the 't' parser didn't have
test-specific arguments like --rdma-mpi.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Parse ninja's [X/Y] output to show compile progress
- Display progress bar with: file count, percentage, current file, elapsed time
- Falls back to spinner with elapsed time for non-TTY environments
- Shows "(build took Xs)" for builds longer than 5 seconds

In interactive terminals, users now see:
  Building simulation [████████░░░░] 42/156 • 0:02:34 m_rhs.fpp.f90

In non-interactive mode:
  Building simulation...
  (build took 234.5s)
  ✓ Built simulation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The 'init' command was originally used to bootstrap the Python environment
without running any command. This restores that behavior and renames the
case template creation to 'new':

- ./mfc.sh init     -> Just bootstrap venv/environment, then exit
- ./mfc.sh new      -> Create a new case from a template

Updated files:
- mfc.sh: Restore original init behavior (exit after python.sh)
- args.py: Rename init parser to new
- main.py: Handle 'new' command instead of 'init'
- user_guide.py: Update all references from init to new
- init.py: Update usage messages to use 'new'

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When --verbose is used, bypass the progress bar and show raw cmake/compiler
output. This applies to both configure and build steps.

Previously, verbose mode would still capture all output in the progress bar,
making the --verbose flag ineffective.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace black with autopep8 due to Python 3.12.5 memory safety issues
- Fix bash completion to allow file path navigation after commands
- Fix format.sh to accept custom path arguments
- Fix pylint errors in build.py and main.py
- Reformat all Python files with autopep8 for CI consistency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement a declarative CLI schema that eliminates the need to manually
update 8+ files when adding commands or options:

- Add cli/schema.py with dataclass definitions for CLI structure
- Add cli/commands.py as SINGLE SOURCE OF TRUTH for all commands
- Add cli/argparse_gen.py to generate argparse parsers from schema
- Add cli/completion_gen.py to generate bash/zsh completions
- Add generate.py and ./mfc.sh generate command

Modified files to use the schema:
- args.py: Now uses generated parser from CLI schema
- user_guide.py: Imports COMMANDS from cli/commands.py
- Completion scripts are now auto-generated, not hand-edited

Adding a new command now requires editing only cli/commands.py,
then running ./mfc.sh generate to update completion scripts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract helper functions to reduce complexity in completion_gen.py and
argparse_gen.py. Add pylint disable for dataclasses that legitimately
need many attributes. Code now scores 10.00/10 on pylint.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cli/docs_gen.py to generate CLI reference markdown from schema
- Update generate.py to also produce docs/cli-reference.md
- Add generate --check step to lint-toolchain CI workflow
- Generated documentation includes quick reference table, all commands
  with options, examples, and common options section

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This adds toolchain/mfc/params_tests/ with tools to capture and verify
validation behavior before refactoring case_validator.py:

- inventory.py: Export all 3300 parameters with types and stages
- snapshot.py: Capture validation results from 134 example cases
- coverage.py: Analyze 306 constraints across 56 check methods
- runner.py: CLI for build/verify/summary commands

Run `python -m mfc.params_tests.runner build` to capture baseline,
then `python -m mfc.params_tests.runner verify` after changes to
detect any unintended changes to validation behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extends the safety net with two new testing approaches:

1. negative_tests.py - Hand-crafted test cases that intentionally
   violate constraints (20 tests, 100% trigger rate)

2. mutation_tests.py - Automatically mutates valid example cases
   to test validator coverage (830 mutations, 82.8% catch rate)

Mutation testing found real validator gaps:
- t_step_save: No validation for 0 or negative values
- mpp_lim/cyl_coord: Invalid strings like "X" not caught
- x_domain%beg/end: Missing value not validated

Run with:
  python -m mfc.params_tests.runner negative
  python -m mfc.params_tests.runner mutation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mutation testing found several gaps where the validator allowed
invalid parameter values. This commit fixes them:

1. Add check_parameter_types() - validates Fortran logicals are 'T'/'F'
   - mpp_lim, cyl_coord, bubbles_euler, etc. now reject 'X', 'yes', etc.

2. Add x_domain validation - x_domain%beg/end required when m > 0

3. Fix t_step_save - now validates t_step_save > 0

4. Fix dt validation - now validates dt > 0 in all modes where dt is set

5. Improve time stepping validation - properly handles cfl_dt, cfl_adap_dt,
   and adap_dt modes

Mutation test results improved from 82.8% to 99.9% catch rate.
All 134 example cases still pass validation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement a central parameter registry that serves as the single source
of truth for MFC's ~3,300 case parameters. This eliminates manual
synchronization between case_dicts.py, case_validator.py, and documentation.

Key changes:
- Create mfc/params/ package with schema definitions and registry
- Refactor case_dicts.py from ~680 lines to ~115 lines (uses registry)
- Add parameter definitions organized by domain (core, weno, patches, etc.)
- Add code generators for case_dicts, validator, and documentation
- Add physics validation for patches, acoustics, and bubbles

The registry provides:
- ParamDef dataclass for parameter metadata (name, type, stages, description)
- ConstraintRule dataclass for validation constraints (26 defined)
- Generators that produce case_dicts-compatible output
- Documentation generator (~194K chars of markdown)
- Comparison tool to verify registry matches original

All tests pass:
- Safety net: 134/134 cases unchanged
- Mutation tests: 99.9% catch rate
- JSON schema validation: working

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 1, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Feb 1, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 1, 2026

CodeAnt AI Incremental review completed.

sbryngelson and others added 2 commits January 31, 2026 23:25
The % character is special in Doxygen. Using %% renders as a literal %.
This fixes parameter names like bc_y%alpha_in showing as bc_yalpha_in.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of listing every combination like (1,1), (1,2), (2,1), etc.,
the docs now show a single pattern like (N, M).

Before: 78 rows for simplex_params (showing every index combination)
After: 8 rows showing unique patterns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="docs/documentation/parameters.md">

<violation number="1" location="docs/documentation/parameters.md:63">
P2: The documentation now lists parameters with `%%` (e.g., `patch_icpp(N)%%Bx`), which appears to be a typo and misdocuments the actual case file syntax (`%`). This will mislead users copying parameter names.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Previously, small families (<20 params) showed full tables even when
they were indexed. Now we always collapse patterns if it reduces rows.

Example: schlieren_alpha with 10 params now shows 1 pattern row
instead of 10 individual rows.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@toolchain/mfc/params/generators/docs_gen.py`:
- Line 137: The type annotation for the variable families incorrectly uses the
builtin any instead of typing.Any; change the annotation from Dict[str,
List[Tuple[str, any]]] to Dict[str, List[Tuple[str, Any]]] and ensure Any is
imported from typing (add or update the import statement that provides Any) so
the annotation references typing.Any; locate the declaration of families in
docs_gen.py to apply the fix.
- Around line 49-74: The nested block that handles parenthesized numeric indices
inside the while i < len(name) loop should be extracted into a helper function
to reduce nesting and fix R1702; create a function (e.g.,
handle_parenthesized_indices or parse_parenthesized_indices) that takes (name,
start_index, placeholders, placeholder_idx), moves the inner logic that collects
paren_content, validates numeric parts, builds new_parts and returns the
replacement string (like '(?, ?)' or with placeholders), the updated index j+1,
and the updated placeholder_idx; then replace the inlined code in the main loop
with a single call to that helper and append the returned segment to result or
fall back to the original flow when the helper indicates no valid parenthesized
numeric indices.
🧹 Nitpick comments (2)
toolchain/mfc/params/generators/docs_gen.py (2)

15-15: Remove unused noqa directive.

Ruff reports the # noqa: F401 comment is unnecessary since no F401 warning is being suppressed. The import is actually used (for side effects of registering definitions).

🧹 Proposed fix
-from .. import definitions  # noqa: F401  pylint: disable=unused-import
+from .. import definitions  # pylint: disable=unused-import

24-26: Simplify unnecessary any() over single-element list.

The expression any(... for _ in [1]) iterates over a single element, making any() pointless. This looks like a refactoring leftover.

🧹 Proposed fix
-        if any(name.startswith(f"{base}(") or name.startswith(f"{base}%") for _ in [1]):
+        if name.startswith(f"{base}(") or name.startswith(f"{base}%"):
             return base

- Change `any` to `Any` from typing module
- Extract _parse_paren_content helper to reduce nesting in _collapse_indices
- Fixes R1702 pylint warning (too many nested blocks)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@docs/documentation/parameters.md`:
- Around line 165-180: Several fluid_pp parameters (`fluid_pp(N)%%D_v`, `%%M_v`,
`%%cp_v`, `%%gamma_v`, `%%gamma_v`, `%%k_v`, `%%mu_v`, `%%mul0`, `%%pv`, `%%ss`)
and general-family params (`Ca`, `Re_inv`, `Web`) are missing human-readable
descriptions in the parameter registry; open the parameter descriptions registry
(toolchain/mfc/params/descriptions.py) and add concise, validated descriptions
and units for each symbol (e.g., D_v = vapor diffusivity [m^2/s], M_v = vapor
molecular weight [kg/mol], cp_v = vapor specific heat at constant pressure
[J/(kg·K)], gamma_v = vapor heat capacity ratio, k_v = vapor thermal
conductivity [W/(m·K)], mu_v = vapor dynamic viscosity [Pa·s], mul0 = reference
viscosity, pv = vapor pressure, ss = surface tension source/flag or clarify
exact meaning, Ca = Capillary number, Re_inv = inverse Reynolds number, Web =
Weber number), verifying physical meanings against source physics before
committing so the generated docs populate correctly.

In `@toolchain/mfc/params/generators/docs_gen.py`:
- Around line 233-242: The description text returned by get_description(example)
isn't escaped for percent signs before being appended to lines, so call the
existing _escape_percent on the (possibly truncated) desc variable before using
it in lines.append to prevent Doxygen format tokens; update the block that
builds the table row (the loop iterating over patterns/examples that sets desc,
truncates it, and appends to lines) to replace desc with _escape_percent(desc)
and apply the identical change to the other similar block later in the file that
builds example rows (the second block that handles examples/patterns around the
same codepath).
- Line 15: Remove the unused "noqa: F401" directive on the import statement in
docs_gen.py: keep the intentional side-effect import "from .. import
definitions" and retain the "pylint: disable=unused-import" comment but delete
the "# noqa: F401" portion so Ruff no longer flags an unused noqa; ensure the
line still imports definitions for side effects.

- Add descriptions for dimensionless numbers: Ca (Cavitation number),
  Web (Weber number), Re_inv (Inverse Reynolds number)
- Add descriptions for fluid_pp vapor phase parameters: mul0, ss, pv,
  gamma_v, M_v, mu_v, k_v, cp_v, D_v
- Add detailed descriptions for bub_pp (sub-grid bubble) parameters
  including thermal properties, viscosities, and gas constants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 1, 2026

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Feb 1, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 1, 2026

CodeAnt AI Incremental review completed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@toolchain/mfc/params/descriptions.py`:
- Around line 566-583: The description normalization in get_pattern_description
leaves numeric indices inside parentheses (e.g., "a(2)", "offset (2)")
unchanged; update get_pattern_description to also replace parenthesized example
indices by mapping "(1)"/"(2)"/"(3)" to "(N)"/"(M)"/"(K)" (use the existing
example variable created from pattern_name) — add regex substitutions targeting
"\(1\)/\(2\)/\(3\)" to "\(N\)/\(M\)/\(K\)" (run these alongside the existing
space-separated replacements so both "component 2" and "component(2)" or "offset
(2)" become generic).

sbryngelson and others added 3 commits February 1, 2026 09:21
Normalize (1)/(2)/(3) to (N)/(M)/(K) in get_pattern_description
to prevent example values like "a(2)" from appearing in pattern docs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add specific descriptions for 17 Lagrangian output fields (lag_*_wrt)
- Add specific descriptions for 17 lag_params fields with physics context
- Add specific descriptions for 4 chem_params fields
- All 3,400 parameters now have meaningful descriptions (100% coverage)

Descriptions derived from Fortran source comments in m_derived_types.fpp.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@docs/documentation/parameters.md`:
- Around line 61-70: The table entries show double-escaped percent signs (e.g.,
"patch_icpp(N)%%Bx", "patch_icpp(1)%%alpha(1)") but the real syntax uses a
single '%' (e.g., "patch_icpp(1)%geometry"); update the doc-generator/template
that produces these parameter patterns to emit a single '%' instead of '%%'
(locate the generation/escaping routine that outputs strings like
"patch_icpp(N)%%Bx" and change the escaping or formatting so '%' is not
doubled), ensure examples (e.g., "patch_icpp(1)%%By", "patch_icpp(1)%%alpha")
are corrected to use a single '%', and add/adjust a unit test or snapshot for
the generator to assert that patterns contain single '%' characters.
🧹 Nitpick comments (1)
toolchain/mfc/params/descriptions.py (1)

517-520: Preserve suffixes if a name ever contains multiple %.

split("%") drops any later segments; split("%", 1) keeps the full suffix and is more robust.

♻️ Suggested change
-        parts = name.split("%")
-        prefix = parts[0]
-        suffix = parts[1]
+        prefix, suffix = name.split("%", 1)

Addresses issues from code review:

Critical fixes:
- Fix import path bug in case_dicts_gen.py (mfc -> ...run)
- Add registry freeze() to prevent post-init mutation
- Validate ParamDef stages is non-empty

Improvements:
- Integrate case_validator.py with registry for LOG params (362 params)
- Add schema validation for CONSTRAINTS/DEPENDENCIES dicts
- Add type system sync verification between params and case_dicts
- Add consistent error message formatting (errors.py)
- Improve error handling in definitions._init_registry()
- Narrow exception handling in snapshot.py and coverage.py

Testing:
- Add 75 unit tests covering registry, definitions, integration
- Add CLI smoke tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Fix all issues with AI agents
In `@toolchain/mfc/cli/test_cli.py`:
- Around line 62-63: The two assertions in test_cli.py that reference cmd.name
use unnecessary f-strings; update the assertion messages in the test (the calls
to self.assertIsNotNone and self.assertTrue that reference cmd.name) to use
plain string literals instead of f-prefixed strings (e.g., change f"Command
missing name" and f"Command has empty name" to "Command missing name" and
"Command has empty name") so there are no needless f-string prefixes.

In `@toolchain/mfc/params_tests/test_definitions.py`:
- Around line 73-78: Add spell-check ignore directives for the intentional typos
used in these tests so the CI spell checker won't fail: update the test function
test_invalid_key_raises and other tests that call _validate_constraint (the
occurrences of "choises", "when_tru", and "requirs") to include the repo's
Spellcheck ignore comment immediately next to those literal typos (and apply the
same fix to the other occurrences noted in the file). Ensure each
intentional-misspelling token has a spell-check exclusion comment so the tests
continue to validate error handling without CI spellcheck failures.
- Around line 111-125: The tests test_invalid_top_level_key_raises and
test_invalid_condition_key_raises use intentional typos ("when_tru" and
"requirs") that trigger spellcheck; add cspell ignore directives so the linter
won't flag them—for example place a single-line comment like "# cspell:ignore
tru requirs" immediately above or on the same lines containing the typos in the
test functions that call _validate_dependency, referencing the exact
misspellings "when_tru" and "requirs".

In `@toolchain/mfc/params_tests/test_validate.py`:
- Around line 93-100: Two tests unpack the tuple returned by validate_case but
don't use one of the values; update the unpacking in the tests (e.g., in the
test that calls validate_case(params) and the test_warn_false_skips_warnings
that calls validate_case(params, warn=False)) to prefix unused variables with an
underscore (use _errors or _warnings) so the linter knows the unused value is
intentional while leaving the used variable name intact.
- Around line 14-16: Remove the unused imports ParamDef, ParamType, and Stage by
deleting the line that imports them from schema; keep the REGISTRY import as-is.
Also remove the trailing " # noqa: F401" from the "from ..params import
definitions  # noqa: F401  Populate registry" line so the file has no unused
noqa directive while still importing definitions to populate the registry.

In `@toolchain/mfc/params/definitions.py`:
- Line 8: Remove the unused typing imports List and Union from the module import
line (currently importing Dict, List, Any, Union) so the statement only imports
the types actually used (Dict and Any); update the import in definitions.py (the
import that names Dict/List/Any/Union) and run tests/lint to ensure no remaining
references to List or Union remain elsewhere in the file.
- Line 472: Update the inline comment that currently reads "# This catches typos
like "choises" instead of "choices"" to correct the misspelling "choises" to
"choices" (or rephrase the comment to avoid demonstrating the typo directly), so
the spell checker no longer flags it; look for that exact comment string in
definitions.py and replace it with the corrected wording while keeping the
explanatory intent.
- Line 27: Update the comment line that currently reads: These validation
functions catch typos like "choises" instead of "choices" to avoid the
spell-check flag; either fix the example by changing "choises" → "choices" or
reword to explicitly label the misspelling (e.g., mention "'choises'
(misspelling of 'choices')") so the intent remains clear but the spell checker
no longer flags the file; target the comment in definitions.py that contains the
example typo.

In `@toolchain/mfc/params/errors.py`:
- Line 22: The import list in this module includes an unused symbol "Union";
remove "Union" from the typing import statement so it reads only the actually
used types (e.g., Any, List, Optional) in the import line at the top of
errors.py to eliminate the unused-import warning.

In `@toolchain/mfc/params/registry.py`:
- Around line 35-37: The class RegistryFrozenError has an unnecessary pass
statement; remove the redundant "pass" from the class body so the docstring
alone defines the empty subclass of RuntimeError (look for the
RegistryFrozenError class in registry.py and delete the pass line).
🧹 Nitpick comments (12)
toolchain/mfc/params_tests/coverage.py (2)

55-60: Return type annotation should include None.

The function can return None (line 60), but the return type is annotated as ast.ClassDef. This should be ast.ClassDef | None for accurate type checking.

Proposed fix
-def _find_case_validator_class(tree: ast.Module) -> ast.ClassDef:
+def _find_case_validator_class(tree: ast.Module) -> ast.ClassDef | None:
     """Find the CaseValidator class in the AST."""

280-290: Fix implicit Optional type annotation.

Per PEP 484 and the static analysis hint (Ruff RUF013), the parameter type should explicitly include None. Additionally, the return type annotation is missing.

Proposed fix
-def save_coverage_report(output_path: Path = None):
+def save_coverage_report(output_path: Path | None = None) -> Path:
     """Save coverage report to JSON file."""
toolchain/mfc/cli/test_cli.py (1)

92-95: Narrow the exception type in format_help() test.

Catching a broad Exception masks potential programming errors. Since format_help() typically raises argparse errors, consider a narrower catch or use self.fail() only for expected failure scenarios.

♻️ Proposed fix
         # Parser should not raise error when printing help
-        try:
-            parser.format_help()
-        except Exception as e:
-            self.fail(f"Parser help failed: {e}")
+        # This should not raise - if it does, the test framework will catch it
+        help_text = parser.format_help()
+        self.assertIsInstance(help_text, str)
toolchain/mfc/params_tests/snapshot.py (2)

135-135: Use explicit Optional type hint.

PEP 484 recommends explicit Optional[Path] instead of Path = None.

♻️ Proposed fix
-def capture_all_examples(examples_dir: Path = None) -> Dict[str, CaseSnapshot]:
+def capture_all_examples(examples_dir: Optional[Path] = None) -> Dict[str, CaseSnapshot]:

Add Optional to the imports at line 12:

-from typing import Dict, Any, List, Optional
+from typing import Dict, Any, List, Optional

(Already imported, just need to use it in the signature)


186-186: Use explicit Optional type hint for consistency.

♻️ Proposed fix
-def save_snapshots(snapshots: Dict[str, CaseSnapshot], output_path: Path = None):
+def save_snapshots(snapshots: Dict[str, CaseSnapshot], output_path: Optional[Path] = None):
toolchain/mfc/params_tests/test_registry.py (1)

121-128: Avoid redefining RegistryFrozenError from outer scope.

The import at line 123 redefines RegistryFrozenError which is already imported at line 8. While this works, it's cleaner to use the already-imported name.

♻️ Proposed fix
     def test_global_registry_cannot_be_modified(self):
         """Global REGISTRY should reject new registrations."""
-        from ..params import REGISTRY, RegistryFrozenError
+        from ..params import REGISTRY

         with self.assertRaises(RegistryFrozenError):
             REGISTRY.register(
                 ParamDef(name="injected", param_type=ParamType.INT, stages={Stage.COMMON})
             )
toolchain/mfc/params/__init__.py (2)

27-27: Remove unused noqa directive.

The noqa: F401 directive appears to be unnecessary. If the linter is configured to ignore unused imports in __init__.py files, this can be removed.

♻️ Proposed fix
-from . import definitions  # noqa: F401  pylint: disable=unused-import
+from . import definitions  # pylint: disable=unused-import

29-29: Consider sorting __all__ alphabetically.

Sorting helps with readability and reduces merge conflicts.

♻️ Proposed fix
-__all__ = ['REGISTRY', 'RegistryFrozenError', 'ParamDef', 'ParamType', 'Stage']
+__all__ = ['ParamDef', 'ParamType', 'REGISTRY', 'RegistryFrozenError', 'Stage']
toolchain/mfc/params/definitions.py (1)

481-486: Consider narrowing exception handling for initialization.

The broad Exception catch could mask unexpected errors. Consider catching more specific exceptions that could reasonably occur during initialization.

♻️ Proposed fix
-    except Exception as e:
+    except (ValueError, TypeError, KeyError) as e:
         # Re-raise with context to help debugging initialization failures
         raise RuntimeError(
             f"Failed to initialize parameter registry: {e}\n"
             "This is likely a bug in the parameter definitions."
         ) from e

This is optional since the current implementation does preserve the original exception via from e, making debugging still possible.

toolchain/mfc/params/generators/case_dicts_gen.py (1)

94-94: Remove unused noqa directive.

The # noqa: F401 directive is flagged as unused by the linter.

🧹 Proposed fix
-    from .. import definitions  # noqa: F401  pylint: disable=unused-import
+    from .. import definitions  # pylint: disable=unused-import
toolchain/mfc/params/registry.py (1)

56-61: Consider using Optional for the type hint.

The _params_proxy is initialized to None but typed as Mapping[str, ParamDef]. Using Optional would be more precise.

🔧 Proposed fix
+from typing import Dict, Set, Mapping, Optional
-from typing import Dict, Set, Mapping

     def __init__(self):
         """Initialize an empty registry."""
         self._params: Dict[str, ParamDef] = {}
         self._by_stage: Dict[Stage, Set[str]] = defaultdict(set)
         self._frozen: bool = False
-        self._params_proxy: Mapping[str, ParamDef] = None
+        self._params_proxy: Optional[Mapping[str, ParamDef]] = None
toolchain/mfc/params/validate.py (1)

40-40: Remove unused noqa directive.

The # noqa: F401 directive is flagged as unused by the linter.

🧹 Proposed fix
-from . import definitions  # noqa: F401  pylint: disable=unused-import
+from . import definitions  # pylint: disable=unused-import

Comment on lines +62 to +63
self.assertIsNotNone(cmd.name, f"Command missing name")
self.assertTrue(len(cmd.name) > 0, f"Command has empty name")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove extraneous f prefix from strings without placeholders.

These f-strings have no placeholders, making the f prefix unnecessary.

🔧 Proposed fix
-            self.assertIsNotNone(cmd.name, f"Command missing name")
-            self.assertTrue(len(cmd.name) > 0, f"Command has empty name")
+            self.assertIsNotNone(cmd.name, "Command missing name")
+            self.assertTrue(len(cmd.name) > 0, "Command has empty name")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.assertIsNotNone(cmd.name, f"Command missing name")
self.assertTrue(len(cmd.name) > 0, f"Command has empty name")
self.assertIsNotNone(cmd.name, "Command missing name")
self.assertTrue(len(cmd.name) > 0, "Command has empty name")
🧰 Tools
🪛 Ruff (0.14.14)

[error] 62-62: f-string without any placeholders

Remove extraneous f prefix

(F541)


[error] 63-63: f-string without any placeholders

Remove extraneous f prefix

(F541)

🤖 Prompt for AI Agents
In `@toolchain/mfc/cli/test_cli.py` around lines 62 - 63, The two assertions in
test_cli.py that reference cmd.name use unnecessary f-strings; update the
assertion messages in the test (the calls to self.assertIsNotNone and
self.assertTrue that reference cmd.name) to use plain string literals instead of
f-prefixed strings (e.g., change f"Command missing name" and f"Command has empty
name" to "Command missing name" and "Command has empty name") so there are no
needless f-string prefixes.

Comment on lines 73 to 78
def test_invalid_key_raises(self):
"""Invalid constraint key should raise ValueError."""
with self.assertRaises(ValueError) as ctx:
_validate_constraint("test", {"choises": [1, 2]}) # Typo

self.assertIn("choises", str(ctx.exception))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add spell-check exceptions for intentional typos in tests.

The pipeline spell checker is flagging the intentional typos (choises, when_tru, requirs) used to test error handling. Add spell-check ignore directives to prevent CI failures.

🔧 Proposed fix
     def test_invalid_key_raises(self):
         """Invalid constraint key should raise ValueError."""
         with self.assertRaises(ValueError) as ctx:
-            _validate_constraint("test", {"choises": [1, 2]})  # Typo
+            _validate_constraint("test", {"choises": [1, 2]})  # Typo  # cspell:ignore choises

-        self.assertIn("choises", str(ctx.exception))
+        self.assertIn("choises", str(ctx.exception))  # cspell:ignore choises

Apply similar fixes to lines 114, 116, 122, and 125 for tru and requirs.

🧰 Tools
🪛 GitHub Actions: Spell Check

[error] 76-76: choises should be choices, chooses


[error] 78-78: choises should be choices, chooses

🤖 Prompt for AI Agents
In `@toolchain/mfc/params_tests/test_definitions.py` around lines 73 - 78, Add
spell-check ignore directives for the intentional typos used in these tests so
the CI spell checker won't fail: update the test function
test_invalid_key_raises and other tests that call _validate_constraint (the
occurrences of "choises", "when_tru", and "requirs") to include the repo's
Spellcheck ignore comment immediately next to those literal typos (and apply the
same fix to the other occurrences noted in the file). Ensure each
intentional-misspelling token has a spell-check exclusion comment so the tests
continue to validate error handling without CI spellcheck failures.

Comment on lines 111 to 125
def test_invalid_top_level_key_raises(self):
"""Invalid top-level dependency key should raise."""
with self.assertRaises(ValueError) as ctx:
_validate_dependency("test", {"when_tru": {"requires": []}}) # Typo

self.assertIn("when_tru", str(ctx.exception))

def test_invalid_condition_key_raises(self):
"""Invalid condition key should raise."""
with self.assertRaises(ValueError) as ctx:
_validate_dependency("test", {
"when_true": {"requirs": ["foo"]} # Typo
})

self.assertIn("requirs", str(ctx.exception))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Same spell-check issue for dependency validation tests.

Add # cspell:ignore directives for tru and requirs.

🔧 Proposed fix
     def test_invalid_top_level_key_raises(self):
         """Invalid top-level dependency key should raise."""
         with self.assertRaises(ValueError) as ctx:
-            _validate_dependency("test", {"when_tru": {"requires": []}})  # Typo
+            _validate_dependency("test", {"when_tru": {"requires": []}})  # Typo  # cspell:ignore tru

-        self.assertIn("when_tru", str(ctx.exception))
+        self.assertIn("when_tru", str(ctx.exception))  # cspell:ignore tru

     def test_invalid_condition_key_raises(self):
         """Invalid condition key should raise."""
         with self.assertRaises(ValueError) as ctx:
             _validate_dependency("test", {
-                "when_true": {"requirs": ["foo"]}  # Typo
+                "when_true": {"requirs": ["foo"]}  # Typo  # cspell:ignore requirs
             })

-        self.assertIn("requirs", str(ctx.exception))
+        self.assertIn("requirs", str(ctx.exception))  # cspell:ignore requirs
🧰 Tools
🪛 GitHub Actions: Spell Check

[error] 114-114: tru should be thru, true


[error] 116-116: tru should be thru, true


[error] 122-122: requirs should be requires


[error] 125-125: requirs should be requires

🤖 Prompt for AI Agents
In `@toolchain/mfc/params_tests/test_definitions.py` around lines 111 - 125, The
tests test_invalid_top_level_key_raises and test_invalid_condition_key_raises
use intentional typos ("when_tru" and "requirs") that trigger spellcheck; add
cspell ignore directives so the linter won't flag them—for example place a
single-line comment like "# cspell:ignore tru requirs" immediately above or on
the same lines containing the typos in the test functions that call
_validate_dependency, referencing the exact misspellings "when_tru" and
"requirs".

# ============================================================================
# Schema Validation for Constraints and Dependencies
# ============================================================================
# These validation functions catch typos like "choises" instead of "choices"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo: "choises" → "choices".

The spell check flagged this typo in the comment.

🔧 Proposed fix
-# These validation functions catch typos like "choises" instead of "choices"
+# These validation functions catch typos like "choises" instead of "choices"

Wait, looking more carefully - the comment is intentionally showing "choises" as an example of a typo that would be caught. However, the spell checker still flags it. Consider rewording:

-# These validation functions catch typos like "choises" instead of "choices"
+# These validation functions catch typos (e.g., misspelled constraint keys)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# These validation functions catch typos like "choises" instead of "choices"
# These validation functions catch typos (e.g., misspelled constraint keys)
🧰 Tools
🪛 GitHub Actions: Spell Check

[error] 27-27: choises should be choices, chooses

🤖 Prompt for AI Agents
In `@toolchain/mfc/params/definitions.py` at line 27, Update the comment line that
currently reads: These validation functions catch typos like "choises" instead
of "choices" to avoid the spell-check flag; either fix the example by changing
"choises" → "choices" or reword to explicitly label the misspelling (e.g.,
mention "'choises' (misspelling of 'choices')") so the intent remains clear but
the spell checker no longer flags the file; target the comment in definitions.py
that contains the example typo.

sbryngelson and others added 3 commits February 1, 2026 11:03
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces manual typo entries with automatic fuzzy matching against MFC-recognized
parameter names, constraint keys, and dependency keys.

Changes:
- Add rapidfuzz dependency to pyproject.toml
- Create suggest.py with fuzzy matching utilities using rapidfuzz
- Update definitions.py to use suggest.py for constraint/dependency validation
- Add unknown_param_error() to errors.py for consistent error formatting
- Add check_unknown_params() to validate.py for unknown parameter detection
- Update validate_case() with check_unknown parameter
- Add comprehensive tests for 'did you mean?' functionality
- Update .typos.toml with intentional test typo values

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@toolchain/mfc/cli/test_cli.py`:
- Around line 93-96: Remove the broad try/except around parser.format_help in
the test and instead assert its return value or simply call it so any exception
will fail the test; update the test method (the block containing
parser.format_help) to either use an assert on the returned help string (e.g.,
assert parser.format_help() is not None or assert
isinstance(parser.format_help(), str)) or just call parser.format_help() without
catching Exception to eliminate the Ruff BLE001 warning and preserve failure
behavior.

In `@toolchain/mfc/params/suggest.py`:
- Around line 84-91: The code in the suggestions formatter uses an unnecessary
else after a return (the block that starts with "else:" after checking
len(suggestions) == 1); remove that else and de-indent its body so the branch
that builds quoted = [f"'{s}'" for s in suggestions] and returns the "Did you
mean one of..." string executes directly after the return, keeping the early
return for the single-suggestion case; update the block surrounding the variable
suggestions and the conditional that returns f"Did you mean '{suggestions[0]}'?"
accordingly.

In `@toolchain/mfc/params/validate.py`:
- Line 42: The import line "from . import definitions" in validate.py currently
has an unnecessary "noqa: F401" directive; remove the "noqa: F401" while keeping
the existing "pylint: disable=unused-import" comment so the unused-import
suppression remains, i.e., update the import statement that references
definitions to drop only the "noqa: F401" token.
🧹 Nitpick comments (5)
toolchain/mfc/params_tests/test_registry.py (1)

117-120: Consider extracting the parameter count threshold.

The hardcoded 3000 works for now but could become brittle if the parameter count changes significantly. Consider using a named constant or a more flexible assertion (e.g., assertGreater(..., 1000) as a sanity check).

toolchain/mfc/params/suggest.py (1)

94-106: Import inside function is acceptable here.

The pipeline flags import-outside-toplevel at line 104, but this is a deliberate pattern to avoid circular imports between suggest.py and registry.py. Consider adding a brief comment explaining this if not already obvious from context.

toolchain/mfc/params/definitions.py (2)

36-36: Import inside function is intentional (pipeline warning).

The pipeline flags import-outside-toplevel at lines 36 and 61. This is a deliberate pattern to avoid circular imports between definitions.py and suggest.py. The pattern is acceptable given the module structure.

Also applies to: 61-61


302-303: Complex ternary reduces readability.

This line combines multiple conditions in a single expression, making it difficult to parse:

_r(n, LOG if "wrt" in n or n in ["alt_soundspeed", "mixture_err"] else (INT if n == "fd_order" else REAL), {POST})

Consider splitting into explicit conditionals for clarity.

♻️ Proposed refactor
-    for n in ["prim_vars_wrt", "alt_soundspeed", "mixture_err", "t_stop", "t_save", "fd_order"]:
-        _r(n, LOG if "wrt" in n or n in ["alt_soundspeed", "mixture_err"] else (INT if n == "fd_order" else REAL), {POST})
+    # POST_PROCESS params with mixed types
+    for n in ["prim_vars_wrt", "alt_soundspeed", "mixture_err"]:
+        _r(n, LOG, {POST})
+    for n in ["t_stop", "t_save"]:
+        _r(n, REAL, {POST})
+    _r("fd_order", INT, {POST})
toolchain/mfc/params/errors.py (1)

137-153: Minor grammar issue when only one conflicting parameter.

When active contains a single element, the message "are all enabled" is grammatically awkward (e.g., "'b' are all enabled"). Consider handling singular vs plural.

✏️ Proposed fix for grammar
 def mutual_exclusion_error(params: List[str], active: List[str]) -> str:
     """
     Create a mutual exclusion error message.

     Args:
         params: List of mutually exclusive parameters
         active: List of parameters that are currently active (conflicting)

     Returns:
         Formatted error message.
     """
     formatted = [format_param(p) for p in params]
     active_formatted = [format_param(p) for p in active]
-    return (
-        f"Only one of {', '.join(formatted)} can be enabled, "
-        f"but {', '.join(active_formatted)} are all enabled"
-    )
+    verb = "is" if len(active) == 1 else "are"
+    return (
+        f"Only one of {', '.join(formatted)} can be enabled, "
+        f"but {', '.join(active_formatted)} {verb} enabled"
+    )

Comment on lines +93 to +96
try:
parser.format_help()
except Exception as e:
self.fail(f"Parser help failed: {e}")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid catching Exception in tests; assert on the return instead.

parser.format_help() already raises if broken; the try/except adds a Ruff BLE001 warning.

Proposed fix
-        try:
-            parser.format_help()
-        except Exception as e:
-            self.fail(f"Parser help failed: {e}")
+        self.assertIsInstance(parser.format_help(), str)
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 95-95: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
In `@toolchain/mfc/cli/test_cli.py` around lines 93 - 96, Remove the broad
try/except around parser.format_help in the test and instead assert its return
value or simply call it so any exception will fail the test; update the test
method (the block containing parser.format_help) to either use an assert on the
returned help string (e.g., assert parser.format_help() is not None or assert
isinstance(parser.format_help(), str)) or just call parser.format_help() without
catching Exception to eliminate the Ruff BLE001 warning and preserve failure
behavior.

# Note: definitions is imported by params/__init__.py to populate REGISTRY.
# This redundant import ensures REGISTRY is populated even if this module
# is imported directly (e.g., during testing).
from . import definitions # noqa: F401 pylint: disable=unused-import
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused noqa directive (static analysis hint).

Ruff flags the noqa: F401 as unused since F401 isn't enabled in its configuration. The pylint: disable=unused-import comment is sufficient.

🧹 Proposed fix
-from . import definitions  # noqa: F401  pylint: disable=unused-import
+from . import definitions  # pylint: disable=unused-import
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from . import definitions # noqa: F401 pylint: disable=unused-import
from . import definitions # pylint: disable=unused-import
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 42-42: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In `@toolchain/mfc/params/validate.py` at line 42, The import line "from . import
definitions" in validate.py currently has an unnecessary "noqa: F401" directive;
remove the "noqa: F401" while keeping the existing "pylint:
disable=unused-import" comment so the unused-import suppression remains, i.e.,
update the import statement that references definitions to drop only the "noqa:
F401" token.

sbryngelson and others added 2 commits February 1, 2026 11:27
- Remove unnecessary else after return in format_suggestion()
- Add pylint disable comments for intentional import-outside-toplevel
  (needed to avoid circular imports at module load time)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test uses 'when_tru' as an intentional typo to test dependency
key validation with 'did you mean?' suggestions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 4/5 size:XXL This PR changes 1000+ lines, ignoring generated files

Development

Successfully merging this pull request may close these issues.

1 participant