Skip to content

Add unified API landing page and fix footer layout#1169

Merged
sbryngelson merged 6 commits intoMFlowCode:masterfrom
sbryngelson:docs-api-landing
Feb 19, 2026
Merged

Add unified API landing page and fix footer layout#1169
sbryngelson merged 6 commits intoMFlowCode:masterfrom
sbryngelson:docs-api-landing

Conversation

@sbryngelson
Copy link
Member

@sbryngelson sbryngelson commented Feb 19, 2026

User description

Summary

  • Adds a unified API Documentation landing page (docs/api/) that links to the Pre-Process, Simulation, and Post-Process API docs
  • Consolidates sidebar navigation from 4 links to 2: User Guide and API Documentation
  • API Documentation link highlights when viewing any API sub-project (pre_process, simulation, post_process)
  • Unifies browser tab title to "MFC" across all Doxygen targets (was "MFC: Pre-Process" etc.)
  • Fixes footer blank space caused by missing #nav-path element needed by navtree.js for content height calculation

Test plan

  • Build docs with ./mfc.sh build -j $(nproc) -t documentation
  • Verify API landing page at docs/mfc/api/index.html shows links to all three sub-projects
  • Verify sidebar shows 2 items on all pages with correct active highlighting
  • Verify browser tab says "MFC" on all pages
  • Verify no blank space in footer

🤖 Generated with Claude Code


CodeAnt-AI Description

Add a unified API landing page, simplify sidebar, and fix footer/tab titles

What Changed

  • New unified API landing page at docs/api/ that links to Pre-Process, Simulation, and Post-Process API references and is included in the build
  • Sidebar navigation reduced to two items ("User Guide" and "API Documentation"); the API item highlights when viewing any API sub-project (pre_process, simulation, post_process, or api)
  • Browser tab title standardized to "MFC" across all generated API pages
  • Removed blank space in the footer by adding the required nav-path element and hiding it with CSS so layout no longer leaves an empty gap

Impact

✅ Unified API landing page
✅ No blank space in footer
✅ Consistent browser tab title

💡 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

  • Documentation

    • Added comprehensive architecture reference and automated architecture page generation
    • Added a unified API landing page and consolidated API navigation into a single API entry
    • Updated contribution guide to require module registration for inclusion in architecture docs
    • Removed per-component API readme files and updated site navigation/layout
    • Added two new example simulations to the homepage
  • Chores

    • Added module-categorization data and automated validation in doc linting
  • Style

    • Hid empty navigation path element to prevent layout artifacts

- Add docs/api/ Doxygen target with a landing page linking to
  Pre-Process, Simulation, and Post-Process API docs
- Consolidate sidebar from 4 links to 2: "User Guide" and
  "API Documentation" (highlights for all API sub-projects)
- Unify browser tab title to "MFC" across all Doxygen targets
- Fix footer blank space caused by missing #nav-path element
  that navtree.js needs for content height calculation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 19, 2026 16:52
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 19, 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 19, 2026

📝 Walkthrough

Walkthrough

This PR centralizes API documentation and adds automated architecture documentation: new CMake targets and Python generators produce an API landing page and an architecture.md generated from module metadata; header/footer/templates and linting are updated; per-target readmes are removed and module categories introduced.

Changes

Cohort / File(s) Summary
Build System
CMakeLists.txt
Added gen_api_landing and gen_architecture custom/public targets; wired them into api_doxygen / documentation_doxygen; unified GEN_DOCS labeling for targets.
API Landing & Templates
docs/gen_api_landing.py, docs/header.html, docs/footer.html, docs/index.html
New generator for unified API landing at docs/api/readme.md; header/footer templates consolidated API nav to a single entry and added nav-path placeholder; index header API entry adjusted/removed.
Architecture Generation & Template
docs/gen_architecture.py, docs/documentation/architecture.md.in, docs/documentation/architecture.md
New generator script that emits architecture.md from template by reading docs/module_categories.json and extracting module briefs; added architecture template describing pipeline, data structures, and extension patterns.
Module Metadata & Validation
docs/module_categories.json, toolchain/mfc/lint_docs.py
Added module_categories.json mapping modules to categories; extended lint_docs.py with check_module_categories() to validate all m_* modules are listed and surface actionable errors.
Removed Per-Target Readmes
docs/pre_process/readme.md, docs/simulation/readme.md, docs/post_process/readme.md
Deleted per-component readme files (content now aggregated into unified API landing / architecture pages).
Docs Styling & Templates
docs/custom.css, docs/footer.html
Hide empty #nav-path via CSS and added div id="nav-path" in footer treeview block to host nav-path content.
Documentation Content & Index
docs/documentation/contributing.md, docs/documentation/readme.md, docs/simulations.json
Added contributing step to register modules in module_categories.json; replaced 3 API links with single API Documentation link; added two simulations entries.
Repo Config
.gitignore
Added generated doc outputs to .gitignore (docs/documentation/architecture.md, per-target and api readmes).

Sequence Diagram(s)

sequenceDiagram
  participant CMake as CMake
  participant GenAPI as gen_api_landing.py
  participant GenArch as gen_architecture.py
  participant Doxygen as Doxygen
  participant Lint as lint_docs.py
  participant Output as docs/

  CMake->>GenAPI: invoke gen_api_landing target
  GenAPI-->>Output: write docs/api/readme.md
  CMake->>GenArch: invoke gen_architecture target
  GenArch-->>Output: write docs/documentation/architecture.md
  CMake->>Doxygen: run api_doxygen (depends on gen_api_landing)
  Doxygen-->>Output: generate API HTML under /api/
  CMake->>Lint: run documentation lint (calls check_module_categories)
  Lint-->>CMake: report missing module-category errors
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Review effort 3/5, size:L

Suggested reviewers

  • wilfonba

Poem

🐰 Hopped through code and docs tonight,
One API, one map, all modules in sight.
I nibble briefs and stitch the plan,
The rabbit builds a tidy docs-land. 📚✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the two main changes: adding a unified API landing page and fixing footer layout issues. It is concise, specific, and directly reflects the primary objectives of the PR.
Description check ✅ Passed The PR description is comprehensive and complete, covering all required template sections including summary, testing approach, and relevant checklist items with clear motivation for the changes.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share

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

@codeant-ai codeant-ai bot added the size:M This PR changes 30-99 lines, ignoring generated files label Feb 19, 2026
@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 19, 2026

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Duplicate element risk
    If Doxygen or other templates also generate a #nav-path element, inserting another could create duplicate IDs and unpredictable behavior for navtree.js and layout calculation. Ensure only a single #nav-path exists or guard the insertion.

  • Generated filename / routing
    The unified API landing page is written to docs/api/readme.md. Ensure your documentation toolchain (Doxygen/site generator) will treat readme.md as the landing page (index) for the /api/ path. If not, links and sidebar highlighting could point to ../api/index.html but the generated file may not be used.

  • Active-link detection
    The new JS logic marks the "API Documentation" nav item active by searching for several substrings in window.location.pathname. This can misfire for pages that don't include a trailing slash or include the token elsewhere (e.g. query strings, different casing, or longer path segments like "/simulation-old/"). Verify the detection handles index pages (like index.html), case differences, and avoids false positives.

  • Path normalization / case-sensitivity
    The path comparisons use raw window.location.pathname and indexOf. Consider lower-casing and normalizing to avoid missing matches on servers that serve differently-cased URLs or when filenames like "Index.html" appear.

  • CSS always hides nav-path
    The new rule forces #nav-path to height:0 and overflow:hidden unconditionally. If navtree.js later populates or relies on the element's visible size, this will prevent the nav from becoming visible. Prefer hiding only when the element is empty so the script can show/populate it when needed.

@codeant-ai
Copy link
Contributor

codeant-ai bot commented Feb 19, 2026

CodeAnt AI finished reviewing your PR.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

No issues found across 6 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

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 improves the MFC documentation structure by creating a unified API landing page and consolidating navigation. The changes simplify the user experience by reducing the sidebar from 4 links to 2 (User Guide and API Documentation), while the new API landing page at docs/api/ provides organized access to all three sub-project APIs (Pre-Process, Simulation, Post-Process). Additionally, it fixes a footer layout issue caused by missing DOM elements that Doxygen's JavaScript expects for content height calculation.

Changes:

  • Added unified API Documentation landing page that links to all three component APIs
  • Consolidated sidebar navigation from 4 API links to 1 unified API Documentation link with smart highlighting
  • Fixed footer blank space by adding required #nav-path element and hiding it with CSS
  • Unified browser tab titles to "MFC" across all documentation targets

Reviewed changes

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

Show a summary per file
File Description
docs/header.html Updated navigation JavaScript to show 2 links instead of 4; added logic to highlight "API Documentation" when viewing any API sub-project
docs/gen_api_landing.py Extended script to generate unified API landing page at docs/api/readme.md with descriptions and links to all three components
docs/footer.html Added empty #nav-path div required by navtree.js for proper content height calculation
docs/custom.css Added CSS rule to hide the empty nav-path element while preserving its layout function
docs/api/readme.md New API landing page content with component descriptions and navigation links
CMakeLists.txt Added 'api' target to documentation build system and made api_doxygen depend on gen_api_landing

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.

🧹 Nitpick comments (2)
docs/gen_api_landing.py (1)

154-180: LGTM — unified landing page generation is clean and consistent with existing patterns.

Minor note: docs/api/readme.md is both committed to the repo (new file in this PR) and regenerated by this script at build time. Because the content is derived solely from the static TARGETS dict, the committed and generated versions will stay in sync as long as TARGETS is not changed without re-committing the output. If TARGETS changes in the future, the committed snapshot will silently become stale until the next build. Consider adding docs/api/readme.md (and the analogous per-target files) to .gitignore and treating them as pure build artifacts, or adding a CI step that diffs the committed file against the generated one.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/gen_api_landing.py` around lines 154 - 180, The generated
docs/api/readme.md (produced via the api_lines -> api_out.write_text flow in
gen_api_landing.py from the TARGETS dict) is committed but should be treated as
a build artifact; either add "docs/api/readme.md" (and per-target counterparts)
to .gitignore to avoid committing the derived output, or add a CI check that
runs the same generation (invoke the gen_api_landing.py logic that produces
api_out from TARGETS) and fails the job if the generated content differs from
the committed file, so the repo never drifts silently.
docs/header.html (1)

76-90: LGTM — active-state detection correctly covers all four API path segments.

The apiPaths list is a manually maintained allowlist. If a new API sub-project is ever added (e.g., syscheck), both this array and the GEN_DOCS/navigation in CMakeLists.txt would need to be updated in concert.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/header.html` around lines 76 - 90, The active-state logic currently uses
a hardcoded apiPaths array which must be updated manually; instead, remove the
apiPaths constant and derive API path segments from the items array itself: when
you detect items[i][1] === 'api', parse items[i][0] (the href string like
'../<subproj>/index.html') to extract the subproject segment (e.g. '/subproj/')
into a local variable or small array and use that to check if
window.location.pathname.indexOf(thatSegment) !== -1 before setting a.className
= 'active'; update the loop around items and the branch that sets a.className so
all API subprojects added to items automatically get active-state detection
without touching GEN_DOCS/CMakeLists.txt.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/gen_api_landing.py`:
- Around line 154-180: The generated docs/api/readme.md (produced via the
api_lines -> api_out.write_text flow in gen_api_landing.py from the TARGETS
dict) is committed but should be treated as a build artifact; either add
"docs/api/readme.md" (and per-target counterparts) to .gitignore to avoid
committing the derived output, or add a CI check that runs the same generation
(invoke the gen_api_landing.py logic that produces api_out from TARGETS) and
fails the job if the generated content differs from the committed file, so the
repo never drifts silently.

In `@docs/header.html`:
- Around line 76-90: The active-state logic currently uses a hardcoded apiPaths
array which must be updated manually; instead, remove the apiPaths constant and
derive API path segments from the items array itself: when you detect
items[i][1] === 'api', parse items[i][0] (the href string like
'../<subproj>/index.html') to extract the subproject segment (e.g. '/subproj/')
into a local variable or small array and use that to check if
window.location.pathname.indexOf(thatSegment) !== -1 before setting a.className
= 'active'; update the loop around items and the branch that sets a.className so
all API subprojects added to items automatically get active-state detection
without touching GEN_DOCS/CMakeLists.txt.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (5)
docs/gen_architecture.py (3)

12-12: from __future__ import annotations is unnecessary for Python 3.10+.

Path | None union syntax (used on line 61) is natively supported in Python 3.10+ via PEP 604 without this import. Since the project targets Python 3.10+, this shim adds no value.

♻️ Proposed fix
-from __future__ import annotations
-
 import json
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/gen_architecture.py` at line 12, Remove the unnecessary future import:
delete the "from __future__ import annotations" statement at the top of
docs/gen_architecture.py because the project targets Python 3.10+ and the union
type syntax used elsewhere (e.g., the "Path | None" annotation on line 61) is
natively supported; ensure no other code relies on postponed evaluation before
committing.

19-19: Module-level src_dir initialization runs at import time.

This is a side effect that makes the module hard to test and import as a library. The value could instead be resolved inside main() and passed as a parameter to generate_module_map() and _find_module_file().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/gen_architecture.py` at line 19, The module-level src_dir is evaluated
at import time causing side effects; move resolution of Path(sys.argv[1]) into
main() and pass the resulting src_dir explicitly into generate_module_map() and
_find_module_file() (update their signatures to accept a src_dir parameter),
removing the global src_dir variable so imports are side-effect free and tests
can supply custom paths.

95-104: Two silent failure modes in main().

  1. If architecture.md.in is missing, template.read_text() raises FileNotFoundError with no user-friendly diagnostic.
  2. If <!-- MODULE_MAP --> is absent from the template, text.replace(...) is a silent no-op — the generated architecture.md would have no module map without any warning.
🛡️ Suggested defensive additions
 def main() -> None:
     template = src_dir / "docs" / "documentation" / "architecture.md.in"
     output = src_dir / "docs" / "documentation" / "architecture.md"

+    if not template.exists():
+        sys.exit(f"ERROR: template not found: {template}")
+
     text = template.read_text(encoding="utf-8")
     module_map = generate_module_map()
+    if "<!-- MODULE_MAP -->" not in text:
+        sys.exit(f"ERROR: placeholder '<!-- MODULE_MAP -->' not found in {template}")
     text = text.replace("<!-- MODULE_MAP -->", module_map)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/gen_architecture.py` around lines 95 - 104, In main(), add defensive
checks around reading and replacing the template: catch FileNotFoundError from
template.read_text and log or print a clear diagnostic referencing the template
variable and exit non‑zero; after reading, verify the marker "<!-- MODULE_MAP
-->" exists in text before calling text.replace (if missing, log/raise a clear
error instead of silently proceeding); only write output.write_text after a
successful replacement (use generate_module_map() when replacing) and ensure any
other unexpected exceptions are surfaced with a helpful message. This targets
the main() function and the template.read_text / text.replace usage to avoid the
two silent failure modes.
toolchain/mfc/lint_docs.py (2)

847-859: cats string is recomputed inside the per-error append, not precomputed.

", ".join(e["category"] for e in categories) is evaluated once per uncategorized module. Precompute it before the loop.

♻️ Proposed fix
+    cats = ", ".join(e["category"] for e in categories)
     errors = []
     for fpp in sorted(src_dir.rglob("m_*.[fF]*")):
         if fpp.suffix not in (".fpp", ".f90", ".F90"):
             continue
         name = fpp.stem
         if name not in categorized:
             rel = fpp.relative_to(repo_root)
-            cats = ", ".join(e["category"] for e in categories)
             errors.append(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@toolchain/mfc/lint_docs.py` around lines 847 - 859, The code recomputes cats
= ", ".join(e["category"] for e in categories) inside the loop for every
uncategorized module; move that computation out of the loop and compute cats
once before iterating over src_dir.rglob, then reference that precomputed cats
inside the errors.append block (keep references to errors, fpp, categorized,
categories, and repo_root as shown).

838-841: No validation of module_categories.json structure before accessing entry["modules"].

If the JSON file is malformed (e.g., missing the "modules" key), the json.loads or entry["modules"] access raises an opaque JSONDecodeError / KeyError with no actionable hint. The existing file-exists guard is good but doesn't cover structural problems.

🛡️ Suggested minimal guard
-    categories = json.loads(categories_file.read_text(encoding="utf-8"))
-    categorized = set()
-    for entry in categories:
-        categorized.update(entry["modules"])
+    try:
+        categories = json.loads(categories_file.read_text(encoding="utf-8"))
+        categorized = {m for entry in categories for m in entry["modules"]}
+    except (json.JSONDecodeError, KeyError, TypeError) as exc:
+        return [f"  docs/module_categories.json is malformed: {exc}"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@toolchain/mfc/lint_docs.py` around lines 838 - 841, The code assumes every
entry in the loaded categories JSON has a "modules" key and that json.loads
succeeds; wrap the json.loads call in a try/except to catch JSONDecodeError and
raise/log a clear error mentioning "module_categories.json", then validate the
parsed object before the loop: ensure `categories` is a list and for each
`entry` (in the loop that updates `categorized`) verify `isinstance(entry,
dict)` and that `"modules"` in entry and `isinstance(entry["modules"], (list,
tuple))`; if any check fails, raise or log a ValueError/TypeError with a
descriptive message referencing `categories` and the offending `entry` so the
caller gets an actionable hint instead of a KeyError/opaque decode error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CMakeLists.txt`:
- Around line 851-867: Add an explicit ordering dependency so inject_page_dates
runs after gen_architecture: update the CMake targets to make the
inject_page_dates target (or its stamp/output) depend on gen_architecture (or
the "${CMAKE_CURRENT_BINARY_DIR}/gen-architecture.stamp") and/or add
add_dependencies(inject_page_dates gen_architecture) so documentation_doxygen
cannot run inject-dates.py in parallel with gen_architecture; reference the
existing gen_architecture target and the gen-architecture.stamp output when
adding the dependency.

In `@docs/documentation/architecture.md`:
- Line 9: Update the source template that generates the architecture docs to add
a language specifier to each fenced code block: replace the opening fences for
the ASCII diagrams (e.g., the block that contains "pre_process ──> simulation
──> post_process" and the three other similarly formatted diagram/pseudo‑code
blocks) with ```text so the generated architecture.md uses ```text for those
fences; ensure all four untagged fenced blocks in the template are changed to
use the text specifier.

In `@docs/gen_architecture.py`:
- Around line 81-84: The Markdown table is emitted immediately after the section
heading in generate_module_map(), causing MD058 warnings; update the code that
appends the section header (where lines.append(f"### {cat}") is called) to
insert a blank line before the table (e.g., append an empty string or newline
into the lines list right after the heading) so the heading and the table are
separated by one blank line.

---

Duplicate comments:
In `@docs/documentation/architecture.md`:
- Line 100: The generated module map tables in
docs/documentation/architecture.md are missing surrounding blank lines (MD058);
update the docs/gen_architecture.py generate_module_map() function to emit an
empty line before and after each markdown table it produces (e.g., ensure the
code path that builds the table string for the "Module | Role" section inserts
'\n' or a blank-line entry both preceding and following the table output), and
apply the same blank-line handling for the other table positions referenced
(lines noted in the review) so every generated table is separated by blank
lines.

---

Nitpick comments:
In `@docs/gen_architecture.py`:
- Line 12: Remove the unnecessary future import: delete the "from __future__
import annotations" statement at the top of docs/gen_architecture.py because the
project targets Python 3.10+ and the union type syntax used elsewhere (e.g., the
"Path | None" annotation on line 61) is natively supported; ensure no other code
relies on postponed evaluation before committing.
- Line 19: The module-level src_dir is evaluated at import time causing side
effects; move resolution of Path(sys.argv[1]) into main() and pass the resulting
src_dir explicitly into generate_module_map() and _find_module_file() (update
their signatures to accept a src_dir parameter), removing the global src_dir
variable so imports are side-effect free and tests can supply custom paths.
- Around line 95-104: In main(), add defensive checks around reading and
replacing the template: catch FileNotFoundError from template.read_text and log
or print a clear diagnostic referencing the template variable and exit non‑zero;
after reading, verify the marker "<!-- MODULE_MAP -->" exists in text before
calling text.replace (if missing, log/raise a clear error instead of silently
proceeding); only write output.write_text after a successful replacement (use
generate_module_map() when replacing) and ensure any other unexpected exceptions
are surfaced with a helpful message. This targets the main() function and the
template.read_text / text.replace usage to avoid the two silent failure modes.

In `@toolchain/mfc/lint_docs.py`:
- Around line 847-859: The code recomputes cats = ", ".join(e["category"] for e
in categories) inside the loop for every uncategorized module; move that
computation out of the loop and compute cats once before iterating over
src_dir.rglob, then reference that precomputed cats inside the errors.append
block (keep references to errors, fpp, categorized, categories, and repo_root as
shown).
- Around line 838-841: The code assumes every entry in the loaded categories
JSON has a "modules" key and that json.loads succeeds; wrap the json.loads call
in a try/except to catch JSONDecodeError and raise/log a clear error mentioning
"module_categories.json", then validate the parsed object before the loop:
ensure `categories` is a list and for each `entry` (in the loop that updates
`categorized`) verify `isinstance(entry, dict)` and that `"modules"` in entry
and `isinstance(entry["modules"], (list, tuple))`; if any check fails, raise or
log a ValueError/TypeError with a descriptive message referencing `categories`
and the offending `entry` so the caller gets an actionable hint instead of a
KeyError/opaque decode error.

- Add docs/documentation/architecture.md.in template with hand-written
  sections (pipeline, data structures, simulation loop, MPI, extending)
- Add docs/gen_architecture.py to generate module map from source briefs
- Add docs/module_categories.json as single source of truth for groupings
- Add linter check: warns when a module is missing from categories JSON
- Update contributing guide with step to register new modules
- Link architecture page from User Guide sidebar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New entry on the landing site gallery with thumbnail from the
YouTube video (https://youtube.com/watch?v=zDJoe0NYZsQ), run on
a single A100 on Phoenix in under 1 hour.

Co-Authored-By: Claude Opus 4.6 <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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
toolchain/mfc/lint_docs.py (1)

373-375: ⚠️ Potential issue | 🔴 Critical

Add "architecture" to the hardcoded page_ids set — this is the root cause of both pipeline failures.

architecture.md is gitignored (generated at build time), so docs/documentation/*.md globbing during CI never collects the {#architecture} anchor. All other auto-generated pages (parameters, case_constraints, etc.) are pre-seeded in this set for exactly this reason. architecture must follow the same pattern.

Fix
-    page_ids = {"citelist", "parameters", "case_constraints", "physics_constraints", "examples", "cli-reference"}
+    page_ids = {"citelist", "parameters", "case_constraints", "physics_constraints", "examples", "cli-reference", "architecture"}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@toolchain/mfc/lint_docs.py` around lines 373 - 375, Add the missing
"architecture" entry to the hardcoded page_ids set so generated/ignored
architecture.md is treated like other auto-generated pages; update the page_ids
declaration (the set assigned to variable page_ids in lint_docs.py) to include
"architecture" alongside "citelist", "parameters", "case_constraints",
"physics_constraints", "examples", and "cli-reference" so the subsequent
doc_dir.glob("*.md") processing/logic recognizes the generated architecture
page.
🧹 Nitpick comments (1)
toolchain/mfc/lint_docs.py (1)

847-859: check_module_categories may emit duplicate errors for the same module name across multiple src/ subdirectories.

Several module names (e.g., m_global_parameters, m_checker) exist independently under src/pre_process/, src/simulation/, and src/post_process/. If any such module is missing from module_categories.json, the current code reports one error per file path rather than one error per unique module name. Consider deduplicating on name before reporting, and computing the cats string once outside the loop.

Suggested refactor
+    cats = ", ".join(e["category"] for e in categories)
     errors = []
-    for fpp in sorted(src_dir.rglob("m_*.[fF]*")):
-        if fpp.suffix not in (".fpp", ".f90", ".F90"):
-            continue
-        name = fpp.stem
-        if name not in categorized:
-            rel = fpp.relative_to(repo_root)
-            cats = ", ".join(e["category"] for e in categories)
-            errors.append(
-                f"  {rel}: module {name} is not in docs/module_categories.json.\n"
-                f"    Fix: open docs/module_categories.json and add \"{name}\" to one of: {cats}.\n"
-                f"    This ensures it appears on the Code Architecture page."
-            )
+    missing = set()
+    for fpp in sorted(src_dir.rglob("m_*.[fF]*")):
+        if fpp.suffix not in (".fpp", ".f90", ".F90"):
+            continue
+        name = fpp.stem
+        if name not in categorized:
+            missing.add(name)
+    for name in sorted(missing):
+        errors.append(
+            f"  module {name} is not in docs/module_categories.json."
+            f" Fix: add \"{name}\" to one of: {cats}."
+            f" This ensures it appears on the Code Architecture page."
+        )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@toolchain/mfc/lint_docs.py` around lines 847 - 859, The loop in
check_module_categories collects errors per file path, causing duplicate
messages for the same module name across subdirs; fix by deduplicating on the
module name and computing the category list string once. Before the for fpp in
sorted(...) loop, compute cats = ", ".join(e["category"] for e in categories);
then add a seen = set() and inside the loop compute name = fpp.stem; if name in
seen: continue; add name to seen and only then check if name not in categorized
and append a single error using the first seen relative path (rel =
fpp.relative_to(repo_root)) so each missing module is reported once.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/documentation/contributing.md`:
- Around line 539-541: check_page_refs in lint_docs.py fails because
"architecture.md" is gitignored and the function's page_ids set isn't pre-seeded
with "architecture"; update the check_page_refs function to add "architecture"
to the initial page_ids set (same one-line approach used to pre-seed "readme")
so the `@ref` architecture link is recognized during the precheck linter run and
both CI failures are resolved.

In `@docs/documentation/readme.md`:
- Line 27: The CI lint fails because the hardcoded page_ids set in
lint_docs.py::check_page_refs doesn't include the generated anchor for
architecture; update the page_ids set to add "architecture" (the {`#architecture`}
anchor) so check_page_refs will recognize `@ref` architecture in readme.md even
though architecture.md is gitignored at build time; modify the page_ids constant
in check_page_refs to include "architecture" and run the docs lint to verify the
CI gate passes.

---

Outside diff comments:
In `@toolchain/mfc/lint_docs.py`:
- Around line 373-375: Add the missing "architecture" entry to the hardcoded
page_ids set so generated/ignored architecture.md is treated like other
auto-generated pages; update the page_ids declaration (the set assigned to
variable page_ids in lint_docs.py) to include "architecture" alongside
"citelist", "parameters", "case_constraints", "physics_constraints", "examples",
and "cli-reference" so the subsequent doc_dir.glob("*.md") processing/logic
recognizes the generated architecture page.

---

Duplicate comments:
In `@CMakeLists.txt`:
- Around line 851-867: The documentation build can race because
documentation_doxygen depends on both gen_architecture and inject_page_dates
with no ordering; add a dependency so the inject_page_dates target depends on
gen_architecture (i.e., call add_dependencies(inject_page_dates
gen_architecture)) to ensure gen_architecture runs and produces architecture.md
before inject_page_dates runs; update the CMake file near the definitions of the
gen_architecture and inject_page_dates targets so inject_page_dates has an
explicit add_dependencies to gen_architecture while leaving
documentation_doxygen dependencies intact.

---

Nitpick comments:
In `@toolchain/mfc/lint_docs.py`:
- Around line 847-859: The loop in check_module_categories collects errors per
file path, causing duplicate messages for the same module name across subdirs;
fix by deduplicating on the module name and computing the category list string
once. Before the for fpp in sorted(...) loop, compute cats = ",
".join(e["category"] for e in categories); then add a seen = set() and inside
the loop compute name = fpp.stem; if name in seen: continue; add name to seen
and only then check if name not in categorized and append a single error using
the first seen relative path (rel = fpp.relative_to(repo_root)) so each missing
module is reported once.

sbryngelson and others added 3 commits February 19, 2026 19:01
- Add flow-over-dog entry (4 B200s on HiPerGator, 1h) to landing
  page and Doxygen gallery with thumbnail
- Add shock-helium entry to landing page inline sims array (was
  only in simulations.json)
- Fix nav button grid: grid-cols-7 → grid-cols-6 after API button
  removal

YouTube: https://youtube.com/watch?v=Xhvr2kkQa30

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Focused ultrasound pulse impinging a phantom kidney stone with
stress visualization, by J.-S. Spratt. 10 V100s on Bridges-2, 2h.

YouTube: https://youtube.com/watch?v=z8j3NH-Y6i0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
architecture.md is gitignored (generated at build time), so the
linter glob never finds its anchor. Pre-seed it like the other
generated pages to prevent CI failure.

Co-Authored-By: Claude Opus 4.6 <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

🧹 Nitpick comments (1)
docs/index.html (1)

178-178: text-md is not a valid Tailwind CSS utility — silently no-ops.

text-md does not exist in Tailwind's font-size scale, which ranges from text-xs through text-9xl but skips text-md. The Play CDN silently ignores unknown utility classes, so elements using text-md fall back to inherited or browser-default sizing. This class appears on lines 170, 178, 219 (as md:text-md), and 252 (as md:text-md). The correct equivalent is text-base.

The responsive grid improvement on line 178 itself is correct.

♻️ Proposed fix — replace all occurrences of `text-md` with `text-base`

Line 170:

-<div class="w-full flex flex-col text-white text-md md:text-lg text-justify font-semibold gap-3">
+<div class="w-full flex flex-col text-white text-base md:text-lg text-justify font-semibold gap-3">

Line 178:

-<div class="justify-center grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-x-4 md:gap-x-8 text-md md:text-xl text-center text-white font-medium">
+<div class="justify-center grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-x-4 md:gap-x-8 text-base md:text-xl text-center text-white font-medium">

Line 219:

-<div class="text-sm md:text-md text-justify">
+<div class="text-sm md:text-base text-justify">

Line 252:

-<div class="font-bold text-center text-sm md:text-md md:text-left">
+<div class="font-bold text-center text-sm md:text-base md:text-left">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/index.html` at line 178, Replace the invalid Tailwind utility "text-md"
(and responsive variant "md:text-md") with the correct "text-base" (and
"md:text-base") wherever used in the HTML; specifically update the class strings
such as the div containing "justify-center grid ... text-md md:text-xl ..." and
the other occurrences referenced (lines noted in the review) so all "text-md"
become "text-base" and all "md:text-md" become "md:text-base".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/index.html`:
- Line 58: The HTML includes three simulation entries referencing missing image
assets (image: "res/simulations/t.png" for "Mach 1.5 shock-helium bubble",
image: "res/simulations/u.png" for "Flow over a dog (pressure)", and image:
"res/simulations/v.png" for "Focused ultrasound on kidney stone"), causing
broken images; fix by either adding the three PNG files into the repository at
the referenced paths (res/simulations/t.png, u.png, v.png) or remove/update
those simulation entries in docs/index.html to point to existing images or
placeholders so the simulation cards no longer reference nonexistent assets.

---

Nitpick comments:
In `@docs/index.html`:
- Line 178: Replace the invalid Tailwind utility "text-md" (and responsive
variant "md:text-md") with the correct "text-base" (and "md:text-base") wherever
used in the HTML; specifically update the class strings such as the div
containing "justify-center grid ... text-md md:text-xl ..." and the other
occurrences referenced (lines noted in the review) so all "text-md" become
"text-base" and all "md:text-md" become "md:text-base".

@sbryngelson sbryngelson merged commit 202033e into MFlowCode:master Feb 19, 2026
31 of 37 checks passed
@codecov
Copy link

codecov bot commented Feb 19, 2026

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1169   +/-   ##
=======================================
  Coverage   44.05%   44.05%           
=======================================
  Files          70       70           
  Lines       20498    20498           
  Branches     1990     1990           
=======================================
  Hits         9030     9030           
  Misses      10329    10329           
  Partials     1139     1139           

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

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Development

Successfully merging this pull request may close these issues.

1 participant

Comments