@avi2dg/checks 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +9 -10
  3. package/dist/data-shape/index.js +428 -0
  4. package/{templates → dist/templates}/reference.md +1 -1
  5. package/docs/configs/commit-messages.md +1 -1
  6. package/docs/configs/dependency-rules.md +7 -1
  7. package/docs/configs/effect-rules.md +12 -2
  8. package/docs/configs/native-settings.md +10 -31
  9. package/docs/configs/typescript-rules.md +43 -1
  10. package/docs/design.md +210 -104
  11. package/docs/gates/checks-changelog.md +8 -5
  12. package/docs/gates/checks-ci-wiring.md +2 -2
  13. package/docs/gates/checks-comment-gate.md +3 -4
  14. package/docs/gates/checks-commit-identity.md +3 -3
  15. package/docs/gates/checks-docs.md +67 -45
  16. package/docs/gates/checks-exports.md +104 -0
  17. package/docs/gates/checks-flake.md +3 -3
  18. package/docs/gates/checks-lint-coverage.md +17 -9
  19. package/docs/gates/checks-lint.md +8 -4
  20. package/docs/gates/checks-mutation-compare.md +3 -3
  21. package/docs/gates/checks-quarantine-clock.md +3 -5
  22. package/docs/gates/checks-release-notes.md +4 -4
  23. package/docs/gates/checks-release-report.md +3 -3
  24. package/docs/gates/checks-repetition.md +2 -1
  25. package/docs/gates/checks-subsumed-tests.md +3 -3
  26. package/docs/gates/checks-suppressions-ratchet.md +3 -4
  27. package/docs/gates/checks-test-layout.md +4 -4
  28. package/docs/gates/checks-test.md +3 -2
  29. package/docs/gates/checks-unused.md +4 -4
  30. package/docs/gates/checks-vendor.md +3 -3
  31. package/oxlintrc.json +22 -2
  32. package/package.json +17 -9
  33. package/src/complexity/exports.ts +188 -0
  34. package/src/complexity/knip.ts +70 -0
  35. package/src/complexity/unused.ts +7 -56
  36. package/src/core/gates.ts +2 -1
  37. package/src/core/swc.ts +1 -1
  38. package/src/delivery/ci-wiring.ts +1 -1
  39. package/src/dependencies/vendor.ts +4 -5
  40. package/src/docs/doc-names.ts +128 -0
  41. package/src/docs/doc-references.ts +1 -1
  42. package/src/docs/doc-snapshot.ts +1 -1
  43. package/src/docs/doc-templates.ts +4 -4
  44. package/src/docs/docs.ts +17 -14
  45. package/src/docs/prose-matchers.ts +11 -1
  46. package/src/quality/comments.ts +2 -2
  47. package/src/quality/lint-coverage.sh +35 -2
  48. package/{presets → src/quality/presets}/effect.language-service.json +3 -1
  49. package/src/testing/mutation-compare.ts +51 -45
  50. package/src/testing/test-layout.ts +1 -1
  51. package/src/testing/test-report.ts +1 -1
  52. package/ts-reset.d.ts +2 -0
  53. package/tsconfig.effect.json +3 -0
  54. /package/{templates → dist/templates}/adr.md +0 -0
  55. /package/{templates → dist/templates}/agents.md +0 -0
  56. /package/{templates → dist/templates}/changelog.md +0 -0
  57. /package/{templates → dist/templates}/claude.md +0 -0
  58. /package/{templates → dist/templates}/explanation.md +0 -0
  59. /package/{templates → dist/templates}/how-to.md +0 -0
  60. /package/{templates → dist/templates}/readme.md +0 -0
  61. /package/{templates → dist/templates}/tutorial.md +0 -0
  62. /package/{presets → src/quality/presets}/effect.oxlint.json +0 -0
@@ -4,35 +4,40 @@ audience: consumers
4
4
  ---
5
5
  # checks-docs
6
6
 
7
- `checks-docs` is the gate that holds each doc file a change touches to the template for its kind, each line a change adds to a living doc or an agent file to the prose rules, and each path, link and command a living doc names to what the repository holds, and a reader looks it up to learn what a doc file answers to.
7
+ `checks-docs` is the gate that holds a repository's doc files to the kit's templates and prose rules.
8
+ It also fails when a doc names a file, a heading or a script that does not exist, or a name the range removed from every file outside the docs.
8
9
 
9
10
  ## What it checks
10
11
 
11
- It holds each doc file a change touches to the template for its kind, and lists every other doc file that does not conform yet without failing.
12
+ It holds each doc file a change touches to the template for its kind.
13
+ It lists every other doc file that does not match its template yet, and does not fail on it.
12
14
  It holds each line a change adds or edits in a living doc or an agent file to the prose rules, as [The prose rules](#the-prose-rules) says.
13
- It fails when a living doc names a path, link or command that does not resolve, and the range added it or broke it, as [Paths, links and commands](#paths-links-and-commands) says.
14
- The package ships one template per kind under `templates/`, and a repository starts a new doc file by copying one:
15
+ It fails when a living doc or an agent file names a path, link or command that does not resolve, and the range added or broke it.
16
+ It fails when a living doc or an agent file names a code span the range removed from every file outside the docs, on any line.
17
+ [Paths, links and commands](#paths-links-and-commands) says how each reference resolves.
18
+ The package ships one template per kind under `dist/templates/`, and a repository starts a new doc file by copying one:
15
19
 
16
20
  ```sh
17
- cp node_modules/@avi2dg/checks/templates/how-to.md docs/add-a-supplier.md
21
+ cp node_modules/@avi2dg/checks/dist/templates/how-to.md docs/add-a-supplier.md
18
22
  ```
19
23
 
24
+ A host resolves a template as `@avi2dg/checks/templates/how-to.md`, which keeps pointing at it wherever the package holds the templates.
25
+
20
26
  <!-- generated doc-kinds: bun run build writes it from src/docs/doc-rules.ts, src/docs/doc-templates.ts and scripts/doc-blocks.ts -->
21
27
 
22
28
  | File | Kind | Template |
23
29
  | --- | --- | --- |
24
- | `README.md` | readme | `templates/readme.md` |
25
- | `CHANGELOG.md` | changelog | `templates/changelog.md` |
26
- | `AGENTS.md` | agents | `templates/agents.md` |
27
- | `CLAUDE.md` | claude | `templates/claude.md` |
28
- | `CONTRIBUTING.md` | how-to | `templates/how-to.md` |
29
- | each file in `docs/adr/` but its generated index, `README.md` | adr | `templates/adr.md` |
30
- | a page with `kind` in front matter | tutorial, how-to, reference or explanation | `templates/<mode>.md` |
30
+ | `README.md` | readme | `dist/templates/readme.md` |
31
+ | `CHANGELOG.md` | changelog | `dist/templates/changelog.md` |
32
+ | `AGENTS.md` | agents | `dist/templates/agents.md` |
33
+ | `CLAUDE.md` | claude | `dist/templates/claude.md` |
34
+ | `CONTRIBUTING.md` | how-to | `dist/templates/how-to.md` |
35
+ | each file in `docs/adr/` but its generated index, `README.md` | adr | `dist/templates/adr.md` |
36
+ | a page with `kind` in front matter | tutorial, how-to, reference or explanation | `dist/templates/<mode>.md` |
31
37
 
32
38
  <!-- end generated doc-kinds -->
33
39
 
34
- A file the table names on its own, such as `README.md`, sits at the repository root.
35
- No other Markdown file is judged, save a page under `docs/`, which needs a mode.
40
+ Each file the table names by name sits at the repository root.
36
41
  A page under `docs/` declares its mode in front matter:
37
42
 
38
43
  ```yaml
@@ -41,24 +46,28 @@ kind: tutorial
41
46
  ---
42
47
  ```
43
48
 
44
- A template decides a file's structure, and the template file itself is the reference for each kind:
49
+ No other Markdown file is held to a template.
50
+ A template decides a file's structure, and the template file itself is the reference for its kind:
45
51
 
46
52
  - A file opens with one `# ` title on its first line and has text before its first section.
47
53
  It skips no heading level, and no heading is Overview, Introduction or How it works.
48
- - Its sections are the template's headings in the template's order.
54
+ - Its sections are the template's headings, in the template's order.
49
55
  A heading in angle brackets is one the writer names.
50
- One marked verb first is left to review, since no program tells a verb from a noun there.
51
- A heading the template does not have, in that place, is refused.
56
+ A heading the template marks verb first is left to review, because no program tells a verb from a noun.
57
+ A heading the template does not have in that place is refused.
52
58
  - A record in `docs/adr/` is named for its four-digit number, and its title opens with the same number.
53
- A `Date: YYYY-MM-DD` line follows the title, the first word under Status is Proposed, Accepted, Rejected, Deprecated, Superseded or Retired, and no other record holds its number.
54
- - A changelog lists its releases newest first, each opening with a `Released YYYY-MM-DD.` line.
59
+ A `Date: YYYY-MM-DD` line follows the title.
60
+ The first word under Status is Proposed, Accepted, Rejected, Deprecated, Superseded or Retired.
61
+ No other record holds its number.
62
+ - A changelog lists its releases newest first, and each opens with a `Released YYYY-MM-DD.` line.
55
63
  - A how-to or tutorial page numbers its steps.
56
64
  - `CLAUDE.md` is its template word for word.
57
- It is a fixed agent pointer rather than a living doc, so it takes only the prose rules for agent files.
65
+ It is a fixed pointer to `AGENTS.md` rather than a living doc, so it takes only the prose rules for agent files.
58
66
 
59
67
  ## The prose rules
60
68
 
61
- A line a change adds or edits in a living doc or an agent file is held to the prose rules, and a line the change leaves alone is not, so a repository needs no cleanup pass before it runs them.
69
+ The prose rules judge each line a change adds or edits in a living doc or an agent file.
70
+ A line the change leaves alone is not judged, so a repository needs no cleanup pass before it runs them.
62
71
 
63
72
  <!-- generated living-docs: bun run build writes it from src/docs/prose-matchers.ts and scripts/doc-blocks.ts -->
64
73
 
@@ -87,6 +96,7 @@ These are records, and take no prose rule:
87
96
  | a hyphen used as a dash | `a - b` or `a -- b` | End the sentence, or use a comma | yes |
88
97
  | a semicolon | `;` | Use two sentences | yes |
89
98
  | a promise about the future | `until #11`, `is planned`, `will soon`, `coming soon`, `in a future release` | Say what is true now | no |
99
+ | a report about the past | `formerly`, `previously`, `as before`, `used to`, `was replaced`, `moved from`, `new owner` | Say what is true now, and leave what changed to the changelog, a commit message or a decision record | yes |
90
100
  | a sentence that opens by talking about the page | `This page explains` | Talk directly about the subject | no |
91
101
  | a second sentence on one line | `It builds. It ships.` | Start it on its own line | no |
92
102
  | a sentence that runs across lines | `It builds` with `and ships.` on the next line | Join the sentence onto one line | no |
@@ -94,27 +104,36 @@ These are records, and take no prose rule:
94
104
  <!-- end generated prose-rules -->
95
105
 
96
106
  A line holds one sentence, so a changed line is a changed sentence.
97
- A bold label that opens a line, as in `**Status.**`, heads the sentence after it rather than counting as one.
98
- Fenced code, inline code, link destinations, URLs, HTML comments and front matter are not prose, so no rule reads them.
107
+ A bold label that opens a line, as in `**Status.**`, heads the sentence after it and is not a sentence of its own.
108
+ No rule reads fenced code, inline code, link destinations, URLs, HTML comments or front matter.
99
109
  Readability scores and word choice, such as easy, are not checked.
100
110
 
101
111
  `src/docs/prose-matchers.ts` holds the rules and a synchronous `proseRefused()`, and imports nothing.
102
- A host such as a hook bundle can therefore copy it alone into a directory with no `node_modules` and import it as `@avi2dg/checks/scripts/prose-matchers.ts`, to refuse the same lines at write time.
112
+ The package exports it as `@avi2dg/checks/scripts/prose-matchers.ts`.
113
+ A host such as a write-time hook can copy that one file into a directory with no `node_modules`, and refuse the same lines.
103
114
 
104
115
  ## Paths, links and commands
105
116
 
106
- Each reference a living doc names has to resolve at the head commit:
117
+ Each reference a living doc or an agent file names has to resolve at the head commit:
107
118
 
108
119
  - A path in inline code that ends in a file extension, such as `src/core/lint.ts`, names a file from the root or from the doc's directory.
109
- - A relative Markdown link names a file or a directory, and its anchor names a heading in the file it links, as GitHub derives the anchor, or an explicit `id`.
120
+ - A relative Markdown link names a file or a directory.
121
+ Its anchor names a heading in that file, as GitHub derives the anchor, or an explicit `id`.
110
122
  - A `bun run` command in code names a script in the nearest `package.json`, a bin in `node_modules/.bin`, or a file that exists.
123
+ - A code span fails when some tracked file outside the docs held that exact text at the base, and none holds it at the head.
124
+ A span the path check already fails on is not reported again.
125
+ A name an installed direct dependency still holds counts as present.
126
+ A span with a space, a placeholder or a leading dash names a command or a flag, and is skipped.
127
+ A span that opens with the repository's own package name and a slash, `node_modules/`, `./` or `~/` reads as the file it names.
111
128
 
112
129
  A reference that does not resolve fails when it sits on a line the range adds or edits.
113
- It fails on any other line when the range broke it, as by deleting the file it names or renaming the heading it links, and is listed as advisory when it was broken before the range.
114
- A path under a top directory the repository lacks at both ends of the range names another repository's file, such as a consumer's, and is passed over.
115
- So is a path git ignores, since a clean checkout lacks a generated file by design.
130
+ On any other line, it fails when the range broke it, for example by deleting the file it names or renaming the heading it links.
131
+ A reference that was broken before the range is listed as advisory.
132
+ A path whose top directory the repository lacks at both ends of the range names another repository's file, such as a consumer's, and is skipped.
133
+ A path git ignores is skipped too, because a clean checkout lacks a generated file by design.
116
134
 
117
- A living doc that speaks to a consuming repository sets `audience: consumers` in its front matter, so no `bun run` command it names is held to a `package.json`:
135
+ A page that speaks to a consuming repository sets `audience: consumers` in its front matter.
136
+ No `bun run` command on such a page is looked up in a `package.json`:
118
137
 
119
138
  ```yaml
120
139
  ---
@@ -125,11 +144,14 @@ audience: consumers
125
144
 
126
145
  ## What it reads
127
146
 
128
- It reads each Markdown file from the head commit and uses its path or front matter to choose a mode.
147
+ It reads each Markdown file at the head commit, and uses its path or front matter to choose its kind.
129
148
  A file the range adds, changes or renames is held to its template, and a file it deletes is not.
130
149
  It reads the lines the range adds or edits from the diff, with renames detected, so a renamed doc is judged only on the lines the rename changed.
131
- It reads the files tracked at both ends of the range and the `scripts` of each `package.json` a living doc sits under.
132
- From the working tree it reads the ignore files git reads, and `node_modules/.bin`.
150
+ It reads the files tracked at both ends of the range, and the `scripts` of each `package.json` a living doc or an agent file sits under.
151
+ It compares each code span a living doc or an agent file names with the text git tracks outside the docs at both ends of the range.
152
+ It reads the repository's own name and its direct dependencies from the root `package.json` at the head commit.
153
+ A name that an installed direct dependency still holds counts as present.
154
+ From the working tree it reads the ignore files git reads, `node_modules/.bin`, and the directory of each direct dependency under `node_modules`.
133
155
 
134
156
  ## Arguments
135
157
 
@@ -145,31 +167,31 @@ With one it is that commit against its parent, or against the empty tree for a r
145
167
 
146
168
  | Code | When |
147
169
  | --- | --- |
148
- | 0 | every doc file the range touches holds to its template, every line it adds to a living doc or an agent file holds to the prose rules, and it adds or breaks no reference that does not resolve |
149
- | 1 | a doc file the range touches does not hold to its template, a line the range adds to a living doc or an agent file breaks a prose rule, or the range adds or breaks a reference that does not resolve |
150
- | 2 | a `package.json` does not decode, or a ref does not resolve |
170
+ | 0 | every doc file the range touches holds to its template, every line it adds to a living doc or an agent file holds to the prose rules, it adds or breaks no reference that does not resolve, and no code span a living doc or an agent file names vanished from every file outside the docs |
171
+ | 1 | a doc file the range touches does not hold to its template, a line the range adds to a living doc or an agent file breaks a prose rule, the range adds or breaks a reference that does not resolve, or the range removes a name a living doc or an agent file still carries |
172
+ | 2 | a `package.json` does not decode, a ref does not resolve, or `grep` cannot read an installed direct dependency |
151
173
 
152
174
  ## Sample output
153
175
 
154
176
  ```
155
- docs: 4 violation(s):
177
+ docs: 6 violation(s):
156
178
  README.md:1: lacks `## Where things are`
157
179
  README.md:12: carries `;`, a semicolon. Use two sentences
180
+ README.md:14: carries `former`, a report about the past. Say what is true now, and leave what changed to the changelog, a commit message or a decision record
158
181
  README.md:20: names `scripts/bild.ts`, which is not in the repository
159
182
  docs/parts.md: is a page under docs/ with no mode; add kind: tutorial, how-to, reference, explanation in YAML front matter
183
+ docs/parts.md:9: names `gates.lint`, which the range removed from every file outside the docs. Say what holds now, or drop the line
160
184
  docs: advisory, 1 doc file(s) the range leaves alone do not hold to their templates yet:
161
185
  docs/adr/0001-quality-gates.md: 5 violation(s)
162
- docs: advisory, 1 path(s), link(s) or command(s) the living docs name were broken before the range:
186
+ docs: advisory, 1 path(s), link(s) or command(s) the living docs or agent files name were broken before the range:
163
187
  docs/parts.md:9: links to `suppliers.md#prices`, and `docs/suppliers.md` has no heading with that anchor
164
188
  ```
165
189
 
166
- ## Opting out
190
+ ## When it runs
167
191
 
168
- It applies to every repository, so no selection leaves it out.
169
- A file the range leaves alone is only listed as advisory, so a repository adopts the templates as its files change.
170
- A line the range leaves alone takes no prose rule, so a repository adopts the prose rules as its lines change.
171
- A living doc with `audience: consumers` in its front matter holds no `bun run` command to a `package.json`.
172
- `checks-lint` runs it over each pull request's range, as [checks-lint](checks-lint.md) says.
192
+ `checks-lint` runs it over each pull request's range in every repository, as [checks-lint](checks-lint.md) says.
193
+ A repository adopts the templates as its files change, and the prose rules as its lines change, because an untouched file or line never fails those checks.
194
+ A name the range removes fails wherever a doc still carries it, because the removal is what turned the line stale.
173
195
 
174
196
  ## Related topics
175
197
 
@@ -0,0 +1,104 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
5
+ # checks-exports
6
+
7
+ `checks-exports` is the gate that refuses an exported value or type nothing imports.
8
+
9
+ ## What it checks
10
+
11
+ It runs Knip with the repository's own configuration and names each exported value and type no file imports.
12
+ It reads only the exports and types issue types, so an unreferenced file or an unused dependency never fails it.
13
+ It asks Knip for those issue types itself, so a configuration that narrows `include` or excludes them still has its exports judged.
14
+ A configuration that turns the exports or types rules off silences those symbols, so keep both rules on.
15
+ It holds each reported symbol against `exports-baseline.json`, and fails on any symbol the baseline does not hold.
16
+ It fails on any baseline entry the range adds unless Knip reports that same symbol unused at the base, so the baseline records debt that already existed and never debt the range creates.
17
+ It fails on any baseline entry Knip no longer reports, so the baseline only shrinks.
18
+ It fails when the repository tracks no TypeScript source, since an empty scan would pass without judging anything.
19
+ It fails when the repository holds no Knip configuration, since Knip's default entries cannot tell a dead export from a public one.
20
+
21
+ ## What it reads
22
+
23
+ It runs Knip over the working tree, so an uncommitted file is judged like a committed one.
24
+ It reads the repository's Knip configuration, which names the entries.
25
+ It reads `exports-baseline.json` in the repository root, which holds each accepted unused export as a file, kind and name triple.
26
+ It reads `exports-baseline.json` again at the base of the range, where a commit without the file counts as empty.
27
+ When the range adds baseline entries, it runs Knip again on a temporary checkout of the base and removes the checkout when it ends.
28
+ That checkout links the repository's `node_modules`, so a configuration importing the kit's base loads there too.
29
+ Knip configurations do not extend a package file, so the consumer configuration imports the kit's base and spreads it:
30
+
31
+ ```ts
32
+ import base from "@avi2dg/checks/knip-base.json";
33
+
34
+ export default { ...base, entry: ["src/index.ts", "tests/**/*.test.ts"] };
35
+ ```
36
+
37
+ The base in `knip-base.json` reports only unreferenced files.
38
+ The gate resolves the Knip binary from the installed kit, so a consumer installs nothing beyond the kit.
39
+
40
+ ## Arguments
41
+
42
+ ```sh
43
+ checks-exports <base-ref> <head-ref>
44
+ checks-exports <ref>
45
+ checks-exports --write
46
+ ```
47
+
48
+ With two arguments the base is where the head branched off, at their merge-base.
49
+ When the checked-out commit is a merge of the head ref and one other commit, as a pull request's default checkout is, the base is that other commit instead.
50
+ So under `checks-lint` a pull request's merge checkout is judged against the base branch tip it merges, and a symbol that branch already baselined does not count as added.
51
+ With one the base is that commit's parent, or the empty tree for a repository's first commit, where nothing counts as already unused.
52
+ With `--write` it records every unused export and type Knip reports into `exports-baseline.json`, the way `oxlint --suppress-all` seeds `oxlint-suppressions.json`.
53
+
54
+ ## Seeding a baseline
55
+
56
+ A repository adopting the gate runs `checks-exports --write` on a branch that changes no source and commits the file it writes.
57
+ The gate passes that range, since Knip reports every seeded symbol unused at the base too.
58
+ A seed written after the range adds a dead export, or after it removes the last import of one, fails on that symbol.
59
+
60
+ ## Exit codes
61
+
62
+ | Code | When |
63
+ | --- | --- |
64
+ | 0 | no reported symbol is unlisted, no baseline entry is added or stale, or `--write` recorded the baseline |
65
+ | 1 | a reported symbol is unlisted, a baseline entry is added or stale or the repository holds no Knip configuration |
66
+ | 2 | a ref does not resolve, the repository tracks no TypeScript source, Knip cannot run, or a report or baseline does not parse |
67
+
68
+ ## Sample output
69
+
70
+ ```
71
+ exports: 2 unused export(s) not in exports-baseline.json:
72
+ src/used.ts: unusedExport (export)
73
+ src/used.ts: UnusedOptions (type)
74
+ ```
75
+
76
+ A baseline entry the range adds fails when Knip does not report its symbol unused at the base:
77
+
78
+ ```
79
+ exports: 1 exports-baseline.json export(s) the range adds that its base did not leave unused, remove the export instead:
80
+ src/used.ts: unusedExport (export)
81
+ ```
82
+
83
+ A passing run with a held baseline counts what it holds:
84
+
85
+ ```
86
+ exports: 2 unused export(s) in exports-baseline.json, and no new ones
87
+ ```
88
+
89
+ A passing run with an empty baseline says so:
90
+
91
+ ```
92
+ exports: no unused exports or types
93
+ ```
94
+
95
+ ## When it runs
96
+
97
+ `checks-lint` runs it over each pull request's range when the repository tracks a `.ts` or `.tsx` file.
98
+ Such a repository names its entries in a Knip configuration.
99
+
100
+ ## Related topics
101
+
102
+ - [checks-lint](checks-lint.md)
103
+ - [checks-suppressions-ratchet](checks-suppressions-ratchet.md)
104
+ - [checks-unused](checks-unused.md)
@@ -4,7 +4,7 @@ audience: consumers
4
4
  ---
5
5
  # checks-flake
6
6
 
7
- `checks-flake` is the scheduled run that finds flaky tests and records the seeds each one fails with, and a reader looks it up to reproduce a flaky failure.
7
+ `checks-flake` is the scheduled run that finds flaky tests and records the seeds each one fails with.
8
8
 
9
9
  ## What it checks
10
10
 
@@ -48,9 +48,9 @@ checks-flake: 3 of 10 run(s) failed, 1 test(s) failing in them
48
48
  Reproduce a failing run with bun test --randomize --seed=<seed>.
49
49
  ```
50
50
 
51
- ## Opting out
51
+ ## When it runs
52
52
 
53
- Nothing runs it but a schedule the repository writes.
53
+ Only a schedule the repository writes runs it.
54
54
 
55
55
  ## Running it on a schedule
56
56
 
@@ -4,18 +4,23 @@ audience: consumers
4
4
  ---
5
5
  # checks-lint-coverage
6
6
 
7
- `checks-lint-coverage` is the gate that fails when oxlint silently skips a tracked TypeScript file, and a reader looks it up when a file seems never to be linted.
7
+ `checks-lint-coverage` is the gate that fails when oxlint skips a tracked TypeScript file, or when the program `tsconfig.json` builds drops the ts-reset rules, without saying so.
8
8
 
9
9
  ## What it checks
10
10
 
11
11
  It fails when oxlint skips a tracked `.ts` or `.tsx` file, for example through a stray `.gitignore` entry.
12
12
  It compares `git ls-files` against oxlint's own file walk and names the missing files.
13
13
 
14
+ It fails when the program `tsconfig.json` builds leaves out the `is-array` or the `json-parse` rule of `@total-typescript/ts-reset`, which `tsconfig.effect.json` lists.
15
+ A `tsconfig.json` that does not extend `@avi2dg/checks/tsconfig.effect.json`, or that sets both `files` and `include`, leaves both rules out.
16
+ [The TypeScript rules](../configs/typescript-rules.md) says what the two rules refuse.
17
+
14
18
  ## What it reads
15
19
 
16
20
  It reads the working tree: the `*.ts` and `*.tsx` files `git ls-files` lists, and the files `oxlint --debug=files` walks.
17
21
  It walks without naming a path, since an explicit path bypasses the ignore files whose skips it looks for.
18
- oxlint must be on `PATH`, as it is under a package script.
22
+ It reads the program from `tsc --listFilesOnly -p tsconfig.json`, and passes over the program when the root holds no `tsconfig.json`.
23
+ oxlint and tsc must be on `PATH`, as they are under a package script.
19
24
 
20
25
  ## Arguments
21
26
 
@@ -25,29 +30,32 @@ It takes none.
25
30
 
26
31
  | Code | When |
27
32
  | --- | --- |
28
- | 0 | oxlint walks every tracked `.ts` and `.tsx` file, or the repository tracks none |
29
- | 1 | oxlint skips a tracked file |
30
- | 2 | oxlint cannot walk the tree, as when it is not on `PATH` or its config does not parse |
33
+ | 0 | the repository tracks no `.ts` or `.tsx` file, or oxlint walks each one and the program holds both ts-reset rules or the root holds no `tsconfig.json` |
34
+ | 1 | oxlint skips a tracked file, or the program drops a ts-reset rule |
35
+ | 2 | oxlint cannot walk the tree, or tsc cannot list the program after oxlint walks every tracked file, as when either is not on `PATH` or a config does not parse |
31
36
 
32
37
  ## Sample output
33
38
 
34
39
  ```
35
40
  lint-coverage: oxlint skips 1/3 tracked .ts/.tsx files; missing:
36
41
  ignored/b.ts
42
+ lint-coverage: the program tsconfig.json builds drops the ts-reset rules: is-array json-parse
43
+ extend @avi2dg/checks/tsconfig.effect.json, and set files or include in tsconfig.json but not both
37
44
  ```
38
45
 
39
- A passing run counts the files:
46
+ A passing run counts the files and names the rules:
40
47
 
41
48
  ```
42
49
  lint-coverage: 71/71 tracked .ts/.tsx files
50
+ lint-coverage: the program tsconfig.json builds holds the ts-reset rules is-array and json-parse
43
51
  ```
44
52
 
45
- ## Opting out
53
+ ## When it runs
46
54
 
47
- `checks-lint` runs this gate only when the repository tracks `.ts` or `.tsx` files.
48
- A repository that tracks one keeps it.
55
+ `checks-lint` runs it when the repository tracks a `.ts` or `.tsx` file.
49
56
 
50
57
  ## Related topics
51
58
 
52
59
  - [checks-lint](checks-lint.md)
53
60
  - [The Effect rules](../configs/effect-rules.md)
61
+ - [The TypeScript rules](../configs/typescript-rules.md)
@@ -40,15 +40,19 @@ With two arguments, the base and head override range discovery.
40
40
 
41
41
  ## Sample output
42
42
 
43
+ <!-- generated lint-sample: bun run build writes it from KIT_GATES in src/core/gates.ts and scripts/doc-blocks.ts -->
44
+
43
45
  ```
44
46
  checks-lint: range 2504acf098d120e73a8ece3c96f22b934f35c6a8..10ba7d8935b73ed72624120a1542e51bd21ca7c7 from HEAD against origin/main
45
- checks-lint: 1 of 9 gate(s) failed: checks-comment-gate
47
+ checks-lint: 1 of 11 gate(s) failed: checks-comment-gate
46
48
  ```
47
49
 
48
- ## Opting out
50
+ <!-- end generated lint-sample -->
51
+
52
+ ## When it runs
49
53
 
50
- A repository runs `checks-lint` in a pull request workflow with the full git history fetched.
51
- The gate automatically omits TypeScript gates when no TypeScript file is tracked.
54
+ A repository runs it from `bun run lint` in a pull request workflow that fetches the whole git history.
55
+ It leaves out the TypeScript gates while the repository tracks no TypeScript file.
52
56
 
53
57
  ## Related topics
54
58
 
@@ -4,7 +4,7 @@ audience: consumers
4
4
  ---
5
5
  # checks-mutation-compare
6
6
 
7
- `checks-mutation-compare` is the gate that holds every mutant in a pull request to no regression rather than an absolute score, and a reader looks it up to wire mutation testing into CI.
7
+ `checks-mutation-compare` is the gate that fails a pull request when any mutant regresses, rather than judging an absolute score.
8
8
 
9
9
  ## What it checks
10
10
 
@@ -65,9 +65,9 @@ mutation-compare: REGRESSION (1 mutant(s))
65
65
  moved src/loader.ts:4:1 ClassDeclaration "class {}": Killed -> RuntimeError
66
66
  ```
67
67
 
68
- ## Opting out
68
+ ## When it runs
69
69
 
70
- Nothing runs it but a CI step the repository writes.
70
+ Only a CI step the repository writes runs it.
71
71
  A repository runs it with `--advisory` for its first month, then drops the flag so it blocks.
72
72
 
73
73
  ## Running it in CI
@@ -4,7 +4,7 @@ audience: consumers
4
4
  ---
5
5
  # checks-quarantine-clock
6
6
 
7
- `checks-quarantine-clock` is the gate that fails a test left in `tests/quarantine/` past 30 days, and a reader looks it up when a quarantined test went red.
7
+ `checks-quarantine-clock` is the gate that fails a test left in `tests/quarantine/` past 30 days.
8
8
 
9
9
  ## What it checks
10
10
 
@@ -12,7 +12,6 @@ It fails naming each test that entered `tests/quarantine/` more than 30 days bef
12
12
  `checks-test-layout` pins `tests/quarantine/` out of every default run, so a test there protects nothing until it moves back.
13
13
  Each failure names the file, the day it entered quarantine, and what to do, which is to fix it and move it back, or delete it.
14
14
  The limit is 30 days for every test, with no setting to raise it.
15
- GitLab quarantines fast for 3 days and long term for at most 3 months, then opens a deletion merge request automatically.
16
15
 
17
16
  ## What it reads
18
17
 
@@ -46,11 +45,10 @@ quarantine-clock: 1 test(s) in tests/quarantine/ is past 30 days; fix each and m
46
45
  tests/quarantine/unit/billing.test.ts entered quarantine on 2026-08-01 (45 days ago)
47
46
  ```
48
47
 
49
- ## Opting out
48
+ ## When it runs
50
49
 
51
- It applies to every repository, so no selection leaves it out.
50
+ `checks-lint` runs it over each pull request's range in every repository, as [checks-lint](checks-lint.md) says.
52
51
  A repository with no test file under `tests/quarantine/` passes with nothing checked.
53
- `checks-lint` runs it over each pull request's range, as [checks-lint](checks-lint.md) says.
54
52
 
55
53
  ## Related topics
56
54
 
@@ -95,7 +95,7 @@ jobs:
95
95
  run: gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file "$RUNNER_TEMP/release-notes.md"
96
96
  ```
97
97
 
98
- A repository that never publishes to npm releases with this workflow instead, since only `checks` publishes a package:
98
+ A repository that never publishes to npm releases with this workflow instead:
99
99
 
100
100
  ```yaml
101
101
  name: release
@@ -130,10 +130,10 @@ jobs:
130
130
  Cut a release by merging a pull request that holds only the version bump and the built changelog, then tagging the merge commit on the target branch and pushing the tag.
131
131
  The workflow refuses a tag that disagrees with `package.json`, so the tag always names the section the notes come from.
132
132
 
133
- ## Opting out
133
+ ## When it runs
134
134
 
135
- Nothing runs it but the release workflow of a repository that publishes GitHub releases.
136
- A repository with no versioned releases leaves it out.
135
+ Only the release workflow of a repository that publishes GitHub releases runs it.
136
+ A repository with no versioned releases does not need it.
137
137
 
138
138
  ## Related topics
139
139
 
@@ -53,10 +53,10 @@ A history with nothing to release prints one line:
53
53
  release-report: no unreleased changes since v0.1.0
54
54
  ```
55
55
 
56
- ## Opting out
56
+ ## When it runs
57
57
 
58
- Nothing runs it but a person or a scheduler deciding when to cut a release.
59
- A repository with no versioned releases leaves it out.
58
+ Only a person or a scheduler deciding when to cut a release runs it.
59
+ A repository with no versioned releases does not need it.
60
60
 
61
61
  ## Related topics
62
62
 
@@ -48,8 +48,9 @@ repetition: 1 file(s) .jscpd.json holds repeat more lines than where the range s
48
48
  src/copy.ts: 10 repeated line(s), up from 0
49
49
  ```
50
50
 
51
- ## Opting out
51
+ ## When it runs
52
52
 
53
+ `checks-lint` runs it over each pull request's range when the repository tracks a `.ts` or `.tsx` file.
53
54
  When the head holds no `.jscpd.json`, the gate reports that no file was measured.
54
55
 
55
56
  ## Related topics
@@ -4,7 +4,7 @@ audience: consumers
4
4
  ---
5
5
  # checks-subsumed-tests
6
6
 
7
- `checks-subsumed-tests` is the report that lists each test another test subsumes in a Stryker mutation run, and a reader looks it up to judge whether the suite carries tests it no longer needs.
7
+ `checks-subsumed-tests` is the report that lists each test in a Stryker mutation run that one other test subsumes, by killing every mutant it kills.
8
8
 
9
9
  ## What it checks
10
10
 
@@ -63,9 +63,9 @@ greedy cover: 3 of 6 test(s) keep all 6 kill(s)
63
63
  cover "tests/mul.test.ts > mul checks its guard"
64
64
  ```
65
65
 
66
- ## Opting out
66
+ ## When it runs
67
67
 
68
- Nothing runs it but a person who wants the figures.
68
+ Only a person who wants the figures runs it.
69
69
 
70
70
  ## Related topics
71
71
 
@@ -4,7 +4,7 @@ audience: consumers
4
4
  ---
5
5
  # checks-suppressions-ratchet
6
6
 
7
- `checks-suppressions-ratchet` is the gate that holds oxlint's bulk-suppression baseline to counts that only fall, and a reader looks it up when a change raised a count.
7
+ `checks-suppressions-ratchet` is the gate that fails when a change raises a count in `oxlint-suppressions.json`.
8
8
 
9
9
  ## What it checks
10
10
 
@@ -43,11 +43,10 @@ suppressions-ratchet: 2 count(s) in oxlint-suppressions.json rose or appeared; f
43
43
  src/dispatch.ts typescript/no-non-null-assertion rose from 12 to 13
44
44
  ```
45
45
 
46
- ## Opting out
46
+ ## When it runs
47
47
 
48
- It applies to every repository, so no selection leaves it out.
48
+ `checks-lint` runs it over each pull request's range in every repository, as [checks-lint](checks-lint.md) says.
49
49
  A repository with no `oxlint-suppressions.json` passes, since both ends count as empty.
50
- `checks-lint` runs it over each pull request's range, as [checks-lint](checks-lint.md) says.
51
50
 
52
51
  ## Related topics
53
52
 
@@ -4,7 +4,7 @@ audience: consumers
4
4
  ---
5
5
  # checks-test-layout
6
6
 
7
- `checks-test-layout` is the gate that holds a repository's tests to one layout, and a reader looks it up to learn where a test file goes and what it may import.
7
+ `checks-test-layout` is the gate that holds a repository's tests to one layout, which says where a test file goes and what it may import.
8
8
 
9
9
  ## What it checks
10
10
 
@@ -83,10 +83,10 @@ test-layout: 4 violation(s)
83
83
  bunfig.toml: bunfig.toml is missing; bun has no bunfig extends, so copy node_modules/@avi2dg/checks/bunfig.toml
84
84
  ```
85
85
 
86
- ## Opting out
86
+ ## When it runs
87
87
 
88
- `checks-lint` runs this gate when the repository tracks TypeScript, so a repository without TypeScript needs neither the test script nor bunfig.
89
- A repository that tracks one keeps it.
88
+ `checks-lint` runs it when the repository tracks TypeScript.
89
+ A repository without TypeScript needs neither the `checks-test` script nor `bunfig.toml`.
90
90
 
91
91
  ## Related topics
92
92
 
@@ -96,9 +96,10 @@ A run with no skipped tests ends with:
96
96
  checks-test: no test skipped
97
97
  ```
98
98
 
99
- ## Opting out
99
+ ## When it runs
100
100
 
101
- A repository that tracks no TypeScript source does not need `checks-test`, as [checks-test-layout](checks-test-layout.md) says.
101
+ The repository's `test` script runs it.
102
+ A repository that tracks no TypeScript source does not need it, as [checks-test-layout](checks-test-layout.md) says.
102
103
 
103
104
  ## Related topics
104
105