Skip to content

Conversation

@sbryngelson
Copy link
Member

@sbryngelson sbryngelson commented Dec 1, 2025

User description

User description

Put constraints in the docs


PR Type

Enhancement, Documentation


Description

  • Generate comprehensive case constraints documentation from validator rules

    • Parses case_validator.py AST to extract all prohibit() constraints
    • Maps constraints to parameters, stages, and generates Markdown tables
  • Create curated case design playbook with working examples

    • Validates 9 hero examples from examples/ directory
    • Renders detailed physics/numerics configuration cards with metadata
  • Integrate constraints doc into build pipeline

    • Add CMake custom command to auto-generate case_constraints.md
    • Update GitHub Actions workflow to upload built documentation
  • Enhance case documentation with compatibility guide link

    • Add reference section in case.md pointing to constraints guide

Diagram Walkthrough

flowchart LR
  A["case_validator.py"] -->|AST parse| B["gen_case_constraints_docs.py"]
  C["examples/"] -->|load params| B
  B -->|render Markdown| D["case_constraints.md"]
  D -->|referenced by| E["case.md"]
  F["CMakeLists.txt"] -->|custom command| D
  G["docs.yml"] -->|upload artifact| H["Built docs"]
Loading

File Walkthrough

Relevant files
Enhancement
gen_case_constraints_docs.py
Constraint documentation generator with playbook                 

toolchain/mfc/gen_case_constraints_docs.py

  • New 947-line Python script that parses case_validator.py using AST
    analysis
  • Extracts all self.prohibit() constraint rules and maps them to
    parameters/stages
  • Generates human-readable Markdown documentation with compatibility
    tables
  • Implements case playbook generation from 9 curated working examples
    with metadata
  • Includes helper functions for message classification, feature
    metadata, and Markdown rendering
+947/-0 
Configuration changes
gen_constraints.sh
Build script for constraint documentation                               

docs/gen_constraints.sh

  • New bash script wrapper that invokes the Python generator
  • Takes repo root as argument and outputs to
    docs/documentation/case_constraints.md
  • Used by CMake build system to auto-generate documentation
+17/-0   
docs.yml
Upload documentation artifacts in CI                                         

.github/workflows/docs.yml

  • Add artifact upload step after documentation build
  • Uploads built documentation to mfc-docs artifact with 7-day retention
  • Enables CI/CD pipeline to preserve generated documentation
+8/-0     
CMakeLists.txt
Integrate constraint doc generation into build                     

CMakeLists.txt

  • Add custom command to generate case_constraints.md from validator and
    examples
  • Depends on gen_case_constraints_docs.py, case_validator.py, and
    example files
  • Integrate constraints doc as dependency for documentation target
  • Ensures constraints guide is built alongside main documentation
+15/-0   
Doxyfile.in
Add custom CSS stylesheet reference                                           

docs/Doxyfile.in

  • Add reference to custom-dark-fixes.css in HTML_EXTRA_STYLESHEET
  • Applies additional CSS styling to generated HTML documentation
+2/-1     
Documentation
case.md
Link to feature compatibility guide                                           

docs/documentation/case.md

  • Add new "Feature Compatibility" section after Parameters heading
  • Link to case_constraints.md guide for feature compatibility
    information
  • Provide context about what users will find in the constraints guide
  • Include tip about validation error troubleshooting
+9/-0     

Summary by CodeRabbit

  • Documentation
    • Expanded case documentation with feature compatibility guidance, including parameter validation requirements, solver options, model details, and design playbook examples to help users configure parameters correctly.
    • Automated case constraints documentation generation ensures validation rules remain synchronized and accurate with the system.

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


CodeAnt-AI Description

Add an auto-generated feature compatibility guide and example-based case playbook

What Changed

  • Introduced an auto-generated Feature Compatibility Guide that explains which case features can be combined, common configuration patterns, and key parameter requirements, published as case_constraints.md
  • Added a curated Case Design Playbook built from working example cases, each with summarized physics and numerics settings to use as copy-and-adapt templates
  • Wired the documentation build to always regenerate the compatibility guide, linked it from the main case documentation for easier troubleshooting of validation errors, and exposed the built docs as a downloadable artifact in the docs CI workflow

Impact

✅ Clearer feature compatibility guidance for case setup
✅ Quicker resolution of case validation and configuration errors
✅ Easier reuse of proven example configurations from the docs

💡 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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The changes introduce a case constraints documentation generation system that parses the CaseValidator to extract validation rules, infers execution stages, and generates formatted Markdown documentation. A new Python script analyzes the validator AST, a shell script orchestrates generation, and build system integration ensures the documentation is built and uploaded as an artifact.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow
.github/workflows/docs.yml
Added "Upload Built Documentation Artifact" step to upload generated documentation from build/install/docs/mfc as mfc-docs artifact with 7-day retention.
Build System Integration
CMakeLists.txt, docs/gen_constraints.sh
Added custom CMake command to generate case constraints documentation via shell script; integrated new opt_constraints_dependency into Doxygen documentation pipeline.
Documentation Content
docs/documentation/case.md, .gitignore
Added "Feature Compatibility" subsection to case parameters documentation; added docs/documentation/case_constraints.md to .gitignore.
Case Constraints Generator
toolchain/mfc/gen_case_constraints_docs.py
New Python script that extracts validation rules from CaseValidator via AST analysis, infers execution stages, classifies messages, and generates Markdown documentation with case design playbook from curated examples.

Sequence Diagram(s)

sequenceDiagram
    participant Build as Build System<br/>(CMake)
    participant Script as gen_constraints.sh
    participant Analyzer as gen_case_constraints_docs.py
    participant Validator as case_validator.py
    participant Examples as examples/
    participant Output as case_constraints.md

    Build->>Script: Execute with repo_root
    Script->>Analyzer: Run Python script
    
    Analyzer->>Validator: Parse AST to extract<br/>validator methods & rules
    Analyzer->>Analyzer: Build call graph<br/>from methods
    Analyzer->>Analyzer: Compute stage inference<br/>via DFS from ROOT roots
    Analyzer->>Analyzer: Classify rule messages<br/>(requirement/incompatibility/range/other)
    
    Analyzer->>Examples: Validate playbook<br/>example existence
    Analyzer->>Examples: Load case parameters<br/>from each example
    Analyzer->>Analyzer: Generate playbook cards<br/>with feature summaries
    
    Analyzer->>Analyzer: Render markdown with<br/>compatibility matrix,<br/>rules, playbook
    Analyzer->>Output: Write Markdown
    Script->>Script: Print success message
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Primary complexity area: toolchain/mfc/gen_case_constraints_docs.py contains substantial AST analysis, call-graph traversal, and multi-stage rendering logic that requires careful review for correctness of rule extraction and stage inference.
  • Build system integration: CMakeLists.txt changes introduce a new dependency chain; verify the command registration, file outputs, and integration with Doxygen pipeline are correct.
  • Example validation: The playbook validation logic that checks all curated examples exist and loads case parameters needs verification for robustness and error handling.

Poem

🐰 Hark, a script to parse constraints with care,
Rules extracted from validators fair!
Stages inferred, messages classified true,
Playbooks crafted, docs fresh and new. 🎨📚
From AST's nodes to Markdown so bright,
Documentation now polished and right!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ⚠️ Warning PR description is incomplete and missing several required sections from the template, including testing details, checklist items, and scope confirmation. Add missing sections: 'How Has This Been Tested?' with test descriptions and configuration details, complete the 'Checklist' with relevant items marked, and confirm scope alignment. Include issue reference if applicable.
Title check ❓ Inconclusive The title "Constraints" is vague and generic, using a single word that doesn't clearly convey the specific changes made (auto-generating documentation, build integration, playbook generation). Use a more descriptive title like "Auto-generate case constraints documentation with playbook" or "Add constraints documentation generation and CI integration."
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sbryngelson sbryngelson marked this pull request as ready for review December 1, 2025 04:50
Copilot AI review requested due to automatic review settings December 1, 2025 04:50
@qodo-code-review
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 Security concerns

Command execution:
Running example cases via subprocess executes arbitrary Python from the repo. If untrusted contributions can modify examples, this may execute unsafe code during docs build (CI). Consider sandboxing, a whitelist, or a flag to disable execution in untrusted contexts.

⚡ Recommended focus areas for review

Possible Issue

Stage inference and parameter extraction rely on exact method/root names and simple self.get() patterns; rules in lambdas, nested functions, or non-standard accessors may be missed, yielding incomplete/incorrect docs.

        self.local_param_stack.pop()
        self.current_method = None

    def _build_local_param_map(self, func: ast.FunctionDef) -> Dict[str, str]:  # pylint: disable=too-many-nested-blocks
        """
        Look for assignments like:
            igr = self.get('igr', 'F') == 'T'
            model_eqns = self.get('model_eqns')
        and record local_name -> 'param_name'.
        """
        m: Dict[str, str] = {}
        for stmt in func.body:  # pylint: disable=too-many-nested-blocks
            if isinstance(stmt, ast.Assign):
                # Handle both direct calls and comparisons
                value = stmt.value
                # Unwrap comparisons like "self.get('igr', 'F') == 'T'"
                if isinstance(value, ast.Compare):
                    value = value.left

                if isinstance(value, ast.Call):
                    call = value
                    if (  # pylint: disable=too-many-boolean-expressions
                        isinstance(call.func, ast.Attribute)
                        and isinstance(call.func.value, ast.Name)
                        and call.func.value.id == "self"
                        and call.func.attr == "get"
                        and call.args
                        and isinstance(call.args[0], ast.Constant)
                        and isinstance(call.args[0].value, str)
                    ):
                        param_name = call.args[0].value
                        for target in stmt.targets:
                            if isinstance(target, ast.Name):
                                m[target.id] = param_name
        return m

    # --- visit calls to build call graph + rules ---

    def visit_Call(self, node: ast.Call):
        # record method call edges: self.some_method(...)
        if (
            isinstance(node.func, ast.Attribute)
            and isinstance(node.func.value, ast.Name)
            and node.func.value.id == "self"
            and isinstance(node.func.attr, str)
        ):
            callee = node.func.attr
            if self.current_method is not None:
                # method call on self
                self.call_graph[self.current_method].add(callee)

        # detect self.prohibit(<condition>, "<message>")
        if (
            isinstance(node.func, ast.Attribute)
            and isinstance(node.func.value, ast.Name)
            and node.func.value.id == "self"
            and node.func.attr == "prohibit"
            and len(node.args) >= 2
        ):
            condition, msg_node = node.args[0], node.args[1]
            if isinstance(msg_node, ast.Constant) and isinstance(msg_node.value, str):
                params = sorted(self._extract_params(condition))
                rule = Rule(
                    method=self.current_method or "<unknown>",
                    lineno=node.lineno,
                    params=params,
                    message=msg_node.value,
                )
                self.rules.append(rule)

        self.generic_visit(node)

    def _extract_params(self, condition: ast.AST) -> Set[str]:
        """
        Collect parameter names used in the condition via:
          - local variables mapped from self.get(...)
          - direct self.get('param_name', ...) calls
        """
        params: Set[str] = set()
        local_map = self.local_param_stack[-1] if self.local_param_stack else {}

        for node in ast.walk(condition):
            # local names
            if isinstance(node, ast.Name) and node.id in local_map:
                params.add(local_map[node.id])

            # direct self.get('param_name')
            if isinstance(node, ast.Call):
                if (  # pylint: disable=too-many-boolean-expressions
                    isinstance(node.func, ast.Attribute)
                    and isinstance(node.func.value, ast.Name)
                    and node.func.value.id == "self"
                    and node.func.attr == "get"
                    and node.args
                    and isinstance(node.args[0], ast.Constant)
                    and isinstance(node.args[0].value, str)
                ):
                    params.add(node.args[0].value)

        return params


# ---------------------------------------------------------------------------
# Stage inference from validate_* roots and call graph
# ---------------------------------------------------------------------------

STAGE_ROOTS: Dict[str, List[str]] = {
    "common": ["validate_common"],
    "simulation": ["validate_simulation"],
    "pre_process": ["validate_pre_process"],
    "post_process": ["validate_post_process"],
}


def compute_method_stages(call_graph: Dict[str, Set[str]]) -> Dict[str, Set[str]]:
    """
    For each stage (simulation/pre_process/post_process/common), starting from
    validate_* roots, walk the call graph and record which methods belong to which stages.
    """
    method_stages: Dict[str, Set[str]] = defaultdict(set)

    def dfs(start: str, stage: str):
        stack = [start]
        visited: Set[str] = set()
        while stack:
            m = stack.pop()
            if m in visited:
                continue
            visited.add(m)
            method_stages[m].add(stage)
            for nxt in call_graph.get(m, ()):
                if nxt not in visited:
                    stack.append(nxt)

    for stage, roots in STAGE_ROOTS.items():
        for root in roots:
            dfs(root, stage)

    return method_stages
Robustness

Playbook generation executes example cases via subprocess and assumes JSON output; failures return empty dicts silently, causing missing cards without visibility in CI.

def load_case_params(case_dir: str) -> Dict[str, Any]:
    """Load parameters from a case.py file"""
    case_path = EXAMPLES_DIR / case_dir / "case.py"
    if not case_path.exists():
        return {}

    try:
        result = subprocess.run(
            ["python3", str(case_path)],
            capture_output=True,
            text=True,
            timeout=10,
            check=True
        )
        params = json.loads(result.stdout)
        return params
    except (subprocess.CalledProcessError, json.JSONDecodeError, subprocess.TimeoutExpired):
        return {}
Build Fragility

The custom command outputs into the source tree and depends on a variable examples_DOCs and a bash wrapper; changes in examples not captured or missing var may skip regeneration.

    VERBATIM
)

# Generate case_constraints.md from case_validator.py and examples/
add_custom_command(
    OUTPUT  "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py"
            "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/case_validator.py"
            "${examples_DOCs}"
    COMMAND "bash" "${CMAKE_CURRENT_SOURCE_DIR}/docs/gen_constraints.sh"
                   "${CMAKE_CURRENT_SOURCE_DIR}"
    COMMENT "Generating case_constraints.md"
    VERBATIM
)

file(GLOB common_DOCs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/*")

# GEN_DOCS: Given a target name (herein <target>), this macro sets up a
# target, <target>_docs, that generates documentation for <target> using
# Doxygen. It is then added as a dependency of the documentation target.
# Doxygen outputs HTML to the binary (build) directory. It is installed into
# its own directory: <prefix>/docs/mfc/<target>. We use configure_file to
# generate the Doxyfile for each target using paths that only apply to that
# target (or when relative paths are impractical), specified by CMake.

macro(GEN_DOCS target name)
    set(DOXYGEN_PROJECT_NAME     "\"${name}\"")
    set(DOXYGEN_INPUT            "\"${CMAKE_CURRENT_SOURCE_DIR}/docs/${target}\"")

    foreach (f90 ${${target}_SRCs})
        set(DOXYGEN_INPUT "${DOXYGEN_INPUT} \"${f90}\"")
    endforeach()

    set(DOXYGEN_HTML_HEADER      "\"${CMAKE_CURRENT_SOURCE_DIR}/docs/header.html\"")
    set(DOXYGEN_HTML_FOOTER      "\"${CMAKE_CURRENT_SOURCE_DIR}/docs/footer.html\"")
    set(DOXYGEN_HTML_OUTPUT      "\"${CMAKE_CURRENT_BINARY_DIR}/${target}\"")
    set(DOXYGEN_MATHJAX_CODEFILE "\"${CMAKE_CURRENT_SOURCE_DIR}/docs/config.js\"")
    set(DOXYGEN_PROJECT_LOGO     "\"${CMAKE_CURRENT_SOURCE_DIR}/docs/res/icon.ico\"")
    set(DOXYGEN_IMAGE_PATH       "\"${CMAKE_CURRENT_SOURCE_DIR}/docs/res\"\
                                  \"${CMAKE_CURRENT_SOURCE_DIR}/docs/${target}\"")

    file(MAKE_DIRECTORY "${DOXYGEN_OUTPUT_DIRECTORY}")

    configure_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in"
        "${CMAKE_CURRENT_BINARY_DIR}/${target}-Doxyfile" @ONLY)

    set(opt_example_dependency "")
    set(opt_constraints_dependency "")
    if (${target} STREQUAL documentation)
        set(opt_example_dependency "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/examples.md")
        set(opt_constraints_dependency "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md")
    endif()

    file(GLOB_RECURSE ${target}_DOCs CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/${target}/*")
    list(APPEND ${target}_DOCs "${common_DOCs}")

    add_custom_command(
        OUTPUT  "${CMAKE_CURRENT_BINARY_DIR}/${target}/html/index.html"
        DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${target}-Doxyfile"
                "${opt_example_dependency}"
                "${opt_constraints_dependency}"
                "${${target}_SRCs}" "${${target}_DOCs}"

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

docs/Doxyfile.in Outdated
Comment on lines 1166 to 1167
HTML_EXTRA_STYLESHEET = @DOXYGEN_HTML_EXTRA_STYLESHEET@ \
@CMAKE_SOURCE_DIR@/docs/custom-dark-fixes.css

Choose a reason for hiding this comment

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

P1 Badge Add missing custom stylesheet for docs build

Doxyfile now tells Doxygen to include docs/custom-dark-fixes.css via HTML_EXTRA_STYLESHEET, but that file does not exist anywhere in the tree (find docs -name custom-dark-fixes.css returns nothing). Doxygen treats missing extra stylesheets as an error, so generating the documentation (e.g., via the updated docs workflow running cmake ... -D MFC_DOCUMENTATION=ON/ninja -C build install) will fail as soon as this tag is processed.

Useful? React with 👍 / 👎.

Copilot finished reviewing on behalf of sbryngelson December 1, 2025 04:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds automated documentation generation for MFC case parameter constraints and a case design playbook with curated examples. The system parses case_validator.py using AST analysis to extract validation rules and generates comprehensive user-friendly documentation in Markdown format.

Key Changes:

  • New Python script that performs AST analysis to extract constraint rules from validation code
  • Automated generation of case constraints documentation integrated into the CMake build system
  • Case design playbook featuring 9 curated working examples from beginner to advanced levels

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
toolchain/mfc/gen_case_constraints_docs.py New Python script that analyzes case_validator.py using AST to extract validation rules and generates comprehensive Markdown documentation with compatibility tables and configuration examples
docs/gen_constraints.sh Bash script that invokes the Python documentation generator and outputs to case_constraints.md
CMakeLists.txt Integrates constraints documentation generation into the build system with proper dependencies on case_validator.py and example files
docs/documentation/case.md Adds reference to the new Feature Compatibility Guide at the top of the parameters section
docs/Doxyfile.in Adds custom-dark-fixes.css to HTML_EXTRA_STYLESHEET (file doesn't exist - critical issue)
.gitignore Adds generated case_constraints.md to ignore list as a build artifact
.github/workflows/docs.yml Adds artifact upload step for built documentation to aid debugging and verification

docs/Doxyfile.in Outdated
Comment on lines 1166 to 1167
HTML_EXTRA_STYLESHEET = @DOXYGEN_HTML_EXTRA_STYLESHEET@ \
@CMAKE_SOURCE_DIR@/docs/custom-dark-fixes.css
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

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

The file @CMAKE_SOURCE_DIR@/docs/custom-dark-fixes.css is referenced but does not exist in the repository. This will cause the documentation build to fail or produce warnings. Either create this file or remove this line from the HTML_EXTRA_STYLESHEET configuration.

Suggested change
HTML_EXTRA_STYLESHEET = @DOXYGEN_HTML_EXTRA_STYLESHEET@ \
@CMAKE_SOURCE_DIR@/docs/custom-dark-fixes.css
HTML_EXTRA_STYLESHEET = @DOXYGEN_HTML_EXTRA_STYLESHEET@

Copilot uses AI. Check for mistakes.
@codeant-ai
Copy link

codeant-ai bot commented Dec 1, 2025

CodeAnt AI is reviewing your PR.


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 the size:XL This PR changes 500-999 lines, ignoring generated files label Dec 1, 2025
@codeant-ai
Copy link

codeant-ai bot commented Dec 1, 2025

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Possible Bug
    load_case_params invokes example case.py files using a hard-coded "python3" executable. In environments using a virtualenv, non-standard Python name, or different default python3 version, this can cause failures or inconsistent behavior compared to the interpreter running the generator. Consider switching to sys.executable so the same interpreter is used for both the generator and the cases.

@codeant-ai
Copy link

codeant-ai bot commented Dec 1, 2025

CodeAnt AI finished reviewing your PR.

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: 0

♻️ Duplicate comments (3)
docs/Doxyfile.in (1)

1166-1167: Ensure docs/custom-dark-fixes.css exists or drop it from HTML_EXTRA_STYLESHEET

Doxygen will error out if any file listed in HTML_EXTRA_STYLESHEET is missing. I don’t see docs/custom-dark-fixes.css added in this PR, so documentation builds (MFC_DOCUMENTATION=ON) will likely fail until that file is created or this entry is removed.

Please confirm that docs/custom-dark-fixes.css is present in the repo. If it isn’t, either add the stylesheet (even as a minimal stub) or remove this path. You can verify with:

#!/bin/bash
# From repo root
test -f docs/custom-dark-fixes.css && echo "found" || echo "missing"
toolchain/mfc/gen_case_constraints_docs.py (2)

415-432: Log failures when loading example case parameters instead of fully silent fallback

load_case_params currently returns {} on any subprocess.CalledProcessError / JSON / timeout error without emitting diagnostics, which can silently drop examples from the playbook and make issues in examples/*/case.py harder to detect.

Consider logging a warning to stderr before returning {} so broken examples show up during docs generation, e.g.:

-    except (subprocess.CalledProcessError, json.JSONDecodeError, subprocess.TimeoutExpired):
-        return {}
+    except (subprocess.CalledProcessError, json.JSONDecodeError, subprocess.TimeoutExpired) as e:
+        print(f"WARNING: Failed to load params from {case_path}: {e}", file=sys.stderr)
+        return {}

592-627: Avoid fully silent except Exception when rendering playbook cards

In generate_playbook, the broad except Exception: continue will hide any unexpected failure (e.g. schema changes in case.py outputs), again silently removing examples from the output.

At minimum, log the error to stderr so it’s visible in CI logs:

-        for entry in level_entries:
-            try:
-                params = load_case_params(entry.case_dir)
-                if not params:
-                    continue
-                summary = summarize_case_params(params)
-                card = render_playbook_card(entry, summary)
-                lines.append(card)
-            except Exception:  # pylint: disable=broad-except
-                continue
+        for entry in level_entries:
+            try:
+                params = load_case_params(entry.case_dir)
+                if not params:
+                    continue
+                summary = summarize_case_params(params)
+                card = render_playbook_card(entry, summary)
+                lines.append(card)
+            except Exception as e:  # pylint: disable=broad-except
+                print(f"WARNING: Failed to process playbook entry '{entry.case_dir}': {e}", file=sys.stderr)
+                continue
🧹 Nitpick comments (4)
docs/documentation/case.md (1)

69-79: Feature Compatibility block wiring looks correct

The new “Feature Compatibility” subsection and link to case_constraints.md are consistent with the generated doc path and Doxygen’s Markdown handling; no structural issues from the docs perspective.

If you want a stricter hierarchy, consider making “Feature Compatibility” a subheading (e.g. ###) under “Parameters” instead of a sibling.

docs/gen_constraints.sh (1)

1-15: Shell wrapper is correct; optionally harden error handling

The script correctly validates REPO_ROOT, quotes paths, and wires the Python generator to the expected output location.

For slightly stronger safety in CI, consider:

-#!/bin/bash
-# Generate case constraints documentation from case_validator.py
-
-set -e
+#!/bin/bash
+# Generate case constraints documentation from case_validator.py
+
+set -euo pipefail

so unset variables and pipeline failures are caught early.

CMakeLists.txt (1)

655-665: Add docs/gen_constraints.sh as an explicit dependency

The custom command for case_constraints.md is wired correctly to gen_case_constraints_docs.py, case_validator.py, and the examples, and integrates cleanly with the documentation Doxygen rule via opt_constraints_dependency.

To ensure changes to the wrapper script also trigger regeneration, add it to DEPENDS:

 add_custom_command(
     OUTPUT  "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
-    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py"
-            "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/case_validator.py"
-            "${examples_DOCs}"
+    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/gen_constraints.sh"
+            "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py"
+            "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/case_validator.py"
+            "${examples_DOCs}"
toolchain/mfc/gen_case_constraints_docs.py (1)

45-189: AST-based rule extraction is well-structured; consider small robustness tweaks

The CaseValidatorAnalyzer and _extract_params logic to discover self.prohibit(...) calls and map them back to case parameters (self.get('param', ...) and local aliases) is clear and nicely localized; the call-graph tracking for later stage attribution is also sound.

If you later need to cover more complex patterns, you could:

  • Walk the full function body in _build_local_param_map (not just top-level Assign nodes) to catch assignments nested inside if/loops.
  • Narrow the analysis to CaseValidator by checking self.in_case_validator in visit_Call, to avoid ever picking up unrelated self.prohibit calls in other classes.
    These aren’t required for correctness with the current validator style, but would make the extractor more future-proof.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d283e5 and ec6f33a.

📒 Files selected for processing (7)
  • .github/workflows/docs.yml (1 hunks)
  • .gitignore (1 hunks)
  • CMakeLists.txt (3 hunks)
  • docs/Doxyfile.in (1 hunks)
  • docs/documentation/case.md (1 hunks)
  • docs/gen_constraints.sh (1 hunks)
  • toolchain/mfc/gen_case_constraints_docs.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.6)
toolchain/mfc/gen_case_constraints_docs.py

1-1: Shebang is present but file is not executable

(EXE001)


284-284: String contains ambiguous (EN DASH). Did you mean - (HYPHEN-MINUS)?

(RUF001)


285-285: String contains ambiguous (EN DASH). Did you mean - (HYPHEN-MINUS)?

(RUF001)


422-422: subprocess call: check for execution of untrusted input

(S603)


423-423: Starting a process with a partial executable path

(S607)


430-430: Consider moving this statement to an else block

(TRY300)


467-467: String contains ambiguous γ (GREEK SMALL LETTER GAMMA). Did you mean y (LATIN SMALL LETTER Y)?

(RUF001)


623-624: try-except-continue detected, consider logging the exception

(S112)


623-623: Do not catch blind exception: Exception

(BLE001)


784-784: String contains ambiguous γ (GREEK SMALL LETTER GAMMA). Did you mean y (LATIN SMALL LETTER Y)?

(RUF001)


893-893: f-string without any placeholders

Remove extraneous f prefix

(F541)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Github (macos, mpi, debug, false)
  • GitHub Check: Github (macos, mpi, no-debug, false)
  • GitHub Check: Github (ubuntu, mpi, debug, false)
  • GitHub Check: Github (ubuntu, mpi, no-debug, false)
  • GitHub Check: Github (ubuntu, mpi, no-debug, true)
  • GitHub Check: Github (ubuntu, mpi, debug, true)
  • GitHub Check: Coverage Test on CodeCov
🔇 Additional comments (4)
.gitignore (1)

35-40: Ignore generated case constraints doc

Adding docs/documentation/case_constraints.md to .gitignore is appropriate since it is now a generated artifact, keeping the tree clean.

.github/workflows/docs.yml (1)

37-43: Uploading built docs artifact is well-integrated

The new Upload Built Documentation Artifact step correctly targets build/install/docs/mfc, aligns with subsequent sitemap/linkcheck steps, and will fail fast if docs aren’t generated.

CMakeLists.txt (1)

699-704: Doxygen dependency on generated constraints doc is correctly modeled

The opt_constraints_dependency mechanism in GEN_DOCS ensures that the documentation target’s Doxygen run waits for both examples.md and case_constraints.md to be generated, without impacting other doc targets.

Also applies to: 713-714

toolchain/mfc/gen_case_constraints_docs.py (1)

19-19: Python 3.10+ type-hint syntax may break docs generation on older Pythons

The use of PEP 604 unions (e.g. model_eqns: int | None) requires Python ≥ 3.10 at parse time, even with from __future__ import annotations. If someone runs MFC_DOCUMENTATION=ON with an older system Python (3.8/3.9 is still common on clusters), this script will fail to start.

If you need compatibility with <3.10, prefer Optional[int]:

-from typing import Dict, List, Set, Iterable, Any
+from typing import Dict, List, Set, Iterable, Any, Optional
@@
-def get_model_name(model_eqns: int | None) -> str:
+def get_model_name(model_eqns: Optional[int]) -> str:
@@
-def get_riemann_solver_name(solver: int | None) -> str:
+def get_riemann_solver_name(solver: Optional[int]) -> str:
@@
-def get_time_stepper_name(stepper: int | None) -> str:
+def get_time_stepper_name(stepper: Optional[int]) -> str:

Please confirm what minimum Python version you intend to support for docs builds and adjust accordingly.

Also applies to: 464-495

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.

3 issues found across 7 files

Prompt for AI agents (all 3 issues)

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


<file name="CMakeLists.txt">

<violation number="1" location="CMakeLists.txt:658">
P2: Add docs/gen_constraints.sh to the DEPENDS list so edits to the generator script retrigger case_constraints.md generation and keep the documentation up to date.</violation>
</file>

<file name="docs/gen_constraints.sh">

<violation number="1" location="docs/gen_constraints.sh:14">
P2: Redirecting the generator output directly risks truncating docs/documentation/case_constraints.md if the Python script fails after the shell creates the file; stage the output in a temporary file and move it only after the generator succeeds to avoid corrupting the docs.</violation>
</file>

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

<violation number="1" location="docs/documentation/case.md:73">
P2: `Feature Compatibility Guide` link points to `case_constraints.md`, which is missing from the repo, resulting in a broken documentation link.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

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.

2 issues found across 6 files

Prompt for AI agents (all 2 issues)

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


<file name="docs/gen_constraints.sh">

<violation number="1" location="docs/gen_constraints.sh:14">
P2: Avoid truncating `case_constraints.md` before successful doc generation; write to a temporary file and only replace the target after the generator succeeds.</violation>
</file>

<file name="CMakeLists.txt">

<violation number="1" location="CMakeLists.txt:658">
P2: Include `docs/gen_constraints.sh` in the custom command dependencies so edits to the generator script retrigger `case_constraints.md`.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

fi

echo "Generating case constraints documentation..."
python3 "$REPO_ROOT/toolchain/mfc/gen_case_constraints_docs.py" > "$REPO_ROOT/docs/documentation/case_constraints.md"
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 1, 2025

Choose a reason for hiding this comment

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

P2: Avoid truncating case_constraints.md before successful doc generation; write to a temporary file and only replace the target after the generator succeeds.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/gen_constraints.sh, line 14:

<comment>Avoid truncating `case_constraints.md` before successful doc generation; write to a temporary file and only replace the target after the generator succeeds.</comment>

<file context>
@@ -0,0 +1,17 @@
+fi
+
+echo &quot;Generating case constraints documentation...&quot;
+python3 &quot;$REPO_ROOT/toolchain/mfc/gen_case_constraints_docs.py&quot; &gt; &quot;$REPO_ROOT/docs/documentation/case_constraints.md&quot;
+echo &quot;✓ Generated docs/documentation/case_constraints.md&quot;
+
</file context>
Fix with Cubic

# Generate case_constraints.md from case_validator.py and examples/
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py"
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 1, 2025

Choose a reason for hiding this comment

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

P2: Include docs/gen_constraints.sh in the custom command dependencies so edits to the generator script retrigger case_constraints.md.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CMakeLists.txt, line 658:

<comment>Include `docs/gen_constraints.sh` in the custom command dependencies so edits to the generator script retrigger `case_constraints.md`.</comment>

<file context>
@@ -652,6 +652,18 @@ if (MFC_DOCUMENTATION)
+    # Generate case_constraints.md from case_validator.py and examples/
+    add_custom_command(
+        OUTPUT  &quot;${CMAKE_CURRENT_SOURCE_DIR}/docs/documentation/case_constraints.md&quot;
+        DEPENDS &quot;${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py&quot;
+                &quot;${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/case_validator.py&quot;
+                &quot;${examples_DOCs}&quot;
</file context>
Suggested change
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/docs/gen_constraints.sh" "${CMAKE_CURRENT_SOURCE_DIR}/toolchain/mfc/gen_case_constraints_docs.py"
Fix with Cubic

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: 0

🧹 Nitpick comments (5)
toolchain/mfc/gen_case_constraints_docs.py (5)

1-1: Shebang vs execution mode

The file has a #!/usr/bin/env python3 shebang but is likely invoked via python/CMake rather than as an executable; either make the script executable in git or drop the shebang to avoid EXE001 noise.


32-39: Stage tracking logic is currently unused

Rule.stages, STAGE_ROOTS, and compute_method_stages() are computed but never read in render_markdown or elsewhere, adding complexity without effect. Consider either surfacing stage information in the docs (e.g., grouping constraints by stage) or removing this machinery to keep the generator simpler and easier to maintain.

Also applies to: 192-229, 940-942


93-124: AST param extraction is intentionally heuristic; verify coverage of validator patterns

_build_local_param_map only inspects top-level ast.Assign nodes and a single self.get(...) pattern (optionally under a top-level comparison), and _extract_params relies on that mapping plus direct self.get calls. Any assignments nested in if/loops or more complex expressions will be missed, and corresponding self.prohibit conditions will yield rules with incomplete params, so those constraints simply won’t appear in the docs. If the current case_validator.py uses more varied patterns, consider expanding these visitors (or documenting the expected patterns) so new validation code doesn’t silently drop constraints from the generated guide.

Also applies to: 162-189


415-433: Tighten subprocess usage and interpreter selection for example cases

load_case_params shells out with ["python3", case_path] and trusts its stdout as JSON. Since case_path is derived from the repo structure, this is acceptable as an internal docs tool, but you can make it safer and more portable by:

  • Using sys.executable instead of bare "python3" to ensure the same interpreter and avoid PATH issues (addresses S607).
  • Making it explicit in comments that this script is intended to run only against trusted repository examples, not arbitrary user-provided directories (mitigates S603 concerns).

For example:

-import subprocess
+import subprocess
+import sys
@@
-        result = subprocess.run(
-            ["python3", str(case_path)],
+        result = subprocess.run(
+            [sys.executable, str(case_path)],
             capture_output=True,
             text=True,
             timeout=10,
             check=True
         )
-        params = json.loads(result.stdout)
-        return params
+        return json.loads(result.stdout)

(The surrounding except already logs and falls back cleanly.)


895-897: Remove unnecessary f-string prefix

lines.append(f"\n<details>") is an f-string without interpolation, which Ruff flags (F541) and doesn’t add value. You can simplify:

-        lines.append(f"\n<details>")
+        lines.append("\n<details>")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec6f33a and dac20d0.

📒 Files selected for processing (1)
  • toolchain/mfc/gen_case_constraints_docs.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.6)
toolchain/mfc/gen_case_constraints_docs.py

1-1: Shebang is present but file is not executable

(EXE001)


284-284: String contains ambiguous (EN DASH). Did you mean - (HYPHEN-MINUS)?

(RUF001)


285-285: String contains ambiguous (EN DASH). Did you mean - (HYPHEN-MINUS)?

(RUF001)


422-422: subprocess call: check for execution of untrusted input

(S603)


423-423: Starting a process with a partial executable path

(S607)


430-430: Consider moving this statement to an else block

(TRY300)


468-468: String contains ambiguous γ (GREEK SMALL LETTER GAMMA). Did you mean y (LATIN SMALL LETTER Y)?

(RUF001)


624-624: Do not catch blind exception: Exception

(BLE001)


786-786: String contains ambiguous γ (GREEK SMALL LETTER GAMMA). Did you mean y (LATIN SMALL LETTER Y)?

(RUF001)


895-895: f-string without any placeholders

Remove extraneous f prefix

(F541)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Coverage Test on CodeCov
  • GitHub Check: Github (macos, mpi, no-debug, false)
  • GitHub Check: Github (ubuntu, no-mpi, single, no-debug, false)
  • GitHub Check: Github (ubuntu, mpi, debug, false)
  • GitHub Check: Github (macos, mpi, debug, false)
  • GitHub Check: Github (ubuntu, mpi, no-debug, false)
  • GitHub Check: Github (ubuntu, mpi, no-debug, true)
  • GitHub Check: Github (ubuntu, mpi, debug, true)
  • GitHub Check: Code Cleanliness Check
  • GitHub Check: Build & Publish
🔇 Additional comments (2)
toolchain/mfc/gen_case_constraints_docs.py (2)

571-588: Verify that manual fragment links match rendered heading IDs

Several links use hard‑coded fragments like #-model-equations, #️-riemann-solvers, #-bubble-models, and #magnetohydrodynamics-mhd-mhd while the corresponding headings include emoji and/or parentheses. Different Markdown engines (GitHub vs Doxygen) derive IDs differently in these cases, so these anchors may not actually resolve. Please build the docs and confirm the links work; if not, consider simplifying headings (no emoji) or adjusting fragments to match the generator’s ID scheme.

Also applies to: 780-807, 815-824


498-590: Broad Exception catch in playbook generation looks acceptable

Catching Exception in generate_playbook is reasonable here since a broken example should not break the entire docs build, and you already log a warning to stderr before continuing. No change is strictly needed; just be aware that truly unexpected errors (e.g., environment issues) will also be swallowed.

Also applies to: 593-628

@codecov
Copy link

codecov bot commented Dec 1, 2025

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1072   +/-   ##
=======================================
  Coverage   44.16%   44.16%           
=======================================
  Files          71       71           
  Lines       20197    20197           
  Branches     1970     1970           
=======================================
  Hits         8921     8921           
  Misses      10148    10148           
  Partials     1128     1128           

☔ View full report in Codecov by Sentry.
📢 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.

@sbryngelson sbryngelson merged commit d8d9e25 into MFlowCode:master Dec 3, 2025
91 of 107 checks passed
@Malmahrouqi3
Copy link
Member

Looks cool. Generated page name typo below.

### Errors in build/install/docs/mfc/documentation/md_case__constraints.html

@sbryngelson
Copy link
Member Author

good find, thanks @Malmahrouqi3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Possible security concern Review effort 4/5 size:XL This PR changes 500-999 lines, ignoring generated files

Development

Successfully merging this pull request may close these issues.

2 participants