plumbbob 0.9.3 → 0.10.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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +92 -89
- package/dist/cli-core.js +25 -8
- package/dist/cli.js +1 -1
- package/dist/lib/agents.js +26 -26
- package/dist/lib/buildlog.js +11 -11
- package/dist/lib/buildlogsync.js +8 -8
- package/dist/lib/check.js +55 -22
- package/dist/lib/commitbody.js +72 -0
- package/dist/lib/commitmsg.js +7 -7
- package/dist/lib/git.js +44 -15
- package/dist/lib/intent.js +21 -20
- package/dist/lib/latch.js +19 -19
- package/dist/lib/orient.js +36 -17
- package/dist/lib/reentry.js +70 -0
- package/dist/lib/settings.js +16 -16
- package/dist/lib/sidecar.js +54 -54
- package/dist/lib/templates.js +1 -1
- package/dist/verbs/agent.js +27 -27
- package/dist/verbs/build.js +9 -9
- package/dist/verbs/check.js +6 -6
- package/dist/verbs/checkpoint.js +48 -47
- package/dist/verbs/doctor.js +31 -30
- package/dist/verbs/finish.js +28 -41
- package/dist/verbs/handoff.js +9 -8
- package/dist/verbs/init.js +9 -9
- package/dist/verbs/park.js +3 -3
- package/dist/verbs/recover.js +297 -0
- package/dist/verbs/revert.js +13 -13
- package/dist/verbs/spike.js +25 -19
- package/dist/verbs/start.js +49 -19
- package/dist/verbs/status.js +8 -8
- package/dist/verbs/turn.js +16 -16
- package/dist/verbs/use.js +4 -4
- package/hooks/post-edit.sh +4 -4
- package/hooks/pre-bash-commit.sh +3 -3
- package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
- package/node_modules/checkride/CHANGELOG.md +1404 -0
- package/node_modules/checkride/LICENSE +201 -21
- package/node_modules/checkride/README.md +197 -38
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
- package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
- package/node_modules/checkride/dist/adapters.d.ts +30 -10
- package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
- package/node_modules/checkride/dist/adapters.js +62 -23
- package/node_modules/checkride/dist/adapters.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
- package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
- package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
- package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/command.js +77 -0
- package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts +69 -0
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/cursor.js +247 -0
- package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
- package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/files.js +80 -0
- package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
- package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/harness.js +93 -0
- package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
- package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
- package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
- package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/index.js +9 -4
- package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts +81 -0
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/scripts.js +604 -0
- package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
- package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
- package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
- package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
- package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/configured.js +45 -0
- package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
- package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/format.js +56 -0
- package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
- package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
- package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
- package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/index.js +19 -0
- package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
- package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/json.js +47 -0
- package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
- package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/raw.js +91 -0
- package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
- package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
- package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
- package/node_modules/checkride/dist/artifacts/summary.js +108 -0
- package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
- package/node_modules/checkride/dist/atomic.d.ts +16 -1
- package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
- package/node_modules/checkride/dist/atomic.js +25 -3
- package/node_modules/checkride/dist/atomic.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
- package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fallow.js +163 -60
- package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts +20 -11
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.js +73 -23
- package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
- package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
- package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/history.js +232 -0
- package/node_modules/checkride/dist/baseline/history.js.map +1 -0
- package/node_modules/checkride/dist/baseline/index.d.ts +7 -5
- package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/index.js +5 -4
- package/node_modules/checkride/dist/baseline/index.js.map +1 -1
- package/node_modules/checkride/dist/baseline/store.d.ts +41 -10
- package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/store.js +65 -24
- package/node_modules/checkride/dist/baseline/store.js.map +1 -1
- package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
- package/node_modules/checkride/dist/baseline-command.js +7 -7
- package/node_modules/checkride/dist/baseline-command.js.map +1 -1
- package/node_modules/checkride/dist/cli.d.ts +21 -4
- package/node_modules/checkride/dist/cli.d.ts.map +1 -1
- package/node_modules/checkride/dist/cli.js +350 -36
- package/node_modules/checkride/dist/cli.js.map +1 -1
- package/node_modules/checkride/dist/config.d.ts +114 -9
- package/node_modules/checkride/dist/config.d.ts.map +1 -1
- package/node_modules/checkride/dist/config.js +142 -23
- package/node_modules/checkride/dist/config.js.map +1 -1
- package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
- package/node_modules/checkride/dist/digest/digest.js +6 -6
- package/node_modules/checkride/dist/digest/index.d.ts +2 -2
- package/node_modules/checkride/dist/digest/index.js +2 -2
- package/node_modules/checkride/dist/doctor.d.ts +27 -6
- package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
- package/node_modules/checkride/dist/doctor.js +231 -27
- package/node_modules/checkride/dist/doctor.js.map +1 -1
- package/node_modules/checkride/dist/gate.d.ts +180 -0
- package/node_modules/checkride/dist/gate.d.ts.map +1 -0
- package/node_modules/checkride/dist/gate.js +617 -0
- package/node_modules/checkride/dist/gate.js.map +1 -0
- package/node_modules/checkride/dist/init.d.ts +79 -12
- package/node_modules/checkride/dist/init.d.ts.map +1 -1
- package/node_modules/checkride/dist/init.js +385 -81
- package/node_modules/checkride/dist/init.js.map +1 -1
- package/node_modules/checkride/dist/json.d.ts +21 -0
- package/node_modules/checkride/dist/json.d.ts.map +1 -0
- package/node_modules/checkride/dist/json.js +21 -0
- package/node_modules/checkride/dist/json.js.map +1 -0
- package/node_modules/checkride/dist/links.d.ts +31 -5
- package/node_modules/checkride/dist/links.d.ts.map +1 -1
- package/node_modules/checkride/dist/links.js +141 -32
- package/node_modules/checkride/dist/links.js.map +1 -1
- package/node_modules/checkride/dist/node-pin.d.ts +129 -0
- package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
- package/node_modules/checkride/dist/node-pin.js +211 -0
- package/node_modules/checkride/dist/node-pin.js.map +1 -0
- package/node_modules/checkride/dist/orchestrator.d.ts +53 -10
- package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
- package/node_modules/checkride/dist/orchestrator.js +312 -113
- package/node_modules/checkride/dist/orchestrator.js.map +1 -1
- package/node_modules/checkride/dist/pack.d.ts +8 -9
- package/node_modules/checkride/dist/pack.d.ts.map +1 -1
- package/node_modules/checkride/dist/pack.js +53 -17
- package/node_modules/checkride/dist/pack.js.map +1 -1
- package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
- package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/detect.js +6 -1
- package/node_modules/checkride/dist/pm/detect.js.map +1 -1
- package/node_modules/checkride/dist/pm/index.d.ts +7 -2
- package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/index.js +6 -2
- package/node_modules/checkride/dist/pm/index.js.map +1 -1
- package/node_modules/checkride/dist/pm/launch.d.ts +72 -0
- package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/launch.js +108 -0
- package/node_modules/checkride/dist/pm/launch.js.map +1 -0
- package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
- package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/tools.js +124 -0
- package/node_modules/checkride/dist/pm/tools.js.map +1 -0
- package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
- package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/translate.js +78 -18
- package/node_modules/checkride/dist/pm/translate.js.map +1 -1
- package/node_modules/checkride/dist/proc.d.ts +30 -0
- package/node_modules/checkride/dist/proc.d.ts.map +1 -0
- package/node_modules/checkride/dist/proc.js +42 -0
- package/node_modules/checkride/dist/proc.js.map +1 -0
- package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
- package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/cli.js +24 -0
- package/node_modules/checkride/dist/qa/cli.js.map +1 -0
- package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
- package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/dead.js +88 -0
- package/node_modules/checkride/dist/qa/dead.js.map +1 -0
- package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
- package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/dupes.js +62 -0
- package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
- package/node_modules/checkride/dist/qa/health.d.ts +85 -0
- package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/health.js +109 -0
- package/node_modules/checkride/dist/qa/health.js.map +1 -0
- package/node_modules/checkride/dist/qa/index.d.ts +23 -0
- package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/index.js +22 -0
- package/node_modules/checkride/dist/qa/index.js.map +1 -0
- package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
- package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/mutation.js +195 -0
- package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
- package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
- package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/qa.js +158 -0
- package/node_modules/checkride/dist/qa/qa.js.map +1 -0
- package/node_modules/checkride/dist/qa/read.d.ts +40 -0
- package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/read.js +47 -0
- package/node_modules/checkride/dist/qa/read.js.map +1 -0
- package/node_modules/checkride/dist/qa/render.d.ts +26 -0
- package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
- package/node_modules/checkride/dist/qa/render.js +310 -0
- package/node_modules/checkride/dist/qa/render.js.map +1 -0
- package/node_modules/checkride/dist/recover.d.ts +48 -0
- package/node_modules/checkride/dist/recover.d.ts.map +1 -0
- package/node_modules/checkride/dist/recover.js +220 -0
- package/node_modules/checkride/dist/recover.js.map +1 -0
- package/node_modules/checkride/dist/security.d.ts +45 -0
- package/node_modules/checkride/dist/security.d.ts.map +1 -0
- package/node_modules/checkride/dist/security.js +86 -0
- package/node_modules/checkride/dist/security.js.map +1 -0
- package/node_modules/checkride/dist/smoke.d.ts +6 -6
- package/node_modules/checkride/dist/smoke.js +6 -6
- package/node_modules/checkride/dist/snippets.d.ts +27 -30
- package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
- package/node_modules/checkride/dist/snippets.js +26 -30
- package/node_modules/checkride/dist/snippets.js.map +1 -1
- package/node_modules/checkride/dist/tool-json.d.ts +33 -0
- package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
- package/node_modules/checkride/dist/tool-json.js +58 -0
- package/node_modules/checkride/dist/tool-json.js.map +1 -0
- package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
- package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/cli.js +26 -0
- package/node_modules/checkride/dist/triage/cli.js.map +1 -0
- package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
- package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
- package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
- package/node_modules/checkride/dist/triage/env.d.ts +54 -0
- package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/env.js +81 -0
- package/node_modules/checkride/dist/triage/env.js.map +1 -0
- package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
- package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/gate.js +121 -0
- package/node_modules/checkride/dist/triage/gate.js.map +1 -0
- package/node_modules/checkride/dist/triage/index.d.ts +22 -0
- package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/index.js +20 -0
- package/node_modules/checkride/dist/triage/index.js.map +1 -0
- package/node_modules/checkride/dist/triage/render.d.ts +19 -0
- package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/render.js +419 -0
- package/node_modules/checkride/dist/triage/render.js.map +1 -0
- package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
- package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
- package/node_modules/checkride/dist/triage/triage.js +131 -0
- package/node_modules/checkride/dist/triage/triage.js.map +1 -0
- package/node_modules/checkride/package.json +18 -15
- package/node_modules/checkride/schema/checkride.config.schema.json +70 -5
- package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
- package/node_modules/checkride/skills/check/SKILL.md +265 -0
- package/node_modules/checkride/skills/qa/SKILL.md +231 -0
- package/node_modules/checkride/templates/shared/cspell.json +1 -0
- package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
- package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
- package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
- package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
- package/node_modules/checkride/templates/shared/vale.ini +34 -0
- package/package.json +10 -9
- package/skills/build/SKILL.md +85 -76
- package/skills/doctor/SKILL.md +11 -11
- package/skills/finish/SKILL.md +21 -18
- package/skills/harvest/SKILL.md +13 -11
- package/skills/park/SKILL.md +10 -10
- package/skills/plan/SKILL.md +69 -59
- package/skills/recover/SKILL.md +28 -0
- package/skills/refine/SKILL.md +21 -18
- package/skills/revert/SKILL.md +6 -6
- package/skills/spike/SKILL.md +9 -9
- package/skills/status/SKILL.md +5 -5
- package/skills/step/SKILL.md +20 -15
- package/skills/verify/SKILL.md +56 -46
- package/templates/build-log.md +7 -7
- package/templates/intent.md +52 -41
- package/templates/spike-report.md +10 -10
|
@@ -4,6 +4,1388 @@ All notable changes to this project are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.12.2] - 2026-08-12
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **A `prose-voice` example** under `examples/`: the `prose` slot end to end —
|
|
12
|
+
a legacy doc grandfathered at eight findings, violations that trip
|
|
13
|
+
`Repo.Drift` in fresh markdown and `Repo.ThereIs`/`Repo.Latin` inside a
|
|
14
|
+
TypeScript doc comment, a ratchet scenario pruning the baseline, and the
|
|
15
|
+
`docs/voice` exemplars the AGENTS.md stanza points writing sessions at. The
|
|
16
|
+
e2e harness grows a `proseRules` violation field so an example asserts
|
|
17
|
+
*which* vale rule fired, not merely that `prose` went red.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- The `prose` exemplars pre-flight now says `is a file, not a directory` when
|
|
22
|
+
a file sits at the configured path, instead of the false `does not exist`.
|
|
23
|
+
- Re-resolved `nanoid` to 3.3.18 for GHSA-2v37-7h3g-55p8 (high severity;
|
|
24
|
+
dev-only, via vitest → vite → postcss). No override entry — postcss's own
|
|
25
|
+
range already permits the patched line.
|
|
26
|
+
|
|
27
|
+
### Internal
|
|
28
|
+
|
|
29
|
+
- New tests pin the default runner's exemplars pre-flight wiring, and the rule
|
|
30
|
+
that a run whose vale output is unreadable masks nothing and prunes nothing
|
|
31
|
+
while the slots the run did observe still ratchet.
|
|
32
|
+
|
|
33
|
+
## [0.12.1] - 2026-08-07
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **A `prose` slot for writing-style linting**, powered by `vale`. Opt-in like
|
|
38
|
+
`format`, it checks markdown and TypeScript doc comments (via a JS format
|
|
39
|
+
mapping, so code and string literals stay untouched) for doubled words,
|
|
40
|
+
Latin abbreviations (`e.g.`/`i.e.`/`etc.`), hyphenated `-ly` adverbs,
|
|
41
|
+
sentence-initial "There is", weasel words (off by default — the one
|
|
42
|
+
subjective rule), and the lexical fingerprints of AI-generated prose:
|
|
43
|
+
overused vocabulary like `delve`/`tapestry`/`meticulous`, stock frames like
|
|
44
|
+
"it's not just X — it's Y", and the minted corporate dialect (`the ask`,
|
|
45
|
+
`learnings`, `leverage`/`utilize` as verbs). `init --add prose` scaffolds a
|
|
46
|
+
hermetic, repo-owned vale config and six house-style rule files under
|
|
47
|
+
`.vale/styles/Repo/` — no upstream package, no `vale sync` needed on the
|
|
48
|
+
default path. Findings ratchet through the shared baseline the same way
|
|
49
|
+
`lint`/`struct`/`spell` already do. `spell` keeps sole ownership of
|
|
50
|
+
spelling; the scaffold disables vale's own dictionary and vocabulary
|
|
51
|
+
checks to avoid a second, conflicting wordlist.
|
|
52
|
+
- **An `exemplars` config key on the `prose` slot**, for anchoring voice
|
|
53
|
+
rather than just policing vocabulary. Point it at a directory of
|
|
54
|
+
hand-written prose and the generated AGENTS.md stanza tells writing
|
|
55
|
+
sessions to read and imitate it before touching markdown or doc comments —
|
|
56
|
+
and never to edit or add to it, since a generated "improvement" would
|
|
57
|
+
replace the human original with a copy of the model's own register. The
|
|
58
|
+
check itself fails if the named directory is missing or empty, so a stale
|
|
59
|
+
config can't stay green; checkride never scores prose against the
|
|
60
|
+
exemplars, since judging voice deliberately stays a human call.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- The README's slot table, its opt-in-slots sentence, the cheat sheet's
|
|
65
|
+
pipeline table, and the config schema's `checks` description had all
|
|
66
|
+
drifted out of sync with the slot registry over several releases (missing
|
|
67
|
+
the publish-ready bundle, missing `dupes`/`health`, undercounting opt-in
|
|
68
|
+
slots). Brought current and pinned by a new test that fails whenever a
|
|
69
|
+
slot is added without updating all four surfaces.
|
|
70
|
+
|
|
71
|
+
### Internal
|
|
72
|
+
|
|
73
|
+
- checkride now dogfoods its own `prose` slot: 112 initial findings fixed by
|
|
74
|
+
hand (11 subject-first rewrites, 28 Latin substitutions, 21 `-ly`-hyphen
|
|
75
|
+
drops), landing at zero findings with no baseline grandfathering needed.
|
|
76
|
+
|
|
77
|
+
## [0.12.0] - 2026-08-07
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- **`checkride recover` — restore a clobbered baseline from git history.** The
|
|
82
|
+
motivating incident: checkride landed in a large monorepo, other open PRs
|
|
83
|
+
merged the trunk back, and `checkride.baseline.json` came out of the merges
|
|
84
|
+
with many entries silently deleted (an agent resolving a conflict by removing
|
|
85
|
+
the "problem" lines, most likely). Missing entries fail closed, so the team
|
|
86
|
+
hit a wall of red with no tooling to diagnose or undo it — the remedy was
|
|
87
|
+
manual git archaeology, and the tempting wrong move, re-running
|
|
88
|
+
`checkride baseline`, would have grandfathered every genuinely-new finding
|
|
89
|
+
introduced since the damage.
|
|
90
|
+
|
|
91
|
+
`checkride recover` does the dig instead: it walks the baseline file's recent
|
|
92
|
+
commits (`--depth`, default 25), dedupes them into at most five distinct
|
|
93
|
+
snapshots plus one synthesized union, and lists them with `+restored/−absent`
|
|
94
|
+
deltas against the current file. `--pick <n|sha|union>` applies one by writing
|
|
95
|
+
the file directly — never `git checkout` — so the restore is an ordinary
|
|
96
|
+
working-tree edit to review and commit. The default write is the union of the
|
|
97
|
+
candidate and the current file: nothing is removed, and a stale resurrected
|
|
98
|
+
key is pruned by the ratchet on the next full green run. `--exact` writes the
|
|
99
|
+
snapshot verbatim (refused while the file has uncommitted changes), `--dry-run`
|
|
100
|
+
previews the per-slot delta, `--json` emits the machine shape. Shallow clones
|
|
101
|
+
list with a truncation note; a repo with no committed baseline history says so
|
|
102
|
+
at exit 0.
|
|
103
|
+
|
|
104
|
+
- **A mangled or plundered baseline now explains itself.** A committed
|
|
105
|
+
`checkride.baseline.json` that no longer parses (a botched merge, usually)
|
|
106
|
+
used to be indistinguishable from having no baseline: every grandfathered
|
|
107
|
+
finding reported red with no hint why. A run now prints one stderr line under
|
|
108
|
+
the summary naming the file as present-but-unparseable and pointing at
|
|
109
|
+
`checkride recover`; `checkride doctor` grows an advisory workspace row with
|
|
110
|
+
the same diagnosis (and the key count when the file is healthy). And when the
|
|
111
|
+
file parses but a merge silently dropped entries, a red run probes git history
|
|
112
|
+
(best-effort, bounded at 750 ms, silent on any failure) and prints one hint —
|
|
113
|
+
`N of M new finding(s) were grandfathered until <sha>` — naming
|
|
114
|
+
`checkride recover` as the remedy, so a wall of red arrives with its diagnosis
|
|
115
|
+
attached.
|
|
116
|
+
|
|
117
|
+
### Changed
|
|
118
|
+
|
|
119
|
+
- **The baseline file is canonical on disk.** `writeBaseline` now sorts the
|
|
120
|
+
top-level slots (keys within a slot were already sorted), so two branches that
|
|
121
|
+
grandfather the same debt produce byte-identical files instead of
|
|
122
|
+
insertion-order diff churn — the README's "the file is canonical" claim is now
|
|
123
|
+
true on disk, not just in comparisons.
|
|
124
|
+
|
|
125
|
+
- **`DoctorEnv` gained a required `readText` probe** (it feeds doctor's new
|
|
126
|
+
baseline row). The type sits outside the promised programmatic surface, but a
|
|
127
|
+
TypeScript consumer injecting a custom `env` into `runDoctor` adds one field
|
|
128
|
+
on upgrade.
|
|
129
|
+
|
|
130
|
+
### Contract
|
|
131
|
+
|
|
132
|
+
- New command `checkride recover` with `--pick <n|sha|union>`, `--exact`,
|
|
133
|
+
`--dry-run`, `--depth <n>`, and `--json` (docs/contract.md §CLI). List mode is
|
|
134
|
+
a reader: Markdown on stdout, exit 0. Apply mode writes
|
|
135
|
+
`checkride.baseline.json` atomically and never mutates git state. Exit codes
|
|
136
|
+
are 0 and 2 only — never 1. Additive; every existing command and flag is
|
|
137
|
+
unchanged.
|
|
138
|
+
|
|
139
|
+
### Internal
|
|
140
|
+
|
|
141
|
+
- The website caught up with the product and can no longer drift: a new
|
|
142
|
+
`agents.html` covers the bundled plugin, the Claude Code / Cursor
|
|
143
|
+
asymmetries, and the "could not run" verdict; the command reference gained
|
|
144
|
+
`recover`, `hooks`, `gate`, `triage`, and `qa`; and `test/site.test.ts` +
|
|
145
|
+
cspell now hold `site/` under `pnpm check` (inline scripts must parse, the
|
|
146
|
+
command and slot tables must track `CLI_COMMANDS` and `SLOTS`, internal links
|
|
147
|
+
must resolve). Every baseline-adjacent doc (README, getting-started, CI,
|
|
148
|
+
cheatsheet, plugin skill) now routes a clobbered baseline to `recover`.
|
|
149
|
+
|
|
150
|
+
## [0.11.2] - 2026-08-04
|
|
151
|
+
|
|
152
|
+
### Changed
|
|
153
|
+
|
|
154
|
+
- **A Cursor stand-down now reaches the user, exactly once.** The promise since
|
|
155
|
+
0.11.0 was that a stand-down is never silent: Claude Code gets a
|
|
156
|
+
`systemMessage`, Cursor gets stderr. Those were never equivalent, and the
|
|
157
|
+
Cursor half does not hold — Cursor documents no channel that shows hook stderr
|
|
158
|
+
to a user, mentioning only a Hooks output panel under **Customize** that
|
|
159
|
+
someone has to go and open. So on the one verdict whose entire purpose is to
|
|
160
|
+
name a fix only a human can apply (`pnpm install`, an `engines` pin), the human
|
|
161
|
+
saw nothing.
|
|
162
|
+
|
|
163
|
+
`followup_message` is the field that reaches the chat, and the reason it was
|
|
164
|
+
avoided is real: it *submits a new turn*, so a stand-down spending it every
|
|
165
|
+
turn rebuilds the unbounded loop 0.11.0 removed. It is therefore rationed to
|
|
166
|
+
one. The generated hook script already reads `loop_count` to bound `block`, and
|
|
167
|
+
that same guard now bounds `stand_down` — one nudge naming the fix, silence
|
|
168
|
+
after. The guard errs toward quiet: Cursor's `loop_count` counts every
|
|
169
|
+
auto-follow-up in a conversation rather than the consecutive ones, so an
|
|
170
|
+
over-count costs a silent stand-down and never a loop.
|
|
171
|
+
|
|
172
|
+
- **`CHECKRIDE_GATE_RETRY`, a new environment variable the generated gate script
|
|
173
|
+
sets.** checkride's own stand-down — a refusal it detects from inside, such as
|
|
174
|
+
an `engines` pin the hook's Node fails — needs the same one-shot bound and
|
|
175
|
+
cannot compute it, because the stop payload reaches the hook script and never
|
|
176
|
+
the child process. The script now exports `0` when the one message is unspent
|
|
177
|
+
and `1` when it is not, and `checkride gate --harness cursor` emits a followup
|
|
178
|
+
only on an explicit `0`.
|
|
179
|
+
|
|
180
|
+
**Absence is not `0`.** A hook script generated before this release exports
|
|
181
|
+
neither value and keeps the older stderr-only behavior. That asymmetry is the
|
|
182
|
+
point: it is what stops a refreshed checkride from looping under an
|
|
183
|
+
unrefreshed script, given the `loop_limit: null` the gate's own hook entry
|
|
184
|
+
asks for. Run `checkride agent-setup` to pick up the new script.
|
|
185
|
+
|
|
186
|
+
The variable is an internal contract between the two halves checkride
|
|
187
|
+
generates, not a knob — setting it by hand only suppresses or unlocks one
|
|
188
|
+
message.
|
|
189
|
+
|
|
190
|
+
## [0.11.1] - 2026-08-04
|
|
191
|
+
|
|
192
|
+
### Fixed
|
|
193
|
+
|
|
194
|
+
- **The Cursor stop gate no longer writes package-manager noise to the channel
|
|
195
|
+
Cursor parses as protocol.** The two generated gate scripts were asymmetric,
|
|
196
|
+
and accidentally so: the Claude Code script captured the run, so a failed
|
|
197
|
+
launch wrote into a variable it could then decline to print, while the Cursor
|
|
198
|
+
script ran the launcher uncaptured in order to let checkride's own JSON pass
|
|
199
|
+
straight through. A *failed* launch writes to that same stdout, and nothing
|
|
200
|
+
filtered it — so in a repo whose dependencies were never installed, two lines
|
|
201
|
+
of pnpm resolution error landed on stdout while the correct stand-down
|
|
202
|
+
explanation went to stderr.
|
|
203
|
+
|
|
204
|
+
The turn still ended as intended, because Cursor does not parse that text as a
|
|
205
|
+
hook body. The reason to fix it anyway is what happens if it ever does: a
|
|
206
|
+
bare-text followup would submit a new turn on every stand-down, rebuilding the
|
|
207
|
+
unbounded loop 0.11.0 removed, and doing it on the one cause an agent can do
|
|
208
|
+
nothing about. It also muddies the gate's own diagnostic — a maintainer
|
|
209
|
+
reading a Cursor transcript sees a dependency-resolution error on the protocol
|
|
210
|
+
channel and a different, correct explanation beside it on stderr.
|
|
211
|
+
|
|
212
|
+
Both scripts now capture, and each re-prints that body only on the two exit
|
|
213
|
+
statuses checkride answers with by design. Anything else is the launcher's
|
|
214
|
+
error rather than a verdict, and `block`/`stand_down` own stdout there alone.
|
|
215
|
+
|
|
216
|
+
### Internal
|
|
217
|
+
|
|
218
|
+
- The marketing site under `site/` picks up Fathom analytics and Open Graph plus
|
|
219
|
+
Twitter Card metadata across all three pages. The published package is
|
|
220
|
+
unchanged.
|
|
221
|
+
|
|
222
|
+
## [0.11.0] - 2026-08-04
|
|
223
|
+
|
|
224
|
+
### Added
|
|
225
|
+
|
|
226
|
+
- **`gate.preflight` — a supported seam for wrapping the stop gate.** checkride
|
|
227
|
+
owns the generated hook scripts and overwrites them on every refresh, so a repo
|
|
228
|
+
with something to say before the gate had nowhere to say it: editing the script
|
|
229
|
+
lost the edit, and re-pointing the harness config lost it to the next
|
|
230
|
+
`hooks add`. A `"preflight"` under `gate` in checkride.config.json names a
|
|
231
|
+
repo-relative script the generated gate runs, from the repo root, before
|
|
232
|
+
checkride is started — which is what lets it answer for a repo where checkride
|
|
233
|
+
*cannot* start.
|
|
234
|
+
|
|
235
|
+
Its exit code is read in the gate's own vocabulary rather than a second
|
|
236
|
+
convention: `0` runs the gate, `2` blocks the turn, anything else stands the
|
|
237
|
+
gate down. Both non-zero branches use the script's output as the message and
|
|
238
|
+
never start checkride. A configured path that does not exist **blocks**, so a
|
|
239
|
+
typo cannot quietly disarm the gate.
|
|
240
|
+
|
|
241
|
+
It is a config key rather than a `hooks add --preflight` flag for one reason:
|
|
242
|
+
the path is re-read on every write, so a teammate running the bare command
|
|
243
|
+
restores the wiring instead of silently dropping it. A preflight narrows
|
|
244
|
+
nothing, so it never adds the "NOT the full check" clause to a verdict.
|
|
245
|
+
|
|
246
|
+
### Contract
|
|
247
|
+
|
|
248
|
+
- **A could-not-run gate now blocks only when blocking could lead to a fix.**
|
|
249
|
+
Previously every could-not-run verdict blocked, in both harnesses, on the
|
|
250
|
+
reasoning that a gate which stops gating is a vacuous green. That reasoning
|
|
251
|
+
holds only while the block can *cause* the fix, and for a whole class of causes
|
|
252
|
+
it cannot: the harness re-prompts the same agent, which has no lever to pull.
|
|
253
|
+
The observed end of that road is an unbounded retry against an impossible
|
|
254
|
+
remedy, and then a contributor removing the gate.
|
|
255
|
+
|
|
256
|
+
Launch refusals are now classified by who can clear them. A **repo** refusal —
|
|
257
|
+
no `check` script, no package.json — blocks exactly as before, because an agent
|
|
258
|
+
holding the edit tools can fix it. (A missing `check` script stays blocking for
|
|
259
|
+
a second reason: it is the one refusal an agent could otherwise *create* to
|
|
260
|
+
escape the gate.) An **environment** refusal — an `engines` pin the hook's Node
|
|
261
|
+
fails, a corepack that will not verify the package manager, a package manager
|
|
262
|
+
absent from `PATH` — stands down: exit 0, no `decision`, `green: false`.
|
|
263
|
+
|
|
264
|
+
Two properties are promised about the stand-down and neither may be weakened:
|
|
265
|
+
it is never silent (Claude Code gets a `systemMessage`, Cursor gets stderr,
|
|
266
|
+
both stating that nothing was verified), and it is never reported as green.
|
|
267
|
+
`docs/contract.md` and `test/contract/gate-verdict.contract.test.ts` are
|
|
268
|
+
updated deliberately; a hook script that reads only the exit status will now
|
|
269
|
+
let a turn end on an environment refusal, which is the intended change.
|
|
270
|
+
|
|
271
|
+
### Changed
|
|
272
|
+
|
|
273
|
+
- **`init` now pins markdownlint-cli2 0.23.2 for the `docs` slot**, up from
|
|
274
|
+
0.23.1 — the version that resolves a vulnerable `js-yaml`
|
|
275
|
+
(GHSA-pm4m-ph32-ghv5) transitively into every repo it sets up. An existing
|
|
276
|
+
repo keeps whatever it installed; re-run `checkride init` or bump it yourself.
|
|
277
|
+
|
|
278
|
+
### Fixed
|
|
279
|
+
|
|
280
|
+
- **An uninstalled repo no longer traps the agent in an unbreakable loop.** A
|
|
281
|
+
developer who pulled a branch that newly added checkride — or cloned fresh —
|
|
282
|
+
and started a session before `<pm> install` got a gate that blocked every turn
|
|
283
|
+
with `checkride gate is not resolvable in this repo. Install checkride (or
|
|
284
|
+
re-run checkride agent-setup)`. Every part of that was a dead end: the
|
|
285
|
+
suggested remedy needs the missing binary, and in a repo with a customized
|
|
286
|
+
AGENTS.md stanza `agent-setup` would refuse and exit 2 even if it could run.
|
|
287
|
+
The actual fix, `<pm> install`, was never named. Nothing bounded the retry.
|
|
288
|
+
|
|
289
|
+
The generated gate now distinguishes the two ways checkride can fail to answer.
|
|
290
|
+
Dependencies never installed → it names `<pm> install`, says checkride is a
|
|
291
|
+
devDependency, and stands down. Installed but not answering → it blocks, as
|
|
292
|
+
before, since there is no remedy to name. Yarn PnP is recognized, so a healthy
|
|
293
|
+
PnP repo is not misread as uninstalled.
|
|
294
|
+
|
|
295
|
+
- **Both generated gates bound every could-not-run cause.** The scripts now read
|
|
296
|
+
the Stop payload from stdin and consult Claude Code's `stop_hook_active` and
|
|
297
|
+
Cursor's `loop_count`. On the second consecutive could-not-run, whatever the
|
|
298
|
+
cause, the gate stands down instead of blocking again — the previous script
|
|
299
|
+
read no stdin at all, so `stop_hook_active` was discarded and
|
|
300
|
+
`"loop_limit": null` left the Cursor gate unbounded by design. A **red**
|
|
301
|
+
pipeline is deliberately still unbounded: that loop is the gate working.
|
|
302
|
+
|
|
303
|
+
- **The claude gate no longer forwards the launcher's error as a hook body.** On
|
|
304
|
+
a missing install pnpm writes `ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL` to *stdout*
|
|
305
|
+
— ahead of a stray `undefined` on pnpm 11 — which the script captured into
|
|
306
|
+
`$body` and printed where Claude Code expects JSON. The status is now checked
|
|
307
|
+
before the body is forwarded, so a body travels only when checkride wrote it.
|
|
308
|
+
|
|
309
|
+
- **A refusal the repo can fix is no longer explained by the hook's Node.** The
|
|
310
|
+
`nodeClause` paragraph rode on every refusal, so "this repo has no `check`
|
|
311
|
+
script" was followed by an account of non-login shells and interpreter
|
|
312
|
+
alignment. It is now attached to environment refusals only.
|
|
313
|
+
|
|
314
|
+
- **A red run could be reported as "could not run" on Linux.** `isFresh` judged
|
|
315
|
+
the summary this run wrote by comparing its mtime against a `Date.now()`
|
|
316
|
+
reading taken just before the check spawned — and those are not the same
|
|
317
|
+
clock. Linux mtimes come from the kernel's coarse timer-tick clock, so a
|
|
318
|
+
summary written *after* `startedAt` routinely landed a few milliseconds behind
|
|
319
|
+
it: 934 of 2000 writes in a container, and 0 of 2000 on APFS. When it misfired
|
|
320
|
+
the gate read its own summary as a previous run's, believed an `engines`-pin
|
|
321
|
+
marker the check had merely printed, and blamed the environment for broken
|
|
322
|
+
code. `MTIME_TOLERANCE_MS` already guarded the same comparison in `triage/`;
|
|
323
|
+
the gate's own copy had dropped it. This is what turned the Linux CI legs red
|
|
324
|
+
on v0.10.2 and v0.10.3 while both macOS legs stayed green.
|
|
325
|
+
|
|
326
|
+
- **A green run that skipped most of its slots says so.** `✔ all checks passed`
|
|
327
|
+
is a true sentence about the checks that ran and a misleading one about the
|
|
328
|
+
repo, and the gap was invisible exactly where it matters: a repo configuring
|
|
329
|
+
almost nothing reported the same confident green as one configuring
|
|
330
|
+
everything. The line now reads `✔ all checks passed in 13ms — only 1 of 8
|
|
331
|
+
checks ran, 7 skipped` whenever any slot sat out. `--strict` is unchanged; its
|
|
332
|
+
floor is *zero* checks, which an always-available slot like `links` keeps a
|
|
333
|
+
repo off by itself.
|
|
334
|
+
|
|
335
|
+
### Internal
|
|
336
|
+
|
|
337
|
+
- CI dumps a failing slot's captured streams into collapsible log groups and
|
|
338
|
+
keeps `.check/` as an artifact. A red run logged `✘ test` and nothing else,
|
|
339
|
+
and on a hosted runner the directory holding the reason died with the
|
|
340
|
+
workspace — so the Linux-only gate failure above had to be reproduced in a
|
|
341
|
+
container before it could be read at all.
|
|
342
|
+
|
|
343
|
+
- Dependency audit cleared and mostly retired. Two high advisories were open
|
|
344
|
+
(`fast-uri` GHSA-7p8r-x3mc-p8w7, `brace-expansion` GHSA-rgw5-rvv9-x895), both
|
|
345
|
+
already carrying an override whose range the advisory had since outgrown.
|
|
346
|
+
Re-resolving showed four of the five overrides were dead weight — the parents'
|
|
347
|
+
own ranges reach patched versions — so they were removed rather than widened,
|
|
348
|
+
leaving one. No runtime `dependencies` are declared, so none of this ever
|
|
349
|
+
reached the tarball.
|
|
350
|
+
|
|
351
|
+
## [0.10.3] - 2026-08-01
|
|
352
|
+
|
|
353
|
+
### Added
|
|
354
|
+
|
|
355
|
+
- **Both Cursor guards now cover the shell.** `protect` and `dirty` each take a
|
|
356
|
+
second `.cursor/hooks.json` entry — on `beforeShellExecution` and
|
|
357
|
+
`afterShellExecution` — whose matchers run against the command string rather
|
|
358
|
+
than a tool name. This closes the older of the two documented Cursor gaps:
|
|
359
|
+
`echo … > checkride.baseline.json` is a shell call, not a `Write`, so no
|
|
360
|
+
file-tool matcher could ever see it, and a turn that wrote only through the
|
|
361
|
+
shell used to skip the gate entirely.
|
|
362
|
+
|
|
363
|
+
The standing objection was that matching the shell means parsing arbitrary
|
|
364
|
+
command lines, and a guard that fires on a wrong parse is worse than one with
|
|
365
|
+
a known hole. That objection is answered rather than dropped. `protect`'s
|
|
366
|
+
matcher admits only commands already naming an accounting path — reads
|
|
367
|
+
included — and the script then denies solely on demonstrated write intent: a
|
|
368
|
+
`>`/`>>` redirect target, or a positional argument of `rm`, `mv`, `tee`,
|
|
369
|
+
`sed -i`, `dd of=` and kin. Anything it cannot read that way is allowed, so
|
|
370
|
+
`cat`, `jq`, `grep` and `cp .check/summary.json /tmp/x` keep working, as
|
|
371
|
+
triage requires. `dirty` decides from its matcher alone and biases the other
|
|
372
|
+
way, toward marking a turn dirty, because there the recoverable error is one
|
|
373
|
+
extra pipeline run.
|
|
374
|
+
|
|
375
|
+
Both entries share their sibling's name and script: one guard, one
|
|
376
|
+
`--remove-hook protect`, one `.cjs` branching on `hook_event_name`. The gate
|
|
377
|
+
takes no shell entry — it is not per-call. Claude Code's half of the gap stays
|
|
378
|
+
open; `permissions.deny` is a file-path list, and a `Bash` matcher there would
|
|
379
|
+
mean shipping a generated script that harness does not currently need.
|
|
380
|
+
|
|
381
|
+
### Changed
|
|
382
|
+
|
|
383
|
+
- **The AGENTS.md stanza no longer promises the gate ran everything.** It said
|
|
384
|
+
the stop-gate hook "runs the full `pnpm check`" and told the agent to "let the
|
|
385
|
+
hook run the authoritative pipeline once at the end" — written before gate
|
|
386
|
+
profiles existed, and false in any repo that declares one. The cost of that is
|
|
387
|
+
specific: the stanza is what an agent reads *first*, so it pre-authorized
|
|
388
|
+
reading a profiled `✔ green` as done, and the `NOT the full check` clause
|
|
389
|
+
arrived after the agent had already been told the hook was the last word. The
|
|
390
|
+
disclosure and the contract disagreed, and the contract was the one being read
|
|
391
|
+
in advance.
|
|
392
|
+
|
|
393
|
+
The paragraph now sends the reader to the gate's own verdict — "read the
|
|
394
|
+
gate's verdict rather than assuming it covered everything" — and says plainly
|
|
395
|
+
that a narrowed green is not the "done" defined above. It names no profile
|
|
396
|
+
deliberately: a repo can add `gate` to `checkride.config.json` without
|
|
397
|
+
re-running `agent-setup`, so any stanza that spelled out a specific profile
|
|
398
|
+
would drift back into over-promising, while the verdict is generated per run
|
|
399
|
+
and cannot.
|
|
400
|
+
|
|
401
|
+
## [0.10.2] - 2026-07-31
|
|
402
|
+
|
|
403
|
+
### Added
|
|
404
|
+
|
|
405
|
+
- **A gate profile, for repos where the full pipeline is too slow to run every
|
|
406
|
+
turn.** `checkride.config.json` gains a `gate` key — `only`, `skip`, `changed`
|
|
407
|
+
— that applies to the stop-gate run and nothing else:
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
{ "gate": { "only": ["types", "lint", "struct"], "changed": true } }
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
The flags are appended after the check script's own, so the profile wins over
|
|
414
|
+
anything the script already carried. The intended shape is a fast gate per
|
|
415
|
+
turn with the full check still binding at commit or in CI; the gate is not the
|
|
416
|
+
only place "done" can be enforced, and in a large repo it should not be the
|
|
417
|
+
expensive one.
|
|
418
|
+
|
|
419
|
+
**Every verdict a profiled gate emits says it was a profile**, in those words:
|
|
420
|
+
`checkride ✔ green in 4.1s — gate profile: only types, lint — NOT the full
|
|
421
|
+
check`. That is the price of the feature and it is deliberately not
|
|
422
|
+
configurable. A gate that runs three of eighteen slots and reports a bare
|
|
423
|
+
green has told the reader the work is done, which is the one thing it does not
|
|
424
|
+
know — the vacuous pass this tool exists to prevent, reached from the
|
|
425
|
+
comfortable direction rather than the alarming one. A narrowed red points past
|
|
426
|
+
itself for the same reason. A profile that narrows nothing is treated as no
|
|
427
|
+
profile, so the warning never appears on a run that was in fact complete.
|
|
428
|
+
|
|
429
|
+
- **checkride aligns the gate to the repo's Node pin.** Before running the check
|
|
430
|
+
script, if the repo names an exact interpreter (`.nvmrc` or `.node-version`)
|
|
431
|
+
and the running Node does not satisfy it, checkride puts a matching installed
|
|
432
|
+
Node in front of the child's `PATH` — so a hook that arrived on the wrong Node
|
|
433
|
+
runs the pipeline on the right one instead of failing to run it at all.
|
|
434
|
+
|
|
435
|
+
Four rules bound it, because choosing the interpreter a repo's whole pipeline
|
|
436
|
+
runs on is not a small thing to do silently: only on an explicit pin file
|
|
437
|
+
(`engines.node` is a *range* — a compatibility declaration, not an instruction
|
|
438
|
+
to switch interpreters — and is read for diagnosis only); only when the running
|
|
439
|
+
Node does not already satisfy it; only an interpreter already installed under a
|
|
440
|
+
known layout (nvm, fnm, nodenv, asdf, volta, n — nothing is downloaded and no
|
|
441
|
+
version manager is invoked, since under a non-login shell `nvm` is a shell
|
|
442
|
+
function and not a binary); and never without a line on stderr saying what it
|
|
443
|
+
aligned to and why.
|
|
444
|
+
|
|
445
|
+
`CHECKRIDE_NODE_BIN` is the escape hatch in both directions: a directory to use
|
|
446
|
+
verbatim — the documented wrapping point for a layout checkride does not know —
|
|
447
|
+
or `off` to disable alignment entirely. When alignment cannot help, nothing
|
|
448
|
+
changes and the refusal above names the pin, the Node that ran, and the lever.
|
|
449
|
+
|
|
450
|
+
- **`doctor` reports the Node a hook would get, not just this shell's.** Every
|
|
451
|
+
other row describes the terminal `doctor` was typed into, which is how it said
|
|
452
|
+
`environment ok` about a repo whose gate could not start — the bug was
|
|
453
|
+
invisible to every read-only command checkride had. The new `node pin` row asks
|
|
454
|
+
the question that *is* answerable from any shell: given the repo's pin, could
|
|
455
|
+
checkride put the right Node back if a hook arrived with the wrong one? It is
|
|
456
|
+
never required, so it flags a risk without failing a repo that works.
|
|
457
|
+
|
|
458
|
+
- **`checkride hooks add <a,b>` / `checkride hooks remove <a,b>` — hook
|
|
459
|
+
management that never touches AGENTS.md.** `agent-setup` writes four things at
|
|
460
|
+
once (the `check` alias, the stanza, the hooks, the Cursor skills) with the
|
|
461
|
+
stanza guard in front of all of them, so managing a hook inherited the stanza's
|
|
462
|
+
problems: a repo whose AGENTS.md had been edited could not remove a hook *at
|
|
463
|
+
all* — the run refused and, by contract, wrote nothing — and a repo mid-upgrade
|
|
464
|
+
had its stanza rewritten by a command it had asked to touch hooks.
|
|
465
|
+
|
|
466
|
+
The new command writes only the harness config entries and the generated
|
|
467
|
+
scripts. It never reads or writes AGENTS.md, so no state of that file can block
|
|
468
|
+
it and no run of it can change that file. `--harness <a,b>` and `--dry-run`
|
|
469
|
+
both apply, and both directions are idempotent. `add` defaults to every hook;
|
|
470
|
+
`remove` requires an explicit list, because a bare command that tore out the
|
|
471
|
+
gate would be the silent un-gating checkride exists to prevent.
|
|
472
|
+
|
|
473
|
+
`agent-setup` is unchanged, flags and refusal included.
|
|
474
|
+
|
|
475
|
+
### Changed
|
|
476
|
+
|
|
477
|
+
- **checkride generates one file for Claude Code, not four.** `protect` is now a
|
|
478
|
+
pair of `permissions.deny` rules and `dirty` is an inline command, so
|
|
479
|
+
`.claude/hooks/checkride-protect.cjs` and `.claude/hooks/checkride-dirty.sh`
|
|
480
|
+
are gone. Both are deleted automatically on the next `agent-setup`, `init`, or
|
|
481
|
+
`hooks add`.
|
|
482
|
+
|
|
483
|
+
`protect` gains more than tidiness from the move. Claude Code evaluates a deny
|
|
484
|
+
rule **regardless of what a `PreToolUse` hook returns**, so the same paths are
|
|
485
|
+
now guarded a layer below the hook that used to guard them — and at no cost
|
|
486
|
+
per tool call, where the script spawned Node on every single edit while
|
|
487
|
+
allowing essentially all of them. The rules are also a list checkride
|
|
488
|
+
*appends* to and removes only its own entries from, so a repo can add its own
|
|
489
|
+
suppression files beside them (a `fallow.baseline`, a lint baseline) and keep
|
|
490
|
+
them across every refresh. The generated script could never offer that: it was
|
|
491
|
+
checkride-owned and overwritten wholesale on every run.
|
|
492
|
+
|
|
493
|
+
```json
|
|
494
|
+
"permissions": {
|
|
495
|
+
"deny": ["Edit(**/checkride.baseline.json)", "Edit(**/.check/**)"]
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
`Edit(...)` is the only correct spelling, and getting it wrong fails silently:
|
|
500
|
+
Claude Code checks file paths against `Edit` and `Read` rules only, and a
|
|
501
|
+
`Write(...)` or `NotebookEdit(...)` path rule is accepted, never consulted, and
|
|
502
|
+
warns at startup. An `Edit` rule covers every file-editing tool. `Read` deny
|
|
503
|
+
rules stay deliberately absent — triage reads `.check/` artifacts.
|
|
504
|
+
|
|
505
|
+
Nothing moves in the user-facing surface: `--hook protect`,
|
|
506
|
+
`--remove-hook protect`, and `checkride hooks add|remove protect` all mean what
|
|
507
|
+
they meant. **Cursor is unchanged** and still gets all three scripts; its
|
|
508
|
+
config is hooks and nothing else, with no documented file-path deny list to
|
|
509
|
+
move `protect` into.
|
|
510
|
+
|
|
511
|
+
- **`checkride hooks` counts files changed, not files deleted.** Removing a hook
|
|
512
|
+
a harness expresses as configuration rewrites the config and deletes nothing,
|
|
513
|
+
and the old wording reported that as `removed 0 file(s)` — a run that did
|
|
514
|
+
exactly what was asked, reading as a no-op. The line now names the hooks and
|
|
515
|
+
counts every file it touched.
|
|
516
|
+
|
|
517
|
+
- **The AGENTS.md stanza no longer prescribes an architecture.** It carried
|
|
518
|
+
checkride's own house style as if it were law — "Named exports only; no
|
|
519
|
+
classes; `.js` extensions on relative imports", plus the barrel-`index.ts`
|
|
520
|
+
rules — into every repo that ran `init` or `agent-setup`. For a repo that uses
|
|
521
|
+
classes, default exports, or bundler-style extensionless imports, that is a
|
|
522
|
+
contract file instructing the agent to write the wrong code. The stanza is
|
|
523
|
+
also the one region a repo cannot correct: editing it is what makes the next
|
|
524
|
+
refresh refuse.
|
|
525
|
+
|
|
526
|
+
The `### Module boundaries` section now names where the rules live instead of
|
|
527
|
+
what they say — the `struct` check runs whatever ast-grep rules `sgconfig.yml`
|
|
528
|
+
points at, and those files are the convention. It is emitted only when
|
|
529
|
+
`struct` is an active check; a repo without it gets no section at all. Delete
|
|
530
|
+
`rules/no-class.yml` and the stanza stays true, which is the property it was
|
|
531
|
+
missing.
|
|
532
|
+
|
|
533
|
+
`init` still *scaffolds* those rules as its opinionated default — that part is
|
|
534
|
+
a starter you own and can edit, and is unchanged.
|
|
535
|
+
|
|
536
|
+
- **`--add struct` scaffolds the boundary rule and stops.** It used to write
|
|
537
|
+
four ast-grep rules, three of which are style, not structure: `no-class`,
|
|
538
|
+
`no-default-export`, and `require-js-extension`. A repo that uses classes,
|
|
539
|
+
default exports, or bundler resolution went red the moment it adopted the
|
|
540
|
+
slot — for code it had always written, over a convention it never chose, which
|
|
541
|
+
reads as checkride being broken rather than as a finding. `--add struct` now
|
|
542
|
+
writes `sgconfig.yml` and `rules/no-deep-sibling-import.yml`: the rule that
|
|
543
|
+
makes `struct` the slot it is, and one whose failures mean what they say.
|
|
544
|
+
|
|
545
|
+
New-mode `init` still writes all four. That is a different bargain — it is
|
|
546
|
+
creating the package, so there is no prior decision to override — and the
|
|
547
|
+
other rules are listed in `docs/deep-modules.md` for any repo that wants them.
|
|
548
|
+
|
|
549
|
+
### Fixed
|
|
550
|
+
|
|
551
|
+
- **A package manager that refuses to start the check script is no longer
|
|
552
|
+
reported as a red pipeline.** In any repo pinning `engines.node`, pnpm answers
|
|
553
|
+
a Node it does not accept with `ERR_PNPM_UNSUPPORTED_ENGINE` and **exit 1** —
|
|
554
|
+
the same exit code a failing test uses. The gate read that as a verdict on the
|
|
555
|
+
code and said so: `checkride ✘ red in 265ms`, exit 2, turn blocked, every turn,
|
|
556
|
+
regardless of what was written. It then sent the reader to
|
|
557
|
+
`.check/summary.json`, which no run had written, because no check had run.
|
|
558
|
+
|
|
559
|
+
That is the vacuous gate inverted — not a silent green but a permanent red no
|
|
560
|
+
code change can clear, whose rational response is to switch the gate off. And
|
|
561
|
+
it is not one repo's problem: agent harnesses run hooks in a **non-login
|
|
562
|
+
shell**, which never sources the rc file a version manager puts its shims in,
|
|
563
|
+
so the hook gets the machine's default Node rather than the contributor's. On
|
|
564
|
+
nvm that is the norm, not the exception.
|
|
565
|
+
|
|
566
|
+
`gate` now answers a third verdict — **could not run** — for a launch that
|
|
567
|
+
never happened, naming the cause and saying plainly that nothing ran and no
|
|
568
|
+
artifact describes this turn. It still blocks, in both harnesses: an unrunnable
|
|
569
|
+
gate has never been a pass. `triage` gained the matching `could-not-start`
|
|
570
|
+
verdict, since it runs the same script and had folded the same exit into `red`,
|
|
571
|
+
confirming the gate's wrong answer to whoever came asking why.
|
|
572
|
+
|
|
573
|
+
The classification is guarded on both sides. Only pnpm's and npm's own error
|
|
574
|
+
codes are matched — npm's `EBADENGINE` *warning* deliberately is not, because
|
|
575
|
+
npm runs the script anyway unless `engine-strict` is set — and a summary
|
|
576
|
+
written by the current run vetoes the whole thing, so a check that merely
|
|
577
|
+
*printed* one of these strings can never be reclassified into an environment
|
|
578
|
+
problem.
|
|
579
|
+
|
|
580
|
+
- **Upgrading no longer looks like an edit.** 0.10.1 started stamping the stanza
|
|
581
|
+
so a refresh could tell its own output from a customization — but a stanza
|
|
582
|
+
written *before* the stamp carries no evidence either way, so every upgrading
|
|
583
|
+
repo read as `unstamped`, refused, and by contract wrote **nothing**: not the
|
|
584
|
+
stanza, not the config, not the hooks. That is how 0.10.1's own gate-timeout
|
|
585
|
+
fix failed to reach the repos it was written for. The guard protecting AGENTS.md
|
|
586
|
+
prose was withholding a fix for a gate that had silently stopped gating.
|
|
587
|
+
|
|
588
|
+
checkride now recognizes the wordings it actually shipped — four distinct texts
|
|
589
|
+
across v0.1.1–v0.10.0, matched on everything but the generated
|
|
590
|
+
`Active checks in this repo:` line, so a repo's own slot list is irrelevant. A
|
|
591
|
+
pre-stamp stanza that matches one is checkride's own output, refreshes without
|
|
592
|
+
`--force`, and comes back stamped; one that matches nothing has been edited and
|
|
593
|
+
is still refused, with a message that now says so plainly instead of hedging
|
|
594
|
+
about indistinguishable wordings.
|
|
595
|
+
|
|
596
|
+
The list is closed and needs no maintenance: every release from 0.10.1 stamps
|
|
597
|
+
what it writes, so no future version can add an unstamped wording.
|
|
598
|
+
|
|
599
|
+
- **The AGENTS.md stanza is package-manager-agnostic.** It hardcoded `pnpm
|
|
600
|
+
check` and `pnpm exec checkride triage` regardless of the repo's package
|
|
601
|
+
manager, while checkride detects that manager everywhere else and README
|
|
602
|
+
promises the tool is agnostic. The stanza is a list of commands an agent is
|
|
603
|
+
told to run, so in an npm repo it was an instruction that cannot succeed: the
|
|
604
|
+
agent either invents a substitute or reports the pipeline as broken. It now
|
|
605
|
+
renders `npm run check` / `npx --no-install checkride triage`, `yarn run
|
|
606
|
+
check`, or `bun run check` from the detected manager, and `pnpm check` is
|
|
607
|
+
unchanged for pnpm repos.
|
|
608
|
+
|
|
609
|
+
The Claude Code gate's `statusMessage` had the same bug from the same source
|
|
610
|
+
and is fixed with it — the spinner said `npm check`, which is not a command,
|
|
611
|
+
and `yarn check` names Yarn 1's integrity checker rather than the repo's
|
|
612
|
+
script.
|
|
613
|
+
|
|
614
|
+
- **The `spell` check no longer trips over checkride's own stanza hash.** The
|
|
615
|
+
`hash=v1…` marker is 16 hex digits, so sooner or later it spells something
|
|
616
|
+
cspell does not recognize (`…fedf…`) and fails a slot for a string checkride
|
|
617
|
+
itself generated. The shipped `cspell.json` now ignores the marker.
|
|
618
|
+
|
|
619
|
+
### Contract
|
|
620
|
+
|
|
621
|
+
- **A gate that could not run answers "could not run", not "red"**
|
|
622
|
+
(docs/contract.md §CLI). The exit codes are unchanged and remain the promise —
|
|
623
|
+
2 while blocked under `--harness claude`, always 0 under `--harness cursor` —
|
|
624
|
+
because an unrunnable gate has always blocked. What is new is that the verdict
|
|
625
|
+
distinguishes a red pipeline from a launch that never happened, so anything
|
|
626
|
+
reading the `systemMessage` / `followup_message` body sees a cause instead of a
|
|
627
|
+
pointer to an artifact this run did not write. Additive: a hook script that
|
|
628
|
+
gates on the exit code alone is unaffected.
|
|
629
|
+
|
|
630
|
+
- **`checkride.config.json` promises a `gate` key** (docs/contract.md §CLI), and
|
|
631
|
+
with it the disclosure: while a profile is active, every gate verdict names the
|
|
632
|
+
profile and states that it was not the full check.
|
|
633
|
+
|
|
634
|
+
- **`CHECKRIDE_NODE_BIN`** is promised as the hook author's wrapping point: a
|
|
635
|
+
directory prepended to the check run's `PATH`, or `off` to disable checkride's
|
|
636
|
+
own Node-pin alignment.
|
|
637
|
+
|
|
638
|
+
- **What a hook *is* belongs to the harness** (docs/contract.md §CLI). The three
|
|
639
|
+
hook names stay promised; whether one lands as a config entry, a permission
|
|
640
|
+
rule, or a generated script is checkride's to choose per harness and may change
|
|
641
|
+
again. What is promised about the Claude Code deny rules is the part a consumer
|
|
642
|
+
builds on: checkride appends its own and removes only those. Anyone scripting
|
|
643
|
+
against the *path* `.claude/hooks/checkride-protect.cjs` should read
|
|
644
|
+
`permissions.deny` instead.
|
|
645
|
+
|
|
646
|
+
## [0.10.1] - 2026-07-31
|
|
647
|
+
|
|
648
|
+
### Added
|
|
649
|
+
|
|
650
|
+
- **`init` and `agent-setup` refuse to overwrite an AGENTS.md stanza that has
|
|
651
|
+
been edited.** Repos routinely need a line or two of their own in the contract
|
|
652
|
+
— a directory the `spell` check is allowed to skip, what a custom check means
|
|
653
|
+
here — and the refresh rewrote the marked region blind, taking those additions
|
|
654
|
+
with it. Idempotent, as promised, and lossy: the second run reported
|
|
655
|
+
`changed: false` precisely because the first one had already discarded the
|
|
656
|
+
edit.
|
|
657
|
+
|
|
658
|
+
The begin marker now carries a hash of the body checkride generated
|
|
659
|
+
(`<!-- checkride:begin hash=v1… -->`), so a later run can tell its own output
|
|
660
|
+
from a block someone has since changed. A changed one stops the run: exit 2, a
|
|
661
|
+
message naming the file and the two ways forward, and **nothing written at
|
|
662
|
+
all** — not the config, not the hooks — so a refused run leaves the repo
|
|
663
|
+
exactly as it found it, the rule new-mode `init` already followed for scaffold
|
|
664
|
+
collisions. `--force` accepts the loss and refreshes, and now carries that
|
|
665
|
+
meaning on `agent-setup` too, where the flag previously reached nothing.
|
|
666
|
+
|
|
667
|
+
Two things are deliberately *not* edits. Reformatting: line endings and
|
|
668
|
+
trailing whitespace are normalized away before hashing, so a Prettier run over
|
|
669
|
+
AGENTS.md does not read as a customization. And anything outside the markers,
|
|
670
|
+
which stays the right home for repo-specific additions — checkride has never
|
|
671
|
+
rewritten a line out there and still does not.
|
|
672
|
+
|
|
673
|
+
One-time cost on upgrade: a stanza written by 0.10.0 or earlier carries no
|
|
674
|
+
hash, and an older version's wording is indistinguishable from an edit, so the
|
|
675
|
+
first run after upgrading refuses with its own wording of the message.
|
|
676
|
+
`--force` once stamps it; detection is automatic from then on.
|
|
677
|
+
|
|
678
|
+
- **`--remove-hook <a,b>` tears an installed hook back out** — the config entry
|
|
679
|
+
and the generated script both. `--hook` only ever chose what to *write*, so
|
|
680
|
+
there was no supported way to drop the gate after the fact. It pairs with
|
|
681
|
+
`--no-hook` to remove without refreshing anything else, and removing `dirty`
|
|
682
|
+
rewrites a surviving gate unguarded, so the gate cannot silently disarm itself
|
|
683
|
+
on the way out.
|
|
684
|
+
|
|
685
|
+
- **A `note` field on any check entry, and at the config root**, for commentary
|
|
686
|
+
aimed at whoever reads `checkride.config.json` next. It is validated as a
|
|
687
|
+
string and then dropped — no code path carries it onto an Adapter, so it
|
|
688
|
+
cannot reach the status line or `summary.json`. `description` keeps its
|
|
689
|
+
user-facing role; this repo's own config dogfoods the split.
|
|
690
|
+
|
|
691
|
+
- **The gate states its verdict in words**, not just an exit code: the wall
|
|
692
|
+
clock and the failing slots, read back from `.check/summary.json` —
|
|
693
|
+
`checkride red in 41.7s, 2 of 15 failed: lint, test`. Under Claude Code it
|
|
694
|
+
rides in the hook body as `systemMessage`, which moves the block onto
|
|
695
|
+
`decision: "block"`, since hook JSON is parsed only on exit 0. `checkride
|
|
696
|
+
gate`'s own exit codes are unchanged: the generated script does the
|
|
697
|
+
translation and falls back to exit-2 blocking when no body comes back, so an
|
|
698
|
+
unrefreshed repo or an older checkride keeps gating either way. Cursor gets
|
|
699
|
+
the same line atop its `followup_message` on red; a green Cursor gate stays
|
|
700
|
+
silent, because its only stop-hook output field submits a new turn, and the
|
|
701
|
+
gap is recorded in docs/cursor.md rather than papered over.
|
|
702
|
+
|
|
703
|
+
- **The Claude Code Stop entry carries `statusMessage` and `timeout: 900`.** The
|
|
704
|
+
spinner now names the command rather than leaving a multi-minute pipeline
|
|
705
|
+
indistinguishable from a hung model, and the timeout closes a live hole: the
|
|
706
|
+
platform default is 600s, and a hook cancelled by it exits non-zero, which
|
|
707
|
+
Claude Code reads as a broken hook and lets the turn end. Any repo whose
|
|
708
|
+
pipeline crossed ten minutes had a gate that had quietly stopped gating.
|
|
709
|
+
|
|
710
|
+
### Fixed
|
|
711
|
+
|
|
712
|
+
- **`triage` no longer reports an unparseable summary as a run with no
|
|
713
|
+
failures.** A repo whose gate is a homegrown script writing a checkride-shaped
|
|
714
|
+
`.check/` — same file names, no `schema_version` — made the reader announce
|
|
715
|
+
"checkride never ran, a compound script short-circuited" about a gate that had
|
|
716
|
+
run all eight of its checks and failed three. An empty slot table now reads as
|
|
717
|
+
"nothing was read", not "nothing failed": the short-circuit verdict is
|
|
718
|
+
reserved for a genuinely absent summary, `covered:` renders `unknown` rather
|
|
719
|
+
than a count nobody measured, a missing `schema_version` becomes its own
|
|
720
|
+
`foreign` state, and a new `.check/ contents` section lists the directory when
|
|
721
|
+
the summary is not an index.
|
|
722
|
+
|
|
723
|
+
- **The gate ignores a summary older than its own start time.** A check script
|
|
724
|
+
shaped `tsc --build && checkride` leaves `summary.json` untouched when the
|
|
725
|
+
build fails, and trusting it would report the previous run's failing slots as
|
|
726
|
+
this run's.
|
|
727
|
+
|
|
728
|
+
### Contract
|
|
729
|
+
|
|
730
|
+
- **checkride owns the AGENTS.md stanza and only the stanza**, and the boundary
|
|
731
|
+
is now enforced rather than documented (docs/contract.md §CLI, locked by
|
|
732
|
+
`test/contract/flags.contract.test.ts`). The promise a consumer can build on:
|
|
733
|
+
a stanza carrying local edits is never overwritten without `--force`, and the
|
|
734
|
+
run that refuses writes nothing. Behavioural break for anyone scripting
|
|
735
|
+
`agent-setup` over a repo with a hand-edited or pre-0.10.1 stanza — that
|
|
736
|
+
invocation exited 0 and now exits 2 until it is re-run with `--force`.
|
|
737
|
+
|
|
738
|
+
## [0.10.0] - 2026-07-31
|
|
739
|
+
|
|
740
|
+
### Added
|
|
741
|
+
|
|
742
|
+
- **Cursor support — hooks and skills.** `init` and `agent-setup` now write the
|
|
743
|
+
same three hooks (`gate`, `dirty`, `protect`) into `.cursor/hooks.json` as
|
|
744
|
+
they do into `.claude/settings.json`, and write the bundled `check` and `qa`
|
|
745
|
+
skills into `.cursor/skills/` as `checkride-check` and `checkride-qa` —
|
|
746
|
+
Cursor has no plugin system to install them from. Which harnesses get wired
|
|
747
|
+
is detected (Claude Code always, Cursor when `.cursor/` exists) and
|
|
748
|
+
overridable with `--harness <a,b>`.
|
|
749
|
+
|
|
750
|
+
The gate had to learn a second protocol to get there. Claude Code blocks a
|
|
751
|
+
turn on **exit 2** and reads stderr; Cursor treats any non-zero stop hook as a
|
|
752
|
+
*broken* hook and lets the turn end, so its verdict rides in a
|
|
753
|
+
`{"followup_message": …}` body on stdout instead. Same decision, two wire
|
|
754
|
+
formats.
|
|
755
|
+
|
|
756
|
+
Cursor's defaults would have made that gate advisory, so the entry overrides
|
|
757
|
+
three of them: `timeout` (a pipeline is minutes), `loop_limit: null` (the
|
|
758
|
+
default of 5 stops the gate replying after five turns, where Claude Code
|
|
759
|
+
re-blocks indefinitely) and `failClosed: true` (Cursor is fail-open, so a
|
|
760
|
+
crashed or timed-out gate would end the turn silently). The `dirty` and
|
|
761
|
+
`protect` guards keep the fail-open default, deliberately.
|
|
762
|
+
|
|
763
|
+
- **[Cursor](docs/cursor.md).** A page for the parts that are not symmetric with
|
|
764
|
+
Claude Code — the reply-don't-block stop protocol, the three overridden
|
|
765
|
+
defaults, the third-party-configs setting, and an explicit list of the
|
|
766
|
+
assumptions Cursor's own docs leave open (chiefly: the `tool_input` path key
|
|
767
|
+
`protect` matches on is a guess, and a wrong guess fails open silently).
|
|
768
|
+
|
|
769
|
+
- **`checkride gate`, `checkride triage`, `checkride qa`.** The gate's body —
|
|
770
|
+
the edit-marker check, the `check` run, the digest-or-summary choice — moved
|
|
771
|
+
out of the generated shell script into a real command, so it is testable and
|
|
772
|
+
every harness's hook script is now a thin adapter over it. `triage` and `qa`
|
|
773
|
+
promote the two bundled plugin readers to first-class commands, so a skill no
|
|
774
|
+
longer needs `${CLAUDE_PLUGIN_ROOT}` (or a hardcoded `node_modules/` path) to
|
|
775
|
+
find them.
|
|
776
|
+
|
|
777
|
+
### Fixed
|
|
778
|
+
|
|
779
|
+
- **The gate no longer fails open when checkride cannot run.** An uninstalled
|
|
780
|
+
or unresolvable checkride made the hook exit 1, which Claude Code reads as
|
|
781
|
+
"hook failed, carry on" — leaving a repo whose gate had silently stopped
|
|
782
|
+
gating. Any exit outside the gate's own 0/2 now blocks, naming the cause.
|
|
783
|
+
(`protect` still fails open, deliberately: a broken protect hook must not
|
|
784
|
+
become a repo where nothing can be written.)
|
|
785
|
+
- **A repo wired for both harnesses no longer runs two gates per turn.** Cursor
|
|
786
|
+
loads `.claude/settings.json` hooks when third-party configs are enabled, maps
|
|
787
|
+
`Stop` onto `stop`, and runs *every* matching source — so the default wiring
|
|
788
|
+
(Claude Code is always selected) fired two full pipelines concurrently into one
|
|
789
|
+
`.check/`, racing on the artifacts the orchestrator clears per slot and on the
|
|
790
|
+
edit marker. `checkride gate --harness claude` now stands down when Cursor is
|
|
791
|
+
running it and a native Cursor gate is registered. Narrow on purpose: a stale
|
|
792
|
+
`CURSOR_PROJECT_DIR` costs a duplicate run, never the gate.
|
|
793
|
+
- **A gate that cannot enter the repo now reports it.** The `cd` guard was a bare
|
|
794
|
+
`exit 2`, which said nothing under Claude Code and — because Cursor reads any
|
|
795
|
+
non-zero stop hook as a broken one — ended the turn silently under Cursor. It
|
|
796
|
+
now emits the same "could not run" verdict as every other way the gate can fail
|
|
797
|
+
to start, in each harness's protocol.
|
|
798
|
+
- **`protect` no longer misses paths under a symlinked repo root.** It compared
|
|
799
|
+
the harness's spelling of a path against the environment's, which on macOS
|
|
800
|
+
routinely differ (`/var/…` vs `/private/var/…`), making every in-repo path
|
|
801
|
+
look external — so an edit to `checkride.baseline.json` was allowed through.
|
|
802
|
+
Both sides are now resolved before comparison.
|
|
803
|
+
|
|
804
|
+
### Contract
|
|
805
|
+
|
|
806
|
+
- The command set gains `gate`, `triage` and `qa`; `init`/`agent-setup` gain
|
|
807
|
+
`--harness <a,b>`. All additive. `gate` is documented as the one command
|
|
808
|
+
outside the 0/1/2 exit split, because it answers a harness's hook protocol
|
|
809
|
+
rather than checkride's own — see `docs/contract.md` §CLI. Its one documented
|
|
810
|
+
no-op is promised there too: `--harness claude` stands down for a registered
|
|
811
|
+
native Cursor gate.
|
|
812
|
+
|
|
813
|
+
## [0.9.6] - 2026-07-30
|
|
814
|
+
|
|
815
|
+
### Fixed
|
|
816
|
+
|
|
817
|
+
- **A slot refused for a missing tool was reported as a harness problem.** The
|
|
818
|
+
refusal carried `exit_code: -1`, which is reserved for a spawn failure or
|
|
819
|
+
timeout — so `triage` matched it and printed "it failed to spawn or timed out.
|
|
820
|
+
That is a harness problem, not a finding," telling the reader to discount the
|
|
821
|
+
one failure the pre-flight exists to make them act on, remediation and all. It
|
|
822
|
+
now exits **1**, a finding like any other. `-1` keeps meaning the harness
|
|
823
|
+
broke, and a triage test now pins the two apart.
|
|
824
|
+
- **A tool installed above the repo root satisfied the pre-flight.** The upward
|
|
825
|
+
search for `node_modules/.bin/<tool>` stopped only at the filesystem root, so
|
|
826
|
+
a stray install in a home or projects directory counted — the same
|
|
827
|
+
machine-state dependence the local resolution was added to remove, reached by
|
|
828
|
+
a different route: the slot passed for whoever had that directory above their
|
|
829
|
+
clone and failed on the clean checkout. The search now stops at the repo root,
|
|
830
|
+
marked by a `.git` or a lockfile, and searches that root before stopping.
|
|
831
|
+
- **A timed-out `yarn bin` probe reported the tool as missing.** Under Yarn PnP
|
|
832
|
+
`doctor` folded every probe failure into "not a dependency", so a slow package
|
|
833
|
+
manager produced a confident `missing` and told you to install a tool that was
|
|
834
|
+
already there. A timeout is now `unknown`, with a hint naming it — the
|
|
835
|
+
treatment the `--version` probe alongside it already had.
|
|
836
|
+
- **`doctor` reported a healthy Yarn PnP project as broken.** Both of its
|
|
837
|
+
install questions were path tests against a `node_modules/` tree, which a PnP
|
|
838
|
+
project does not have: `install` asserted the directory and so reported
|
|
839
|
+
`lockfile only`, and each slot's tool was looked for at
|
|
840
|
+
`node_modules/.bin/<tool>` and so reported missing — on a repo where every
|
|
841
|
+
tool was installed and every check ran green. The two commands therefore
|
|
842
|
+
contradicted each other, `doctor` calling the environment broken while the
|
|
843
|
+
gate passed. `install` is now satisfied by `.pnp.cjs` plus the lockfile, and a
|
|
844
|
+
tool is resolved with `yarn bin <tool>`, whose exit code carries the answer.
|
|
845
|
+
A tool that genuinely does not resolve still reports missing — the looser
|
|
846
|
+
question must not become a softer one, or this would trade a false red for a
|
|
847
|
+
false green, which is the worse of the two. Detection is gated on yarn so a
|
|
848
|
+
`.pnp.cjs` left by a migration off Yarn cannot reroute an npm or pnpm repo.
|
|
849
|
+
|
|
850
|
+
## [0.9.5] - 2026-07-30
|
|
851
|
+
|
|
852
|
+
### Contract
|
|
853
|
+
|
|
854
|
+
- **A slot's tool is now resolved in the local tree before the check spawns,
|
|
855
|
+
under `npx` and `bunx`.** 0.9.3 stopped those launchers *fetching* a missing
|
|
856
|
+
tool, but `--no-install` bounds the download and not the per-user cache, so
|
|
857
|
+
both still run a copy left behind by some earlier unrelated invocation. The
|
|
858
|
+
gate's verdict therefore depended on machine state nobody declared: a repo
|
|
859
|
+
whose `docs` slot was detected from `.markdownlint-cli2.jsonc` but never
|
|
860
|
+
installed `markdownlint-cli2` passed for every developer holding a cached copy
|
|
861
|
+
and failed on the clean checkout — which is the CI runner, the most expensive
|
|
862
|
+
place to find out. The tool is now looked up at `node_modules/.bin/<tool>`,
|
|
863
|
+
searched from the check's directory upward so a workspace tool hoisted to the
|
|
864
|
+
repo root still counts, and a slot whose tool is absent fails there with a
|
|
865
|
+
message naming the slot, the path searched, and the PM's own install command
|
|
866
|
+
instead of the launcher's `npx canceled due to missing packages`. **Behavior
|
|
867
|
+
change:** a slot passing only because of a cached tool now fails until that
|
|
868
|
+
tool is a declared dependency — the same trade 0.9.3 made, applied to the
|
|
869
|
+
fallback it left open, and it fails on the developer's machine rather than
|
|
870
|
+
only in CI. Scoped to the two launchers that keep such a cache: `pnpm exec`
|
|
871
|
+
and `yarn` resolve from the project tree already and are not pre-flighted,
|
|
872
|
+
which also leaves Yarn PnP — where no `node_modules/.bin` exists to find —
|
|
873
|
+
working as before. See `docs/contract.md` §Vacuous green and `docs/tools.md`
|
|
874
|
+
§Package managers.
|
|
875
|
+
|
|
876
|
+
### Fixed
|
|
877
|
+
|
|
878
|
+
- **`doctor` told npm, yarn and bun repos to run `pnpm install`.** The
|
|
879
|
+
remediation hint on a missing-tool row was a hardcoded string, so the one
|
|
880
|
+
actionable line on a red row named a package manager the repo does not use —
|
|
881
|
+
while `checkInstall` two functions above it had been PM-aware all along. It
|
|
882
|
+
now names the detected manager and the exact dev-dependency install.
|
|
883
|
+
- **`doctor` reported a hoisted workspace tool as missing.** The probe tested
|
|
884
|
+
`<cwd>/node_modules/.bin/<tool>` and nothing above it, but pnpm and npm both
|
|
885
|
+
hoist a shared tool's bin to the workspace root — so a correctly installed
|
|
886
|
+
monorepo showed a false `missing` for every tool from any package
|
|
887
|
+
subdirectory, on exactly the repos the workspace presets generate. It now
|
|
888
|
+
walks upward like the package managers do, sharing one resolver with the run
|
|
889
|
+
path so the two cannot disagree about where a tool lives.
|
|
890
|
+
|
|
891
|
+
## [0.9.4] - 2026-07-30
|
|
892
|
+
|
|
893
|
+
### Fixed
|
|
894
|
+
|
|
895
|
+
- **Member-scoped fallow findings now key on `<container>.<leaf>` instead of a
|
|
896
|
+
line and column.** fallow reports an unused class/enum/store member as
|
|
897
|
+
`parent_name` + `member_name`, a component binding as `component_name` +
|
|
898
|
+
`prop_name`/`input_name`/`output_name`/`emit_name`/`event_name`, and a catalog
|
|
899
|
+
entry as `catalog_name` + `entry_name` — none of which the extractor
|
|
900
|
+
recognized, so every such finding fell through to the `<path>:<line>:<col>`
|
|
901
|
+
fallback. That key moves whenever code above it does, so editing anything
|
|
902
|
+
earlier in a file re-keyed its grandfathered members and re-surfaced them as
|
|
903
|
+
new findings. They are now line-free
|
|
904
|
+
(`dead-code:unused_class_members:src/a.ts:Svc.unusedOne`) and survive the edit,
|
|
905
|
+
as every other category already did. The same pass gave the report's remaining
|
|
906
|
+
`*_name` categories a stable identity too, so they key on a symbol rather than
|
|
907
|
+
a position as well. **This changes the `dead` slot's fingerprints — re-run
|
|
908
|
+
`checkride baseline` to re-capture, or those findings will report as new
|
|
909
|
+
once.**
|
|
910
|
+
- **Report arrays that fallow does not count are no longer fingerprinted.**
|
|
911
|
+
`workspace_diagnostics` carries a `path`, and the opt-in `thin_wrappers` and
|
|
912
|
+
`duplicate_prop_shapes` rules a `file`, so all three produced keys while
|
|
913
|
+
fallow's issue registry marks them `counts_in_total: false`. The extra keys
|
|
914
|
+
pushed the key count past the issue count, where the un-keyable-findings guard
|
|
915
|
+
clamped the difference to zero — so a spurious key could offset a finding that
|
|
916
|
+
genuinely had no stable identity, and the baseline masked a slot green that it
|
|
917
|
+
had never grandfathered. The guard now counts un-keyable findings directly
|
|
918
|
+
rather than inferring them from the totals, which closes that offset even if a
|
|
919
|
+
future fallow adds an uncounted array this version does not know to skip.
|
|
920
|
+
|
|
921
|
+
## [0.9.3] - 2026-07-29
|
|
922
|
+
|
|
923
|
+
### Contract
|
|
924
|
+
|
|
925
|
+
- **An empty slot selection is now a usage error.** `--only`, `--skip` or
|
|
926
|
+
`--include` given a value that names nothing after trimming (`--only ,`,
|
|
927
|
+
`--only ''`, `--only ' '`) exits **2**, naming the flag. It previously
|
|
928
|
+
parsed to an empty list, which is truthy, so `--only ,` filtered every check
|
|
929
|
+
out and exited **0** having verified nothing — the same vacuous green that
|
|
930
|
+
`--only lints` was fixed for in 0.5.0, reached by a different route. The two
|
|
931
|
+
empty spellings also disagreed: `--only ''` ran the whole pipeline. The rule
|
|
932
|
+
now holds for a programmatic caller too — `runChecks({ only: [] })` throws
|
|
933
|
+
rather than selecting nothing. See `docs/contract.md` §CLI and §Exit codes.
|
|
934
|
+
- **`summary.json`'s published schema described `total_duration_ms` as a sum.**
|
|
935
|
+
It is, and has been since concurrency landed, the **wall-clock** span of the
|
|
936
|
+
run; the two diverge whenever checks overlap. No behavior changed — the
|
|
937
|
+
description in `schema/checkride.summary.schema.json` was simply wrong, and a
|
|
938
|
+
consumer implementing against it would derive the wrong run-start
|
|
939
|
+
(`timestamp - total_duration_ms`) and read stale artifacts as fresh. The
|
|
940
|
+
semantics are now pinned by a test, not just prose. See `docs/contract.md`
|
|
941
|
+
§`.check/summary.json`.
|
|
942
|
+
|
|
943
|
+
### Fixed
|
|
944
|
+
|
|
945
|
+
- **Tools are no longer installed from the registry mid-run under npm or bun.**
|
|
946
|
+
The exec translation emitted a bare `npx <tool>` / `bunx <tool>`, and both
|
|
947
|
+
launchers fetch a missing package and run it rather than failing — checks are
|
|
948
|
+
spawned without a TTY, which is precisely the non-interactive case where
|
|
949
|
+
neither stops to prompt. A repo missing a tool could therefore have its gate
|
|
950
|
+
silently execute an unpinned `latest`. Both now carry `--no-install`, which
|
|
951
|
+
bounds the download but not the launcher's global cache — the guarantee is
|
|
952
|
+
"nothing new is fetched mid-run". **Behavior change:** a tool that would have
|
|
953
|
+
to be downloaded now fails its slot. `pnpm exec` and `yarn` have no such cache
|
|
954
|
+
path and are unchanged.
|
|
955
|
+
- **The triage reader's gate timeout could not reap what it started.** It
|
|
956
|
+
spawned without `detached` and sent a bare `SIGTERM` with no escalation, so
|
|
957
|
+
the signal reached the package-manager wrapper and left the checks themselves
|
|
958
|
+
running — which also meant `close` could wait on their inherited pipes
|
|
959
|
+
forever, hanging the reader the timeout existed to protect. It now leads its
|
|
960
|
+
own process group and escalates to `SIGKILL`, the same discipline the
|
|
961
|
+
orchestrator already applied; both share the new `killGroup` helper.
|
|
962
|
+
- **`.check/` artifacts are now flushed before the rename that publishes them.**
|
|
963
|
+
The atomic write promised each file was "either the previous complete version
|
|
964
|
+
or the new complete version", but without an `fsync` a crash could leave the
|
|
965
|
+
renamed inode holding nothing — the torn read it exists to prevent, relocated.
|
|
966
|
+
- **A committed baseline whose `slots` is an array is rejected instead of being
|
|
967
|
+
keyed by index.** Two of the four copies of the `isRecord` guard accepted
|
|
968
|
+
arrays (`typeof [] === 'object'`); the baseline read was one of them, so such
|
|
969
|
+
a file loaded cleanly and masked nothing. All four now share one definition.
|
|
970
|
+
- **A baseline from a newer schema version is dropped rather than half-read.**
|
|
971
|
+
`schema_version` was recorded and never checked. Dropping it fails closed: the
|
|
972
|
+
run reports the diagnostics that are really there, where guessing risks
|
|
973
|
+
masking findings the author never grandfathered.
|
|
974
|
+
- **AGENTS.md described a tree the repo does not have.** It named four folder
|
|
975
|
+
modules where there are seven (`artifacts/`, `qa/` and `triage/` were
|
|
976
|
+
missing), and stated a test-placement rule — colocate beside the source file —
|
|
977
|
+
that no test in the repo has ever followed. Both are corrected, and both are
|
|
978
|
+
now checked against the tree.
|
|
979
|
+
- **Report columns no longer break on long check names.** Fixed widths were
|
|
980
|
+
sized for catalogue slots, so a config custom check (`typecheck-tests`, or
|
|
981
|
+
`custom:typecheck-tests` in the adapter column) shunted every later column
|
|
982
|
+
right on its own row. `doctor` and the run status lines now size each column
|
|
983
|
+
to the rows it holds.
|
|
984
|
+
|
|
985
|
+
### Internal
|
|
986
|
+
|
|
987
|
+
- **This repo's own gate now runs the `security` slot.** `pnpm audit` takes well
|
|
988
|
+
under a second and reports zero advisories at every level, and a package that
|
|
989
|
+
publishes to npm with provenance should be auditing its own dependency tree as
|
|
990
|
+
part of "done" rather than out of band. Note the trade-off: the gate now needs
|
|
991
|
+
the registry to be reachable, and a failure to *verify* is a failure, not a
|
|
992
|
+
pass — so a network outage turns the run red rather than quietly skipping the
|
|
993
|
+
check.
|
|
994
|
+
- **The stryker break threshold moves 55 → 68.** The measured score is 73.2%
|
|
995
|
+
(up from 71.7%), so the old gate sat 18 points below reality and could not
|
|
996
|
+
have failed on anything short of deleting a suite. It now sits ~5 points
|
|
997
|
+
under — enough headroom that a mutant timing out on a loaded machine does not
|
|
998
|
+
turn the run red, which is the only reason not to set it tighter. The two
|
|
999
|
+
bundled-plugin bins are excluded from the mutate set: they are three lines
|
|
1000
|
+
each, do their work at module top level, and are unreachable from the unit
|
|
1001
|
+
runner stryker drives, so they reported a permanent 0% no test could move.
|
|
1002
|
+
They are covered as processes by `test/e2e/plugin-readers.e2e.test.ts`.
|
|
1003
|
+
- Tests for the last uncovered code in the package. The two bundled-plugin
|
|
1004
|
+
entry points (`dist/triage/cli.js`, `dist/qa/cli.js`) are exercised as
|
|
1005
|
+
processes, which is the only way to reach a bin that works at module top
|
|
1006
|
+
level; `checkride fix` gained CLI-dispatch coverage it never had; and the
|
|
1007
|
+
three `qa/` extractors gained tests for their truncation caps and
|
|
1008
|
+
malformed-input fallbacks — the bounded-reader behavior those modules exist
|
|
1009
|
+
for. Branch coverage 84.3% → 85.5%.
|
|
1010
|
+
- New guards for the claims that drifted: `test/conventions.test.ts` checks
|
|
1011
|
+
AGENTS.md's folder-module list and test placement against the tree, and the
|
|
1012
|
+
summary contract suite now pins `total_duration_ms` behaviorally — wall-clock
|
|
1013
|
+
under concurrency, equal to the summed durations when sequential. Both fail
|
|
1014
|
+
when reverted, which is the point.
|
|
1015
|
+
- `test/e2e/defaults.e2e.test.ts` resolves a fixture repo that has the tool
|
|
1016
|
+
configs but **no `checkride.config.json`**, so the shipped catalogue and the
|
|
1017
|
+
detection path are exercised. This repo's own config names all twenty slots,
|
|
1018
|
+
which is deliberate but meant daily runs never walked a consumer's path.
|
|
1019
|
+
- First tests for `src/triage/env.ts`, previously the only module in the package
|
|
1020
|
+
with no coverage at all.
|
|
1021
|
+
- Two new single-file modules: `src/proc.ts` (process-group kill and escalation,
|
|
1022
|
+
shared by both spawners) and `src/json.ts` (the one `isRecord`).
|
|
1023
|
+
- Long-form rationale moved out of source comments and into the docs that own
|
|
1024
|
+
it: the pnpm stdout-narration investigation to `docs/tools.md` §Launcher
|
|
1025
|
+
quirks, and the freshness-window derivation to `docs/plugin.md`. The comments
|
|
1026
|
+
keep the "why" and point at the rest.
|
|
1027
|
+
|
|
1028
|
+
## [0.9.2] - 2026-07-28
|
|
1029
|
+
|
|
1030
|
+
### Changed
|
|
1031
|
+
|
|
1032
|
+
- **`checkride init` now writes a newer toolchain into generated projects.**
|
|
1033
|
+
The pinned versions a new project receives move to oxlint 1.74.0 (with
|
|
1034
|
+
oxlint-tsgolint 0.25.0), fallow 3.9.1, ast-grep 0.45.0, vitest 4.1.10,
|
|
1035
|
+
markdownlint-cli2 0.23.1, cspell 10.0.1, prettier 3.9.6, biome 2.5.6, jest
|
|
1036
|
+
30.4.2, publint 0.3.22, attw 0.18.5, and `@types/node` 22.20.1. A freshly
|
|
1037
|
+
generated project still installs and passes green out of the box. TypeScript
|
|
1038
|
+
stays at 6.0.3, and the eslint and knip pins stay on their current majors —
|
|
1039
|
+
all three are deliberate holds, now marked as such in the adapter registry.
|
|
1040
|
+
- **The documented fallow pin is 3.9.1.** The supported floor is unchanged:
|
|
1041
|
+
fallow ≥ 3.5, JSON `schema_version` 7. Every release from 3.5.0 through 3.9.1
|
|
1042
|
+
emits schema 7 with identical report layouts, so an existing baseline keeps
|
|
1043
|
+
masking and no consumer has to move.
|
|
1044
|
+
|
|
1045
|
+
### Fixed
|
|
1046
|
+
|
|
1047
|
+
- **The bundled `check` skill quoted a markdownlint summary line that no longer
|
|
1048
|
+
exists.** Its guidance on reading a failing `docs` slot cited
|
|
1049
|
+
`Summary: 1 error(s)`; markdownlint-cli2 0.23 emits `Summary: 1 issue in 1
|
|
1050
|
+
file`. The surrounding advice was still right — that tool puts the count on
|
|
1051
|
+
stdout and the `file:line:rule` you actually need on stderr — but the quoted
|
|
1052
|
+
string sent agents looking for text no run produces.
|
|
1053
|
+
|
|
1054
|
+
### Internal
|
|
1055
|
+
|
|
1056
|
+
- Development dependencies upgraded across the board, in separate verified
|
|
1057
|
+
steps: fallow's report schema and layouts confirmed unchanged, ast-grep's
|
|
1058
|
+
rules confirmed to still fire (repo *and* shipped template copies), and
|
|
1059
|
+
oxlint's diagnostic text confirmed byte-identical for the baseline fixtures
|
|
1060
|
+
it fingerprints.
|
|
1061
|
+
- Nine new oxlint errors from the 1.61 → 1.74 jump were fixed at the root
|
|
1062
|
+
rather than suppressed: two genuinely unnecessary type assertions, and seven
|
|
1063
|
+
test helpers hoisted out of the scopes they never captured.
|
|
1064
|
+
- `pnpm audit` is clean again. The `brace-expansion` override had gone stale as
|
|
1065
|
+
its advisory widened, `fast-uri`, `postcss`, and a js-yaml 5.x entry were
|
|
1066
|
+
added, and the `markdown-it` and js-yaml 4.x overrides were retired as
|
|
1067
|
+
redundant — each verified by removal and re-audit, not by inspection.
|
|
1068
|
+
- Every GitHub Actions ref is now SHA-pinned with a version comment. `ci.yml`
|
|
1069
|
+
alone had floated on mutable major tags, which made the workflow gating every
|
|
1070
|
+
merge the one an upstream tag move could reach. CI's pnpm moves to 11.17.0,
|
|
1071
|
+
verified to accept the committed lockfile unmodified.
|
|
1072
|
+
|
|
1073
|
+
## [0.9.1] - 2026-07-28
|
|
1074
|
+
|
|
1075
|
+
### Fixed
|
|
1076
|
+
|
|
1077
|
+
- **The `links` check no longer flags example links inside code blocks.** A
|
|
1078
|
+
`[text](target)` shown inside a fenced block or inline backticks was resolved
|
|
1079
|
+
against disk like any real link, so documentation that demonstrates Markdown
|
|
1080
|
+
syntax could only pass by enumerating every example target in
|
|
1081
|
+
`checks.links.allowlist`. Fence state is now tracked across the file —
|
|
1082
|
+
honoring CommonMark on marker length, tilde fences, and info strings — and
|
|
1083
|
+
inline code spans are masked before parsing. Two limits are deliberate and
|
|
1084
|
+
tested: 4-space indented blocks are still checked, since indentation is
|
|
1085
|
+
ambiguous with list continuation, and code spans straddling a newline stay
|
|
1086
|
+
unmatched. The check only became less strict, so a repo passing on 0.9.0
|
|
1087
|
+
still passes.
|
|
1088
|
+
|
|
1089
|
+
## [0.9.0] - 2026-07-28
|
|
1090
|
+
|
|
1091
|
+
### Added
|
|
1092
|
+
|
|
1093
|
+
- **A PreToolUse deny hook guards checkride's accounting files.** "Never add
|
|
1094
|
+
to the baseline to make a check pass" was README advice that an agent
|
|
1095
|
+
editing the file has every local incentive to ignore; it is now
|
|
1096
|
+
enforcement. Edits (Edit/Write/NotebookEdit) to `checkride.baseline.json`
|
|
1097
|
+
and `.check/**` are blocked with a message explaining the ratchet; reads
|
|
1098
|
+
are never denied — the stanza's own triage procedure and both plugin
|
|
1099
|
+
skills read `.check/` artifacts. Both paths are unambiguous, so the deny
|
|
1100
|
+
is exact; module-boundary rules deliberately stay in ast-grep, where they
|
|
1101
|
+
are enforced over parsed code rather than approximated by paths.
|
|
1102
|
+
- **The gate now skips turns that edited nothing.** A new PostToolUse hook
|
|
1103
|
+
(`dirty`) touches `.check/.dirty` on every Edit/Write/NotebookEdit; the gate
|
|
1104
|
+
script exits 0 immediately when the marker is absent and clears it after a
|
|
1105
|
+
green run. Stop fires at the end of *every* turn, including
|
|
1106
|
+
pure-conversation ones — on a real repo that was a multi-second pipeline
|
|
1107
|
+
tax (plus formatter writes) for a turn that changed nothing, the single
|
|
1108
|
+
best reason to disable the gate. File writes made through Bash don't set
|
|
1109
|
+
the marker (a known, accepted gap — matching Bash would fire on every
|
|
1110
|
+
command); the next tool-edited turn re-covers it. A `--hook gate`
|
|
1111
|
+
selection without `dirty` writes an unconditional script, so the guard can
|
|
1112
|
+
never disarm a gate that has no marker source.
|
|
1113
|
+
- **The generated gate runs `--strict --digest`.** The Stop hook is a gate,
|
|
1114
|
+
and the contract says anything that gates should pass `--strict` — now
|
|
1115
|
+
checkride's own generated hook does. `--digest` writes the token-bounded
|
|
1116
|
+
`.check/digest.md` on red, and the guidance message points there when it
|
|
1117
|
+
exists (summary.json otherwise) and names `/checkride:check` for full
|
|
1118
|
+
triage. npm repos get the `--` passthrough form; pnpm/yarn/bun forward
|
|
1119
|
+
flags directly.
|
|
1120
|
+
|
|
1121
|
+
### Changed
|
|
1122
|
+
|
|
1123
|
+
- **The Stop-hook gate moved into a checkride-owned script,
|
|
1124
|
+
`.claude/hooks/checkride-gate.sh`.** The settings.json entry is now a stable
|
|
1125
|
+
one-liner invoking it (`sh "${CLAUDE_PROJECT_DIR:-.}/…"`), so refreshing is
|
|
1126
|
+
genuinely lossless: checkride overwrites its script freely, and consumer
|
|
1127
|
+
customization has a natural home (a sibling script, or the environment)
|
|
1128
|
+
instead of an inline command the next `agent-setup` would clobber. Repos
|
|
1129
|
+
carrying the old inline form are migrated in place on the next
|
|
1130
|
+
`agent-setup`/`init` — detected by the existing sentinel and replaced, never
|
|
1131
|
+
duplicated. `init`/`agent-setup` grow `--hook <a,b>` to select which hooks
|
|
1132
|
+
to write (default: all); `--no-hook` remains the write-none escape.
|
|
1133
|
+
|
|
1134
|
+
### Fixed
|
|
1135
|
+
|
|
1136
|
+
- **The `security` slot now gates at `--audit-level`, not at any advisory.**
|
|
1137
|
+
pnpm's JSON mode exits 1 on *any* advisory regardless of `--audit-level`
|
|
1138
|
+
(only table mode lets the level gate the exit code — reproduced with a
|
|
1139
|
+
single-moderate lockfile: `--json` exits 1, table exits 0), so the slot
|
|
1140
|
+
judged by exit code effectively gated at zero advisories of any severity
|
|
1141
|
+
rather than the declared `high`. `security` is now a built-in evaluator: it
|
|
1142
|
+
runs the audit with `--json`, parses `metadata.vulnerabilities`, and fails
|
|
1143
|
+
only on advisories at or above the threshold parsed from the adapter's own
|
|
1144
|
+
`--audit-level` arg — so a consumer override keeps meaning what it says,
|
|
1145
|
+
and "audit could not run" (registry unreachable, malformed output) stays a
|
|
1146
|
+
failure rather than a silent pass. Consumers who dropped `--json` to work
|
|
1147
|
+
around this can return to the default args and get the
|
|
1148
|
+
`.check/security.json` artifact back (`--json` is appended if an override
|
|
1149
|
+
omits it).
|
|
1150
|
+
- **`pack` no longer fails hard under pnpm older than 10.26.** pnpm only
|
|
1151
|
+
learned `pack --dry-run` in 10.26.0; every earlier pnpm — including 10.18.x
|
|
1152
|
+
lines consumers actually pin — rejects the flag with
|
|
1153
|
+
`Unknown option: 'dry-run'`, and the slot failed on a manager checkride
|
|
1154
|
+
has promised since 0.5.0 (reported by a real consumer on 10.18.1). On that
|
|
1155
|
+
rejection checkride now falls back to a real pack into a temp destination
|
|
1156
|
+
outside the repo (`pnpm pack --json --pack-destination <tmp>` — same
|
|
1157
|
+
npm-shaped `files[].path` JSON, verified back to 10.18.1), with lifecycle
|
|
1158
|
+
scripts suppressed the same way, and deletes the tarball afterward whether
|
|
1159
|
+
the check passes or not. Capability fallback, not version sniffing, so it
|
|
1160
|
+
keeps working wherever the flag is missing.
|
|
1161
|
+
- **The default concurrency no longer collapses to 1 on a 2-core CI runner.**
|
|
1162
|
+
`defaultConcurrency` reserved a core to keep the machine responsive — sound
|
|
1163
|
+
on a laptop, inapplicable on a hosted runner with no human at it. A
|
|
1164
|
+
standard GitHub-hosted runner reports 2 CPUs, so the pool was 1 and a
|
|
1165
|
+
wave-scheduled config executed fully sequentially (measured on a real
|
|
1166
|
+
consumer: 27.4s wall against 27.4s of summed check time — 1.00x), on
|
|
1167
|
+
exactly the machine class the docs say to gate on. With `CI` set (every
|
|
1168
|
+
provider sets it) no core is reserved, so that runner now gets a pool of 2.
|
|
1169
|
+
The cap of 4, the `--concurrency` override, and `--bail`'s sequential
|
|
1170
|
+
behavior are unchanged. How much a 2-wide pool on 2 cores buys depends on
|
|
1171
|
+
the mix: checks dominated by process startup and file discovery overlap
|
|
1172
|
+
well; two CPU-bound tools may be closer to a wash. It is never slower than
|
|
1173
|
+
the serialized pool it replaces, and `order` waves now schedule as
|
|
1174
|
+
documented. docs/ci.md explains the runner-size effect and how to read
|
|
1175
|
+
`total_duration_ms` against the per-check sum.
|
|
1176
|
+
- **The AGENTS.md stanza reports the configured gate, not the detected one.**
|
|
1177
|
+
`init` and `agent-setup` derived the stanza's "Active checks in this repo"
|
|
1178
|
+
line from the adoption inventory, which has detection semantics and never
|
|
1179
|
+
reads `checkride.config.json` — so opt-in slots a config entry opts in
|
|
1180
|
+
(`format`, `build`, …) and non-catalogue custom checks were silently missing
|
|
1181
|
+
from the agent-facing contract while the gate ran them. The stanza now
|
|
1182
|
+
derives from the same selection a default run makes (the pattern `doctor`
|
|
1183
|
+
already used), so what it names and what `pnpm check` runs agree.
|
|
1184
|
+
|
|
1185
|
+
### Internal
|
|
1186
|
+
|
|
1187
|
+
- The design record for this release is
|
|
1188
|
+
[docs/spec-agent-setup-upgrade.md](./docs/spec-agent-setup-upgrade.md): two
|
|
1189
|
+
consumers' reports validated against source, with the measured pnpm version
|
|
1190
|
+
boundaries. docs/getting-started.md's hard-gate section was rewritten for
|
|
1191
|
+
the three-hook suite.
|
|
1192
|
+
|
|
1193
|
+
## [0.8.1] - 2026-07-28
|
|
1194
|
+
|
|
1195
|
+
### Fixed
|
|
1196
|
+
|
|
1197
|
+
- **A package-manager banner on stdout no longer fails the JSON-reading slots.**
|
|
1198
|
+
pnpm verifies dependencies before `exec`/`run` and narrates it on **stdout**
|
|
1199
|
+
(`Already up to date`, `Done in Xms using pnpm vN`) whenever no outer pnpm
|
|
1200
|
+
process has already done so. That preamble landed ahead of the tool's own
|
|
1201
|
+
JSON, so `checkride` invoked directly — `node dist/cli.js`, which is what the
|
|
1202
|
+
bundled triage reader and any non-pnpm-wrapped call does — failed `dead`,
|
|
1203
|
+
`dupes` and `health` with "fallow did not emit valid JSON" while the tools
|
|
1204
|
+
themselves exited 0, and silently cost `lint`, `struct` and `attw` their JSON
|
|
1205
|
+
artifacts. The same gate under `pnpm run check` passed, which is what made it
|
|
1206
|
+
hard to see. Fixed at both ends: checkride now passes
|
|
1207
|
+
`--config.verify-deps-before-run=false` ahead of `exec`/`run` under pnpm (the
|
|
1208
|
+
only form that works — `--silent` does not suppress it, and after `exec` pnpm
|
|
1209
|
+
reads it as the tool's argument), and every stdout-JSON parse tolerates up to
|
|
1210
|
+
ten leading non-JSON lines, because a consumer's launcher is not checkride's
|
|
1211
|
+
to pin. The `<slot>.json` artifact is written from the first JSON character
|
|
1212
|
+
on, so it parses on its own; nothing inside the tool's output is altered.
|
|
1213
|
+
- **`summary.json`'s `output_file` no longer names files that were never
|
|
1214
|
+
written.** It was copied from the adapter's declaration, so any run where a
|
|
1215
|
+
JSON-declaring tool emitted something else — a warning first, a crash, or the
|
|
1216
|
+
banner above — left the summary pointing at a `<slot>.json` that did not
|
|
1217
|
+
exist while the real bytes sat in `<slot>.stdout.txt` beside it. It is now
|
|
1218
|
+
what the run actually wrote, and `null` when that is nothing (including for a
|
|
1219
|
+
skipped check, which writes nothing at all). This is the field's documented
|
|
1220
|
+
meaning; see [docs/contract.md](./docs/contract.md).
|
|
1221
|
+
|
|
1222
|
+
## [0.8.0] - 2026-07-28
|
|
1223
|
+
|
|
1224
|
+
### Added
|
|
1225
|
+
|
|
1226
|
+
- **A bundled Claude Code plugin, shipped from the package root.** The published
|
|
1227
|
+
package now carries `.claude-plugin/plugin.json` and a `skills/` directory, so
|
|
1228
|
+
`checkride` installs as a plugin from the same npm tarball you already depend
|
|
1229
|
+
on (`/plugin marketplace add robmclarty/agent-tools`, then
|
|
1230
|
+
`/plugin install checkride@robmclarty`). It is bundled rather than published
|
|
1231
|
+
separately so the readers version in lockstep with the `.check/` contract they
|
|
1232
|
+
parse; a test asserts the manifest's version equals `package.json`'s. Nothing
|
|
1233
|
+
about the CLI, the exit codes or the `.check/` contract changes, installed or
|
|
1234
|
+
not. See [docs/plugin.md](./docs/plugin.md).
|
|
1235
|
+
- **`/checkride:check` — triage a red gate.** Runs the repo's own `check` script
|
|
1236
|
+
(the definition of done, which may carry deliberate `--only`/`--skip`), branches
|
|
1237
|
+
on the promised 0/1/2 exit split, and names one root cause plus what it is
|
|
1238
|
+
deliberately not reading. It covers the contract corners a hand-read of
|
|
1239
|
+
`summary.json` gets wrong — exit 2 versus exit 1, vacuous green, a narrow run's
|
|
1240
|
+
green, `baselined` counts, `skipped` slots, `exit_code: -1`, an unexpected
|
|
1241
|
+
`schema_version`, stale artifacts, and a red gate whose compound `check` script
|
|
1242
|
+
died before checkride ran — then opens exactly one raw file. Artifacts are
|
|
1243
|
+
measured, never opened: a green 17-slot run renders in about 2 kB.
|
|
1244
|
+
- **`/checkride:qa` — read the quality signal.** Folds `mutation.json`,
|
|
1245
|
+
`dead.json`, `dupes.json` and `health.json` into a report under 8 kB (2.2 MB of
|
|
1246
|
+
mutation data becomes a ranked page), runs nothing at all, and opens with a
|
|
1247
|
+
present / stale / not-opted-in ledger naming the command or config entry that
|
|
1248
|
+
would produce each missing artifact — three of the four come from opt-in slots,
|
|
1249
|
+
so partial data is the normal case.
|
|
1250
|
+
- **Two dependency-free readers behind those skills**, shipped prebuilt in
|
|
1251
|
+
`dist/` so a plugin install needs no build step, and runnable without Claude
|
|
1252
|
+
Code: `node node_modules/checkride/dist/triage/cli.js` and
|
|
1253
|
+
`node node_modules/checkride/dist/qa/cli.js`, each taking an optional repo
|
|
1254
|
+
path. Both use `node:` builtins only. Every artifact read is bounded, dated
|
|
1255
|
+
against the run that claims it (an artifact older than the run's start is
|
|
1256
|
+
labelled stale with its age, never silently dropped), and resolved by the
|
|
1257
|
+
documented `output_file` → `<slot>.json` → `<slot>.stdout.txt`/`.stderr.txt`
|
|
1258
|
+
convention, which matters because `output_file` is null for 8 of this repo's
|
|
1259
|
+
17 slots — `test` among them.
|
|
1260
|
+
- **`examples/` — eight runnable projects, each demonstrating one thing.** They
|
|
1261
|
+
are standalone packages rather than workspace members, so you `cd` in, install,
|
|
1262
|
+
and run one without the rest of the repo: `agent-loop` (what an agent reads
|
|
1263
|
+
when the gate is red), `existing-repo-baseline` (adopting checkride on a repo
|
|
1264
|
+
that already has findings), `custom-checks` (the escape hatch — a bespoke
|
|
1265
|
+
formatter ahead of the built-ins, `detect`-gated checks that stand down),
|
|
1266
|
+
`shared-preset` (org-wide policy as one versioned package), `polyglot` (a
|
|
1267
|
+
Python repo where the TypeScript built-ins stand down and ast-grep enforces
|
|
1268
|
+
boundaries in Python), and `module-boundaries` / `dal-boundaries` /
|
|
1269
|
+
`dal-boundaries-declarative` for boundary enforcement — the last expressing a
|
|
1270
|
+
data-access policy with fallow zones and ast-grep rules alone, no custom script.
|
|
1271
|
+
Each declares the exit code it expects and `test/e2e/examples.e2e.test.ts`
|
|
1272
|
+
asserts it on every push, so an example that stops behaving as its README
|
|
1273
|
+
claims fails CI.
|
|
1274
|
+
|
|
1275
|
+
### Changed
|
|
1276
|
+
|
|
1277
|
+
- **The AGENTS.md stanza written by `checkride init` and `checkride agent-setup`
|
|
1278
|
+
names `/checkride:check`.** Exactly one added line; the prose procedure is
|
|
1279
|
+
unchanged and still works standalone in a repo that never installs the plugin.
|
|
1280
|
+
|
|
1281
|
+
### Internal
|
|
1282
|
+
|
|
1283
|
+
- `/version` now folds an existing `## [Unreleased]` changelog section into the
|
|
1284
|
+
new release heading instead of inserting above it.
|
|
1285
|
+
|
|
1286
|
+
## [0.7.0] - 2026-07-22
|
|
1287
|
+
|
|
1288
|
+
### Changed
|
|
1289
|
+
|
|
1290
|
+
- **checkride is now licensed [Apache-2.0](./LICENSE), previously MIT.** No code
|
|
1291
|
+
or API changed; the terms you receive it under did. Apache-2.0 adds an express
|
|
1292
|
+
patent grant and, via section 5, makes contributions inbound under the same
|
|
1293
|
+
license without a CLA — the reason for the switch, ahead of accepting outside
|
|
1294
|
+
contributions. Consumers redistributing checkride should note the section 4
|
|
1295
|
+
conditions (include the license, mark modified files); there is deliberately
|
|
1296
|
+
no `NOTICE` file, so nothing to propagate. `checkride init --license` still
|
|
1297
|
+
defaults to `MIT` for scaffolded projects — that remains the user's choice and
|
|
1298
|
+
is unaffected.
|
|
1299
|
+
|
|
1300
|
+
### Internal
|
|
1301
|
+
|
|
1302
|
+
- `CONTRIBUTING.md` gains a licensing section: how section 5 works, why an
|
|
1303
|
+
employer may own contributions written on their time, and DCO sign-off via
|
|
1304
|
+
`git commit -s`.
|
|
1305
|
+
|
|
1306
|
+
## [0.6.0] - 2026-07-21
|
|
1307
|
+
|
|
1308
|
+
### Added
|
|
1309
|
+
|
|
1310
|
+
- **`optIn` override to configure a slot without opting it into the default
|
|
1311
|
+
run.** A slot entry (both the `{ use }` and custom `{ command }` forms) now
|
|
1312
|
+
takes `optIn?: boolean`: `true` configures the slot but keeps it reachable
|
|
1313
|
+
only via `--all`/`--include` (so giving `attw` a profile no longer drags
|
|
1314
|
+
`attw`/`build`/`pack`/`smoke` into a plain `checkride` run), and `false`
|
|
1315
|
+
forces a slot into the default run. Resolution-side only, so selection, the
|
|
1316
|
+
vacuous-green warning, and `doctor` all adjust automatically.
|
|
1317
|
+
- **Config-driven `exclude` and `allowlist` for the built-in `links` check.**
|
|
1318
|
+
`exclude` adds directory names to skip on top of the built-in set, and
|
|
1319
|
+
`allowlist` takes regex sources whose matching link targets count as valid
|
|
1320
|
+
(for generated or illustrative markdown that never resolves on disk).
|
|
1321
|
+
Patterns are compiled and validated at config load, so a bad one is a
|
|
1322
|
+
friendly exit-2 error rather than a mid-run crash. Both are declared in the
|
|
1323
|
+
JSON schema.
|
|
1324
|
+
- **`profile` shortcut for the `attw` slot.** A `profile` string on the config
|
|
1325
|
+
entry appends `--profile <name>` to attw's invocation instead of re-typing
|
|
1326
|
+
the full args array (a no-op on other slots; a non-string is a friendly
|
|
1327
|
+
config error).
|
|
1328
|
+
|
|
1329
|
+
### Changed
|
|
1330
|
+
|
|
1331
|
+
- **`publint` and `attw` stand down when their tool isn't installed.** Both
|
|
1332
|
+
were always-available and hard-failed an `--all` run with "Command not found"
|
|
1333
|
+
on a repo that never installed them; they now gate on their package
|
|
1334
|
+
(`publint`, `@arethetypeswrong/cli`) and skip cleanly when absent, matching
|
|
1335
|
+
checkride's skip-not-fail principle for opt-in slots. Naming one explicitly
|
|
1336
|
+
in config still forces it to run.
|
|
1337
|
+
|
|
1338
|
+
### Fixed
|
|
1339
|
+
|
|
1340
|
+
- **A single duplicate fingerprint no longer disables baselining for a whole
|
|
1341
|
+
fallow slot.** The baseline gate guarded against un-fingerprintable findings by
|
|
1342
|
+
comparing the deduplicated key count to the raw issue count, but that
|
|
1343
|
+
comparison could not tell a finding that produced *no* key apart from two
|
|
1344
|
+
findings that produced the *same* key. One key collision (two `<arrow>`
|
|
1345
|
+
functions in a file, or two symbol-less `unused_class_members`) made the slot
|
|
1346
|
+
look untracked, so `checkride baseline` followed by `checkride` stayed red
|
|
1347
|
+
forever. The gate now tracks an explicit un-keyed count instead, so a collision
|
|
1348
|
+
merely coarsens the baseline (grandfathering one finding grandfathers its twin)
|
|
1349
|
+
rather than disabling it, while a genuinely un-keyable finding still holds the
|
|
1350
|
+
slot red.
|
|
1351
|
+
- **Colliding fallow fingerprints are now disambiguated.** Anonymous health
|
|
1352
|
+
functions (`<arrow>`, `<anonymous>`) and symbol-less dead-code findings
|
|
1353
|
+
(`unused_class_members`) append their line and column, so a real sibling
|
|
1354
|
+
finding can no longer be masked by a baseline captured for a different one.
|
|
1355
|
+
Named functions and symbol-bearing findings keep their line-free keys.
|
|
1356
|
+
|
|
1357
|
+
This changes the fingerprint strings for the `dead` and `health` slots, which
|
|
1358
|
+
**invalidates existing `checkride.baseline.json` entries for those slots**.
|
|
1359
|
+
Re-run `checkride baseline` to recapture them.
|
|
1360
|
+
|
|
1361
|
+
### Internal
|
|
1362
|
+
|
|
1363
|
+
- **Cleared all `pnpm audit` advisories** via `pnpm-workspace.yaml` overrides:
|
|
1364
|
+
`brace-expansion` (GHSA-3jxr-9vmj-r5cp) and `js-yaml` (GHSA-52cp-r559-cp3m)
|
|
1365
|
+
were high, `qs` (GHSA-q8mj-m7cp-5q26) and `markdown-it` (GHSA-6v5v-wf23-fmfq)
|
|
1366
|
+
moderate. Each is a transitive **dev** dependency (of stryker and
|
|
1367
|
+
markdownlint-cli2), so none reached the published package; each override is
|
|
1368
|
+
scoped to its advisory's vulnerable range and capped to the compatible major.
|
|
1369
|
+
- Docs: added a deep-modules guide and a fleet-presets guide for org-wide
|
|
1370
|
+
rollout, reframed swappable module boundaries as the default, dropped the
|
|
1371
|
+
"TypeScript-only" framing from the README, homepage, and npm package
|
|
1372
|
+
description, clarified the README for first-time readers, and pointed
|
|
1373
|
+
`package.json` `homepage` at the GitHub Pages site.
|
|
1374
|
+
|
|
1375
|
+
## [0.5.3] - 2026-07-19
|
|
1376
|
+
|
|
1377
|
+
### Internal
|
|
1378
|
+
|
|
1379
|
+
- **Docs: `docs/ordering-in-practice.md`** — a worked guide to `order`
|
|
1380
|
+
scheduling waves, now with a second example where waves encode a *dependency*
|
|
1381
|
+
(`build` produces `dist/`; the publish bundle — `publint`, `attw`, `pack`,
|
|
1382
|
+
`smoke`, `snippets-dist` — consumes it) rather than just a duration tier.
|
|
1383
|
+
- Adopt explicit ordering waves in checkride's own `checkride.config.json`, so
|
|
1384
|
+
the gate config states its execution plan instead of leaning on adapter
|
|
1385
|
+
defaults and pool arithmetic.
|
|
1386
|
+
- CI: bump `upload-pages-artifact` to v5 and drop the Node 20 pages runtime.
|
|
1387
|
+
- Expand the `cspell` dictionary with words the docs introduced.
|
|
1388
|
+
|
|
7
1389
|
## [0.5.2] - 2026-07-19
|
|
8
1390
|
|
|
9
1391
|
### Internal
|
|
@@ -465,6 +1847,28 @@ The first real release. (`0.0.0` was a name-claim placeholder.)
|
|
|
465
1847
|
- Flags: `--only`, `--skip`, `--bail`, `--json`, `--changed`, `--all`,
|
|
466
1848
|
`--include`.
|
|
467
1849
|
|
|
1850
|
+
[0.12.2]: https://www.npmjs.com/package/checkride/v/0.12.2
|
|
1851
|
+
[0.12.1]: https://www.npmjs.com/package/checkride/v/0.12.1
|
|
1852
|
+
[0.12.0]: https://www.npmjs.com/package/checkride/v/0.12.0
|
|
1853
|
+
[0.11.2]: https://www.npmjs.com/package/checkride/v/0.11.2
|
|
1854
|
+
[0.11.1]: https://www.npmjs.com/package/checkride/v/0.11.1
|
|
1855
|
+
[0.11.0]: https://www.npmjs.com/package/checkride/v/0.11.0
|
|
1856
|
+
[0.10.3]: https://www.npmjs.com/package/checkride/v/0.10.3
|
|
1857
|
+
[0.10.2]: https://www.npmjs.com/package/checkride/v/0.10.2
|
|
1858
|
+
[0.10.1]: https://www.npmjs.com/package/checkride/v/0.10.1
|
|
1859
|
+
[0.10.0]: https://www.npmjs.com/package/checkride/v/0.10.0
|
|
1860
|
+
[0.9.6]: https://www.npmjs.com/package/checkride/v/0.9.6
|
|
1861
|
+
[0.9.5]: https://www.npmjs.com/package/checkride/v/0.9.5
|
|
1862
|
+
[0.9.4]: https://www.npmjs.com/package/checkride/v/0.9.4
|
|
1863
|
+
[0.9.3]: https://www.npmjs.com/package/checkride/v/0.9.3
|
|
1864
|
+
[0.9.2]: https://www.npmjs.com/package/checkride/v/0.9.2
|
|
1865
|
+
[0.9.1]: https://www.npmjs.com/package/checkride/v/0.9.1
|
|
1866
|
+
[0.9.0]: https://www.npmjs.com/package/checkride/v/0.9.0
|
|
1867
|
+
[0.8.1]: https://www.npmjs.com/package/checkride/v/0.8.1
|
|
1868
|
+
[0.8.0]: https://www.npmjs.com/package/checkride/v/0.8.0
|
|
1869
|
+
[0.7.0]: https://www.npmjs.com/package/checkride/v/0.7.0
|
|
1870
|
+
[0.6.0]: https://www.npmjs.com/package/checkride/v/0.6.0
|
|
1871
|
+
[0.5.3]: https://www.npmjs.com/package/checkride/v/0.5.3
|
|
468
1872
|
[0.5.2]: https://www.npmjs.com/package/checkride/v/0.5.2
|
|
469
1873
|
[0.5.1]: https://www.npmjs.com/package/checkride/v/0.5.1
|
|
470
1874
|
[0.5.0]: https://www.npmjs.com/package/checkride/v/0.5.0
|