Skip to content

Docs testing framework: static checks, anchor validation, live smoke checks, and CI wiring - #6991

Open
emmanueletienne-blip wants to merge 26 commits into
mainfrom
devin/1789659014-docs-check-framework
Open

emmanueletienne-blip wants to merge 26 commits into
mainfrom
devin/1789659014-docs-check-framework

Conversation

@emmanueletienne-blip

@emmanueletienne-blip emmanueletienne-blip commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

A layered docs testing framework for buildwithfern.com/learn that fails at the earliest stage that can catch a problem:

Stage Workflow What runs
PR, source docs-checks.yml unit tests, scripts/docs_check static checks, fern check
PR, external links docs-checks.yml lychee over http(s) links in changed files (shared .github/lychee.toml, extracted from check-links.yml)
PR, rendered preview preview-docs.yml scripts/docs_check/smoke.py against the preview for every page the PR touches
push to main publish-docs.yml smoke.py against production for every derived URL after fern generate
weekday schedule docs-checks.yml full static run + full production smoke run; failures open/update a tracking issue

Static checker (python3 -m scripts.docs_check, PyYAML only) rebuilds every page's published /learn/... URL from fern/docs.yml + product navigation (product slug, skip-slug, slug: overrides, frontmatter slug relative to the product root, CamelCase splitting GitLabgit-lab, APIsap-is) and validates the tree against that model. Errors: nav-path-missing, broken-internal-link, broken-anchor, missing-snippet, missing-asset, changelog-filename, changelog-missing-tags. Warnings: redirected-link, relative-page-link, orphan-page, unused-snippet, missing-title, missing-description, stub-page, changelog-h1. Plus a per-product coverage table in the job summary and a JSON artifact.

broken-anchor: #fragment on same-page and /learn/... links must match an id the target page renders. Ids are derived from source in document order with a shared duplicate counter (api, api-1): headings (with optional [#id]), <Step>/<Tab>/<Accordion> titles, <ParamField path>, <Anchor id>, recursing into included snippets. A first version that only modeled headings produced 164 false positives; the shipped version reports 36, every one confirmed missing in the live HTML. A residual gap: some generated components apply their own id transformation (one link, #user-agent on the PHP configuration page, resolves in source but not on the site), documented in the README.

smoke.py: fetch derived URLs from a deployed origin; fail on non-200, Page not found / Something went wrong in the body, or an image under <main> that does not load. --changed maps edited pages to their URL and edited snippets to every including page; an edited navigation YAML widens the run to the whole site. 404/5xx are retried with backoff so a propagating deploy does not fail the run.

$ python3 -m scripts.docs_check.smoke
checking 335 pages on https://buildwithfern.com
0 failures across 335 pages

The one 404 the first run found (/learn/api-definitions/ferndef/depending-on-other-apis) was a slug-derivation bug, not an unpublished page: the platform splits APIs as ap-is. Fixed in slugify.

Baseline: scripts/docs_check/baseline.txt suppresses 194 pre-existing findings (<check> <path> <message>, one occurrence per line) so the job is green today and only new problems fail a PR; the 36 anchor entries are real broken fragments for triage. Content fixes: two broken internal links on main.

Verification

  • python3 -m unittest discover -s scripts/docs_check/tests -t . → 13 tests OK
  • python3 -m scripts.docs_check --strict0 errors, 0 warnings (194 suppressed by baseline)
  • smoke.py against production → 0 failures across 335 pages; against the PR preview with --changed → 0 failures
  • lychee 0.18 with .github/lychee.toml over sample changed files → 0 errors
  • fern check --warnings unchanged; zizmor: no new findings; Vale passes

Link to Devin session: https://app.devin.ai/sessions/4b823dd919a841988f58f31b6dc722a2
Open in Devin Desktop: https://app.devin.ai/desktop/session/4b823dd919a841988f58f31b6dc722a2?variant=devin
Requested by: @emmanueletienne-blip


Devin Review

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

github-actions Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

…n pages, guard --write-baseline --only

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…includes and every snippet includer, tolerate folder/ref versions

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…link user feedback to its canonical URL

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…ding

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…b, preview and post-publish verification

- broken-anchor check: #fragment links must match a heading, explicit [#id],
  <Anchor id>, Step/Tab/Accordion title or ParamField path on the target page
  (snippet anchors included). All 36 findings confirmed against the live site.
- slugify: split trailing capitals (APIs -> ap-is), matching the platform;
  every derived URL now returns 200 on buildwithfern.com.
- smoke.py: fetch derived page URLs from a deployed site; fail on non-200,
  error-page markers and broken <main> images. --changed maps pages and
  snippets to URLs; navigation YAML edits widen to the whole site.
- docs-checks.yml: lychee over changed files on PRs (shared .github/lychee.toml,
  extracted from check-links.yml); scheduled production smoke run feeds the
  tracking issue.
- preview-docs.yml smoke-tests changed pages on the preview; publish-docs.yml
  verifies every URL after fern generate.
- untrack __pycache__

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration devin-ai-integration Bot changed the title Add docs_check static framework and Docs Checks CI workflow Docs testing framework: static checks, anchor validation, live smoke checks, and CI wiring Sep 17, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

…de them from lychee; trigger on README.md

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…nges

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…e on link-free changes

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…checks

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…ing, chain-before-page

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ge sample), weekday job

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…as nightly

Fragments are matched to the schema object that declares their keys, elided
and templated values are ignored, and the 27 real discrepancies found today
are baselined in examples-baseline.txt for triage.

Also: console smoke ignores prefetches of other pages (the preview changelog
index 500s on every preview) and duplicate resource-load console lines, and
the PR external-link job includes .md/.yaml files.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ng in smoke.py

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…atic checker

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ors: accept any explicit id attribute

Production publishes the home page at /learn/home (sitemap and navigation
slug both say so); /learn is only a redirect. Restores the original
/learn/home#get-support link, which targets a raw <div id> the anchor
check previously did not recognise.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… not rendered

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…elCase SVG ids)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant