@avi2dg/checks 0.21.0 → 0.23.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 (57) hide show
  1. package/CHANGELOG.md +66 -40
  2. package/CONTRIBUTING.md +14 -10
  3. package/README.md +15 -24
  4. package/bunfig.toml +1 -1
  5. package/dist/effect-channel/index.js +122 -0
  6. package/dist/{index.js → readability/index.js} +8 -120
  7. package/docs/configs/commit-messages.md +5 -1
  8. package/docs/configs/dependency-rules.md +5 -2
  9. package/docs/configs/effect-rules.md +32 -33
  10. package/docs/configs/native-settings.md +74 -0
  11. package/docs/configs/typescript-rules.md +4 -0
  12. package/docs/design.md +26 -27
  13. package/docs/gates/checks-backtest.md +4 -0
  14. package/docs/gates/checks-ci-wiring.md +30 -93
  15. package/docs/gates/checks-comment-gate.md +4 -0
  16. package/docs/gates/checks-commit-identity.md +23 -27
  17. package/docs/gates/checks-docs.md +23 -21
  18. package/docs/gates/checks-flake.md +4 -10
  19. package/docs/gates/checks-lint-coverage.md +5 -1
  20. package/docs/gates/checks-lint.md +22 -104
  21. package/docs/gates/checks-mutation-compare.md +4 -0
  22. package/docs/gates/checks-quarantine-clock.md +4 -0
  23. package/docs/gates/checks-repetition.md +27 -41
  24. package/docs/gates/checks-subsumed-tests.md +4 -0
  25. package/docs/gates/checks-suppressions-ratchet.md +4 -0
  26. package/docs/gates/checks-test-layout.md +16 -8
  27. package/docs/gates/checks-test.md +68 -36
  28. package/docs/gates/checks-vendor.md +20 -13
  29. package/oxlintrc.json +1 -1
  30. package/package.json +10 -21
  31. package/scripts/ci-wiring.ts +28 -97
  32. package/scripts/commit-identity.ts +32 -4
  33. package/scripts/doc-rules.ts +26 -11
  34. package/scripts/doc-templates.ts +2 -1
  35. package/scripts/docs.ts +4 -7
  36. package/scripts/gates.ts +0 -29
  37. package/scripts/git.ts +24 -1
  38. package/scripts/lint.ts +15 -34
  39. package/scripts/range-gate.ts +1 -2
  40. package/scripts/repetition.ts +51 -40
  41. package/scripts/shell-command.ts +7 -1
  42. package/scripts/swc.ts +46 -0
  43. package/scripts/test-layout.ts +40 -56
  44. package/scripts/test-skips.ts +180 -0
  45. package/scripts/test.ts +33 -38
  46. package/scripts/vendor.ts +55 -11
  47. package/dist/feature-rules.js +0 -354
  48. package/docs/configs/quality-file.md +0 -103
  49. package/docs/gates/checks-feature-owners.md +0 -113
  50. package/docs/gates/checks-quality.md +0 -111
  51. package/docs/gates/checks-size-budget.md +0 -107
  52. package/quality.schema.json +0 -514
  53. package/scripts/feature-owners.ts +0 -139
  54. package/scripts/quality-file.ts +0 -353
  55. package/scripts/quality.ts +0 -363
  56. package/scripts/size-budget.ts +0 -285
  57. package/scripts/size-rules.ts +0 -126
@@ -1,122 +1,59 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-ci-wiring
2
6
 
3
- `checks-ci-wiring` is the gate that fails when a command the repository's CI must run no longer runs on pull requests to the default branch, and a reader looks it up to learn which workflow step counts.
7
+ `checks-ci-wiring` verifies that required commands run in the repository's own pull request workflows.
4
8
 
5
9
  ## What it checks
6
10
 
7
- No local check sees a gate drop out of CI, since a workflow whose lint step became a no-op leaves `bun run lint` green.
8
- The repository declares its gates once, in `quality.json`:
11
+ The kit requires `./node_modules/.bin/commitlint` on every pull request.
12
+ It requires `bun run lint`, `bun run build`, `bun run typecheck` and `bun run test` for each of those scripts that `package.json` defines.
13
+ A `build` script also requires `git diff --exit-code`.
14
+ The target branch is the pull request base in CI, else the branch `refs/remotes/origin/HEAD` names, else the default branch of the repository in GitHub's event, else `main`.
15
+ A `pull_request` trigger without a branch filter covers every target branch.
9
16
 
10
- ```json
11
- "gates": {
12
- "ci": ["bun run lint", "bun run typecheck", "bun run test"]
13
- }
14
- ```
15
-
16
- It looks, for each gate, for a `run:` step that is the gate command alone on one line, optionally followed by plain arguments.
17
- Plain arguments are words, quoted strings, and `$VAR` or `${VAR}` expansions.
18
- `bun run lint --quiet` and `bunx checks-comment-gate "origin/$BASE_REF" "$HEAD_SHA"` count.
19
- `bun run lint:deps`, `echo bun run lint` and a step `name:` do not.
20
-
21
- A step never counts when its script has a second line or any of these, because each can run the gate without its failure failing the step:
22
-
23
- - `|`, `||`, `&&`, `;` or `&`
24
- - `$(...)` or backticks
25
- - `<` or `>` redirection
26
- - a comment
27
- - a leading `NAME=value`
28
-
29
- The report names such a gate and says to give it its own step with nothing else in it.
30
- A gate step counts only when all of these hold:
31
-
32
- - Its workflow triggers on `pull_request`.
33
- Any `branches` or `branches-ignore` filter there keeps the default branch, any `types` filter keeps `opened` and `synchronize`, and it sets no `paths` or `paths-ignore` filter, which would let some pull requests skip the gate.
34
- - Neither the step nor its job sets `if: false` or `continue-on-error: true`, bare or as `${{ false }}` and `${{ true }}`.
35
- - Its job needs no job, directly or through a chain, that sets `if: false`, unless a job on that chain has an `if:` calling `always()`, `failure()` or `cancelled()`.
36
- GitHub prefixes every other `if:`, including `true` and `success()`, with `success()`, so a job whose needed job was skipped is skipped too.
37
-
38
- A job calling a local reusable workflow, such as `uses: ./.github/workflows/x.yml`, passes its own trigger and `if:` down to the called workflow's steps.
39
- A remote reusable workflow, such as `uses: owner/repo/...@ref`, is not a supported way to wire a gate.
40
- It is not read, so a gate must run as a `run:` step in the repository's own workflows, such as `bunx checks-comment-gate`.
41
-
42
- A step running `checks-lint` also counts for a declared gate that calls one of the gates `checks-lint` runs by its bare bin name, when the step calls `checks-lint` the same way.
43
- `bunx checks-lint` counts for `bunx checks-comment-gate "origin/$BASE_REF" "$HEAD_SHA"`.
44
- A step running `bun run lint` counts only for the `bun run lint` gate, since the check never reads what a package script runs.
45
- So once `lint` runs `checks-lint`, the per-gate entries can leave `gates.ci` along with the workflows that ran them.
46
-
47
- A command a schedule must run, such as the flake run, goes in `gates.scheduled`:
48
-
49
- ```json
50
- "gates": {
51
- "ci": ["bun run lint", "bun run typecheck", "bun run test"],
52
- "scheduled": ["bunx checks-flake --runs 10 --report flake-report.json"]
53
- }
54
- ```
55
-
56
- Each counts only as a step of the same plain shape in a workflow whose `on` carries `schedule` with at least one `cron`, under the same `if: false`, `continue-on-error: true` and `needs` rules as a gate.
57
-
58
- It also checks `gates.lint`, as [Gate selection](checks-lint.md#gate-selection) says.
17
+ Each command needs its own plain `run` step.
18
+ A step can call a path command through `bun run`.
19
+ The check follows local reusable workflows but not remote reusable workflows.
20
+ It refuses a step or job with `if: false` or `continue-on-error: true`.
21
+ It also refuses a workflow that does not trigger on both `opened` and `synchronize` pull requests to the target branch.
22
+ A path filter cannot cover every pull request and therefore cannot satisfy the check.
59
23
 
60
24
  ## What it reads
61
25
 
62
- It reads the working tree: `quality.json` for `defaultBranch`, `gates.ci`, `gates.scheduled` and `gates.lint`, and every `.github/workflows/*.yml` and `*.yaml`.
63
- The default branch is `main` when `quality.json` declares none.
64
- It parses each workflow with `Bun.YAML` and never runs it.
26
+ The bin reads `.github/workflows/*.yml`, `*.yaml` and the `scripts` in `package.json` from the working tree.
27
+ It reads the target branch from `GITHUB_BASE_REF`, then from `refs/remotes/origin/HEAD` and then from the event file `GITHUB_EVENT_PATH` names.
28
+ It parses the workflows with `Bun.YAML` without executing them.
65
29
 
66
30
  ## Arguments
67
31
 
68
- It takes none.
32
+ It takes no arguments.
69
33
 
70
34
  ## Exit codes
71
35
 
72
- | Code | When |
36
+ | Code | Result |
73
37
  | --- | --- |
74
- | 0 | every declared command runs where it must |
75
- | 1 | a gate does not run on pull requests to the default branch, a scheduled command runs on no schedule, or `gates.lint` leaves out a gate that applies |
76
- | 2 | `quality.json` declares no `gates.ci` or does not decode, a gate or scheduled command is not one plain command, or a workflow does not parse |
77
-
78
- Whether a workflow is well formed is actionlint's question, not this one's.
38
+ | 0 | Every required command has a reachable step. |
39
+ | 1 | A required command is missing or blocked. |
40
+ | 2 | A workflow or `package.json` cannot be decoded. |
79
41
 
80
42
  ## Sample output
81
43
 
82
- It names each gap, with every step that runs the gate and why that step does not count:
83
-
84
- ```
85
- ci-wiring: 1 of 8 gate(s) do not run on pull requests to main:
86
- bun run lint
87
- .github/workflows/release.yml job publish step 7: .github/workflows/release.yml does not trigger on pull_request
88
- ```
89
-
90
- It names each scheduled command no schedule runs:
44
+ A missing step produces a report like this:
91
45
 
92
46
  ```
93
- ci-wiring: 1 of 1 scheduled command(s) do not run on a schedule:
94
- bunx checks-flake --runs 10 --report flake-report.json
95
- .github/workflows/ci.yml job checks step 5: .github/workflows/ci.yml does not trigger on a schedule
47
+ ci-wiring: 1 of 6 gate(s) do not run on pull requests to main:
48
+ bun run test
49
+ no run step invokes it
96
50
  ```
97
51
 
98
52
  ## Opting out
99
53
 
100
- It applies to every repository, so no selection leaves it out.
101
- It runs inside `lint`, through `checks-lint`, because deleting the step that runs a check is the violation it catches:
102
-
103
- ```json
104
- "scripts": {
105
- "lint": "oxlint --type-aware && checks-lint"
106
- }
107
- ```
108
-
109
- ## Limits
110
-
111
- The check reads workflow files and never runs them, so it deliberately does not evaluate these:
112
-
113
- - an `if:` expression other than a constant `true` or `false`, which counts as running
114
- - a `strategy.matrix` `include` or `exclude`, so a matrix that drops every combination still counts as running its steps
115
- - a remote reusable workflow, whose steps are never read
116
- - anything that happens at run time on the runner, such as what the gate command itself does, the shell's options, and a step or job that fails or times out before the gate step
54
+ Every repository runs this gate through `checks-lint`.
117
55
 
118
56
  ## Related topics
119
57
 
120
58
  - [checks-lint](checks-lint.md)
121
- - [checks-flake](checks-flake.md)
122
- - [The quality file](../configs/quality-file.md)
59
+ - [Native settings](../configs/native-settings.md)
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-comment-gate
2
6
 
3
7
  `checks-comment-gate` is the gate that refuses a banned comment on a line a change adds, and a reader looks it up to learn which comments it refuses.
@@ -1,19 +1,25 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-commit-identity
2
6
 
3
- `checks-commit-identity` is the gate that refuses a commit carrying an identity other than the repository owner's, and a reader looks it up to allow another author.
7
+ `checks-commit-identity` checks a commit's author and committer against the owners in `package.json` and refuses coauthor trailers.
4
8
 
5
9
  ## What it checks
6
10
 
7
- It walks every commit in a range and fails when one carries an identity outside the allowlist, naming the offending commit and the reason.
8
- It refuses a commit whose author or committer is outside the allowlist.
9
- It refuses a commit whose trailer block carries a `Co-authored-by:` trailer, as git parses it.
10
- Other trailers, and prose in the body that mentions an address, are left alone.
11
- `GitHub <noreply@github.com>` is allowed as committer only, since that is who writes a squash merge.
11
+ The author and committer of each commit must be allowed.
12
+ A commit whose trailer block carries a `Co-authored-by` trailer, as git parses it, is refused.
13
+ `GitHub <noreply@github.com>` is allowed as committer only.
12
14
 
13
15
  ## What it reads
14
16
 
15
- It reads the author, the committer and the trailers of each commit in the range, and `commitIdentity.authors` from `quality.json`.
16
- The allowlist is `avi2d <avi2dg@gmail.com>` when `quality.json` declares none.
17
+ `package.json` uses its standard `author` and `contributors` fields for allowed authors.
18
+ Each person can be any form npm allows, an object with `name` and optional `email` and `url`, or a string such as `Avi <avi@example.com> (https://example.com)`.
19
+ A person with both a name and an email is an allowed author.
20
+ A person without an email is ignored.
21
+ When no person carries an email, the kit allows `avi2d <avi2dg@gmail.com>`.
22
+ The bin reads commits from git and parses their trailer blocks.
17
23
 
18
24
  ## Arguments
19
25
 
@@ -22,16 +28,16 @@ checks-commit-identity <base-ref> <head-ref>
22
28
  checks-commit-identity <ref>
23
29
  ```
24
30
 
25
- With two arguments it checks every commit the head holds and the base does not.
26
- With one it checks that commit alone.
31
+ With two arguments, the bin checks every commit the head holds and the base does not.
32
+ With one argument, it checks that commit alone.
27
33
 
28
34
  ## Exit codes
29
35
 
30
- | Code | When |
36
+ | Code | Result |
31
37
  | --- | --- |
32
- | 0 | every commit carries only allowed identities |
33
- | 1 | a commit carries a foreign identity |
34
- | 2 | a ref does not resolve, the arguments do not parse, or `quality.json` does not decode |
38
+ | 0 | Every commit carries an allowed identity. |
39
+ | 1 | A commit carries a foreign identity. |
40
+ | 2 | A ref, argument or `package.json` cannot be decoded. |
35
41
 
36
42
  ## Sample output
37
43
 
@@ -39,25 +45,15 @@ With one it checks that commit alone.
39
45
  commit-identity: 1 of 1 commit(s) in HEAD carry a foreign identity:
40
46
  79fa94f9f027 feat: foreign
41
47
  author someone <someone@example.com>
42
- committer someone <someone@example.com>
43
48
  allowed: avi2d <avi2dg@gmail.com>
44
- allowed as committer only: GitHub <noreply@github.com>
45
49
  ```
46
50
 
47
51
  ## Opting out
48
52
 
49
- It applies to every repository, so no selection leaves it out.
50
- A repository with other owners restates the allowlist in `quality.json`:
51
-
52
- ```json
53
- "commitIdentity": {
54
- "authors": [{ "name": "avi2d", "email": "avi2dg@gmail.com" }]
55
- }
56
- ```
57
-
58
- `checks-lint` runs it over each pull request's range, as [checks-lint](checks-lint.md) says.
53
+ This gate runs on every repository through `checks-lint`.
54
+ The repository adds owners through `package.json` rather than omitting the gate.
59
55
 
60
56
  ## Related topics
61
57
 
62
- - [The commit message lint](../configs/commit-messages.md)
58
+ - [Native settings](../configs/native-settings.md)
63
59
  - [checks-lint](checks-lint.md)
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-docs
2
6
 
3
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.
@@ -13,7 +17,7 @@ The package ships one template per kind under `templates/`, and a repository sta
13
17
  cp node_modules/@avi2dg/checks/templates/how-to.md docs/add-a-supplier.md
14
18
  ```
15
19
 
16
- <!-- generated doc-kinds: bun run build writes it from scripts/doc-rules.ts, scripts/quality-file.ts, scripts/doc-templates.ts and scripts/doc-blocks.ts -->
20
+ <!-- generated doc-kinds: bun run build writes it from scripts/doc-rules.ts, scripts/doc-templates.ts and scripts/doc-blocks.ts -->
17
21
 
18
22
  | File | Kind | Template |
19
23
  | --- | --- | --- |
@@ -23,21 +27,18 @@ cp node_modules/@avi2dg/checks/templates/how-to.md docs/add-a-supplier.md
23
27
  | `CLAUDE.md` | claude | `templates/claude.md` |
24
28
  | `CONTRIBUTING.md` | how-to | `templates/how-to.md` |
25
29
  | each file in `docs/adr/` but its generated index, `README.md` | adr | `templates/adr.md` |
26
- | a page `docs.pages` declares | tutorial, how-to, reference or explanation | `templates/<mode>.md` |
30
+ | a page with `kind` in front matter | tutorial, how-to, reference or explanation | `templates/<mode>.md` |
27
31
 
28
32
  <!-- end generated doc-kinds -->
29
33
 
30
34
  A file the table names on its own, such as `README.md`, sits at the repository root.
31
35
  No other Markdown file is judged, save a page under `docs/`, which needs a mode.
32
- Which Diátaxis mode a page is written in is a judgment, so `quality.json` declares it:
33
-
34
- ```json
35
- "docs": {
36
- "pages": {
37
- "reference": ["docs/gates/*.md"],
38
- "explanation": ["docs/design.md"]
39
- }
40
- }
36
+ A page under `docs/` declares its mode in front matter:
37
+
38
+ ```yaml
39
+ ---
40
+ kind: tutorial
41
+ ---
41
42
  ```
42
43
 
43
44
  A template decides a file's structure, and the template file itself is the reference for each kind:
@@ -113,20 +114,21 @@ It fails on any other line when the range broke it, as by deleting the file it n
113
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.
114
115
  So is a path git ignores, since a clean checkout lacks a generated file by design.
115
116
 
116
- A doc that speaks to a repository installing this one is declared under `docs.forConsumers` in `quality.json`, and its commands are not held to this repository's `package.json`:
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`:
117
118
 
118
- ```json
119
- "docs": {
120
- "forConsumers": ["README.md", "docs/gates/*.md"]
121
- }
119
+ ```yaml
120
+ ---
121
+ kind: reference
122
+ audience: consumers
123
+ ---
122
124
  ```
123
125
 
124
126
  ## What it reads
125
127
 
126
- It reads each Markdown file from the head commit, and `docs.pages` from `quality.json`.
128
+ It reads each Markdown file from the head commit and uses its path or front matter to choose a mode.
127
129
  A file the range adds, changes or renames is held to its template, and a file it deletes is not.
128
130
  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.
129
- It reads the files tracked at both ends of the range, the `scripts` of each `package.json` a living doc sits under, and `docs.forConsumers` from `quality.json`.
131
+ It reads the files tracked at both ends of the range and the `scripts` of each `package.json` a living doc sits under.
130
132
  From the working tree it reads the ignore files git reads, and `node_modules/.bin`.
131
133
 
132
134
  ## Arguments
@@ -145,7 +147,7 @@ With one it is that commit against its parent, or against the empty tree for a r
145
147
  | --- | --- |
146
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 |
147
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 |
148
- | 2 | `quality.json` or a `package.json` does not decode, or a ref does not resolve |
150
+ | 2 | a `package.json` does not decode, or a ref does not resolve |
149
151
 
150
152
  ## Sample output
151
153
 
@@ -154,7 +156,7 @@ docs: 4 violation(s):
154
156
  README.md:1: lacks `## Where things are`
155
157
  README.md:12: carries `;`, a semicolon. Use two sentences
156
158
  README.md:20: names `scripts/bild.ts`, which is not in the repository
157
- docs/parts.md: is a page under docs/ with no mode; declare it under docs.pages in quality.json as tutorial, how-to, reference, explanation
159
+ docs/parts.md: is a page under docs/ with no mode; add kind: tutorial, how-to, reference, explanation in YAML front matter
158
160
  docs: advisory, 1 doc file(s) the range leaves alone do not hold to their templates yet:
159
161
  docs/adr/0001-quality-gates.md: 5 violation(s)
160
162
  docs: advisory, 1 path(s), link(s) or command(s) the living docs name were broken before the range:
@@ -166,7 +168,7 @@ docs: advisory, 1 path(s), link(s) or command(s) the living docs name were broke
166
168
  It applies to every repository, so no selection leaves it out.
167
169
  A file the range leaves alone is only listed as advisory, so a repository adopts the templates as its files change.
168
170
  A line the range leaves alone takes no prose rule, so a repository adopts the prose rules as its lines change.
169
- A doc listed under `docs.forConsumers` holds no `bun run` command to this repository's `package.json`.
171
+ A living doc with `audience: consumers` in its front matter holds no `bun run` command to a `package.json`.
170
172
  `checks-lint` runs it over each pull request's range, as [checks-lint](checks-lint.md) says.
171
173
 
172
174
  ## Related topics
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-flake
2
6
 
3
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.
@@ -47,7 +51,6 @@ Reproduce a failing run with bun test --randomize --seed=<seed>.
47
51
  ## Opting out
48
52
 
49
53
  Nothing runs it but a schedule the repository writes.
50
- A repository that stops scheduling it also drops it from `gates.scheduled`, which `checks-ci-wiring` otherwise fails on.
51
54
 
52
55
  ## Running it on a schedule
53
56
 
@@ -73,15 +76,6 @@ jobs:
73
76
  path: flake-report.json
74
77
  ```
75
78
 
76
- It declares the step in `gates.scheduled`, so `checks-ci-wiring` fails once the schedule stops running it:
77
-
78
- ```json
79
- "gates": {
80
- "ci": ["bun run lint", "bun run typecheck", "bun run test"],
81
- "scheduled": ["bunx checks-flake --runs 10 --report flake-report.json"]
82
- }
83
- ```
84
-
85
79
  ## Related topics
86
80
 
87
81
  - [checks-test](checks-test.md)
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-lint-coverage
2
6
 
3
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.
@@ -40,7 +44,7 @@ lint-coverage: 71/71 tracked .ts/.tsx files
40
44
 
41
45
  ## Opting out
42
46
 
43
- A repository that tracks no `.ts` or `.tsx` file leaves it out of `gates.lint`, as [Gate selection](checks-lint.md#gate-selection) says.
47
+ `checks-lint` runs this gate only when the repository tracks `.ts` or `.tsx` files.
44
48
  A repository that tracks one keeps it.
45
49
 
46
50
  ## Related topics
@@ -1,43 +1,25 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-lint
2
6
 
3
- `checks-lint` is the entry point that runs every lint gate of the kit over one range, and a reader looks it up to learn which range it resolves and how a repository selects its gates.
7
+ `checks-lint` runs every applicable kit lint gate over one range and reports each failure.
4
8
 
5
9
  ## What it checks
6
10
 
7
- It runs each gate the table under [What runs](../../README.md#what-runs) lists, in that table's order, and names every one that fails rather than stopping at the first.
8
- Each gate runs as its own bin in a child process, with its output passed straight through, so a gate behaves the same called alone or through `checks-lint`.
9
- `checks-ci-wiring` always runs, so a repository on `checks-lint` declares `gates.ci`, as [checks-ci-wiring](checks-ci-wiring.md) says.
10
- It holds the test layout unless the selection leaves out `checks-test-layout`.
11
+ It runs the gates under [What runs](../../README.md#what-runs) in table order, each in its own process.
12
+ Gates requiring tracked TypeScript files begin running when the repository tracks TypeScript.
13
+ All other gates run for every repository.
11
14
 
12
15
  ## What it reads
13
16
 
14
- It reads `quality.json` for `defaultBranch` and `gates.lint`, and resolves the range once, handing the same one to every range gate.
15
- A tree gate reads the working tree and is handed no range.
16
-
17
- Locally, and on any event other than a pull request, the range ends at `HEAD` and starts where `HEAD` branched from the origin default branch.
18
- That branch is `origin/HEAD`.
19
- When `origin/HEAD` is not set, as in an `actions/checkout` clone, it is `origin/<defaultBranch>` from `quality.json`, and `origin/main` when that is not declared.
20
-
21
- In a GitHub Actions pull request, where `GITHUB_EVENT_NAME` is `pull_request`, the range ends at the event's head sha and starts where that branched from `origin/<base branch>`, so GitHub's merge commit is never in it.
22
- The base branch is read from the fetch, not from the event's recorded base sha, which GitHub leaves stale once the base branch advances after the pull request opens.
23
-
24
- The range always starts at the merge base, never at the base branch's tip, since commits the base branch gained after the head branched off would otherwise count against the head.
25
- When the head is the merge base, as on a push to the default branch or a local run on it, the range would be empty.
26
- Each range gate is then handed that tip commit alone, and checks it against its parent, or against the empty tree when it is a repository's first commit:
27
-
28
- ```
29
- checks-lint: tip 10ba7d8935b73ed72624120a1542e51bd21ca7c7 from HEAD against origin/main
30
- ```
31
-
32
- A clone with no remote-tracking refs at all has no default branch to start from, such as a freshly initialised repository with no remote or one whose remote was never fetched.
33
- Each range gate is then handed `HEAD` alone the same way:
34
-
35
- ```
36
- checks-lint: tip 10ba7d8935b73ed72624120a1542e51bd21ca7c7 from HEAD alone, as the clone has no remote-tracking refs
37
- ```
38
-
39
- Once any ref sits under `refs/remotes/`, a missing `origin/<default branch>` exits 2 instead.
40
- That is the shape of a shallow CI checkout, where `HEAD` alone would leave the commits before it unchecked.
17
+ The range ends at `HEAD` and starts at the merge base with `origin/HEAD` for a local run.
18
+ If remote HEAD is absent, the range starts at the default branch GitHub's event names in CI, or at `origin/main`.
19
+ A local run with `GITHUB_BASE_REF` set starts at that branch on `origin` instead.
20
+ A clone with no remote tracking refs checks `HEAD` alone.
21
+ On a pull request the range ends at the event's head commit and starts at its merge base with the event's base branch.
22
+ Tree gates read the working tree rather than the range.
41
23
 
42
24
  ## Arguments
43
25
 
@@ -46,93 +28,29 @@ checks-lint
46
28
  checks-lint <base-ref> <head-ref>
47
29
  ```
48
30
 
49
- With no arguments it resolves the range as What it reads says.
50
- A base and a head override that resolution.
31
+ With two arguments, the base and head override range discovery.
51
32
 
52
33
  ## Exit codes
53
34
 
54
- | Code | When |
35
+ | Code | Result |
55
36
  | --- | --- |
56
- | 0 | every gate passed |
57
- | 1 | a gate found a violation |
58
- | 2 | the range or the selection does not resolve, or no failing gate could decide |
37
+ | 0 | Every applicable gate passed. |
38
+ | 1 | At least one gate found a violation. |
39
+ | 2 | The range could not resolve or no failed gate could decide. |
59
40
 
60
41
  ## Sample output
61
42
 
62
- It prints the range, the declared selection if there is one, each gate's own report, then its verdict:
63
-
64
43
  ```
65
44
  checks-lint: range 2504acf098d120e73a8ece3c96f22b934f35c6a8..10ba7d8935b73ed72624120a1542e51bd21ca7c7 from HEAD against origin/main
66
- ...
67
- checks-lint: 3 of 12 gate(s) failed: checks-commit-identity, checks-comment-gate, checks-suppressions-ratchet
45
+ checks-lint: 1 of 9 gate(s) failed: checks-comment-gate
68
46
  ```
69
47
 
70
48
  ## Opting out
71
49
 
72
- A repository leaves out a gate that does not apply to it, as Gate selection says.
73
- A repository that runs its gates without `checks-lint` calls each gate's bin in its own CI step and declares each command in `gates.ci`.
74
-
75
- ## Gate selection
76
-
77
- A repository with no TypeScript source gives `checks-lint-coverage`, `checks-test-layout`, `checks-size-budget`, `checks-repetition` and `checks-feature-owners` nothing to check, and test-layout would still refuse its missing `bun test` script and `bunfig.toml`.
78
- It declares the gates `checks-lint` runs as `gates.lint`:
79
-
80
- ```json
81
- "gates": {
82
- "ci": ["bun run lint"],
83
- "lint": [
84
- "checks-commit-identity",
85
- "checks-comment-gate",
86
- "checks-suppressions-ratchet",
87
- "checks-ci-wiring",
88
- "checks-docs",
89
- "checks-quarantine-clock",
90
- "checks-quality"
91
- ]
92
- }
93
- ```
94
-
95
- `checks-lint` runs exactly those, in the order of the table under What runs, and every gate when `gates.lint` is absent.
96
- A selection in `quality.json` always keeps `checks-quality`, since the file it sits in is what makes that gate apply.
97
- A step running `checks-lint` then counts only for a declared gate that `gates.lint` keeps.
98
-
99
- A selection may leave out only a gate that does not apply, and the Runs in column of the table under What runs says where each gate applies.
100
- Both `checks-lint` and `checks-ci-wiring` exit 2 on a `gates.lint` that names an unknown gate or leaves out one that applies to every repository.
101
- `checks-ci-wiring` exits 1 when the selection leaves out a gate the repository's tracked files make applicable, and names the gate and the files:
102
-
103
- ```
104
- ci-wiring: quality.json gates.lint leaves out 5 gate(s) this repository's contents make applicable:
105
- checks-lint-coverage: the repository tracks TypeScript source (src/widget.ts)
106
- checks-test-layout: the repository tracks TypeScript source (src/widget.ts)
107
- checks-size-budget: the repository tracks TypeScript source (src/widget.ts)
108
- checks-repetition: the repository tracks TypeScript source (src/widget.ts)
109
- checks-feature-owners: the repository tracks TypeScript source (src/widget.ts)
110
- ```
111
-
112
- It reads the files tracked at the checkout, so the pull request that adds the first TypeScript file is the one refused.
113
-
114
- ## Running it in CI
115
-
116
- CI runs it through `lint`.
117
- The checkout fetches the whole history, which the merge base needs:
118
-
119
- ```yaml
120
- on:
121
- pull_request:
122
- jobs:
123
- lint:
124
- runs-on: ubuntu-latest
125
- steps:
126
- - uses: actions/checkout@v5
127
- with:
128
- fetch-depth: 0
129
- - uses: oven-sh/setup-bun@v2
130
- - run: bun install --frozen-lockfile
131
- - run: bun run lint
132
- ```
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.
133
52
 
134
53
  ## Related topics
135
54
 
136
55
  - [What runs](../../README.md#what-runs)
137
56
  - [checks-ci-wiring](checks-ci-wiring.md)
138
- - [The quality file](../configs/quality-file.md)
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-mutation-compare
2
6
 
3
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.
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-quarantine-clock
2
6
 
3
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.