Lint a technote#
Documenteer provides a command-line linter, documenteer technote lint, that checks a technote’s metadata and structure before it is built and published.
Its most important job is verifying that every author has an internal_id that resolves in the Rubin author database (authordb.yaml), since these IDs are needed to mint a DOI for the technote.
The command also checks that the content declares an abstract and that requirements.txt installs Documenteer correctly.
Rubin’s technote CI (from the rubin-sphinx-technote-workflows repository) runs this command so that builds fail early when a technote’s metadata is incomplete.
Run the linter#
Run the linter from the root of a technote repository:
documenteer technote lint
If your technote uses the standard Makefile (see Migrate legacy reStructuredText/Sphinx technical notes), the linter also runs as part of the repository’s combined lint target, alongside the Pre-commit hooks and the link checker:
make lint
The command prints each issue it finds, prefixed with its stable rule code (for example, [TN101]), followed by a summary and a link to the documentation page for every rule that fired:
[TN101] Author Yusra AlSayyad is missing an internal_id. Did you mean 'alsayyady' (matched by ORCID)? Run 'documenteer technote sync-authors' after adding it.
Found 1 error(s) and 0 warning(s).
Learn more:
TN101: https://documenteer.lsst.io/technotes/lint/tn101.html
The command exits with a non-zero status when any error-level issue remains, which is what causes a CI build to fail.
Warning-level issues are reported but do not fail the command unless you pass --strict.
Options#
--dir <path>,-d <path>Path to the technote directory to lint. Defaults to the current directory (
.). The command locatestechnote.toml, the content file (index.rst,index.md, orindex.ipynb), andrequirements.txtwithin this directory.--strict,-sPromote all warnings to errors. With this flag, any finding — including the warning-level rules below — causes the command to exit non-zero.
Rules#
Each rule has a stable code so that findings are easy to triage (and, in the future, to except individually), and a landing page describing the rule, showing a failing technote, and walking through the fix.
Codes are grouped by concern: TN0xx for structural rules, TN1xx for metadata, and TN2xx for content.
Code |
Group |
Rule |
Default severity |
|---|---|---|---|
Structural |
|
Error |
|
Structural |
|
Warning |
|
Structural |
|
Warning |
|
Structural |
|
Error |
|
Structural |
|
Error |
|
Structural |
The technote has a content file ( |
Error |
|
Metadata |
Every author declares an |
Error |
|
Metadata |
Each author’s |
Error |
|
Metadata |
The author database is reachable so that IDs can be resolved. |
Warning |
|
Content |
The content file declares an abstract directive. |
Error |
|
Content |
The abstract uses the abstract directive rather than a section heading. |
Error |
|
Content |
The content file can be parsed to scan for an abstract. |
Error |
|
Content |
The abstract directive has body content. |
Error |
How the abstract is found#
The abstract rules (TN2xx) work by scanning the source, not by running a Sphinx build, so it is worth knowing what the scan does and does not see.
Both the reStructuredText directive (
.. abstract::) and the MyST fenced directive (a triple-backtick or:::fence opening with{abstract}) are recognized, in any letter case — docutils lowercases directive names, so a{Abstract}fence builds and passes.In reStructuredText, text on the marker line itself (
.. abstract:: The abstract.) is directive content and passes.Directive options (for example
:class: dropdown) are configuration rather than content, so a directive holding only options is empty (TN204).An abstract factored into another file and pulled in with
.. include::or a MyST{include}fence is found: those includes are resolved one level deep, relative to the content file. Includes within an included file are not followed, and an include that is missing or points outside the technote directory is ignored (Sphinx reports those itself).An
index.ipynbnotebook’s markdown cells are concatenated before scanning, so its findings name the file without a line number.
Non-Sphinx technotes#
Some technote-series repositories are not Sphinx projects at all: they publish through the shared technote CI with a custom build command (an Org-mode deck, for example).
When a directory has no content file (index.rst, index.md, or index.ipynb) and no conf.py, the linter treats it as one of these and checks only that its technote.toml is well formed — TN004, TN005, TN001, and the author rules (TN1xx).
The requirements.txt rules (TN002/TN003), the content rules (TN2xx), and TN006 are skipped, since they describe a Documenteer/Sphinx build that these repositories do not have.
A repository that does have a conf.py but no content file is a broken Sphinx technote, and is reported as TN006.
Note
Author internal_id values are the key to consistent author identification across Rubin documents, and a missing or unknown ID blocks DOI generation.
See Maintaining author metadata to learn how to add and update the authors that TN101–TN103 check.