Skip to content

[Docs] Check the API pages against the checkout before mkdocs reads it - #46

Merged
lcy-seso merged 2 commits into
tile-ai:mainfrom
lcy-seso:docs/check-api-pages-drift
Sep 5, 2026
Merged

[Docs] Check the API pages against the checkout before mkdocs reads it#46
lcy-seso merged 2 commits into
tile-ai:mainfrom
lcy-seso:docs/check-api-pages-drift

Conversation

@lcy-seso

@lcy-seso lcy-seso commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

problems

  • The API pages name their ops one by one and every build checks TileOPs out fresh, so an op that leaves __all__ upstream aborts the next build. That is how the daily refresh broke (run 33930934575), and the report was a Could not collect line part-way through a mkdocs log.
  • An op TileOPs adds is absent from the site until someone happens to notice.

changes

  • scripts/check_api_pages.py compares the ::: tileops.<family>.<Op> identifiers under docs/api/ against the op list of a TileOPs checkout: families from _FAMILIES, ops from each family's __all__, read with ast because importing a family pulls in torch and the docs environment does not install it.
  • An op the pages name and the checkout does not export fails the run, and the message names the op and the page. A family name matching no family fails the same way.
  • An op exported with no page is printed and does not fail: TileOPs adds ops on its own schedule, and neither an unrelated PR here nor the daily refresh of the whole site is the place to stop for one.
  • The check runs in checks.yml, deploy.yml and render-benchmarks.yml — the three workflows that check TileOPs out — with the same command in each.
  • A run that matches no identifier at all, or finds no checkout, fails rather than passing vacuously. A non-literal __all__ fails rather than being read past, so no op is silently dropped from the comparison.
  • A path of more than two segments, tileops.trace.api._Trace, belongs to no family and is left alone.

checks

  • Against tile-ai/TileOPs@main: 183 ops, on the page and exported, exit 0. Full mkdocs build with that checkout: 0 errors, no warning outside griffe. ruff check scripts hooks.py tests, pytest: pass.
  • Failing inputs exercised: an op documented and removed from __all__; a family name typo; a starred __all__; an ::: line indented or CRLF-terminated; a docs directory with no identifiers; a missing checkout.

The API pages name their ops one by one, and every build checks TileOPs out
fresh, so an op that leaves `__all__` upstream aborts the next build with
`Could not collect` part-way through the log. scripts/check_api_pages.py reads
`_FAMILIES` and each family's `__all__` with ast — importing a family pulls in
torch, which the docs environment does not install — and names the op, and the
page that names it, before mkdocs starts.

An op the pages name and the checkout does not export fails the run. An op
exported with no page is printed and does not: TileOPs adds ops on its own
schedule, and neither an unrelated pull request here nor the daily refresh of
the whole site is the place to stop for one.

The check runs in all three workflows that check TileOPs out.
Copilot AI lite review requested due to automatic review settings September 5, 2026 15:30
@lcy-seso lcy-seso added the docs Documentation label Sep 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new checker has a failure-path logic issue (typo-only families) and a parsing correctness gap (non-string ast.Constants accepted), which can produce misleading results or silently accept invalid data.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a pre-mkdocs validation step to ensure docs/api/ mkdocstrings identifiers remain consistent with the exported TileOPs op surface, preventing mid-build Could not collect failures when upstream __all__ changes.

Changes:

  • Introduces scripts/check_api_pages.py to parse TileOPs _FAMILIES/__all__ via ast and compare against ::: tileops.<family>.<Op> directives under docs/api/.
  • Wires the check into the three GitHub Actions workflows that check out TileOPs (checks.yml, deploy.yml, render-benchmarks.yml).
  • Documents the new check and its intent in CLAUDE.md.
File summaries
File Description
scripts/check_api_pages.py New AST-based consistency check between docs ::: tileops.* directives and TileOPs exported ops.
CLAUDE.md Documents the new check and when it runs.
.github/workflows/checks.yml Runs the API pages check after the TileOPs checkout and deps install.
.github/workflows/deploy.yml Runs the API pages check before generating benchmarks and deploying.
.github/workflows/render-benchmarks.yml Runs the API pages check before the daily refresh render/deploy.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/check_api_pages.py Outdated
Comment on lines +35 to +47
for node in ast.parse(path.read_text(encoding="utf-8")).body:
if not isinstance(node, ast.Assign):
continue
if not any(isinstance(t, ast.Name) and t.id == variable for t in node.targets):
continue
# Anything but a literal of strings is refused rather than read past: a
# name silently dropped here is an op this check would stop looking at.
if not isinstance(node.value, ast.Tuple | ast.List):
raise SystemExit(f"{path}: {variable} is not a list or tuple literal")
names = [e.value for e in node.value.elts if isinstance(e, ast.Constant)]
if len(names) != len(node.value.elts):
raise SystemExit(f"{path}: {variable} holds something other than plain strings")
return names
Comment thread scripts/check_api_pages.py Outdated
Comment on lines +74 to +75
if not any(pages.get(family) for family in families):
raise SystemExit(f"no `::: tileops.<family>.<Op>` identifier under {args.docs}")
A name in `__all__` that is not a string was read as an op name; it is now
refused with the rest of a non-literal list. `ast.parse` gets the filename, so a
syntax error in the checkout names the file it is in.

Pages holding nothing but a mistyped family raised the generic "no identifier"
error, which hid the family the message would have named. That guard is for a
regex that stopped matching, so it now asks whether any identifier was found at
all.
@lcy-seso
lcy-seso merged commit abb742f into tile-ai:main Sep 5, 2026
3 checks passed
@lcy-seso
lcy-seso deleted the docs/check-api-pages-drift branch September 5, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants