check-informal-definitions.yml
Flags technical concepts defined in running prose rather than inside formal Quarto definition divs (::: {#def-...}). In content repositories (such as Quarto books and sites using theorem-type cross-reference divs), technical concepts must be formally defined in dedicated theorem divs (::: {#def-...}), never left in running prose. Concepts defined only in prose lack stable cross-reference IDs, cannot be cited downstream, break hyperlink-on-first-mention requirements, and escape cross-repository consistency audits.
The check flags:
- Bold terms followed by defining language. A bolded term followed by “is”, “are”, “means”, “refers to”, “is defined as”,
\eqdef, or\triangleqoutside a formal::: {#def-...}(or sibling theorem) div. - Mathematical definition operators outside def divs.
\eqdefor\triangleqused in inline or display math outside a def div. - Prose paragraphs under Definitions headings. Prose paragraphs or bolded terms directly under a heading titled “Definitions” that are not wrapped in formal def divs.
- Naming sentences before display math. Sentences ending in “is:” or “are:” immediately preceding display math (
$$...$$) outside a def div. - More than one term in one def div. A
::: {#def-...}div whose body bolds more than one distinct term that is not introduced as an alias (“also called x”, “or x”). A repeated term, a bare abbreviation, a symbol, a gloss in parentheses or quotes, and bold inside a nested div are not counted. One definition per div, so each term gets its own cross-reference ID.
Sections titled “Notation”, “Typographic Conventions”, or “Symbols” are recognized as notation guides and exempt from definition requirements.
Individual lines or files can opt out using directive comments:
- Line or block level:
<!-- check-informal-definitions: allow -->or<!-- check-informal-definitions: ignore --> - File level:
<!-- check-informal-definitions: ignore-file -->
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
path |
string | '.' |
Target directory or file path to scan. |
globs |
string | '*.qmd' |
Space-separated file globs to check. |
paths-ignore |
string | '.git, .github, tests, test, vendor, scratch, _site, node_modules, .venv, venv' |
Comma- or newline-separated paths or glob patterns to ignore. |
fail |
boolean | false |
Whether to fail the workflow if informal definitions are detected (warn-only by default). |
diff-scoped |
boolean | false |
Report only lines added since base-ref. |
base-ref |
string | '' |
Git ref/SHA to diff against when diff-scoped is true. |
diff |
string | '' |
Path to unified diff file to scan added lines from. |
output-markdown |
string | '' |
Path to write Markdown findings report. |
output-json |
string | '' |
Path to write structured JSON findings report. |
python-version |
string | '3.x' |
Python version to set up. |
runs-on |
string | empty (CI_RUNNER variable, else ubuntu-latest) |
Runner label for the job. Use a self-hosted label only for a private repository; never for a public one, whose pull requests can run arbitrary code on it (#1167). |
Permissions
Only contents: read (the default), so no permissions: block is needed.
Example
# Copy to .github/workflows/check-informal-definitions.yml in your repo.
# Flags technical concepts defined in running prose rather than inside formal
# Quarto definition divs (`::: {#def-...}`).
# Only contents:read is needed (the default), so no permissions block is required.
name: Check informal definitions in prose
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
jobs:
check:
uses: Morrison-Lab/gha/.github/workflows/check-informal-definitions.yml@v3
# with:
# globs: '*.qmd' # pathspecs to check (recursive)
# paths-ignore: 'chapters/outtakes/**' # skip known-noisy paths
# fail: true # block instead of warn (warn-only by default)
# diff-scoped: true # report only lines a PR adds
# runs-on: private-runner # self-hosted runner label (private repositories only)See examples/check-informal-definitions.yml for the full caller stub.