docs: validate internal links#828
Conversation
|
Fern preview: https://nvidia-preview-pr-828.docs.buildwithfern.com/nemo/datadesigner
|
Code Review: PR #828 —
|
Greptile SummaryThis PR adds a deterministic internal-link validator (
|
| Filename | Overview |
|---|---|
| fern/scripts/check-internal-links.py | New 351-line deterministic link validator: builds a route index from Fern navigation YAML, then checks every internal link and fragment across all pages. Logic for slugify/anchor-slugify, redirect pattern matching, code-block masking, and notebook markdown extraction all look correct. |
| fern/scripts/tests/test_check_internal_links.py | 215-line pytest suite covering slug behaviour, nested navigation, skip-slug, redirect pattern matching, fragment validation, relative links, code-block exclusion, and notebook heading anchor injection. All parameterised cases match expected Fern URL conventions. |
| Makefile | Adds check-fern-links target and wires it into check-fern-docs; correctly gates on prepare-fern-docs and propagates failures through the sub-make call. |
| fern/versions/latest/pages/concepts/tool_use_and_mcp.mdx | Fixes 8 broken links: path segment changed from tool-use-and-mcp to tool-use-mcp across all sub-page references, and the stale #mcpprovider-remote-sse fragment corrected to #mcpprovider-remote to match the actual heading 'MCPProvider (Remote)'. |
| fern/versions/latest/pages/index.mdx | Two links to Architecture & Performance corrected from /concepts/architecture-and-performance to /concepts/architecture-performance, matching the Fern slug derived from the page title. |
| fern/versions/latest/pages/plugins/overview.mdx | Three links updated from the stale filesystemseedreader-plugins slug to file-system-seed-reader-plugins, and stale plugin guide destinations replaced with the active example-plugin and file-system-seed-reader-plugins routes. |
| fern/versions/latest/pages/devnotes/posts/structured-outputs-from-nemotron.mdx | Updates the StructEval repository URL from the stale StructEval/StructEval to the current TIGER-AI-Lab/StructEval GitHub path. |
| docs/notebook_source/3-seeding-with-a-dataset.py | Replaces a repository-relative relative link data (which resolved to a non-existent Fern route) with plain prose, fixing a broken link that was also propagated to the generated Colab notebook. |
| .agents/skills/datadesigner-docs/SKILL.md | Updates the docs skill to document that make check-fern-docs now validates internal links deterministically, replacing the previous note about known false positives in the old file-path-based checker. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[make check-fern-docs] --> B[prepare-fern-docs\ngenerate notebooks]
A --> C[make check-fern-links]
A --> D[fern check\nYAML + MDX validation]
C --> E[build_index\nparse docs.yml + version YAMLs]
E --> F[Walk navigation tree\nslugify section/page titles]
F --> G[Compute routes\nlatest pages get /latest/ aliases]
G --> H[Extract anchors\nheadings + explicit IDs per page]
E --> I[Load redirects\nnormalize configured paths]
C --> J[notebook_sources\nmap .py sources to wrapper page routes\nextract markdown-cell anchors]
E --> K[validate_links\nfor each page source]
J --> K
K --> L{For each link}
L --> M[normalize_target\nresolve relative / strip base path]
M --> N{Path in index.routes?}
N -- yes --> O{Fragment in page.anchors?}
O -- pass --> P[valid]
O -- fail --> Q[broken fragment]
N -- no --> R{asset_exists or\nredirect_matches?}
R -- yes --> P
R -- no --> S[broken route\n+ closest_route suggestion]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[make check-fern-docs] --> B[prepare-fern-docs\ngenerate notebooks]
A --> C[make check-fern-links]
A --> D[fern check\nYAML + MDX validation]
C --> E[build_index\nparse docs.yml + version YAMLs]
E --> F[Walk navigation tree\nslugify section/page titles]
F --> G[Compute routes\nlatest pages get /latest/ aliases]
G --> H[Extract anchors\nheadings + explicit IDs per page]
E --> I[Load redirects\nnormalize configured paths]
C --> J[notebook_sources\nmap .py sources to wrapper page routes\nextract markdown-cell anchors]
E --> K[validate_links\nfor each page source]
J --> K
K --> L{For each link}
L --> M[normalize_target\nresolve relative / strip base path]
M --> N{Path in index.routes?}
N -- yes --> O{Fragment in page.anchors?}
O -- pass --> P[valid]
O -- fail --> Q[broken fragment]
N -- no --> R{asset_exists or\nredirect_matches?}
R -- yes --> P
R -- no --> S[broken route\n+ closest_route suggestion]
Reviews (4): Last reviewed commit: "Merge branch 'main' into codex/fix-docs-..." | Re-trigger Greptile
Fix broken Fern routes and fragments found by the live docs audit. Add a navigation-aware internal link validator to the standard docs build so regressions fail CI with source locations and route suggestions. Fixes #826 Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
Signed-off-by: Nabin Mulepati <nmulepati@nvidia.com>
37f1ac5 to
fe4bfbb
Compare
andreatnvidia
left a comment
There was a problem hiding this comment.
LGTM. The navigation-aware link checker is well scoped, tested, and correctly wired into the docs build. Limiting validation to latest makes sense for immutable historical snapshots. Approved.
📋 Summary
Fixes the dead internal routes and fragments identified by the published-docs audit, then prevents regressions by validating links against Fern's navigation-derived URLs during the standard docs build. The validator understands nested sections,
skip-slug, camel-case route splitting, Fern heading anchors, configured redirects, version aliases, MDX links, and notebook source content.🔗 Related Issue
Fixes #826
🔄 Changes
✨ Added
make check-fern-linksand run it automatically frommake check-fern-docs.🐛 Fixed
🔧 Changed
🔍 Attention Areas
fern/scripts/check-internal-links.py— route slugs and heading fragments intentionally use different Fern-compatible normalization rules.🧪 Testing
make check-fern-docspasses — internal links pass and Fern reports 0 errorsmake check-fern-linkspasses across 86 current authoring pages.venv/bin/pytest fern/scripts/tests -q— 25 passedmake check-license-headerspasses✅ Checklist