Skip to content

Add CI lint gate and local precheck command#1122

Merged
sbryngelson merged 16 commits intoMFlowCode:masterfrom
sbryngelson:triage
Feb 5, 2026
Merged

Add CI lint gate and local precheck command#1122
sbryngelson merged 16 commits intoMFlowCode:masterfrom
sbryngelson:triage

Conversation

@sbryngelson
Copy link
Member

@sbryngelson sbryngelson commented Feb 4, 2026

User description

User description

Summary

  • Add lint-gate job to test.yml that runs fast checks (formatting, spelling, linting) before expensive test matrix and HPC jobs start
  • Add concurrency groups to test.yml, coverage.yml, cleanliness.yml, and bench.yml to cancel superseded runs on new pushes
  • Add ./mfc.sh precheck command for local CI validation before pushing

Motivation

  1. Prevent wasted CI resources: Expensive HPC and test matrix jobs won't start if basic lint checks fail
  2. Faster feedback: Developers know within ~1-2 minutes if their code has formatting/lint issues
  3. Cancel superseded runs: New pushes cancel in-progress runs on the same branch
  4. Local validation: ./mfc.sh precheck lets developers catch issues before pushing

Test plan

  • Verify ./mfc.sh precheck runs locally and catches formatting issues
  • Verify lint-gate job runs before test matrix in CI
  • Verify concurrency cancellation works on rapid pushes

Generated with Claude Code

PR Type

Enhancement, Tests

Description

  • Add lint-gate CI job running fast checks before expensive tests

  • Add ./mfc.sh precheck command for local pre-push validation

  • Implement concurrency groups to cancel superseded CI runs

  • Lint-gate checks formatting, spelling, toolchain, and source code

Diagram Walkthrough

flowchart LR
  A["Developer Code"] -->|"./mfc.sh precheck"| B["Local Validation"]
  B -->|"Pass"| C["Push to Branch"]
  C -->|"Trigger CI"| D["lint-gate Job"]
  D -->|"Pass"| E["Test Matrix & HPC"]
  D -->|"Fail"| F["Cancel Expensive Jobs"]
  B -->|"Fail"| G["Fix Issues Locally"]
Loading

File Walkthrough

Relevant files
Enhancement
mfc.sh
Add precheck command entry point                                                 

mfc.sh

  • Add new precheck command branch that sources precheck.sh script
  • Follows same pattern as existing spelling and lint commands
  • Requires Python bootstrap initialization
+4/-0     
precheck.sh
Implement local precheck validation script                             

toolchain/bootstrap/precheck.sh

  • New script implementing local CI validation with 4 sequential checks
  • Checks formatting, spelling, toolchain lint, and source code patterns
  • Detects raw OpenACC/OpenMP directives, double precision intrinsics,
    and junk code
  • Supports parallel jobs option (-j) for formatting check
  • Provides colored output and detailed error messages
+118/-0 
test.yml
Add lint-gate job and concurrency configuration                   

.github/workflows/test.yml

  • Add concurrency group to cancel superseded runs on new pushes
  • Add new lint-gate job running 5 fast checks before test matrix
  • Lint-gate checks formatting, spelling, toolchain lint, raw directives,
    double precision intrinsics, and junk code patterns
  • Make github and self jobs depend on lint-gate completion
  • Expensive test matrix and HPC jobs only start after lint-gate passes
+45/-3   
Configuration changes
coverage.yml
Add concurrency group configuration                                           

.github/workflows/coverage.yml

  • Add concurrency group to cancel superseded runs on new pushes
  • Uses workflow name and git ref to group concurrent runs
+4/-0     
cleanliness.yml
Add concurrency group configuration                                           

.github/workflows/cleanliness.yml

  • Add concurrency group to cancel superseded runs on new pushes
  • Uses workflow name and git ref to group concurrent runs
+4/-0     
bench.yml
Add concurrency group configuration                                           

.github/workflows/bench.yml

  • Add concurrency group to cancel superseded runs on new pushes
  • Uses workflow name and git ref to group concurrent runs
+4/-0     

CodeAnt-AI Description

Run CI lint gate locally and block expensive CI/benchmarks until fast checks pass

What Changed

  • Add a new local precheck command (mfc.sh precheck) that runs formatting, spelling, toolchain lint, and basic source checks; it fails if formatting auto-changed files or if any checks fail
  • Install and run a git pre-commit hook that invokes the precheck to block commits (can be bypassed with --no-verify); auto-installs on first mfc.sh invocation
  • CI now runs a fast "Lint Gate" job before the full test matrix; test and benchmark jobs wait for Lint Gate success and tests to complete before starting
  • Add concurrency groups across workflows so superseded runs on the same branch are cancelled automatically
  • Auto-install tab completions on first run and update installed completions when regenerated; zsh/bash completion behavior improved and help text clarified for debug/verbosity flags

Impact

✅ Fewer wasted HPC/benchmark runs
✅ Shorter pre-push feedback loop (catch formatting/lint locally)
✅ Fewer redundant CI runs on rapid pushes

💡 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

    • Local "precheck" command to run formatting, spelling, lint and source checks (parallel jobs supported).
    • Installable pre-commit hook that runs precheck before commits.
    • Automatic installation/updating of shell completions with prompts to reload the shell.
    • CI "Wait for Test Suite" step that polls test/lint outcomes and enforces timeouts; new lint-gate phase.
  • Chores

    • CI workflows now use concurrency with cancel-in-progress; job dependency ordering updated so checks run earlier and block downstream jobs.
  • Documentation

    • Improved CLI help text and option descriptions; completion behavior tweaks.

- Add lint-gate job to test.yml that runs fast checks (formatting,
  spelling, linting) before expensive test matrix and HPC jobs start
- Add concurrency groups to test.yml, coverage.yml, cleanliness.yml,
  and bench.yml to cancel superseded runs on new pushes
- Add ./mfc.sh precheck command for local CI validation before pushing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 4, 2026 21:20
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 4, 2026

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Adds top-level concurrency to multiple GitHub Actions workflows; introduces a CI lint-gate job and a new bench wait-for-tests job that polls test/lint outcomes and becomes a dependency; adds local precheck tooling, a git pre-commit hook, CLI integration, and completion-update logic.

Changes

Cohort / File(s) Summary
Bench workflow (wait-for-tests)
​.github/workflows/bench.yml
Adds top-level concurrency; adds job wait-for-tests ("Wait for Test Suite") that polls CI test-suite and lint-gate outcomes; updates self job needs to include wait-for-tests.
Test workflow (lint-gate)
​.github/workflows/test.yml
Adds top-level concurrency; introduces lint-gate job (format, spell, toolchain lint, source-rule checks); updates downstream jobs to needs: [lint-gate, file-changes].
Coverage & Cleanliness workflows
​.github/workflows/coverage.yml, ​.github/workflows/cleanliness.yml
Adds identical concurrency blocks using group: ${{ github.workflow }}-${{ github.ref }} and cancel-in-progress: true.
Local precheck tooling & git hook
mfc.sh, toolchain/bootstrap/precheck.sh, ​.githooks/pre-commit
Adds mfc.sh precheck entry and auto-install steps for pre-commit hook; new toolchain/bootstrap/precheck.sh implements local CI-like checks (format diff-check, spell, toolchain lint, source-rule checks) with -j/--jobs; adds executable .githooks/pre-commit to invoke precheck on commit.
CLI, completions & docs generation
toolchain/mfc/cli/commands.py, toolchain/main.py, toolchain/mfc/cli/completion_gen.py, toolchain/mfc/cli/docs_gen.py
Adds PRECHECK_COMMAND to CLI registry; adjusts help text and INTERACTIVE_COMMAND description; updates completion-generation behavior and adds logic to update installed completions when regenerated.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant BenchWF as Bench Workflow
    end
    rect rgba(200,255,200,0.5)
    participant Wait as wait-for-tests job
    end
    rect rgba(255,200,200,0.5)
    participant CI as GitHub Test Suite
    end
    rect rgba(255,255,200,0.5)
    participant Lint as lint-gate job
    end

    BenchWF->>Wait: start wait-for-tests
    Wait->>CI: poll test-suite job statuses
    CI-->>Wait: return statuses (passed/failed/pending)
    Wait->>Lint: query lint-gate result
    Lint-->>Wait: return lint outcome
    alt all required checks passed
        Wait-->>BenchWF: allow `self` job to proceed
    else failures or timeout
        Wait-->>BenchWF: fail or block downstream
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • wilfonba

Poem

🐇 I hop through diffs and chase a test,
I lint and spell and tidy the nest.
I poll the gates and guard the lane,
A precheck hop to catch the pain.
Commit with care — the pipeline's sane.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description covers summary, motivation, test plan, and detailed file changes. However, several checklist items from the template are incomplete or unchecked (testing, documentation, regression tests, code comments, Doxygen docstrings). Clarify which checklist items apply to this PR (e.g., documentation, regression tests). If not applicable, explicitly note why. Ensure test plan items are verified before merging.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding a CI lint gate job and a local precheck command, which aligns with the changeset's core objectives.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 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.

@codeant-ai codeant-ai bot added the size:L This PR changes 100-499 lines, ignoring generated files label Feb 4, 2026
@qodo-code-review
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

Argument parsing for -j|--jobs assigns JOBS="$2" without validating that a value exists or that it is numeric; this can mis-handle --jobs at end-of-args or swallow the next flag. Consider checking for missing/invalid values before shifting and using it.

while [[ $# -gt 0 ]]; do
    case "$1" in
        -j|--jobs)
            JOBS="$2"
            shift
            ;;
        -h | --help)
            show_help
            ;;
        *)
            echo "Precheck: unknown argument: $1."
            exit 1
            ;;
    esac

    shift
done
False Positives

The “double precision intrinsics” grep pattern includes very broad tokens (notably d0 and double), which can match innocuous identifiers/strings/comments and cause spurious failures. Tighten the regex with word boundaries / more specific Fortran patterns (e.g., \bd?sqrt\b, \breal\s*\(\s*8\s*\), \b[0-9]+d0\b) and consider excluding comments if applicable.

# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
    error "Found double precision intrinsics. Use generic intrinsics."
    SOURCE_FAILED=1
fi
Duplicate Logic

The precheck’s source lint and formatting/spell/lint steps largely duplicate the GitHub Actions lint-gate logic, which risks drift over time. Consider centralizing the checks (e.g., have CI call ./mfc.sh precheck or extract shared patterns into a single script) to keep local and CI gates consistent.

log "Running$MAGENTA precheck$COLOR_RESET (same checks as CI lint-gate)..."
echo ""

# 1. Check formatting
log "[$CYAN 1/4$COLOR_RESET] Checking$MAGENTA formatting$COLOR_RESET..."
# Capture state before formatting
BEFORE_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
if ! ./mfc.sh format -j "$JOBS" > /dev/null 2>&1; then
    error "Formatting check failed to run."
    FAILED=1
else
    # Check if formatting changed any Fortran/Python files
    AFTER_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
    if [ "$BEFORE_HASH" != "$AFTER_HASH" ]; then
        error "Code is not formatted. Run$MAGENTA ./mfc.sh format$COLOR_RESET to fix."
        echo ""
        git diff --stat -- '*.f90' '*.fpp' '*.py' 2>/dev/null || true
        echo ""
        FAILED=1
    else
        ok "Formatting check passed."
    fi
fi

# 2. Spell check
log "[$CYAN 2/4$COLOR_RESET] Running$MAGENTA spell check$COLOR_RESET..."
if ./mfc.sh spelling > /dev/null 2>&1; then
    ok "Spell check passed."
else
    error "Spell check failed."
    FAILED=1
fi

# 3. Lint toolchain (Python)
log "[$CYAN 3/4$COLOR_RESET] Running$MAGENTA toolchain lint$COLOR_RESET..."
if ./mfc.sh lint > /dev/null 2>&1; then
    ok "Toolchain lint passed."
else
    error "Toolchain lint failed. Run$MAGENTA ./mfc.sh lint$COLOR_RESET for details."
    FAILED=1
fi

# 4. Source code lint checks
log "[$CYAN 4/4$COLOR_RESET] Running$MAGENTA source lint$COLOR_RESET checks..."
SOURCE_FAILED=0

# Check for raw OpenACC/OpenMP directives
if grep -qiR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/* 2>/dev/null; then
    error "Found raw OpenACC/OpenMP directives. Use macros instead."
    SOURCE_FAILED=1
fi

# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
    error "Found double precision intrinsics. Use generic intrinsics."
    SOURCE_FAILED=1
fi

# Check for junk code patterns
if grep -qiR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/* 2>/dev/null; then
    error "Found junk code patterns (..., ---, ===) in source."
    SOURCE_FAILED=1
fi

if [ $SOURCE_FAILED -eq 0 ]; then
    ok "Source lint passed."
else
    FAILED=1
fi

Copy link
Contributor

Choose a reason for hiding this comment

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

High-level Suggestion

The linting logic is duplicated in both the test.yml CI workflow and the new precheck.sh script. To improve maintainability and prevent divergence, the CI workflow should call ./mfc.sh precheck directly, making the script the single source of truth. [High-level, importance: 8]

Solution Walkthrough:

Before:

# In .github/workflows/test.yml
jobs:
  lint-gate:
    steps:
      - name: Check Formatting
        run: |
          ./mfc.sh format ...
          git diff --exit-code ...
      - name: Spell Check
        run: ./mfc.sh spelling
      - name: Lint Toolchain
        run: ./mfc.sh lint
      - name: Lint Source - No Raw Directives
        run: ! grep ...
      # ... and other source lint steps

# In toolchain/bootstrap/precheck.sh
# ... similar checks for formatting, spelling, toolchain, and source linting are defined again.

After:

# In .github/workflows/test.yml
jobs:
  lint-gate:
    steps:
      - name: Clone
        ...
      - name: Initialize MFC
        run: ./mfc.sh init
      - name: Run Pre-push Checks
        run: ./mfc.sh precheck

# In toolchain/bootstrap/precheck.sh
# This script becomes the single source of truth for all checks.
# ... checks for formatting, spelling, linting, and source code ...

Comment on lines +1 to +3
#!/bin/bash
set -e
set -o pipefail
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: Source the logging.sh script at the beginning of precheck.sh. This is necessary to define the log, ok, and error helper functions used throughout the script. [possible issue, importance: 9]

Suggested change
#!/bin/bash
set -e
set -o pipefail
#!/bin/bash
set -e
set -o pipefail
. "$(pwd)/toolchain/bootstrap/logging.sh"

Comment on lines 43 to 62
# 1. Check formatting
log "[$CYAN 1/4$COLOR_RESET] Checking$MAGENTA formatting$COLOR_RESET..."
# Capture state before formatting
BEFORE_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
if ! ./mfc.sh format -j "$JOBS" > /dev/null 2>&1; then
error "Formatting check failed to run."
FAILED=1
else
# Check if formatting changed any Fortran/Python files
AFTER_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
if [ "$BEFORE_HASH" != "$AFTER_HASH" ]; then
error "Code is not formatted. Run$MAGENTA ./mfc.sh format$COLOR_RESET to fix."
echo ""
git diff --stat -- '*.f90' '*.fpp' '*.py' 2>/dev/null || true
echo ""
FAILED=1
else
ok "Formatting check passed."
fi
fi
Copy link
Contributor

@qodo-code-review qodo-code-review bot Feb 4, 2026

Choose a reason for hiding this comment

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

Suggestion: Simplify the formatting check by replacing the md5sum hash comparison with a git diff --exit-code check. This removes a dependency and makes the script more portable and robust. [general, importance: 7]

Suggested change
# 1. Check formatting
log "[$CYAN 1/4$COLOR_RESET] Checking$MAGENTA formatting$COLOR_RESET..."
# Capture state before formatting
BEFORE_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
if ! ./mfc.sh format -j "$JOBS" > /dev/null 2>&1; then
error "Formatting check failed to run."
FAILED=1
else
# Check if formatting changed any Fortran/Python files
AFTER_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
if [ "$BEFORE_HASH" != "$AFTER_HASH" ]; then
error "Code is not formatted. Run$MAGENTA ./mfc.sh format$COLOR_RESET to fix."
echo ""
git diff --stat -- '*.f90' '*.fpp' '*.py' 2>/dev/null || true
echo ""
FAILED=1
else
ok "Formatting check passed."
fi
fi
# 1. Check formatting
log "[$CYAN 1/4$COLOR_RESET] Checking$MAGENTA formatting$COLOR_RESET..."
if ! ./mfc.sh format -j "$JOBS" > /dev/null 2>&1; then
error "Formatting check failed to run."
FAILED=1
elif ! git diff -- '*.f90' '*.fpp' '*.py' > /dev/null; then
error "Code is not formatted. Run$MAGENTA ./mfc.sh format$COLOR_RESET to fix."
echo ""
git diff --stat -- '*.f90' '*.fpp' '*.py' 2>/dev/null || true
echo ""
FAILED=1
else
ok "Formatting check passed."
fi

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 4, 2026

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Exit status masked
    The new precheck branch sources precheck.sh then unconditionally exits with 0. If the sourced script returns a non-zero status (indicating failure), that status will be lost and the caller/CI will see success. Verify that failures in precheck propagate correctly.

  • Sourcing vs. exiting
    This script is sometimes sourced (for venv/load). Calling 'precheck' when mfc.sh is sourced will run the branch and call 'exit 0', which will terminate the user's shell session. Confirm intended behavior (return vs exit) and make precheck consistent with other commands that deliberately use 'return' when mfc.sh is sourced.

  • Missing helper definitions
    The script calls log, ok, error and uses color vars (MAGENTA, CYAN, COLOR_RESET) but does not define them or check they exist. Running the script in environments where these functions/vars are not present will cause failures or noisy output. Ensure the script either defines fallbacks or checks/exports these helpers before use.

  • Argument parsing robustness
    The -j|--jobs handler assigns JOBS="$2" without validating that a value was provided or is numeric. If -j is the last argument or followed by another option, this will produce an empty or wrong value and shift logic may break. Validate presence and type and avoid unintended shifts.

  • Git diff hashing portability
    The script uses git diff ... | md5sum to detect formatting changes. md5sum is not available on all platforms (macOS uses md5) and git diff output may be empty causing md5 behavior differences. Consider a portable approach and explicit handling when no files are present.

elif [ "$1" '==' "precheck" ]; then
. "$(pwd)/toolchain/bootstrap/python.sh"

shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The precheck command always exits with status 0, ignoring any non-zero status from the precheck script or Python bootstrap, so failures in the underlying checks will not cause this wrapper to fail, breaking its use as a gating/pre-push check. [logic error]

Severity Level: Critical 🚨
- ❌ ./mfc.sh precheck reports success despite failures.
- ⚠️ Local pre-push validation may be misleading.
- ⚠️ Developers may push changes with lint errors.
Suggested change
shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit $?
Steps of Reproduction ✅
1. From the repository root, run the wrapper command: `./mfc.sh precheck`. This enters the
precheck branch in `mfc.sh` (see `mfc.sh` hunk lines 43-46: the `elif [ "$1" '=='
"precheck" ]` block).

2. `mfc.sh` sources the Python bootstrap at `mfc.sh` line 44 (`.
"$(pwd)/toolchain/bootstrap/python.sh"`), then executes the precheck script by sourcing
`toolchain/bootstrap/precheck.sh` at `mfc.sh` line 46 (`shift; .
"$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0`).

3. If `toolchain/bootstrap/precheck.sh` detects failures and returns/non-zero (for example
a linter or formatting check exits 1), that non-zero status is lost because `mfc.sh`
immediately executes `exit 0` on line 46.

4. Verify by running a deliberately-failing precheck (or a small wrapper
`toolchain/bootstrap/precheck.sh` that does `exit 1`): after `./mfc.sh precheck` observe
the shell exit code is 0 (`echo $?`), proving the wrapper masks failures and reports
success.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** mfc.sh
**Line:** 46:46
**Comment:**
	*Logic Error: The precheck command always exits with status 0, ignoring any non-zero status from the precheck script or Python bootstrap, so failures in the underlying checks will not cause this wrapper to fail, breaking its use as a gating/pre-push check.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

set -e
set -o pipefail

# Function to display help message
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The script relies on helper functions (log, ok, error) and color variables (MAGENTA, CYAN, COLOR_RESET) that are not defined anywhere in this file, so if precheck.sh is executed directly in a clean shell (rather than being sourced from a wrapper that defines them), the first call to log will result in "command not found" and the script will exit due to set -e. Adding safe fallback definitions for these helpers ensures the script runs correctly both standalone and when invoked via a parent script that may already define them. [possible bug]

Severity Level: Major ⚠️
- ❌ Local `./mfc.sh precheck` may abort with "command not found".
- ⚠️ Developer convenience: standalone usage inconsistent.
Suggested change
# Function to display help message
# Provide fallbacks for logging functions and color variables when not pre-defined
: "${MAGENTA:=}"
: "${CYAN:=}"
: "${COLOR_RESET:=}"
if ! declare -f log >/dev/null 2>&1; then
log() { printf '%s\n' "$*"; }
fi
if ! declare -f ok >/dev/null 2>&1; then
ok() { printf '%s\n' "$*"; }
fi
if ! declare -f error >/dev/null 2>&1; then
error() { printf '%s\n' "$*" >&2; }
fi
Steps of Reproduction ✅
1. Invoke the script directly in a clean shell: `./toolchain/bootstrap/precheck.sh` (file
`toolchain/bootstrap/precheck.sh`, execution starts at line 1; `set -e` and `set -o
pipefail` are on lines 2-3).

2. Execution reaches the first logging call at line 40: `log "Running$MAGENTA
precheck$COLOR_RESET (same checks as CI lint-gate)..."` (see final file lines around 40).
The script expects `log`, `ok`, `error`, and color variables to exist.

3. If those functions/variables are not defined by the higher-level wrapper (e.g.
`./mfc.sh`) and the script is executed standalone, the shell reports `./precheck.sh: line
40: log: command not found` and, because `set -e` is enabled (line 2), the script exits
immediately.

4. Observable outcome: precheck aborts with "command not found" instead of running checks.
The suggested fallback definitions ensure the script prints sensible messages when run
standalone.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** toolchain/bootstrap/precheck.sh
**Line:** 5:5
**Comment:**
	*Possible Bug: The script relies on helper functions (`log`, `ok`, `error`) and color variables (`MAGENTA`, `CYAN`, `COLOR_RESET`) that are not defined anywhere in this file, so if `precheck.sh` is executed directly in a clean shell (rather than being sourced from a wrapper that defines them), the first call to `log` will result in "command not found" and the script will exit due to `set -e`. Adding safe fallback definitions for these helpers ensures the script runs correctly both standalone and when invoked via a parent script that may already define them.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

Comment on lines +23 to +26
JOBS="$2"
shift
;;
-h | --help)
Copy link
Contributor

@codeant-ai codeant-ai bot Feb 4, 2026

Choose a reason for hiding this comment

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

Suggestion: The -j/--jobs argument handling assumes a value is always present; running the script with "-j" (without a value) will cause an extra shift on an empty argument list, triggering "shift: shift count out of range" and immediate exit due to set -e, instead of a clear error about the missing jobs value. The fix is to validate that a value exists for -j/--jobs and to shift exactly two arguments (option and value) when it is provided. [logic error]

Severity Level: Major ⚠️
- ❌ Local precheck crashes on `./mfc.sh precheck -j` misuse.
- ⚠️ Developer pre-push validation interrupted, confusing error messages.
Suggested change
JOBS="$2"
shift
;;
-h | --help)
if [[ $# -lt 2 ]] || [[ "$2" == -* ]]; then
echo "Precheck: -j|--jobs requires a positive integer argument."
exit 1
fi
JOBS="$2"
shift 2
continue
;;
-h|--help)
Steps of Reproduction ✅
1. From the repository root, run the precheck script directly:
`./toolchain/bootstrap/precheck.sh -j` (this file is `toolchain/bootstrap/precheck.sh`,
see lines 1-4 for `set -e` and the argument loop at lines 20-36).

2. Execution enters the while-case at line 20; the `-j|--jobs)` branch executes lines
22-25 which assign `JOBS="$2"` and perform a single `shift` (line 24), expecting a value
in `$2`.

3. Because no value was provided, `$2` is empty; the script continues and reaches the
unconditional `shift` at line 35. Bash then raises `shift: shift count out of range`
(shift with no positional parameters), and because `set -e` is active (line 2), the script
exits immediately with an error.

4. Observable outcome: abrupt exit with shell `shift` error message instead of a clear,
actionable error about the missing `-j` argument. The fix in the suggestion prevents the
out-of-range shift by validating `$2` and shifting by 2 (lines 22-25 area).
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** toolchain/bootstrap/precheck.sh
**Line:** 23:26
**Comment:**
	*Logic Error: The -j/--jobs argument handling assumes a value is always present; running the script with "-j" (without a value) will cause an extra shift on an empty argument list, triggering "shift: shift count out of range" and immediate exit due to `set -e`, instead of a clear error about the missing jobs value. The fix is to validate that a value exists for -j/--jobs and to shift exactly two arguments (option and value) when it is provided.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

Comment on lines +93 to +95
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The double-precision intrinsic check uses grep -qiR ... ./src/* 2>/dev/null inside an if without inspecting grep's exit status, so if grep fails for reasons like a missing ./src directory or read errors (exit status >1), the script silently treats it as "no matches" and later reports "Source lint passed," giving a false sense of success. The fix is to distinguish between "no matches" (exit status 1) and real grep errors (>1), and to mark the source lint as failed in the latter case instead of ignoring them. [logic error]

Severity Level: Major ⚠️
- ❌ Source lint can falsely report success when scanning fails.
- ⚠️ Local precheck trustworthiness reduced for wrong directory.
Suggested change
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/*; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
else
grep_status=$?
if [ "$grep_status" -gt 1 ]; then
error "Source lint failed: could not scan files for double precision intrinsics."
SOURCE_FAILED=1
FAILED=1
fi
Steps of Reproduction ✅
1. From repository root, rename or remove the `src` directory: `mv src src.bak` (this
causes `./src/*` glob to fail). The double-precision check is at
`toolchain/bootstrap/precheck.sh` lines 92-96 (`# Check for double precision intrinsics`
through `fi`).

2. Run `./toolchain/bootstrap/precheck.sh`. The script executes the `grep -qiR ... ./src/*
2>/dev/null` command at line 93; because `./src/*` doesn't expand to files, `grep` exits
with status 2 (error). stderr was redirected to /dev/null, so no error message is shown.

3. The `if` condition tests only for a successful match (exit status 0). On grep exit
status 2, the `if` body is skipped and `SOURCE_FAILED` remains unchanged. Later (lines
104-108) the script reports "Source lint passed." despite the scan failing.

4. Observable outcome: false-positive "Source lint passed" when files were not scanned.
The suggested change inspects grep's exit status and treats scanning errors as failures.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** toolchain/bootstrap/precheck.sh
**Line:** 93:95
**Comment:**
	*Logic Error: The double-precision intrinsic check uses `grep -qiR ... ./src/* 2>/dev/null` inside an `if` without inspecting grep's exit status, so if grep fails for reasons like a missing `./src` directory or read errors (exit status >1), the script silently treats it as "no matches" and later reports "Source lint passed," giving a false sense of success. The fix is to distinguish between "no matches" (exit status 1) and real grep errors (>1), and to mark the source lint as failed in the latter case instead of ignoring them.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 4, 2026

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

🤖 Fix all issues with AI agents
In `@toolchain/bootstrap/precheck.sh`:
- Around line 46-52: BEFORE_HASH and AFTER_HASH use the non-portable md5sum;
make the script detect available checksum tool and use it portably: add a
detection block that sets a MD5_CMD variable to "md5sum" if present, otherwise
to "md5 -r" (or fail with a clear error), then replace uses of "md5sum | cut -d'
' -f1" with a pipeline using $MD5_CMD that yields only the hash (accounting for
md5's output format) so the BEFORE_HASH and AFTER_HASH assignments continue to
produce the same single-hash string on Linux and macOS.
🧹 Nitpick comments (3)
mfc.sh (1)

43-46: Quote $@ to prevent word splitting.

The static analysis tool correctly flags that $@ should be double-quoted to prevent re-splitting of arguments containing spaces. While this follows the existing pattern in the file (lines 26, 30, 34, 36, 42), it's worth fixing for robustness.

Proposed fix
 elif [ "$1" '==' "precheck" ]; then
     . "$(pwd)/toolchain/bootstrap/python.sh"
 
-    shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
+    shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" "$@"; exit 0
 fi
.github/workflows/bench.yml (1)

29-32: Consider adding lint-gate dependency for consistency.

Unlike the test.yml workflow, the benchmark job doesn't depend on lint-gate. Since benchmarks are expensive HPC jobs, you may want to gate them behind lint checks as well to avoid wasting resources on code that will fail basic formatting/linting.

This could be intentional given the different trigger conditions (approved reviews or specific users), so flagging for consideration only.

Optional: Add lint-gate dependency
   self:
     name: "${{ matrix.name }} (${{ matrix.device }}${{ matrix.interface != 'none' && format('-{0}', matrix.interface) || '' }})"
     if: ${{ github.repository=='MFlowCode/MFC' && needs.file-changes.outputs.checkall=='true' && ((github.event_name=='pull_request_review' && github.event.review.state=='approved') || (github.event_name=='pull_request' && (github.event.pull_request.user.login=='sbryngelson' || github.event.pull_request.user.login=='wilfonba'))) }}
-    needs: file-changes
+    needs: [lint-gate, file-changes]

This would also require adding the lint-gate job definition to bench.yml.

toolchain/bootstrap/precheck.sh (1)

20-36: Edge case: -j without a value.

If -j is provided as the last argument without a value, $2 will be empty, and JOBS will be set to an empty string, which could cause issues downstream.

Proposed fix with validation
 while [[ $# -gt 0 ]]; do
     case "$1" in
         -j|--jobs)
+            if [[ -z "$2" || "$2" == -* ]]; then
+                echo "Error: -j/--jobs requires a numeric argument."
+                exit 1
+            fi
             JOBS="$2"
             shift
             ;;

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 a fast-failing lint gate to the CI pipeline and provides a local precheck command for developers to validate their code before pushing.

Changes:

  • Adds a lint-gate job to test.yml that runs formatting, spelling, and linting checks before expensive test matrix and HPC jobs start, providing faster feedback (1-2 minutes) for common issues
  • Adds concurrency groups to test.yml, coverage.yml, cleanliness.yml, and bench.yml workflows to automatically cancel superseded runs when new commits are pushed to the same branch
  • Adds a new ./mfc.sh precheck command that mirrors the CI lint-gate checks for local validation before pushing

Reviewed changes

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

Show a summary per file
File Description
toolchain/bootstrap/precheck.sh New script implementing local precheck functionality with formatting, spelling, and source lint checks
mfc.sh Integrates the new precheck command into the MFC toolchain
.github/workflows/test.yml Adds lint-gate job that must pass before test matrix runs, plus concurrency cancellation
.github/workflows/coverage.yml Adds concurrency group to cancel superseded runs
.github/workflows/cleanliness.yml Adds concurrency group to cancel superseded runs
.github/workflows/bench.yml Adds concurrency group to cancel superseded runs


while [[ $# -gt 0 ]]; do
case "$1" in
-j|--jobs)
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Missing validation for the --jobs argument value. If the user runs './mfc.sh precheck -j' without providing a number, JOBS will be set to an empty string, potentially causing issues when passed to './mfc.sh format'. Add a check to ensure $2 is provided and is a valid number before using it.

Suggested change
-j|--jobs)
-j|--jobs)
if [[ -z "$2" || "$2" == -* ]]; then
echo "Precheck: option '$1' requires a positive integer argument."
exit 1
fi
if ! [[ "$2" =~ ^[1-9][0-9]*$ ]]; then
echo "Precheck: jobs value '$2' is not a valid positive integer."
exit 1
fi

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +99
if grep -qiR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/* 2>/dev/null; then
error "Found raw OpenACC/OpenMP directives. Use macros instead."
SOURCE_FAILED=1
fi

# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi

# Check for junk code patterns
if grep -qiR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/* 2>/dev/null; then
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The stderr redirection '2>/dev/null' on grep commands differs from the CI implementation in test.yml (lines 38, 42, 46), which doesn't suppress stderr. This could cause the local precheck to silently hide errors that would be visible in CI, creating inconsistent behavior. Remove the '2>/dev/null' redirection to match CI behavior.

Suggested change
if grep -qiR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/* 2>/dev/null; then
error "Found raw OpenACC/OpenMP directives. Use macros instead."
SOURCE_FAILED=1
fi
# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
# Check for junk code patterns
if grep -qiR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/* 2>/dev/null; then
if grep -qiR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/*; then
error "Found raw OpenACC/OpenMP directives. Use macros instead."
SOURCE_FAILED=1
fi
# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/*; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
# Check for junk code patterns
if grep -qiR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/*; then

Copilot uses AI. Check for mistakes.
if ./mfc.sh spelling > /dev/null 2>&1; then
ok "Spell check passed."
else
error "Spell check failed."
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The spell check error message on line 69 doesn't provide guidance on how to see details or fix the issue. The lint error message on line 78 includes helpful guidance. Update the spell check error message to match this pattern, suggesting users run './mfc.sh spelling' for details.

Suggested change
error "Spell check failed."
error "Spell check failed. Run$MAGENTA ./mfc.sh spelling$COLOR_RESET for details."

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +99
if grep -qiR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/* 2>/dev/null; then
error "Found raw OpenACC/OpenMP directives. Use macros instead."
SOURCE_FAILED=1
fi

# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi

# Check for junk code patterns
if grep -qiR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/* 2>/dev/null; then
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The error messages for source lint failures don't provide enough actionable information. Users are told that raw directives or forbidden patterns were found, but not shown where they are or how to find them. Consider either showing the grep output or providing guidance on how to locate the offending code.

Suggested change
if grep -qiR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/* 2>/dev/null; then
error "Found raw OpenACC/OpenMP directives. Use macros instead."
SOURCE_FAILED=1
fi
# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
# Check for junk code patterns
if grep -qiR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/* 2>/dev/null; then
if grep -niR '!\$acc\|!\$omp' --exclude="parallel_macros.fpp" --exclude="acc_macros.fpp" --exclude="omp_macros.fpp" --exclude="shared_parallel_macros.fpp" --exclude="syscheck.fpp" ./src/* 2>/dev/null; then
error "Found raw OpenACC/OpenMP directives. Use macros instead."
SOURCE_FAILED=1
fi
# Check for double precision intrinsics
if grep -niR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
# Check for junk code patterns
if grep -niR -e '\.\.\.' -e '\-\-\-' -e '===' ./src/* 2>/dev/null; then

Copilot uses AI. Check for mistakes.

- name: Lint Source - No Double Precision Intrinsics
run: |
! grep -iR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/*
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The pattern 'double\ precision' (with backslash before space) will match a literal backslash followed by a space, not just a space. In grep basic regex without -E flag, the backslash before a space has no special meaning. The pattern should be 'double precision' (without backslash) to match "double precision" with a space. This affects both the CI workflow and local precheck script.

Suggested change
! grep -iR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/*
! grep -iR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/*

Copilot uses AI. Check for mistakes.
fi

# Check for double precision intrinsics
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The pattern 'double\ precision' (with backslash before space) will match a literal backslash followed by a space, not just a space. In grep basic regex, the backslash before a space has no special meaning. The pattern should be 'double precision' (without backslash) to match "double precision" with a space. This matches the same issue in the CI workflow.

Suggested change
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then

Copilot uses AI. Check for mistakes.
# Check if formatting changed any Fortran/Python files
AFTER_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
if [ "$BEFORE_HASH" != "$AFTER_HASH" ]; then
error "Code is not formatted. Run$MAGENTA ./mfc.sh format$COLOR_RESET to fix."
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The error message says "Run ./mfc.sh format to fix" but the formatting has already been applied by the precheck script itself (line 47). The files are already formatted, so the user just needs to review and stage the changes. Consider updating the message to something like "Code has been auto-formatted. Review and commit the changes." to better reflect what happened.

Suggested change
error "Code is not formatted. Run$MAGENTA ./mfc.sh format$COLOR_RESET to fix."
error "Code has been auto-formatted. Review and commit the changes."

Copilot uses AI. Check for mistakes.
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 6 files

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="toolchain/bootstrap/precheck.sh">

<violation number="1" location="toolchain/bootstrap/precheck.sh:22">
P3: Validate that --jobs has a value before shifting so missing arguments produce a clear error instead of exiting with a shift error.</violation>
</file>

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

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on March 8

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

# 1. Check formatting
log "[$CYAN 1/4$COLOR_RESET] Checking$MAGENTA formatting$COLOR_RESET..."
# Capture state before formatting
BEFORE_HASH=$(git diff -- '*.f90' '*.fpp' '*.py' 2>/dev/null | md5sum | cut -d' ' -f1)
Copy link

Choose a reason for hiding this comment

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

md5sum unavailable on macOS breaks local precheck

Medium Severity

The precheck.sh script uses md5sum to hash git diff output, but md5sum is a GNU coreutils command not available on macOS by default. macOS provides md5 instead, or requires installing coreutils via Homebrew. Since precheck is designed for local development use and the script has set -e enabled, macOS developers will see a "command not found" error when running ./mfc.sh precheck. A cross-platform alternative like shasum -a 256 or a conditional using md5 -q for macOS would resolve this.

Additional Locations (1)

Fix in Cursor Fix in Web

- Add cross-platform hash function (macOS uses md5, Linux uses md5sum)
- Validate -j/--jobs argument (require value, must be numeric)
- Improve error messages with actionable guidance
- Clarify that formatting has been auto-applied when check fails

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 `@toolchain/bootstrap/precheck.sh`:
- Around line 113-116: The existing grep pattern uses the token "d0" which is
too narrow; update the check in the if-condition (the grep command that
currently searches for 'double_precision\|... \|d0') to use an extended regex
that matches Fortran double-precision literals with a 'd' exponent (e.g. 1d-2,
5.0d-11) and switch to extended regex mode (grep -E or --extended-regexp).
Replace the 'd0' fragment with a pattern such as
'([0-9]+(\.[0-9]*)?|\.[0-9]+)d[+-]?[0-9]+' so hardcoded double literals like
1d-2 and 5.0d-11 are detected while avoiding accidental matches to non-literals.

Comment on lines +113 to +116
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, locate and read the precheck.sh file
find . -name "precheck.sh" -type f

Repository: MFlowCode/MFC

Length of output: 90


🏁 Script executed:

# Read the specific lines mentioned in the review
sed -n '113,116p' ./toolchain/bootstrap/precheck.sh

Repository: MFlowCode/MFC

Length of output: 433


🏁 Script executed:

# Check context around those lines
sed -n '100,130p' ./toolchain/bootstrap/precheck.sh

Repository: MFlowCode/MFC

Length of output: 1229


🏁 Script executed:

# Check for potential false positives from 'd0' pattern in fortran source files
echo "=== Potential false positives (d0 in variable names or non-literal contexts) ==="
grep -riH 'd0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src --include="*.f90" --include="*.fpp" 2>/dev/null | grep -v '\.[0-9]*[dD]' | head -30 || echo "No false positive candidates found"

Repository: MFlowCode/MFC

Length of output: 197


🏁 Script executed:

# Check for actual double precision literals (what the pattern should catch)
echo "=== Actual double precision literals (intended matches) ==="
grep -rEH '[0-9]+\.[0-9]*[dD][+-]?[0-9]+|[0-9]+[dD][+-]?[0-9]+' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src --include="*.f90" --include="*.fpp" 2>/dev/null | head -20 || echo "No double precision literals found"

Repository: MFlowCode/MFC

Length of output: 701


🏁 Script executed:

# Count total d0 matches to understand the scope
echo "=== Total 'd0' matches in source ==="
grep -ric 'd0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src --include="*.f90" --include="*.fpp" 2>/dev/null | awk -F: '{sum+=$2} END {print "Total d0 matches:", sum}'

Repository: MFlowCode/MFC

Length of output: 113


The d0 pattern is too broad and fails to catch most double precision literals.

The pattern d0 is intended to catch hardcoded double precision literals like 1.0d0, but it fails to match actual double precision literals in the codebase such as 1d-2 and 5.0d-11 (which contain d- not d0). Additionally, the pattern would match variable names like reserved0 if they weren't already excluded.

The codebase contains double precision literals that should be flagged:

  • src/pre_process/m_start_up.fpp: 1d-2
  • src/simulation/m_bubbles_EL.fpp: 5.0d-11

Use a more specific regex to match floating-point literals with d exponent notation and ensure all violations are caught:

Proposed fix
-if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
+if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
     error "Found double precision intrinsics. Use generic intrinsics."
     SOURCE_FAILED=1
 fi
+# Separate check for double precision literals (e.g., 1.0d0, 1d-2, 5.0d-11)
+if grep -qER '[0-9]+\.?[0-9]*[dD][+-]?[0-9]+' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
+    error "Found double precision literals (e.g., 1.0d0). Use wp kind parameter."
+    SOURCE_FAILED=1
+fi
📝 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
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh\|d0' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
if grep -qiR 'double_precision\|dsqrt\|dexp\|dlog\|dble\|dabs\|double\ precision\|real(8)\|real(4)\|dprod\|dmin\|dmax\|dfloat\|dreal\|dcos\|dsin\|dtan\|dsign\|dtanh\|dsinh\|dcosh' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision intrinsics. Use generic intrinsics."
SOURCE_FAILED=1
fi
# Separate check for double precision literals (e.g., 1.0d0, 1d-2, 5.0d-11)
if grep -qER '[0-9]+\.?[0-9]*[dD][+-]?[0-9]+' --exclude-dir=syscheck --exclude="*nvtx*" --exclude="*precision_select*" ./src/* 2>/dev/null; then
error "Found double precision literals (e.g., 1.0d0). Use wp kind parameter."
SOURCE_FAILED=1
fi
🤖 Prompt for AI Agents
In `@toolchain/bootstrap/precheck.sh` around lines 113 - 116, The existing grep
pattern uses the token "d0" which is too narrow; update the check in the
if-condition (the grep command that currently searches for
'double_precision\|... \|d0') to use an extended regex that matches Fortran
double-precision literals with a 'd' exponent (e.g. 1d-2, 5.0d-11) and switch to
extended regex mode (grep -E or --extended-regexp). Replace the 'd0' fragment
with a pattern such as '([0-9]+(\.[0-9]*)?|\.[0-9]+)d[+-]?[0-9]+' so hardcoded
double literals like 1d-2 and 5.0d-11 are detected while avoiding accidental
matches to non-literals.

Add wait-for-tests job that polls GitHub API to ensure:
- Lint Gate passes first (fast fail)
- All Github test jobs complete successfully
- Only then do benchmark jobs start

This prevents wasting HPC resources on benchmarking code that
fails tests, while preserving the existing maintainer approval gate.

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 @.github/workflows/bench.yml:
- Around line 37-79: Replace the current check-runs polling with logic that
scopes to the latest Test Suite workflow run and inspects that run's jobs: use
the Actions workflow-runs endpoint to find the most recent run for the Test
Suite (scoped to the PR/head SHA stored in SHA), then call the workflow run jobs
endpoint to get job-level conclusions for that run; look up the "Lint Gate" job
conclusion and all jobs whose name starts with "Github" from that run (not
aggregated check-runs), and immediately fail if "Lint Gate" is any terminal
non-success (failure, cancelled, timed_out, skipped, neutral, etc.), or if any
"Github"-prefixed job has a terminal non-success conclusion; only wait/poll
while the latest run has non-terminal in-progress/null conclusions, and loop by
re-querying the latest workflow run id each iteration so reruns don’t get
blocked by earlier runs.
- Around line 29-36: Update the workflow job "wait-for-tests" to remove the
unnecessary permissions entry granting actions: read and instead grant only
checks: read so the "Wait for Test Suite to Pass" step can call the Checks API;
locate the permissions block for the wait-for-tests job (associated with the job
name wait-for-tests and the step named "Wait for Test Suite to Pass") and
replace actions: read with checks: read.

Comment on lines +29 to +36
wait-for-tests:
name: Wait for Test Suite
runs-on: ubuntu-latest
steps:
- name: Wait for Test Suite to Pass
env:
GH_TOKEN: ${{ github.token }}
run: |
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/bench.yml

Repository: MFlowCode/MFC

Length of output: 8041


🏁 Script executed:

# Check for any actions API calls in the workflow
rg "actions/runs|actions/workflows" .github/workflows/bench.yml

# Also verify the check-runs API endpoint requirements
echo "=== Checking all gh api calls in wait-for-tests job ==="
sed -n '36,79p' .github/workflows/bench.yml | grep -E "gh api|--jq"

Repository: MFlowCode/MFC

Length of output: 704


🏁 Script executed:

# Check if there are any other workflow files that might show permission patterns
find .github/workflows -name "*.yml" -type f | head -10 | xargs grep -l "permissions:" 2>/dev/null

# Also check if this is a public repo to understand default token permissions
git remote -v | head -5

Repository: MFlowCode/MFC

Length of output: 345


🏁 Script executed:

# Check what permissions are used in those files
echo "=== deploy-tap.yml permissions ==="
grep -A 5 "permissions:" .github/workflows/deploy-tap.yml | head -15

echo -e "\n=== line-count.yml permissions ==="
grep -A 5 "permissions:" .github/workflows/line-count.yml | head -15

# Also check if the repo has a default permissions setting at workflow level
grep -n "permissions:" .github/workflows/bench.yml

Repository: MFlowCode/MFC

Length of output: 511


🌐 Web query:

GitHub Actions default GITHUB_TOKEN permissions check-runs API public repository

💡 Result:

  • Default GITHUB_TOKEN permissions (public repo): By default (for newly created repos in a personal account), GITHUB_TOKEN is restricted to read access for contents and packages only; org repos inherit the org’s setting. You can switch the repo/org default to a more permissive “read/write for all scopes” in Settings → Actions → General → Workflow permissions. [1]
  • Check Runs API needs checks: write: Creating/managing check runs via the REST API requires a token with Checks (write) permission, and GitHub notes that write access to Checks via the REST API is only available to GitHub Apps (not OAuth apps/authenticated users). [2]
  • So, why it fails by default: With the restricted default, GITHUB_TOKEN won’t have checks: write, so calls like Create a check run will be denied unless you grant that permission. [1][2]
  • Fix in workflow: explicitly grant it:
    permissions:
      checks: write
    (Any permission you don’t list is set to none.) [3]
  • Fork PR caveat (public repos): workflows triggered from pull requests from public forks get a read-only token regardless of these settings, so creating/updating check runs may still be blocked in that scenario. [3]

Sources: [1] GitHub Docs – repository Actions settings / default GITHUB_TOKEN permissions; [2] GitHub Docs – REST API “check runs” (Create a check run) permission notes; [3] GitHub Changelog – permissions: syntax + public-fork PR read-only behavior.


Remove unnecessary actions: read permission; add only checks: read.

The job makes read-only calls to the Checks API endpoint (repos/{owner}/{repo}/commits/{ref}/check-runs), not the Actions API. With restricted default GITHUB_TOKEN permissions, the job will fail without explicit read access to checks. Add checks: read only:

Corrected permissions block
  wait-for-tests:
    name: Wait for Test Suite
    runs-on: ubuntu-latest
+   permissions:
+     checks: read
📝 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
wait-for-tests:
name: Wait for Test Suite
runs-on: ubuntu-latest
steps:
- name: Wait for Test Suite to Pass
env:
GH_TOKEN: ${{ github.token }}
run: |
wait-for-tests:
name: Wait for Test Suite
runs-on: ubuntu-latest
permissions:
checks: read
steps:
- name: Wait for Test Suite to Pass
env:
GH_TOKEN: ${{ github.token }}
run: |
🤖 Prompt for AI Agents
In @.github/workflows/bench.yml around lines 29 - 36, Update the workflow job
"wait-for-tests" to remove the unnecessary permissions entry granting actions:
read and instead grant only checks: read so the "Wait for Test Suite to Pass"
step can call the Checks API; locate the permissions block for the
wait-for-tests job (associated with the job name wait-for-tests and the step
named "Wait for Test Suite to Pass") and replace actions: read with checks:
read.

Comment on lines +37 to +79
echo "Waiting for Test Suite workflow to complete..."
SHA="${{ github.event.pull_request.head.sha || github.sha }}"

# Poll every 60 seconds for up to 3 hours
for i in $(seq 1 180); do
# Get the Test Suite workflow runs for this commit
STATUS=$(gh api repos/${{ github.repository }}/commits/$SHA/check-runs \
--jq '.check_runs[] | select(.name == "Lint Gate") | .conclusion' | head -1)

if [ "$STATUS" = "success" ]; then
echo "Lint Gate passed. Checking test jobs..."

# Check if any Github test jobs failed
FAILED=$(gh api repos/${{ github.repository }}/commits/$SHA/check-runs \
--jq '[.check_runs[] | select(.name | startswith("Github")) | select(.conclusion == "failure")] | length')

if [ "$FAILED" != "0" ]; then
echo "::error::Test Suite has failing jobs. Benchmarks will not run."
exit 1
fi

# Check if Github tests are still running
PENDING=$(gh api repos/${{ github.repository }}/commits/$SHA/check-runs \
--jq '[.check_runs[] | select(.name | startswith("Github")) | select(.conclusion == null)] | length')

if [ "$PENDING" = "0" ]; then
echo "All Test Suite jobs completed successfully!"
exit 0
fi

echo "Tests still running ($PENDING pending)..."
elif [ "$STATUS" = "failure" ]; then
echo "::error::Lint Gate failed. Benchmarks will not run."
exit 1
else
echo "Lint Gate status: ${STATUS:-pending}..."
fi

sleep 60
done

echo "::error::Timeout waiting for Test Suite to complete."
exit 1
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/test.yml | head -100

Repository: MFlowCode/MFC

Length of output: 3596


🏁 Script executed:

rg -n "name:" .github/workflows/test.yml | grep -E "(Lint|Github|GitHub)"

Repository: MFlowCode/MFC

Length of output: 286


🏁 Script executed:

cat -n .github/workflows/bench.yml | sed -n '37,79p'

Repository: MFlowCode/MFC

Length of output: 2205


Scope polling to the latest Test Suite run and handle terminal non-success states.

The check-runs endpoint aggregates across reruns for the same SHA, so a prior failed run can block benchmarks even if a newer run succeeds. Additionally, skipped, cancelled, timed_out, or other non-success states for the Lint Gate job will currently hang until timeout instead of failing fast, as they fall through to the status logging logic and continue polling. Switch to the workflow runs and jobs endpoints to scope to the latest Test Suite run, and explicitly handle all terminal non-success states.

The job names are confirmed as correct: "Lint Gate" (line 11 of test.yml) and "Github" (line 64 of test.yml).

🛠️ Suggested update to poll the latest Test Suite run
-            # Get the Test Suite workflow runs for this commit
-            STATUS=$(gh api repos/${{ github.repository }}/commits/$SHA/check-runs \
-              --jq '.check_runs[] | select(.name == "Lint Gate") | .conclusion' | head -1)
+            # Get the latest Test Suite workflow run for this commit
+            RUN_ID=$(gh api repos/${{ github.repository }}/actions/workflows/test.yml/runs?head_sha=$SHA \
+              --jq '.workflow_runs | sort_by(.created_at) | last | .id')
+
+            if [ -z "$RUN_ID" ]; then
+              echo "No Test Suite run found yet..."
+              sleep 60
+              continue
+            fi
+
+            STATUS=$(gh api repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \
+              --jq '.jobs[] | select(.name == "Lint Gate") | .conclusion' | head -1)

-              FAILED=$(gh api repos/${{ github.repository }}/commits/$SHA/check-runs \
-                --jq '[.check_runs[] | select(.name | startswith("Github")) | select(.conclusion == "failure")] | length')
+              FAILED=$(gh api repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \
+                --jq '[.jobs[] | select(.name | startswith("Github")) | select(.conclusion == "failure")] | length')

-              PENDING=$(gh api repos/${{ github.repository }}/commits/$SHA/check-runs \
-                --jq '[.check_runs[] | select(.name | startswith("Github")) | select(.conclusion == null)] | length')
+              PENDING=$(gh api repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \
+                --jq '[.jobs[] | select(.name | startswith("Github")) | select(.conclusion == null)] | length')

-            elif [ "$STATUS" = "failure" ]; then
+            elif [ "$STATUS" = "failure" ] || [ "$STATUS" = "cancelled" ] || [ "$STATUS" = "timed_out" ] || [ "$STATUS" = "skipped" ]; then
               echo "::error::Lint Gate failed. Benchmarks will not run."
               exit 1
🤖 Prompt for AI Agents
In @.github/workflows/bench.yml around lines 37 - 79, Replace the current
check-runs polling with logic that scopes to the latest Test Suite workflow run
and inspects that run's jobs: use the Actions workflow-runs endpoint to find the
most recent run for the Test Suite (scoped to the PR/head SHA stored in SHA),
then call the workflow run jobs endpoint to get job-level conclusions for that
run; look up the "Lint Gate" job conclusion and all jobs whose name starts with
"Github" from that run (not aggregated check-runs), and immediately fail if
"Lint Gate" is any terminal non-success (failure, cancelled, timed_out, skipped,
neutral, etc.), or if any "Github"-prefixed job has a terminal non-success
conclusion; only wait/poll while the latest run has non-terminal
in-progress/null conclusions, and loop by re-querying the latest workflow run id
each iteration so reruns don’t get blocked by earlier runs.

- Add .githooks/pre-commit that runs ./mfc.sh precheck before commits
- Auto-install hook on first ./mfc.sh invocation (symlinks to .git/hooks/)
- Hook only installs once; subsequent runs skip if already present
- Developers can bypass with: git commit --no-verify

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="mfc.sh">

<violation number="1" location="mfc.sh:14">
P2: The auto-install hook check only supports repositories where `.git` is a directory; in worktrees `.git` is a file, so the hook never installs and precheck won’t run on commit. Consider resolving the git dir via `git rev-parse` so it works in worktrees/submodules too.</violation>
</file>

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

Comment on lines +14 to +17
if [ -d "$(pwd)/.git" ] && [ ! -e "$(pwd)/.git/hooks/pre-commit" ] && [ -f "$(pwd)/.githooks/pre-commit" ]; then
ln -sf "$(pwd)/.githooks/pre-commit" "$(pwd)/.git/hooks/pre-commit"
log "Installed git pre-commit hook (runs$MAGENTA ./mfc.sh precheck$COLOR_RESET before commits)."
fi
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 4, 2026

Choose a reason for hiding this comment

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

P2: The auto-install hook check only supports repositories where .git is a directory; in worktrees .git is a file, so the hook never installs and precheck won’t run on commit. Consider resolving the git dir via git rev-parse so it works in worktrees/submodules too.

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

<comment>The auto-install hook check only supports repositories where `.git` is a directory; in worktrees `.git` is a file, so the hook never installs and precheck won’t run on commit. Consider resolving the git dir via `git rev-parse` so it works in worktrees/submodules too.</comment>

<file context>
@@ -10,6 +10,12 @@ fi
 . "$(pwd)/toolchain/util.sh"
 
+# Auto-install git pre-commit hook (once, silently)
+if [ -d "$(pwd)/.git" ] && [ ! -e "$(pwd)/.git/hooks/pre-commit" ] && [ -f "$(pwd)/.githooks/pre-commit" ]; then
+    ln -sf "$(pwd)/.githooks/pre-commit" "$(pwd)/.git/hooks/pre-commit"
+    log "Installed git pre-commit hook (runs$MAGENTA ./mfc.sh precheck$COLOR_RESET before commits)."
</file context>
Suggested change
if [ -d "$(pwd)/.git" ] && [ ! -e "$(pwd)/.git/hooks/pre-commit" ] && [ -f "$(pwd)/.githooks/pre-commit" ]; then
ln -sf "$(pwd)/.githooks/pre-commit" "$(pwd)/.git/hooks/pre-commit"
log "Installed git pre-commit hook (runs$MAGENTA ./mfc.sh precheck$COLOR_RESET before commits)."
fi
git_dir="$(git rev-parse --git-dir 2>/dev/null)"
hooks_dir="$(git rev-parse --git-path hooks 2>/dev/null)"
if [ -n "$hooks_dir" ] && [ -d "$git_dir" ] && [ ! -e "$hooks_dir/pre-commit" ] && [ -f "$(pwd)/.githooks/pre-commit" ]; then
ln -sf "$(pwd)/.githooks/pre-commit" "$hooks_dir/pre-commit"
log "Installed git pre-commit hook (runs$MAGENTA ./mfc.sh precheck$COLOR_RESET before commits)."
fi
Fix with Cubic

sbryngelson and others added 3 commits February 4, 2026 18:41
Auto-detect available CPUs for parallel formatting:
- Linux: nproc
- macOS: sysctl -n hw.ncpu
- Fallback: 4

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Keep both: pre-commit hook auto-install and 'Starting...' log message

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 `@mfc.sh`:
- Around line 65-68: The precheck branch in mfc.sh currently calls precheck.sh
with unquoted $@ which can split arguments containing spaces; update the
invocation in the elif block that sources toolchain/bootstrap/precheck.sh to use
"$@" (preserve argument boundaries) so the call is .
"$(pwd)/toolchain/bootstrap/precheck.sh" "$@"; also consider applying the same
change to the similar invocations for lint, format and spelling for consistency.

Comment on lines +65 to +68
elif [ "$1" '==' "precheck" ]; then
. "$(pwd)/toolchain/bootstrap/python.sh"

shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
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

Quote $@ to preserve argument boundaries.

The unquoted $@ on line 68 will re-split arguments containing spaces (e.g., ./mfc.sh precheck -j "4 cores" would incorrectly become three separate arguments). While this follows the existing pattern used by lint, format, and spelling commands, it's still a latent bug.

Proposed fix
 elif [ "$1" '==' "precheck" ]; then
     . "$(pwd)/toolchain/bootstrap/python.sh"

-    shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
+    shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" "$@"; exit 0
 fi

Note: Consider applying this fix to the other commands (lint, format, spelling) for consistency, though that's outside the scope of this PR.

🧰 Tools
🪛 Shellcheck (0.11.0)

[error] 68-68: Double quote array expansions to avoid re-splitting elements.

(SC2068)

🤖 Prompt for AI Agents
In `@mfc.sh` around lines 65 - 68, The precheck branch in mfc.sh currently calls
precheck.sh with unquoted $@ which can split arguments containing spaces; update
the invocation in the elif block that sources toolchain/bootstrap/precheck.sh to
use "$@" (preserve argument boundaries) so the call is .
"$(pwd)/toolchain/bootstrap/precheck.sh" "$@"; also consider applying the same
change to the similar invocations for lint, format and spelling for consistency.

Register precheck in commands.py so it appears in:
- Shell tab completion
- CLI documentation
- ./mfc.sh precheck --help

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 `@toolchain/mfc/cli/commands.py`:
- Around line 758-765: The Argument entry for "jobs" is missing type and default
so argparse will treat values as strings and return None when omitted; update
the Argument(...) for name="jobs" to include type=int and default=1 (and keep
short="j", help, metavar), or replace the explicit argument with
include_common=["jobs"] to reuse the COMMON_JOBS definition used elsewhere;
ensure you modify the Argument(...) block that defines "jobs" or swap it to
include_common so the parser receives an integer and a default.

Comment on lines +758 to +765
arguments=[
Argument(
name="jobs",
short="j",
help="Number of parallel jobs for formatting.",
metavar="N",
),
],
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

Missing type and default for jobs argument.

The jobs argument lacks type=int and default=1, which other job-related arguments define (see COMMON_JOBS at lines 71-78). Without type=int, argparse will treat the value as a string rather than an integer. Without a default, the argument will be None when unspecified.

Consider either adding the missing attributes or using include_common=["jobs"] to reuse the common definition.

Proposed fix
 PRECHECK_COMMAND = Command(
     name="precheck",
     help="Run CI lint checks locally before committing.",
     description="Run the same fast checks that CI runs before expensive tests start. Use this locally before pushing to catch issues early.",
     arguments=[
         Argument(
             name="jobs",
             short="j",
             help="Number of parallel jobs for formatting.",
+            type=int,
+            default=1,
             metavar="N",
         ),
     ],

Alternatively, use the common set:

 PRECHECK_COMMAND = Command(
     name="precheck",
     help="Run CI lint checks locally before committing.",
     description="Run the same fast checks that CI runs before expensive tests start. Use this locally before pushing to catch issues early.",
+    include_common=["jobs"],
-    arguments=[
-        Argument(
-            name="jobs",
-            short="j",
-            help="Number of parallel jobs for formatting.",
-            metavar="N",
-        ),
-    ],
+    arguments=[],
📝 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
arguments=[
Argument(
name="jobs",
short="j",
help="Number of parallel jobs for formatting.",
metavar="N",
),
],
arguments=[
Argument(
name="jobs",
short="j",
help="Number of parallel jobs for formatting.",
type=int,
default=1,
metavar="N",
),
],
🤖 Prompt for AI Agents
In `@toolchain/mfc/cli/commands.py` around lines 758 - 765, The Argument entry for
"jobs" is missing type and default so argparse will treat values as strings and
return None when omitted; update the Argument(...) for name="jobs" to include
type=int and default=1 (and keep short="j", help, metavar), or replace the
explicit argument with include_common=["jobs"] to reuse the COMMON_JOBS
definition used elsewhere; ensure you modify the Argument(...) block that
defines "jobs" or swap it to include_common so the parser receives an integer
and a default.

When completion scripts are auto-regenerated, also update the installed
completions at ~/.local/share/mfc/completions/ if they exist.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
sbryngelson and others added 2 commits February 4, 2026 20:39
When installed shell completions are auto-updated, print a message
with the appropriate source command for the user's detected shell.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, installed completions only updated when source files
changed and regeneration occurred. Now we also check if the installed
completions are older than the generated ones (e.g., after git pull
brings new pre-generated completions).

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 `@toolchain/main.py`:
- Around line 35-48: The copy operations that update completions in install_dir
are unguarded and can raise OSError on read-only installs; wrap the shutil.copy2
calls inside try/except and make them best-effort: for each copy (for mfc.bash
and _mfc) catch OSError/PermissionError (or Exception) and on failure log a
non-fatal warning via cons.print that the completion update failed and continue
startup; apply the same try/except approach to the identical copy block around
lines 62-67 so neither __ensure_generated_files nor CLI startup aborts due to
permission issues.

Comment on lines 35 to 48
install_dir = Path.home() / ".local" / "share" / "mfc" / "completions"
if install_dir.exists():
bash_updated = (install_dir / "mfc.bash").exists()
zsh_updated = (install_dir / "_mfc").exists()
if bash_updated:
shutil.copy2(completions_dir / "mfc.bash", install_dir / "mfc.bash")
if zsh_updated:
shutil.copy2(completions_dir / "_mfc", install_dir / "_mfc")
if bash_updated or zsh_updated:
# Detect user's shell and show appropriate source command
if "zsh" in os.environ.get("SHELL", "") and zsh_updated:
cons.print(f"[dim]Tab completions updated. Run: source {install_dir}/_mfc[/dim]")
elif bash_updated:
cons.print(f"[dim]Tab completions updated. Run: source {install_dir}/mfc.bash[/dim]")
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 | 🟠 Major

Guard completion copies against permission errors to avoid blocking CLI startup.

__ensure_generated_files() runs on every invocation, so a read‑only ~/.local/share/mfc/completions will raise OSError and abort the command. Make the copy best‑effort and warn instead.

🛠️ Suggested fix (best‑effort copy with warning)
@@
-        if bash_updated:
-            shutil.copy2(completions_dir / "mfc.bash", install_dir / "mfc.bash")
-        if zsh_updated:
-            shutil.copy2(completions_dir / "_mfc", install_dir / "_mfc")
+        try:
+            if bash_updated:
+                shutil.copy2(completions_dir / "mfc.bash", install_dir / "mfc.bash")
+            if zsh_updated:
+                shutil.copy2(completions_dir / "_mfc", install_dir / "_mfc")
+        except OSError as exc:
+            cons.print(
+                f"[dim]Warning: couldn't update installed completions in {install_dir}: {exc}[/dim]"
+            )
@@
-        if src.exists() and dst.exists() and os.path.getmtime(src) > os.path.getmtime(dst):
-            shutil.copy2(src, dst)
-            updated.append(("bash" if src_name == "mfc.bash" else "zsh", dst))
+        if src.exists() and dst.exists() and os.path.getmtime(src) > os.path.getmtime(dst):
+            try:
+                shutil.copy2(src, dst)
+            except OSError as exc:
+                cons.print(
+                    f"[dim]Warning: couldn't update installed completions in {install_dir}: {exc}[/dim]"
+                )
+                continue
+            updated.append(("bash" if src_name == "mfc.bash" else "zsh", dst))

Also applies to: 62-67

🤖 Prompt for AI Agents
In `@toolchain/main.py` around lines 35 - 48, The copy operations that update
completions in install_dir are unguarded and can raise OSError on read-only
installs; wrap the shutil.copy2 calls inside try/except and make them
best-effort: for each copy (for mfc.bash and _mfc) catch OSError/PermissionError
(or Exception) and on failure log a non-fatal warning via cons.print that the
completion update failed and continue startup; apply the same try/except
approach to the identical copy block around lines 62-67 so neither
__ensure_generated_files nor CLI startup aborts due to permission issues.

sbryngelson and others added 3 commits February 4, 2026 21:11
- Remove -o bashdefault from bash complete command to prevent
  falling back to directory completion when no matches found
- Add explicit : (no-op) for zsh commands without arguments to
  prevent default file/directory completion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-install completions on first mfc.sh run (via main.py)
- Add -o filenames back to bash complete (needed for file completion)
- Keep -o bashdefault removed to prevent directory fallback
- Simplify code by having __update_installed_completions handle both
  install and update cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move completion auto-install to mfc.sh so it runs for ALL commands
including help, precheck, etc. This ensures completions are always
set up on first run.

- Install completion files to ~/.local/share/mfc/completions/
- Add source line to .bashrc or fpath to .zshrc
- Tell user to restart shell or source the file
- main.py now only handles updates when generated files change

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

codeant-ai bot commented Feb 5, 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:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Feb 5, 2026
# Add to shell rc file based on current shell
if [[ "$SHELL" == *"zsh"* ]]; then
RC_FILE="$HOME/.zshrc"
RC_LINE="fpath=(\"$COMPLETION_DIR\" \$fpath)"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: For zsh, the completion directory is added to fpath but compinit is not rerun, so on a typical .zshrc where compinit is called earlier in the file the newly added directory will not actually be used for completions despite the log message claiming they are installed. [logic error]

Severity Level: Major ⚠️
- ⚠️ Zsh tab completions not active after installation.
- ⚠️ Users misled by completion-installed success message.
Suggested change
RC_LINE="fpath=(\"$COMPLETION_DIR\" \$fpath)"
RC_LINE="fpath=(\"$COMPLETION_DIR\" \$fpath); autoload -Uz compinit; compinit"
Steps of Reproduction ✅
1. Run ./mfc.sh from the repo root on a system without the completions directory; the
script creates completions and sets RC_LINE at mfc.sh:29 (PR hunk).

2. mfc.sh appends RC_LINE to the user's ~/.zshrc (code path around mfc.sh:37-41) but does
not re-run compinit in the current shell.

3. If the user's ~/.zshrc contains an earlier compinit invocation (common setup: "autoload
-Uz compinit; compinit"), the newly appended fpath entry will be processed only on next
shell start. The current shell will not pick up the new fpath, so completions are
effectively inactive.

4. The script logs "Installed tab completions. Restart shell or run: source ..." at
mfc.sh:43, which can mislead users into thinking sourcing the completion file alone is
sufficient; without running compinit after modifying fpath the completion will still not
be activated in zsh.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** mfc.sh
**Line:** 29:29
**Comment:**
	*Logic Error: For zsh, the completion directory is added to `fpath` but `compinit` is not rerun, so on a typical `.zshrc` where `compinit` is called earlier in the file the newly added directory will not actually be used for completions despite the log message claiming they are installed.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

elif [ "$1" '==' "precheck" ]; then
. "$(pwd)/toolchain/bootstrap/python.sh"

shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The arguments to the precheck subcommand are expanded as $@ instead of "$@", so any argument containing whitespace will be split into multiple arguments when passed to precheck.sh, causing its CLI parsing to misbehave for such inputs. [logic error]

Severity Level: Major ⚠️
- ⚠️ Local precheck CLI parsing can break with spaced arguments.
- ⚠️ Developers using filenames/paths with spaces affected.
Suggested change
shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0
shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" "$@"; exit 0
Steps of Reproduction ✅
1. From the repository root, run the precheck command with an argument that contains a
space, e.g.:

   ./mfc.sh precheck "path/with space/file.txt"

   (mfc.sh branch handling starts at mfc.sh:92 in the PR new hunk).

2. Execution enters the precheck branch at mfc.sh:92 and sources python bootstrap at
mfc.sh:93.

3. mfc.sh then executes (mfc.sh:95) the line:

   shift; . "$(pwd)/toolchain/bootstrap/precheck.sh" $@; exit 0

   Because $@ is unquoted, the single argument "path/with space/file.txt" is split into
   two words by the shell.

4. The sourced script toolchain/bootstrap/precheck.sh receives two separate arguments
instead of one, causing its argument parsing to behave incorrectly (incorrect
option/filename boundaries) or to error. This reproduces the described misbehavior.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** mfc.sh
**Line:** 95:95
**Comment:**
	*Logic Error: The arguments to the `precheck` subcommand are expanded as `$@` instead of `"$@"`, so any argument containing whitespace will be split into multiple arguments when passed to `precheck.sh`, causing its CLI parsing to misbehave for such inputs.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

#!/bin/bash
set -e
set -o pipefail

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The script assumes it is always run from the repository root by hardcoding ./mfc.sh and ./src/* paths, so invoking precheck.sh from any other working directory (for example, running it directly from toolchain/bootstrap/) will cause it to fail to find mfc.sh or to skip source checks; computing the repo root from the script location and changing to it makes these relative paths reliable. [possible bug]

Severity Level: Major ⚠️
- ❌ Local precheck fails when run outside repository root.
- ⚠️ Formatting check errors due to missing ./mfc.sh file.
- ⚠️ Source lint searches miss files if cwd incorrect.
Suggested change
# Ensure we run from the repository root so relative paths like ./mfc.sh and ./src/* resolve correctly
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
cd "$REPO_ROOT"
Steps of Reproduction ✅
1. From a clone of the repository, change to the toolchain/bootstrap directory: cd
toolchain/bootstrap. This changes the cwd away from the repo root.

2. Execute the script directly: ./precheck.sh. The script later invokes ./mfc.sh in
toolchain/bootstrap/precheck.sh:67 (if ! ./mfc.sh format -j "$JOBS" > /dev/null 2>&1;
then). Because cwd=toolchain/bootstrap, ./mfc.sh does not exist and bash reports "No such
file or directory" from that line.

3. The script is run with set -e (toolchain/bootstrap/precheck.sh:2), so the missing
./mfc.sh call causes an immediate exit and the formatting check never runs.

4. Additionally, source checks use relative paths such as ./src/* in
toolchain/bootstrap/precheck.sh:107 (grep ... ./src/*) which will not point to repository
sources when cwd is not repo root, causing skipped or failing source lint checks. These
steps reproduce the issue using concrete file and line references.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** toolchain/bootstrap/precheck.sh
**Line:** 4:4
**Comment:**
	*Possible Bug: The script assumes it is always run from the repository root by hardcoding `./mfc.sh` and `./src/*` paths, so invoking `precheck.sh` from any other working directory (for example, running it directly from `toolchain/bootstrap/`) will cause it to fail to find `mfc.sh` or to skip source checks; computing the repo root from the script location and changing to it makes these relative paths reliable.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

shift
done

FAILED=0
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The script calls logging helpers log, ok, and error without defining them locally or sourcing any shared library, so running this script directly (or from an environment that does not export these functions) will immediately fail with "command not found" when the first log is executed; providing local fallbacks when these functions are absent makes the script robust in all invocation contexts. [possible bug]

Severity Level: Major ⚠️
- ❌ Local precheck command fails immediately when run directly.
- ⚠️ Developers cannot run prechecks without wrapper functions.
- ⚠️ CI-wrapper may mask this but direct execution breaks.
Suggested change
FAILED=0
# Provide basic logging helpers if they are not already defined by the caller
if ! declare -F log >/dev/null 2>&1; then
log() { echo "$@"; }
fi
if ! declare -F ok >/dev/null 2>&1; then
ok() { echo "$@"; }
fi
if ! declare -F error >/dev/null 2>&1; then
error() { echo "$@" >&2; }
fi
Steps of Reproduction ✅
1. Open the file toolchain/bootstrap/precheck.sh and inspect for logging helpers: there
are no definitions for log/ok/error in this file (verify entire file content shown in PR).

2. Run the script directly from the repository root: bash toolchain/bootstrap/precheck.sh.
Execution reaches the first logging call on toolchain/bootstrap/precheck.sh:60 where the
script runs:

   log "Running$MAGENTA precheck$COLOR_RESET (same checks as CI lint-gate)..."

3. Because log is not defined, bash prints "toolchain/bootstrap/precheck.sh: line 60: log:
command not found" and, due to set -e at toolchain/bootstrap/precheck.sh:2, the script
immediately exits with non-zero status.

4. Confirm by searching file for other uses of ok/error (e.g.,
toolchain/bootstrap/precheck.sh:80, :87, :96, :125, :133) — these will not be reached if
the first log call fails. This reproduces the failure with concrete file:line references.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** toolchain/bootstrap/precheck.sh
**Line:** 58:58
**Comment:**
	*Possible Bug: The script calls logging helpers `log`, `ok`, and `error` without defining them locally or sourcing any shared library, so running this script directly (or from an environment that does not export these functions) will immediately fail with "command not found" when the first `log` is executed; providing local fallbacks when these functions are absent makes the script robust in all invocation contexts.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

name="jobs",
short="j",
help="Number of parallel jobs for formatting.",
metavar="N",
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The jobs option for the new command is missing an explicit integer type and default value, unlike the shared COMMON_JOBS definition used elsewhere; this means -j will be parsed as a string with a default of None, which is inconsistent with other commands and can cause downstream code that expects an integer with a default concurrency of 1 to misbehave or fail. [type error]

Severity Level: Major ⚠️
- ⚠️ CLI precheck parsing inconsistent with other commands.
- ⚠️ Local ./mfc.sh precheck uses different jobs semantics.
- ⚠️ Developers may receive confusing concurrency behavior.
- ⚠️ Tooling that introspects schema sees inconsistent types.
Suggested change
metavar="N",
type=int,
default=1,
Steps of Reproduction ✅
1. Open a Python REPL in the repository root and import the CLI schema:

   from toolchain.mfc.cli.commands import MFC_CLI_SCHEMA

   (MFC_CLI_SCHEMA is defined in toolchain/mfc/cli/commands.py; PRECHECK_COMMAND is added
   at commands.py:754-773).

2. Resolve the 'precheck' command via the schema helper (implementation at
toolchain/mfc/cli/schema.py:158-204):

   cmd = MFC_CLI_SCHEMA.get_command("precheck")

   This returns the Command object that was added in commands.py:754-773.

3. Inspect the argument definition (Argument dataclass is declared at
toolchain/mfc/cli/schema.py:44-81):

   jobs_arg = cmd.arguments[0]

   Observe jobs_arg.type is None and jobs_arg.default is None (i.e., no explicit
   type/default).

4. Contrast with the shared COMMON_JOBS definition in the same file (COMMON_JOBS sets
Argument.type=int and default=1):

   from toolchain.mfc.cli.commands import COMMON_JOBS

   assert COMMON_JOBS.arguments[0].type is int and COMMON_JOBS.arguments[0].default == 1

   The mismatch is concrete: PRECHECK_COMMAND.jobs lacks type/default while COMMON_JOBS
   uses type=int default=1.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** toolchain/mfc/cli/commands.py
**Line:** 763:763
**Comment:**
	*Type Error: The `jobs` option for the new command is missing an explicit integer type and default value, unlike the shared `COMMON_JOBS` definition used elsewhere; this means `-j` will be parsed as a string with a default of `None`, which is inconsistent with other commands and can cause downstream code that expects an integer with a default concurrency of 1 to misbehave or fail.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 5, 2026

CodeAnt AI Incremental review completed.

- -v/-vv/-vvv: output verbosity levels
- --debug: build with debug compiler flags (for MFC Fortran code)
- --debug-log/-d: Python toolchain debug logging (not MFC code)

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

codecov bot commented Feb 5, 2026

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1122   +/-   ##
=======================================
  Coverage   44.03%   44.03%           
=======================================
  Files          70       70           
  Lines       20649    20649           
  Branches     2053     2053           
=======================================
  Hits         9093     9093           
  Misses      10368    10368           
  Partials     1188     1188           

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

Avoid hogging resources on machines with many cores.

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

codeant-ai bot commented Feb 5, 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:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Feb 5, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 5, 2026

CodeAnt AI Incremental review completed.

@sbryngelson sbryngelson merged commit 7b35b59 into MFlowCode:master Feb 5, 2026
30 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 3/5 size:L This PR changes 100-499 lines, ignoring generated files

Development

Successfully merging this pull request may close these issues.

1 participant