ArchDoc Design record
ArchDoc

Lint

Comparing
v11 to v12
Current
Read the document

archdoc lint runs every L rule over every document and prints findings. With --merge it also runs the merge rules. Exit code 2 if any error, 0 otherwise. Warnings do not affect the exit code unless --strict-warnings is given, in which case a warning alone exits 2.

Severity

Every rule reports an error unless stated. A rule comparing a front matter value against something else does not report where that value did not parse, which L01 reports, and L02 and L10 do not report a title or id that is missing or empty. A finding that no permitted edit to the named document could clear is a warning. This applies to L01, L02, L07, L08, L09, L10, L14, L16, L17, L20 and L21 when the document is frozen, to the L04 and L05 faults that only an edit to a frozen document could clear, and to L03 when every document holding the identifier is frozen. It does not apply to a fault another permitted edit can clear, such as a reference to a document that can be written, nor to L11.

Rules

  • L01 Front matter parses and matches the schema for the type: no unknown keys, no missing required keys, no wrong types, no required key left empty, no as_of left empty, and no empty item in a list. Front matter that is not valid YAML, or not a mapping, is reported once, at the first line at which it stops being valid, and no key in it is reported missing. That line is the first from which the block, cut after it or after any later line, fails as the whole block does, so a construct left open can be reported on a line after the one it opens on: a bracketed list left open after a comma is reported on the line that follows it. So is a file with no front matter block, or one never closed. Error in an editable document; warning in a frozen one.
  • L02 id equals the identifier derived from type and filename. The filename matches <NNNN>-<slug>.md. Error in an editable document; warning in a frozen one.
  • L03 No identifier appears on more than one document. Error, or a warning when every document holding the identifier is frozen.
  • L04 Every identifier in depends, updates, obsoletes and includes, and a term's named_by, resolves to an existing document of a permitted type. Every member of a group resolves, an identifier to an RFC, ADR or ref and any other member to a spec page, and no group lists a member twice. Each finding is reported at the line of the list. A document in no group is not reported. A ref named in depends or includes, and a reference that is not an identifier any document can hold, such as foo, rfc-0001 or ADR-0000, are warnings in a frozen document. A reference to a valid identifier no document holds is always an error.
  • L05 updates and obsoletes reference only accepted documents of the same type. No document updates or obsoletes itself. No document appears in both lists of the same document. Error in an editable document; warning in a frozen one, except that a target that is not accepted is an error unless it is frozen too.
  • L06 includes references only accepted documents.
  • L07 decided is set if and only if the status is terminal. decided is not before created. If backfilled is set, the status is terminal and backfilled is not before decided. Neither condition on the status is checked against an empty status, which L01 reports. On a ref, as_of is not after verified. Error in an editable document; warning in a frozen one.
  • L08 Required sections are present, with exact titles, in the listed relative order. Other H2 sections are permitted between or after them. Rejection rationale is present if and only if the document is rejected. Where the type has a closing section, it is the document's last H2. Error in an editable document; warning in a frozen one.
  • L09 An accepted document has no non-empty Open questions section. Error in an editable document; warning in a frozen one.
  • L10 The H1 matches the front matter. Error in an editable document; warning in a frozen one.
  • L11 Frozen documents are unchanged. For every document whose status on branch is terminal, the working tree file is unchanged from the file at the merge base of HEAD and branch, or from the file at branch's tip, as git judges it; on branch itself, the merge base is its tip. Each revision's documents are found under its own root, from its own archdoc.json, and matched to the working tree's by their path within root, so moving the root is followed. The whole of each revision is listed, whichever directory archdoc runs in. A revision's archdoc.json is the one at the working tree's location, or failing that the one the working tree's moved from: of every archdoc.json in the revision, the only one absent from the working tree, where the revision holds no document under the root it names or holds one that is still under the working tree's root. Where there is no such file, or several, the working tree's settings stand. Where the file cannot be read they stand too, and the rule reports one warning naming branch, whichever revision holds it. Where the revision lists nothing under the root its file names, and the file is at the working tree's location, that root is the directory it names in the working tree, as git spells it, so a root differing from git's listing in case, in Unicode normalisation or through a symbolic link is matched. Where the revision still lists nothing under it, or the file is the one moved from, the root is the first directory in the revision's listing, in git's order, that matches it case-folded and in Unicode normalisation form C, whatever the filesystem; with none, it is taken as written. branch is always the working tree's, so a pull request changing it is judged against the branch it names. A file absent from branch is new and the rule does not apply. A document terminal on branch, present at the merge base and absent from the working tree is an error; a rename is a deletion and a new file. Where HEAD and branch share no commit, the rule reports an error saying a shallow clone needs its full history (fetch-depth: 0). With no commits, the rule is skipped with a warning. When branch does not exist in a repository that has commits, the rule reports an error naming the branch. Outside a git repository, the rule is skipped with a warning.
  • L12 A spec page includes no document that is effectively obsolete. Warning.
  • L13 A ref's verified date is not older than ref_stale_days. A ref carrying as_of is not reported. Warning.
  • L14 No required section is empty. Warning for proposed; error for a document that is terminal in the working tree but not yet on branch; warning once frozen. Not applied to withdrawn.
  • L15 Term structure: exactly one paragraph of definition, and nothing else. The definition runs from the H1 to the end of the file, subsections included. A heading, a thematic break, a setext underline, a list, a blockquote, a table row, or a code or HTML block in it is reported, whether or not a blank line precedes it, as is prose above the H1. A setext underline or table row is one indented at most three spaces. A lone carriage return ends a line. A comment beginning a line outside a code block opens an HTML block, and text after the marker closing it is reported as one. No terms is valid.
  • L19 A spec/glossary.md left behind by a repository scaffolded before terms became files. A warning: the page is valid Markdown and nothing else is wrong with the repository.
  • L16 No unresolved [[...]] wiki link anywhere. Error in an editable document; warning in a frozen one.
  • L17 Every relative Markdown link resolves to an existing file within the repository, named in its exact case, and where it has an anchor, to an existing heading or explicit anchor. A destination with a URI scheme or beginning with / is not relative. The repository is the git repository holding root, or root outside one. Error in an editable document; warning in a frozen one.
  • L18 Every depends entry references a document that is accepted, or that shares the referencing document's non-terminal status. Warning.
  • L20 The question sections have the shape markdown Markdown gives them. Reported at the first line before a section's first question that is not blank or a comment; at a question whose heading produces no anchor, or the same anchor as another heading, and of two questions at the later; at a heading beneath a question; at a blockquote line holding a heading, a comment, or a fence's opening line, the lines within a quoted fence being code; at an open question's final blockquote; at an empty Resolved questions section's heading, or, in a document that has an Open questions section, one that does not follow it; at a resolved question with no heading beneath it that does not end with a blockquote; at an answer with another blockquote before it, or an empty one; and at each Resolved questions heading after the first, whose questions and blockquotes are checked as the first section's are and whose section is otherwise not checked. Not applied to the Open questions section of an accepted document, which L09 checks, or to a withdrawn document. Error in an editable document; warning in a frozen one.
  • L21 Every Changelog section has the shape markdown Markdown gives it. Reported at the first line belonging to no entry after the section's heading and after each entry; at a heading opening or ending the section that is indented by two or three spaces, or is a heading only once a comment on its line is masked; at an entry with no date, one beginning with a date shape not followed by : and a space or the end of the line, one whose date is not a real date, and one with a date and no text; at an entry dated earlier than the dated entry before it, before a valid created, or after decided, the last two unchecked where decided is before created; at each Changelog heading after the first; and at a level two heading differing from Changelog only in case, spacing or punctuation. Not applied to a withdrawn document. Error in an editable document; warning in a frozen one.
  • L01 Front matter parses and matches the schema for the type: no unknown keys, no missing required keys, no wrong types, no required key left empty, no as_of left empty, and no empty item in a list. Front matter that is not valid YAML, or not a mapping, is reported once, at the first line at which it stops being valid, and no key in it is reported missing. That line is the first from which the block, cut after it or after any later line, fails as the whole block does, so a construct left open can be reported on a line after the one it opens on: a bracketed list left open after a comma is reported on the line that follows it. So is a file with no front matter block, or one never closed. Error in an editable document; warning in a frozen one.
  • L02 id equals the identifier derived from type and filename. The filename matches <NNNN>-<slug>.md. Error in an editable document; warning in a frozen one.
  • L03 No identifier appears on more than one document. Error, or a warning when every document holding the identifier is frozen.
  • L04 Every identifier in depends, updates, obsoletes and includes, and a term's named_by, resolves to an existing document of a permitted type. Every member of a group resolves, an identifier to an RFC, ADR or ref and any other member to a spec page, and no group lists a member twice. Each finding is reported at the line of the list. A document in no group is not reported. A ref named in depends or includes, and a reference that is not an identifier any document can hold, such as foo, rfc-0001 or ADR-0000, are warnings in a frozen document. A reference to a valid identifier no document holds is always an error.
  • L05 updates and obsoletes reference only accepted documents of the same type. No document updates or obsoletes itself. No document appears in both lists of the same document. Error in an editable document; warning in a frozen one, except that a target that is not accepted is an error unless it is frozen too.
  • L06 includes references only accepted documents.
  • L07 decided is set if and only if the status is terminal. decided is not before created. If backfilled is set, the status is terminal and backfilled is not before decided. Neither condition on the status is checked against an empty status, which L01 reports. On a ref, as_of is not after verified. Error in an editable document; warning in a frozen one.
  • L08 Required sections are present, with exact titles, in the listed relative order. Other H2 sections are permitted between or after them. Rejection rationale is present if and only if the document is rejected. Where the type has a closing section, it is the document's last H2. Error in an editable document; warning in a frozen one.
  • L09 An accepted document has no non-empty Open questions section. Error in an editable document; warning in a frozen one.
  • L10 The H1 matches the front matter. Error in an editable document; warning in a frozen one.
  • L11 Frozen documents are unchanged. For every document whose status on branch is terminal, the working tree file is unchanged from the file at the merge base of HEAD and branch, or from the file at branch's tip, as git judges it; on branch itself, the merge base is its tip. Each revision's documents are found under its own root, from its own archdoc.json, and matched to the working tree's by their path within root, so moving the root is followed. The whole of each revision is listed, whichever directory archdoc runs in. A revision's archdoc.json is the one at the working tree's location, or failing that the one the working tree's moved from: of every archdoc.json in the revision, the only one absent from the working tree, where the revision holds no document under the root it names or holds one that is still under the working tree's root. Where there is no such file, or several, the working tree's settings stand. Where the file cannot be read they stand too, and the rule reports one warning naming branch, whichever revision holds it. Where the revision lists nothing under the root its file names, and the file is at the working tree's location, that root is the directory it names in the working tree, as git spells it, so a root differing from git's listing in case, in Unicode normalisation or through a symbolic link is matched. Where the revision still lists nothing under it, or the file is the one moved from, the root is the first directory in the revision's listing, in git's order, that matches it case-folded and in Unicode normalisation form C, whatever the filesystem; with none, it is taken as written. branch is always the working tree's, so a pull request changing it is judged against the branch it names. It names the local branch, refs/heads/<branch>, or refs/remotes/origin/<branch> where there is no local one, never a tag or one of git's own refs of the same name. A file absent from branch is new and the rule does not apply. A document terminal on branch, present at the merge base and absent from the working tree is an error; a rename is a deletion and a new file. Where HEAD and branch share no commit, the rule reports an error saying a shallow clone needs its full history (fetch-depth: 0). With no commits, the rule is skipped with a warning. When branch does not exist in a repository that has commits, the rule reports an error naming the branch. Outside a git repository, the rule is skipped with a warning.
  • L12 A spec page includes no document that is effectively obsolete. Warning.
  • L13 A ref's verified date is not older than ref_stale_days. A ref carrying as_of is not reported. Warning.
  • L14 No required section is empty. Warning for proposed; error for a document that is terminal in the working tree but not yet on branch; warning once frozen. Not applied to withdrawn.
  • L15 Term structure: exactly one paragraph of definition, and nothing else. The definition runs from the H1 to the end of the file, subsections included. A heading, a thematic break, a setext underline, a list, a blockquote, a table row, or a code or HTML block in it is reported, whether or not a blank line precedes it, as is prose above the H1. A setext underline or table row is one indented at most three spaces. A lone carriage return ends a line. A comment beginning a line outside a code block opens an HTML block, and text after the marker closing it is reported as one. No terms is valid.
  • L19 A spec/glossary.md left behind by a repository scaffolded before terms became files. A warning: the page is valid Markdown and nothing else is wrong with the repository.
  • L16 No unresolved [[...]] wiki link anywhere. The finding names the edit that clears it: running archdoc link, writing a heading without the link, or, for a terminal document outside a git repository, replacing it by hand. In a frozen document, heading or not, it says the link is left as written. Error in an editable document; warning in a frozen one.
  • L17 Every relative Markdown link resolves to an existing file within the repository, named in its exact case, and where it has an anchor, to an existing heading or explicit anchor. A destination with a URI scheme or beginning with / is not relative. The repository is the git repository holding root, or root outside one. Error in an editable document; warning in a frozen one.
  • L18 Every depends entry references a document that is accepted, or that shares the referencing document's non-terminal status. Warning.
  • L20 The question sections have the shape markdown Markdown gives them. Reported at the first line before a section's first question that is not blank or a comment; at a question whose heading produces no anchor, or the same anchor as another heading, and of two questions at the later; at a heading beneath a question; at a blockquote line holding a heading, a comment, or a fence's opening line, the lines within a quoted fence being code; at an open question's final blockquote; at an empty Resolved questions section's heading, or, in a document that has an Open questions section, one that does not follow it; at a resolved question with no heading beneath it that does not end with a blockquote; at an answer with another blockquote before it, or an empty one; and at each Resolved questions heading after the first, whose questions and blockquotes are checked as the first section's are and whose section is otherwise not checked. Not applied to the Open questions section of an accepted document, which L09 checks, or to a withdrawn document. Error in an editable document; warning in a frozen one.
  • L21 Every Changelog section has the shape markdown Markdown gives it. Reported at the first line belonging to no entry after the section's heading and after each entry; at a heading opening or ending the section that is indented by two or three spaces, or is a heading only once a comment on its line is masked; at an entry with no date, one beginning with a date shape not followed by : and a space or the end of the line, one whose date is not a real date, and one with a date and no text; at an entry dated earlier than the dated entry before it, before a valid created, or after decided, the last two unchecked where decided is before created; at each Changelog heading after the first; and at a level two heading differing from Changelog only in case, spacing or punctuation. Not applied to a withdrawn document. Error in an editable document; warning in a frozen one.

Merge rules

archdoc lint --merge also runs M01 to M04, which compare the working tree with the base: the merge base of HEAD and the configured branch, the branch resolved as L11 resolves it, with the same fallback to origin/<branch>. In a checkout of a pull request merged into the branch, that is the branch as the merge was made; on a branch not rebased since it was cut, it is the commit it was cut from. Every document on the base is read in one batch from its file listing, and the base's archdoc.json in another. Outside a git repository, where the branch does not exist, or where HEAD shares no history with it, --merge exits 1 naming the branch and reports nothing; the last case says a shallow clone needs its full history (fetch-depth: 0). Without --merge no merge rule runs, including in the transition commands. The merge rules report alongside the L rules, with the same output, --json, --strict-warnings and exit codes, and every one reports an error.

A document in the working tree was on the base when the base holds a document at its path, or, for a numbered document, one carrying its identifier at a path absent from the working tree, which is a rename. Any other document arrives.

  • M01 An RFC or ADR arrives as a draft. Reported at its status line, naming archdoc propose with its identifier where it has one.
  • M02 A numbered document arrives carrying an identifier that a document on the base, still in the working tree, carries. Reported at the arriving document's id line, naming the other document's path and archdoc renumber with the arriving document's path.
  • M03 An RFC or ADR's status differs from its status on the base by a transition lifecycle Lifecycle does not permit, under the strict of the base's archdoc.json, found as L11 finds it, or of the working tree's where none is found or it cannot be read. An arriving document is judged as moving from draft, except an arriving draft, which M01 reports, and one carrying backfilled, which L07 requires to be terminal. A document terminal on the base, and a status on either side that is not one of the five, are not judged. Reported at the status line; where the base's strict is on and the move is from draft, the message says to merge the proposal first.
  • M04 An RFC or ADR proposed on the base whose identifier no document in the working tree carries: deleted, or renumbered. Reported at its path on the base, naming archdoc withdraw. A draft may be deleted, and a terminal document's deletion is L11's.

Rule entries

Each rule in the registry carries, besides its code and check:

Field Content
Title A few words naming what the rule checks
Summary What a finding means, as inline Markdown
Remedy How a finding is cleared, as inline Markdown
Since The tag of the first release carrying the rule: v0.1.0-alpha.1 for L01 to L18, v0.5.0 for L19, v0.6.0 for L20, L21 and M01 to M04
Changes Each later release that changed what the rule reports, with a one-line account, in release order. Changes made before the registry recorded them are not listed

A test refuses an entry without a title, summary, remedy or since. The table of rules in the triage guide is the registry's summaries and remedies, one row per rule in code order; a test compares the two, and go test ./internal/template -update-triage rewrites the table. archdoc reference publishes every entry.

Output

One finding per line: <path>:<line>: <severity>: <message> where a line is known, <path>: <severity>: <message> otherwise. <path> is relative to root. Findings are sorted by path, then line, then rule. With --json, a bare JSON array of objects with path, line, severity, message and rule; line is omitted where unknown.

Source spec/lint.md · commit 59ecbf6 · published