@avi2dg/checks 0.20.0 → 0.22.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 (54) hide show
  1. package/CHANGELOG.md +65 -39
  2. package/CONTRIBUTING.md +11 -8
  3. package/README.md +15 -24
  4. package/bunfig.toml +1 -1
  5. package/docs/configs/commit-messages.md +5 -1
  6. package/docs/configs/dependency-rules.md +5 -2
  7. package/docs/configs/effect-rules.md +32 -33
  8. package/docs/configs/native-settings.md +74 -0
  9. package/docs/configs/typescript-rules.md +4 -0
  10. package/docs/design.md +24 -25
  11. package/docs/gates/checks-backtest.md +4 -0
  12. package/docs/gates/checks-ci-wiring.md +30 -93
  13. package/docs/gates/checks-comment-gate.md +4 -0
  14. package/docs/gates/checks-commit-identity.md +23 -27
  15. package/docs/gates/checks-docs.md +23 -21
  16. package/docs/gates/checks-flake.md +4 -10
  17. package/docs/gates/checks-lint-coverage.md +5 -1
  18. package/docs/gates/checks-lint.md +22 -104
  19. package/docs/gates/checks-mutation-compare.md +4 -0
  20. package/docs/gates/checks-quarantine-clock.md +4 -0
  21. package/docs/gates/checks-repetition.md +26 -41
  22. package/docs/gates/checks-subsumed-tests.md +4 -0
  23. package/docs/gates/checks-suppressions-ratchet.md +4 -0
  24. package/docs/gates/checks-test-layout.md +16 -8
  25. package/docs/gates/checks-test.md +68 -36
  26. package/docs/gates/checks-vendor.md +20 -13
  27. package/package.json +8 -21
  28. package/scripts/ci-wiring.ts +28 -97
  29. package/scripts/commit-identity.ts +32 -4
  30. package/scripts/doc-rules.ts +26 -11
  31. package/scripts/doc-templates.ts +2 -1
  32. package/scripts/docs.ts +4 -7
  33. package/scripts/gates.ts +0 -29
  34. package/scripts/git.ts +24 -1
  35. package/scripts/lint.ts +15 -34
  36. package/scripts/range-gate.ts +1 -2
  37. package/scripts/repetition.ts +40 -40
  38. package/scripts/shell-command.ts +7 -1
  39. package/scripts/swc.ts +46 -0
  40. package/scripts/test-layout.ts +40 -56
  41. package/scripts/test-skips.ts +180 -0
  42. package/scripts/test.ts +33 -38
  43. package/scripts/vendor.ts +55 -11
  44. package/dist/feature-rules.js +0 -349
  45. package/docs/configs/quality-file.md +0 -101
  46. package/docs/gates/checks-feature-owners.md +0 -113
  47. package/docs/gates/checks-quality.md +0 -109
  48. package/docs/gates/checks-size-budget.md +0 -107
  49. package/quality.schema.json +0 -496
  50. package/scripts/feature-owners.ts +0 -139
  51. package/scripts/quality-file.ts +0 -347
  52. package/scripts/quality.ts +0 -342
  53. package/scripts/size-budget.ts +0 -285
  54. package/scripts/size-rules.ts +0 -126
package/docs/design.md CHANGED
@@ -1,32 +1,30 @@
1
+ ---
2
+ kind: explanation
3
+ ---
1
4
  # Why it is shaped this way
2
5
 
3
6
  Each entry below is a choice in the kit's shape and the constraint that forced it.
4
7
 
5
8
  - Every config in an oxlint `extends` chain brings its own `plugins`, and one that sets none brings oxlint's default plugins, whose category rules the base's `categories` then turn on across the tree.
6
9
  `rules`, `categories` and `jsPlugins` inherit as expected.
7
- That is why the consumer snippet restates `plugins` and nothing else, and why the generated fragment always sets them.
10
+ That is why the consumer config and each override restate `plugins`.
8
11
  - `node_modules/` is excluded through the consumer's `.gitignore`, not `ignorePatterns`: oxlint still walks the installed package when only `ignorePatterns` names it.
9
12
  - `files` in package.json is the published surface: `tests/`, `AGENTS.md` and the `.ts` plugin source never reach an install.
10
13
  npm adds `package.json`, `README` and `LICENSE` to the tarball whatever `files` says.
11
14
  `bun pm pack` builds the same tarball the registry serves, which is what the packed-tarball consumer e2e test installs.
12
15
  - The plugin ships compiled as `dist/index.js`, built with `bun build effect-channel/index.ts --outdir dist --target node --format esm`.
13
16
  Node refuses to type-strip a `.ts` plugin under `node_modules`, so the `.ts` source would fail to load from an installed package.
14
- - `featureRules` ships compiled as `dist/feature-rules.js` for the same reason, with `effect` left out of the bundle so it resolves the consumer's own copy.
15
- dependency-cruiser uses a config's export as it is and never awaits it, so the declaration decodes synchronously, and `quality.json` exempts that one file from the Effect rules.
16
- - `checks-size-budget` writes the head commit's files to a temporary directory and runs oxlint there.
17
- Its configuration loads the kit's own plugin bundle for the complexity rule and turns every category off.
18
- The consumer's own `.oxlintrc.json`, its ignore files and its other rules never reach the count.
19
- - `checks-size-budget` ratchets against the base of the range rather than a committed baseline such as `oxlint-suppressions.json`.
20
- A suppression file stores a count of sites per file and rule, and `max-lines` reports a file once however long it grows, so the count stays at one while the file doubles.
21
- The gate sums how far each site runs over its limit instead, which grows with the file.
22
- The base commit already holds that sum, so nothing is generated, committed or pruned.
23
- - `checks-repetition` writes the production files of both ends of the range to temporary directories and runs jscpd in each, so the consumer's `.jscpd.json` and ignore files never reach the count.
17
+ - The size rules are plain oxlint rules at `error` in `.oxlintrc.json`, and `bun run lint` enforces them on the whole tree.
18
+ A repository records its existing violations with `oxlint --suppress-all`, and `checks-suppressions-ratchet` refuses any count that rises.
19
+ The kit runs no size script of its own, since restating how oxlint reads its config and compares sites left corners the native rules never had.
20
+ The suppression count lets a file or function already over its limit grow without a new site, which was accepted in exchange for dropping that script, and each repository is to work its counts down to zero.
21
+ - `checks-repetition` writes both ends of the range to temporary directories and runs jscpd in each with the head's `.jscpd.json`, so its `path` and `ignore` globs decide the files at both ends.
24
22
  It compares each file's count of repeated lines rather than using jscpd's `--baseline-from-ref`.
25
23
  That flag reports a repeated block as new once its text changes, so a change that shortens a grandfathered block would fail.
26
24
  - `dist/` is committed.
27
25
  No `prepack` or `prepublishOnly` builds it, so a publish ships whatever bundle the publishing worktree holds.
28
26
  Rebuild it after pulling with `bun run build`.
29
- `bun run build` also emits `quality.schema.json`, `templates/` and `CHANGELOG.md`, which are committed the same way.
27
+ `bun run build` also emits `templates/` and `CHANGELOG.md`, which are committed the same way.
30
28
  CI runs `git diff --exit-code` over the whole tree after the build, because a test that compares a generated file with its source passes on the copy the build just rewrote.
31
29
  - `CHANGELOG.md` is generated, so a release commit carries it and the tarball ships it.
32
30
  The commit that bumps package.json `version` closes its release, and the `v*` tag goes on that commit, so commits merged after it wait for the next release.
@@ -36,12 +34,13 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
36
34
  A section keeps the date it was written with, since the squash merge that lands the release commit may fall on another day.
37
35
  Entries come from commit subjects, the squash-merged pull request titles commitlint holds to the conventional format.
38
36
  The bodies are the branch's own messages, which nothing lints.
39
- The release path needs no `contents: write`: the changelog arrives in the release commit's pull request, not from a workflow that pushes.
40
- - `quality.json` is JSON, not TOML or a TypeScript module: a bun bin, a hook running without `node_modules`, a `.cjs` or `.mjs` config and `jq` all parse it with nothing installed, and nobody runs a repository's own code to learn its policy.
41
- It holds declarations only.
42
- The kit's bins read it directly.
43
- oxlint and tsc read nothing but their own JSON, so they extend generated fragments, which `checks-quality --check` holds to the declarations.
44
- - `quality.json` refuses a key its schema does not name, so a kit that cannot enforce a newer key refuses it rather than let the repository believe it enforced.
37
+ The changelog still arrives in the release commit's pull request, not from a workflow that pushes.
38
+ The release path writes to the repository only through the `github-release` job's `contents: write`, which creates or updates the GitHub release from the tag's `CHANGELOG.md` section.
39
+ - Workflow YAML owns CI execution, and the kit owns the required commands, but a repository is held only to the commands its own `package.json` can run.
40
+ `checks-ci-wiring` requires `bun run` with each of `lint`, `build`, `typecheck` and `test` that `package.json` defines as a script, `git diff --exit-code` when a `build` script exists, and commitlint always.
41
+ The target branch comes from git's own record in `refs/remotes/origin/HEAD`, or in CI from the pull request base or the default branch GitHub's event names, and never from a guess at the workflow files, and `checks-lint` starts its local range from the same branch.
42
+ Oxlint and TypeScript read their own overrides directly, so the consumer can change a rule where its tool reads it.
43
+ The Effect scopes occur in two native files, and the installed consumer test checks both independently.
45
44
  - The base parses with swc because typescript 7, which is tsgo, has no compiler API for dependency-cruiser to use.
46
45
  Without `@swc/core` installed the cruise silently skips every `.ts` file, so this repo's test asserts its own TypeScript is cruised.
47
46
  - `bunfig.toml` has no `extends` and no include: bun ignores an unknown top-level key in silence, so a preset cannot be inherited and the consumer's copy is compared key by key against the installed one instead.
@@ -55,8 +54,8 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
55
54
  The `.ts` checks keep a `bun` shebang, which needs no build step and no `dist/` entry, unlike the oxlint plugin that node loads.
56
55
  - `checks-lint` runs each gate as its own bin in a child process rather than importing it, so a gate behaves the same called alone or through the entry point, and `lint-coverage.sh` stays a shell script.
57
56
  The gates run one at a time with their output passed straight through, so each report reads whole and in the table's order.
58
- - A gate selection is checked against the repository's contents rather than trusted, so it cannot skip a gate that applies.
59
- ci-wiring does that check, which is why a selection without it, or without another gate that applies everywhere, is refused as `checks-lint` reads it: nothing would check the selection otherwise.
57
+ - `checks-lint` determines applicable gates from tracked files instead of accepting a repository selection.
58
+ A TypeScript gate starts running as soon as TypeScript source is tracked.
60
59
  - `checks-test` runs bun itself rather than reading a report some other run left: a skip taken only on CI is visible only in CI's own run, and an earlier run's report may be stale or narrowed.
61
60
  It reads the JUnit report bun writes to a temporary directory, since bun has no other per-test output meant for a program.
62
61
  - `checks-ci-wiring` runs inside `lint`, not in a workflow of its own: deleting the step that runs a check is the violation it catches, so the local `lint` is where it has to fail.
@@ -75,9 +74,9 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
75
74
  That is the entry-point and layer recipe under Boundaries in [The dependency rules](configs/dependency-rules.md).
76
75
  - The templates in `templates/` are rendered from `scripts/doc-templates.ts`, the spec `checks-docs` reads.
77
76
  A template written by hand beside the check agrees with it only until someone edits one of them.
78
- - A page's Diátaxis mode is declared in `quality.json` rather than read from the page.
79
- Whether a page teaches, walks a task, describes or explains is a judgment no program makes, so the repository states it once and the check holds the page to it.
80
- - `checks-docs` holds a doc file to its template when a change touches it, the way `checks-size-budget` holds a file to its budget.
77
+ - A page's Diátaxis mode comes from `kind` front matter on the page, whatever directory holds it.
78
+ The repository makes the judgment beside the page, and the check holds it to that template.
79
+ - `checks-docs` holds a doc file to its template when a change touches it, the way `checks-comment-gate` judges the comments a change adds.
81
80
  A repository adopts the templates as its files change, and an untouched file is listed as advisory rather than failing a change that never read it.
82
81
  - A task heading is verb first, and review holds it there rather than the check.
83
82
  No word list tells `Test layout` from `Test the layout`, and a check that passes the noun is worse than none.
@@ -95,8 +94,8 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
95
94
  A reference goes stale when the code it names moves far more often than when its own line is edited, so a gate on edited lines alone would miss the usual break.
96
95
  - A path under a top directory the repository lacks names a file in another repository, such as a consumer's, and no program tells that from a typo.
97
96
  A directory the range deletes still counts as this repository's, so a path under it reads as stale rather than foreign.
98
- - The command check passes over the docs a repository declares under `docs.forConsumers`.
99
- This kit's README and reference pages speak to a consuming repository, whose scripts are not this one's, and no program tells an example for a consumer from an instruction for a contributor.
97
+ - The command check passes over a page whose front matter sets `audience: consumers`.
98
+ Such a page speaks to a consuming repository, whose scripts are not this one's.
100
99
 
101
100
  ## Related topics
102
101
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
1
5
  # checks-backtest
2
6
 
3
7
  `checks-backtest` is the report of what the comment check would have refused at each recent commit, and a reader looks it up to measure a repository's own history before adopting the check.
@@ -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