@avi2dg/checks 0.12.0 → 0.14.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 (41) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/CONTRIBUTING.md +89 -0
  3. package/README.md +137 -1230
  4. package/dist/feature-rules.js +14 -1
  5. package/docs/configs/commit-messages.md +43 -0
  6. package/docs/configs/dependency-rules.md +62 -0
  7. package/docs/configs/effect-rules.md +48 -0
  8. package/docs/configs/quality-file.md +99 -0
  9. package/docs/design.md +77 -0
  10. package/docs/gates/checks-backtest.md +50 -0
  11. package/docs/gates/checks-ci-wiring.md +122 -0
  12. package/docs/gates/checks-comment-gate.md +58 -0
  13. package/docs/gates/checks-commit-identity.md +63 -0
  14. package/docs/gates/checks-docs.md +98 -0
  15. package/docs/gates/checks-feature-owners.md +113 -0
  16. package/docs/gates/checks-flake.md +88 -0
  17. package/docs/gates/checks-lint-coverage.md +49 -0
  18. package/docs/gates/checks-lint.md +136 -0
  19. package/docs/gates/checks-mutation-compare.md +84 -0
  20. package/docs/gates/checks-quality.md +94 -0
  21. package/docs/gates/checks-size-budget.md +64 -0
  22. package/docs/gates/checks-suppressions-ratchet.md +51 -0
  23. package/docs/gates/checks-test-layout.md +77 -0
  24. package/docs/gates/checks-test.md +75 -0
  25. package/package.json +24 -3
  26. package/quality.schema.json +48 -0
  27. package/scripts/doc-outline.ts +215 -0
  28. package/scripts/doc-rules.ts +177 -0
  29. package/scripts/doc-templates.ts +208 -0
  30. package/scripts/docs.ts +90 -0
  31. package/scripts/gates.ts +1 -0
  32. package/scripts/quality-file.ts +22 -1
  33. package/templates/adr.md +29 -0
  34. package/templates/agents.md +17 -0
  35. package/templates/changelog.md +37 -0
  36. package/templates/claude.md +2 -0
  37. package/templates/explanation.md +15 -0
  38. package/templates/how-to.md +33 -0
  39. package/templates/readme.md +45 -0
  40. package/templates/reference.md +15 -0
  41. package/templates/tutorial.md +31 -0
@@ -0,0 +1,94 @@
1
+ # checks-quality
2
+
3
+ `checks-quality` is the bin that writes what `quality.json` declares for oxlint and tsc into generated fragments and checks them, and a reader looks it up when a fragment is stale.
4
+
5
+ ## What it checks
6
+
7
+ oxlint and tsc read their own JSON and nothing else, so `checks-quality generate` writes what `sources.effect` declares into two fragments at the repository root, and the hand-written configs extend them.
8
+ Both fragments are committed.
9
+
10
+ `oxlintrc.quality.json` holds one override: the declared paths as `files`, the exempt ones as `excludeFiles`, and the kit's Effect rule block, `presets/effect.oxlint.json`.
11
+ `tsconfig.quality.json` holds the language-service override: the same paths as `include`, the exempt ones as `exclude`, and `presets/effect.language-service.json`.
12
+ A kit release that changes a preset reaches the repository through its next `generate`.
13
+ A rule only this repository needs stays in its own `.oxlintrc.json`, whose overrides come after the fragment's and so win.
14
+
15
+ `.oxlintrc.json` extends its fragment:
16
+
17
+ ```json
18
+ {
19
+ "extends": ["./node_modules/@avi2dg/checks/oxlintrc.json", "./oxlintrc.quality.json"],
20
+ "plugins": ["typescript", "oxc", "eslint", "import"]
21
+ }
22
+ ```
23
+
24
+ `tsconfig.json` extends its fragment:
25
+
26
+ ```json
27
+ {
28
+ "extends": ["@avi2dg/checks/tsconfig.effect.json", "./tsconfig.quality.json"]
29
+ }
30
+ ```
31
+
32
+ `checks-quality --check` fails when any of these holds:
33
+
34
+ - A fragment is missing, or differs from what `generate` would write from `quality.json` and the installed kit's presets.
35
+ - A fragment is left over once `quality.json` stops declaring `sources.effect`.
36
+ - `.oxlintrc.json` or `tsconfig.json` does not list its fragment in `extends`, so the tool never reads it.
37
+ - A `sources.effect.paths` glob, or a `sources.production` glob while `size` is declared, matches no tracked or untracked file, so it holds nothing.
38
+
39
+ Two details of the fragments are easy to get wrong, so the kit's tests pin both:
40
+
41
+ - A fragment sits at the repository root.
42
+ oxlint resolves an override's `files`, and the language service an override's `include`, against the directory of the config holding it.
43
+ From `.quality/` the language service reports no error at all on an `async function` planted under a declared path.
44
+ - The oxlint fragment always sets `plugins`, to the kit's.
45
+ A config in `extends` that sets none brings in oxlint's default plugins, whose category rules then fire across the whole tree.
46
+ The override names the kit's plugins beside the preset's `node`, `promise` and `unicorn`, because one that leaves any of the kit's out turns on the category rules of the plugins it adds under every declared path.
47
+
48
+ ## What it reads
49
+
50
+ It reads the working tree: `quality.json`, the presets of the installed kit, `.oxlintrc.json`, `tsconfig.json` and the two fragments.
51
+ It lists the tracked and untracked files to see what each declared glob matches.
52
+
53
+ ## Arguments
54
+
55
+ ```sh
56
+ checks-quality generate
57
+ checks-quality --check
58
+ ```
59
+
60
+ `generate` writes the fragments, removes a left-over one, then runs the same check as `--check`.
61
+ `--check` writes nothing.
62
+
63
+ ## Exit codes
64
+
65
+ | Code | When |
66
+ | --- | --- |
67
+ | 0 | the fragments hold what `quality.json` declares |
68
+ | 1 | a fragment is stale, missing, left over or not extended, or a declared glob matches no file |
69
+ | 2 | `quality.json` does not decode, or the arguments are neither `generate` nor `--check` |
70
+
71
+ ## Sample output
72
+
73
+ ```
74
+ checks-quality: 2 problem(s) with what quality.json declares:
75
+ oxlintrc.quality.json is stale against quality.json and the kit's presets; run checks-quality generate
76
+ tsconfig.json does not extend ./tsconfig.quality.json, so the language service never reads it
77
+ ```
78
+
79
+ A passing run says what the fragments hold:
80
+
81
+ ```
82
+ checks-quality: oxlintrc.quality.json and tsconfig.quality.json hold what quality.json declares
83
+ ```
84
+
85
+ ## Opting out
86
+
87
+ It runs only in a repository that tracks `quality.json`, and a selection in `quality.json` always keeps it, since the file it sits in is what makes it apply.
88
+ A repository that declares no `sources.effect` gets no fragment, and the check then only refuses a left-over one.
89
+
90
+ ## Related topics
91
+
92
+ - [The quality file](../configs/quality-file.md)
93
+ - [The Effect rules](../configs/effect-rules.md)
94
+ - [checks-lint](checks-lint.md)
@@ -0,0 +1,64 @@
1
+ # checks-size-budget
2
+
3
+ `checks-size-budget` is the gate that holds production files to the line budget `quality.json` declares, and a reader looks it up when a file or a function runs over it.
4
+
5
+ ## What it checks
6
+
7
+ It holds production files to the line budget `quality.json` declares, and lists every other file over it without failing:
8
+
9
+ ```json
10
+ "sources": { "production": ["src/**/*.ts"] },
11
+ "size": { "fileLines": 400, "functionLines": 100, "applies": "changed" }
12
+ ```
13
+
14
+ It runs oxlint with a configuration of two rules and nothing else, `max-lines` at `fileLines` and `max-lines-per-function` at `functionLines`, both counting blank and comment lines.
15
+ With `applies` set to `changed` it holds the files under `sources.production` that the range adds or changes, a rename that edits the file included.
16
+ With `all` it holds every file under `sources.production`.
17
+ A file the range deletes or only renames is not held.
18
+ Every other tracked `.ts` or `.tsx` file over the budget, tests and unchanged production files alike, is listed as advisory and never fails the gate.
19
+ `.d.ts` files are not measured.
20
+
21
+ ## What it reads
22
+
23
+ It reads each file from the head commit rather than the working tree, so an uncommitted edit neither fails nor passes a range, and a pull request's merge checkout measures what the pull request holds.
24
+ It reads `sources.production` and `size` from `quality.json`.
25
+ oxlint must be on `PATH`, as it is under a package script.
26
+
27
+ ## Arguments
28
+
29
+ ```sh
30
+ checks-size-budget <base-ref> <head-ref>
31
+ checks-size-budget <ref>
32
+ ```
33
+
34
+ With two arguments the range starts where the head branched from the base, at their merge-base.
35
+ With one it is that commit against its parent, or against the empty tree for a repository's first commit.
36
+
37
+ ## Exit codes
38
+
39
+ | Code | When |
40
+ | --- | --- |
41
+ | 0 | every file it holds keeps within the budget |
42
+ | 1 | a file it holds runs over the budget |
43
+ | 2 | `quality.json` does not decode, a ref does not resolve, or oxlint cannot run |
44
+
45
+ ## Sample output
46
+
47
+ ```
48
+ size-budget: 1 overrun(s) of 400 lines per file and 100 per function in the production files the range adds or changes:
49
+ src/billing/ledger.ts:12: The function `settle` has too many lines (131). Maximum allowed is 100.
50
+ size-budget: advisory, 1 overrun(s) where the budget does not hold yet:
51
+ tests/e2e/billing.test.ts: File has too many lines (512).
52
+ ```
53
+
54
+ ## Opting out
55
+
56
+ A repository that declares no `size` passes.
57
+ `quality.json` refuses a `size` without `sources.production`, which would hold nothing, and with `size` declared `checks-quality` refuses a `sources.production` glob that matches no file.
58
+ A repository that tracks no `.ts` or `.tsx` file leaves it out of `gates.lint`, as [Gate selection](checks-lint.md#gate-selection) says.
59
+ Moving `applies` from `changed` to `all` tightens the budget to every production file, once the advisory list names none.
60
+
61
+ ## Related topics
62
+
63
+ - [The quality file](../configs/quality-file.md)
64
+ - [checks-lint](checks-lint.md)
@@ -0,0 +1,51 @@
1
+ # checks-suppressions-ratchet
2
+
3
+ `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.
4
+
5
+ ## What it checks
6
+
7
+ oxlint accepts whatever `oxlint --suppress-all` writes to `oxlint-suppressions.json`, so raising a count to let a new site through passes the lint.
8
+ The ratchet fails naming each file and rule whose count rose or that appeared.
9
+ A count that fell and an entry that went both pass.
10
+
11
+ ## What it reads
12
+
13
+ It reads `oxlint-suppressions.json` at a base and at a head, from the directory the command runs in, which is where oxlint writes it.
14
+ A commit without the file counts as empty, so the commit that first adds a baseline fails with every entry appearing.
15
+
16
+ ## Arguments
17
+
18
+ ```sh
19
+ checks-suppressions-ratchet <base-ref> <head-ref>
20
+ checks-suppressions-ratchet <ref>
21
+ ```
22
+
23
+ With two arguments it reads the base where the head branched off, at their merge-base, so a count the base branch lowered since does not read as a rise at the head.
24
+ With one it compares that commit with its parent, or with the empty tree for a repository's first commit.
25
+
26
+ ## Exit codes
27
+
28
+ | Code | When |
29
+ | --- | --- |
30
+ | 0 | no count rose and no entry appeared |
31
+ | 1 | a count rose or an entry appeared |
32
+ | 2 | a ref does not resolve, the parent exists but is not in the clone, or the file is not oxlint's count per rule per file |
33
+
34
+ ## Sample output
35
+
36
+ ```
37
+ suppressions-ratchet: 2 count(s) in oxlint-suppressions.json rose or appeared; fix the site instead of suppressing it:
38
+ src/added.ts typescript/no-unsafe-type-assertion appeared with 1
39
+ src/dispatch.ts typescript/no-non-null-assertion rose from 12 to 13
40
+ ```
41
+
42
+ ## Opting out
43
+
44
+ It applies to every repository, so no selection leaves it out.
45
+ A repository with no `oxlint-suppressions.json` passes, since both ends count as empty.
46
+ `checks-lint` runs it over each pull request's range, as [checks-lint](checks-lint.md) says.
47
+
48
+ ## Related topics
49
+
50
+ - [The Effect rules](../configs/effect-rules.md)
51
+ - [checks-lint](checks-lint.md)
@@ -0,0 +1,77 @@
1
+ # checks-test-layout
2
+
3
+ `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.
4
+
5
+ ## What it checks
6
+
7
+ It fails unless the repository holds this shape, and names the file and the path to move it to when it does not.
8
+
9
+ - Every test file is `tests/**/*.test.ts` or `.tsx`.
10
+ A `*.test.ts`, `*.spec.ts` or `*_test.ts` under `src/`, `test/`, `__tests__/` or the repository root fails.
11
+ - `tests/lib/**` holds helpers and `tests/fixtures/**` holds data, and neither may hold a test file.
12
+ Every other directory directly under `tests/` is a test group and may nest as deep as it likes.
13
+ - A test runs at one of two levels.
14
+ A test outside `tests/e2e/` runs in-process, so it may not import `node:child_process`, `net`, `http`, `https`, `http2`, `tls` or `dgram`.
15
+ It may not import `$`, `spawn`, `spawnSync`, `connect`, `serve` or `listen` from `bun`, may not touch `Bun.$` or `Bun.spawn`, and may not call `fetch`.
16
+ A test inside `tests/e2e/` may do all of it.
17
+ Helpers in `tests/lib/**` answer to the same rule, since an in-process test reaches them.
18
+ - `scripts.test` is exactly `checks-test`, which runs `bun test --randomize` as [checks-test](checks-test.md) says.
19
+ - `scripts.lint` runs this check, itself or through `checks-lint` called by its bare bin name.
20
+ - `bunfig.toml` carries every `[test]` key of the shipped preset with the same value.
21
+ `[test].pathIgnorePatterns` is always `["**/tests/quarantine/**"]`, which the check pins itself, so the kit's own repository, whose bunfig is the preset, cannot drift it either.
22
+ Other tables, and extra `[test]` keys, are the repository's own.
23
+
24
+ The in-process half is what a mutation run can mutate.
25
+ `tests/e2e/**` is left out of a mutate scope by construction, because a subprocess kills both the speed and the coverage signal a mutant needs.
26
+
27
+ The preset also skips `tests/quarantine/**` on a default run.
28
+ A test that turns flaky moves there, so the suite stays trustworthy, and the flake still runs on demand:
29
+
30
+ ```sh
31
+ bun test --path-ignore-patterns='' tests/quarantine
32
+ ```
33
+
34
+ ## What it reads
35
+
36
+ It reads the working tree.
37
+ It scans the tracked and untracked files that `git ls-files --exclude-standard` reports, so `node_modules/` and every gitignored tree are out of reach, and a local run agrees with CI before `git add`.
38
+ It parses each test and helper with swc and reads import specifiers and identifier use, so a test that only carries `"node:child_process"` as a string is not a violation.
39
+ `tests/fixtures/**` is data and is not parsed.
40
+ It reads `package.json` for `scripts.test` and `scripts.lint`, and compares `bunfig.toml` with the preset the installed kit ships.
41
+
42
+ ## Arguments
43
+
44
+ ```sh
45
+ checks-test-layout [<directory>]
46
+ ```
47
+
48
+ It checks the directory it runs in, or the directory it is given.
49
+
50
+ ## Exit codes
51
+
52
+ | Code | When |
53
+ | --- | --- |
54
+ | 0 | the repository holds the layout |
55
+ | 1 | a file breaks the layout |
56
+ | 2 | a test, a helper or `package.json` does not parse |
57
+
58
+ ## Sample output
59
+
60
+ ```
61
+ test-layout: 4 violation(s)
62
+ src/a.test.ts: a test file must live at tests/**/*.test.ts; move it to tests/a.test.ts
63
+ package.json: scripts.test must be exactly "checks-test", which runs bun test --randomize and judges its skips, found "bun test"
64
+ package.json: scripts.lint must run the layout check: add "checks-lint"
65
+ bunfig.toml: bunfig.toml is missing; bun has no bunfig extends, so copy node_modules/@avi2dg/checks/bunfig.toml
66
+ ```
67
+
68
+ ## Opting out
69
+
70
+ A repository that tracks no `.ts` or `.tsx` file leaves it out of `gates.lint`, as [Gate selection](checks-lint.md#gate-selection) says, and then needs no `checks-test` script and no `bunfig.toml`.
71
+ A repository that tracks one keeps it.
72
+
73
+ ## Related topics
74
+
75
+ - [checks-test](checks-test.md)
76
+ - [checks-flake](checks-flake.md)
77
+ - [checks-mutation-compare](checks-mutation-compare.md)
@@ -0,0 +1,75 @@
1
+ # checks-test
2
+
3
+ `checks-test` is the entry point that runs the whole suite and refuses a skip the repository has not declared, and a reader looks it up to declare a skip.
4
+
5
+ ## What it checks
6
+
7
+ It runs the whole suite with `bun test --randomize`, passes bun's output through, and then reads bun's JUnit report of the same run.
8
+ bun exits 0 with tests skipped, so a green run says nothing about the tests that never ran.
9
+ `checks-test` fails when a test failed, or when a test was skipped without a declaration in `package.json`.
10
+ A test counts as skipped through `test.skip`, `test.skipIf`, `test.if`, `describe.skip` or `test.todo`.
11
+
12
+ A declaration names the test and says why it skips:
13
+
14
+ ```json
15
+ "testSkips": [
16
+ {
17
+ "file": "tests/e2e/docker.test.ts",
18
+ "test": "images > builds the release image",
19
+ "reason": "the runner has no docker daemon",
20
+ "when": "ci"
21
+ }
22
+ ]
23
+ ```
24
+
25
+ `file` is the path bun reports, relative to the package root.
26
+ `test` is the name bun's console prints, the describe blocks and the test name joined by ` > `.
27
+ `reason` is required.
28
+ `when` is `ci` or `local` for a test skipped only there, and a declaration without it holds in both.
29
+
30
+ A declaration that holds for the run but matches no skipped test fails a ci run too, so a fixed or renamed test takes its declaration with it.
31
+ A local run only warns about it, because whether a test skips there can hang on the machine, such as a docker daemon being up.
32
+ Files under `tests/quarantine/` are never run and so never reported, as [checks-test-layout](checks-test-layout.md) says.
33
+
34
+ ## What it reads
35
+
36
+ It reads bun's JUnit report of its own run, which bun writes to a temporary directory, and `testSkips` in `package.json`.
37
+ It counts a run as `ci` when `CI` is set true, as GitHub Actions sets it, and as `local` otherwise.
38
+
39
+ ## Arguments
40
+
41
+ It takes none.
42
+ A `-t` filter would report every test it leaves out as skipped, and a path filter would drop files a declaration names.
43
+ A narrowed run is therefore plain `bun test --randomize` with the arguments.
44
+
45
+ ## Exit codes
46
+
47
+ | Code | When |
48
+ | --- | --- |
49
+ | 0 | every test that ran passed, and every skip is declared |
50
+ | 1 | a test failed, a skip is undeclared, or in a ci run a declaration is stale |
51
+ | 2 | `testSkips` does not parse, `CI` is set to something other than a boolean, or bun passed without writing its report |
52
+
53
+ ## Sample output
54
+
55
+ ```
56
+ checks-test: 1 skipped test(s) undeclared and 1 declaration(s) matching no skipped test in this ci run:
57
+ tests/pricing.test.ts:12 pricing > rounds half to even: skipped with no declaration; run it, or declare it in package.json testSkips with its reason
58
+ tests/e2e/docker.test.ts > images > builds the release image: declared, but no such test skipped; delete the declaration
59
+ ```
60
+
61
+ A run with nothing skipped ends with:
62
+
63
+ ```
64
+ checks-test: no test skipped
65
+ ```
66
+
67
+ ## Opting out
68
+
69
+ A test opts out of a run through its declaration in `testSkips`.
70
+ A repository that tracks TypeScript source runs `checks-test` as `scripts.test`, since [checks-test-layout](checks-test-layout.md) requires it.
71
+
72
+ ## Related topics
73
+
74
+ - [checks-test-layout](checks-test-layout.md)
75
+ - [checks-flake](checks-flake.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avi2dg/checks",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Deterministic checks shared across the captain's TypeScript repos",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -12,6 +12,11 @@
12
12
  },
13
13
  "type": "module",
14
14
  "files": [
15
+ "CHANGELOG.md",
16
+ "CONTRIBUTING.md",
17
+ "docs/configs/",
18
+ "docs/design.md",
19
+ "docs/gates/",
15
20
  "bunfig.toml",
16
21
  "commitlint.config.js",
17
22
  "dependency-cruiser.config.js",
@@ -36,6 +41,11 @@
36
41
  "scripts/quality.ts",
37
42
  "scripts/size-budget.ts",
38
43
  "scripts/feature-owners.ts",
44
+ "scripts/docs.ts",
45
+ "scripts/doc-outline.ts",
46
+ "scripts/doc-rules.ts",
47
+ "scripts/doc-templates.ts",
48
+ "templates/",
39
49
  "presets/effect.oxlint.json",
40
50
  "presets/effect.language-service.json",
41
51
  "quality.schema.json",
@@ -66,6 +76,16 @@
66
76
  "./scripts/quality.ts": "./scripts/quality.ts",
67
77
  "./scripts/size-budget.ts": "./scripts/size-budget.ts",
68
78
  "./scripts/feature-owners.ts": "./scripts/feature-owners.ts",
79
+ "./scripts/docs.ts": "./scripts/docs.ts",
80
+ "./templates/readme.md": "./templates/readme.md",
81
+ "./templates/changelog.md": "./templates/changelog.md",
82
+ "./templates/adr.md": "./templates/adr.md",
83
+ "./templates/agents.md": "./templates/agents.md",
84
+ "./templates/claude.md": "./templates/claude.md",
85
+ "./templates/tutorial.md": "./templates/tutorial.md",
86
+ "./templates/how-to.md": "./templates/how-to.md",
87
+ "./templates/reference.md": "./templates/reference.md",
88
+ "./templates/explanation.md": "./templates/explanation.md",
69
89
  "./presets/effect.oxlint.json": "./presets/effect.oxlint.json",
70
90
  "./presets/effect.language-service.json": "./presets/effect.language-service.json",
71
91
  "./quality.schema.json": "./quality.schema.json",
@@ -89,10 +109,11 @@
89
109
  "checks-backtest": "scripts/backtest.ts",
90
110
  "checks-quality": "scripts/quality.ts",
91
111
  "checks-size-budget": "scripts/size-budget.ts",
92
- "checks-feature-owners": "scripts/feature-owners.ts"
112
+ "checks-feature-owners": "scripts/feature-owners.ts",
113
+ "checks-docs": "scripts/docs.ts"
93
114
  },
94
115
  "scripts": {
95
- "build": "bun build effect-channel/index.ts --outdir dist --target node --format esm && bun build scripts/feature-rules.ts --outdir dist --target node --format esm --packages external && bun scripts/quality-schema.ts",
116
+ "build": "bun build effect-channel/index.ts --outdir dist --target node --format esm && bun build scripts/feature-rules.ts --outdir dist --target node --format esm --packages external && bun scripts/quality-schema.ts && bun scripts/doc-templates-write.ts && bun scripts/changelog-write.ts && bun scripts/doc-blocks-write.ts",
96
117
  "lint": "oxlint --type-aware && bun scripts/lint.ts && depcruise --config .dependency-cruiser.cjs .",
97
118
  "typecheck": "tsc --noEmit && effect-tsgo diagnostics --project tsconfig.json --format text --strict",
98
119
  "test": "bun scripts/test.ts"
@@ -44,6 +44,7 @@
44
44
  "checks-comment-gate",
45
45
  "checks-suppressions-ratchet",
46
46
  "checks-ci-wiring",
47
+ "checks-docs",
47
48
  "checks-quality",
48
49
  "checks-size-budget",
49
50
  "checks-feature-owners"
@@ -69,6 +70,11 @@
69
70
  "contains": {
70
71
  "const": "checks-ci-wiring"
71
72
  }
73
+ },
74
+ {
75
+ "contains": {
76
+ "const": "checks-docs"
77
+ }
72
78
  }
73
79
  ]
74
80
  }
@@ -241,6 +247,48 @@
241
247
  }
242
248
  },
243
249
  "additionalProperties": false
250
+ },
251
+ "docs": {
252
+ "type": "object",
253
+ "properties": {
254
+ "pages": {
255
+ "type": "object",
256
+ "properties": {
257
+ "tutorial": {
258
+ "type": "array",
259
+ "items": {
260
+ "$ref": "#/$defs/PathGlob"
261
+ },
262
+ "description": "The pages written as a tutorial, which teaches by building one thing"
263
+ },
264
+ "how-to": {
265
+ "type": "array",
266
+ "items": {
267
+ "$ref": "#/$defs/PathGlob"
268
+ },
269
+ "description": "The pages written as a how-to, which walks one task"
270
+ },
271
+ "reference": {
272
+ "type": "array",
273
+ "items": {
274
+ "$ref": "#/$defs/PathGlob"
275
+ },
276
+ "description": "The pages written as reference, which describes a thing to be looked up"
277
+ },
278
+ "explanation": {
279
+ "type": "array",
280
+ "items": {
281
+ "$ref": "#/$defs/PathGlob"
282
+ },
283
+ "description": "The pages written as an explanation, which says why"
284
+ }
285
+ },
286
+ "additionalProperties": false,
287
+ "description": "The Diátaxis mode of each page, whose template checks-docs holds the page to; a page under docs/ needs one"
288
+ }
289
+ },
290
+ "additionalProperties": false,
291
+ "description": "What checks-docs reads to map a doc file to its template"
244
292
  }
245
293
  },
246
294
  "additionalProperties": false,