plumbbob 0.9.3 → 0.9.5
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 +15 -13
- package/dist/cli-core.js +19 -2
- package/dist/lib/check.js +46 -13
- package/dist/lib/intent.js +1 -1
- package/dist/lib/latch.js +3 -3
- package/dist/lib/reentry.js +70 -0
- package/dist/verbs/agent.js +2 -2
- package/dist/verbs/doctor.js +4 -4
- package/dist/verbs/finish.js +1 -1
- package/dist/verbs/recover.js +297 -0
- package/dist/verbs/revert.js +2 -2
- package/dist/verbs/spike.js +8 -2
- 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 +1003 -0
- package/node_modules/checkride/LICENSE +201 -21
- package/node_modules/checkride/README.md +171 -30
- 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 +18 -6
- package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
- package/node_modules/checkride/dist/adapters.js +42 -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 +61 -0
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/cursor.js +189 -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 +84 -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 +58 -0
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
- package/node_modules/checkride/dist/agent-setup/scripts.js +299 -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 +161 -58
- package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts +7 -7
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.js +16 -19
- package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
- package/node_modules/checkride/dist/baseline/index.d.ts +4 -4
- package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/index.js +4 -4
- package/node_modules/checkride/dist/baseline/index.js.map +1 -1
- package/node_modules/checkride/dist/baseline/store.d.ts +12 -4
- package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/store.js +16 -9
- 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 +17 -4
- package/node_modules/checkride/dist/cli.d.ts.map +1 -1
- package/node_modules/checkride/dist/cli.js +259 -18
- package/node_modules/checkride/dist/cli.js.map +1 -1
- package/node_modules/checkride/dist/config.d.ts +84 -8
- package/node_modules/checkride/dist/config.d.ts.map +1 -1
- package/node_modules/checkride/dist/config.js +122 -18
- 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 +5 -5
- 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 +25 -6
- package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
- package/node_modules/checkride/dist/doctor.js +193 -27
- package/node_modules/checkride/dist/doctor.js.map +1 -1
- package/node_modules/checkride/dist/gate.d.ts +135 -0
- package/node_modules/checkride/dist/gate.d.ts.map +1 -0
- package/node_modules/checkride/dist/gate.js +490 -0
- package/node_modules/checkride/dist/gate.js.map +1 -0
- package/node_modules/checkride/dist/init.d.ts +72 -12
- package/node_modules/checkride/dist/init.d.ts.map +1 -1
- package/node_modules/checkride/dist/init.js +324 -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 +40 -10
- package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
- package/node_modules/checkride/dist/orchestrator.js +196 -102
- 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 +6 -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 +51 -0
- package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
- package/node_modules/checkride/dist/pm/launch.js +92 -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/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 +5 -5
- package/node_modules/checkride/dist/smoke.js +5 -5
- package/node_modules/checkride/dist/snippets.d.ts +26 -29
- 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 +17 -15
- package/node_modules/checkride/schema/checkride.config.schema.json +62 -5
- package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
- package/node_modules/checkride/skills/check/SKILL.md +257 -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/package.json +2 -2
- package/skills/build/SKILL.md +23 -19
- package/skills/finish/SKILL.md +3 -1
- package/skills/harvest/SKILL.md +2 -1
- package/skills/plan/SKILL.md +8 -7
- package/skills/recover/SKILL.md +28 -0
- package/skills/refine/SKILL.md +5 -4
- package/skills/spike/SKILL.md +1 -1
- package/skills/step/SKILL.md +4 -4
- package/skills/verify/SKILL.md +19 -14
- package/templates/intent.md +8 -7
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assembling the triage report — everything the skill reasons over, and nothing
|
|
3
|
+
* it would have to open a file to learn.
|
|
4
|
+
*
|
|
5
|
+
* The shape is deliberately a *model*, not text: the run's provenance, one row
|
|
6
|
+
* per slot with its raw output located and sized, what the run did and did not
|
|
7
|
+
* cover, and the traps (vacuous green, narrow green, baselined findings, stale
|
|
8
|
+
* artifacts) each surfaced as its own field. Rendering is `./render.ts`'s job.
|
|
9
|
+
*
|
|
10
|
+
* Two facts drive almost all of it. First, the summary is an index, not
|
|
11
|
+
* evidence: it is overwritten by every run, so triage runs the gate itself and
|
|
12
|
+
* then checks that the summary on disk is the one that run wrote. Second, sizes
|
|
13
|
+
* are the product: `mutation.json` is 2.3 MB in this repo, and a reader that
|
|
14
|
+
* reports contents instead of bytes has spent the context it exists to save.
|
|
15
|
+
*/
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { CHECK_DIR, configuredSlots, listArtifacts, readSummary, resolveRawOutput, runWindowStart, statArtifact } from '../artifacts/index.js';
|
|
18
|
+
import { DIGEST_FILE } from '../digest/index.js';
|
|
19
|
+
import { foldDoctor } from './doctor-fold.js';
|
|
20
|
+
import { isHarnessProblem, runGate } from './gate.js';
|
|
21
|
+
/**
|
|
22
|
+
* mtime can be second-granular on older filesystems, so a summary written a
|
|
23
|
+
* moment after the gate started could otherwise read as older than it. The
|
|
24
|
+
* tolerance is far smaller than any real gate run, so it cannot launder a
|
|
25
|
+
* genuinely stale summary into a fresh one.
|
|
26
|
+
*/
|
|
27
|
+
const MTIME_TOLERANCE_MS = 1000;
|
|
28
|
+
function statusOf(check) {
|
|
29
|
+
if (check.skipped === true)
|
|
30
|
+
return 'skipped';
|
|
31
|
+
return check.ok ? 'pass' : 'fail';
|
|
32
|
+
}
|
|
33
|
+
async function buildRow(checkDir, check, windowStart) {
|
|
34
|
+
// A skipped slot produced no output; any file under its name is a leftover
|
|
35
|
+
// from an earlier run, and offering it would be the stale read this module
|
|
36
|
+
// exists to prevent.
|
|
37
|
+
const raw = check.skipped === true ? null : await resolveRawOutput(checkDir, check.name, check.output_file, windowStart);
|
|
38
|
+
return {
|
|
39
|
+
slot: check.name,
|
|
40
|
+
adapter: check.adapter,
|
|
41
|
+
status: statusOf(check),
|
|
42
|
+
exitCode: check.exit_code,
|
|
43
|
+
durationMs: check.duration_ms,
|
|
44
|
+
baselined: check.baselined ?? null,
|
|
45
|
+
reason: check.reason ?? null,
|
|
46
|
+
raw,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function buildCoverage(cwd, rows) {
|
|
50
|
+
const configured = configuredSlots(cwd);
|
|
51
|
+
const present = new Set(rows.map((r) => r.slot));
|
|
52
|
+
return {
|
|
53
|
+
ran: rows.filter((r) => r.status !== 'skipped').map((r) => r.slot),
|
|
54
|
+
skipped: rows.filter((r) => r.status === 'skipped').map((r) => r.slot),
|
|
55
|
+
configured,
|
|
56
|
+
uncovered: (configured ?? []).filter((slot) => !present.has(slot)),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Whether the summary on disk is the one the gate just wrote. */
|
|
60
|
+
function writtenByThisRun(summary, gate) {
|
|
61
|
+
if (summary.state === 'missing' || summary.state === 'unreadable')
|
|
62
|
+
return null;
|
|
63
|
+
if (gate.verdict === 'not-run')
|
|
64
|
+
return null;
|
|
65
|
+
return summary.mtimeMs >= gate.startedMs - MTIME_TOLERANCE_MS;
|
|
66
|
+
}
|
|
67
|
+
/** Every stale file the run measured, deduped — a stale read is the classic wrong answer. */
|
|
68
|
+
function collectStale(rows, digest) {
|
|
69
|
+
const measured = [...rows.flatMap((r) => r.raw?.candidates ?? []), ...(digest ? [digest] : [])];
|
|
70
|
+
const stale = new Map();
|
|
71
|
+
for (const file of measured) {
|
|
72
|
+
if (file.freshness.state === 'stale')
|
|
73
|
+
stale.set(file.path, file);
|
|
74
|
+
}
|
|
75
|
+
return [...stale.values()];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* When the summary is gone, an anchor for judging what in `.check/` is a
|
|
79
|
+
* leftover. The contract window comes from the summary's own `timestamp`, so an
|
|
80
|
+
* unparseable summary leaves none — but the reader *ran the gate* and knows
|
|
81
|
+
* when it started, which is a strictly better anchor than giving up and
|
|
82
|
+
* labelling every file `?`. Not applied to the parsed path, where the
|
|
83
|
+
* documented derivation in `../artifacts/freshness.ts` is the contract.
|
|
84
|
+
*/
|
|
85
|
+
function gateAnchor(gate) {
|
|
86
|
+
return gate.verdict === 'not-run' ? null : gate.startedMs - MTIME_TOLERANCE_MS;
|
|
87
|
+
}
|
|
88
|
+
/** Read everything the run left behind, measuring and never opening. */
|
|
89
|
+
async function readArtifacts(cwd, gate) {
|
|
90
|
+
const checkDir = join(cwd, CHECK_DIR);
|
|
91
|
+
const summary = await readSummary(cwd);
|
|
92
|
+
const parsed = summary.state === 'ok';
|
|
93
|
+
const windowStart = parsed ? runWindowStart(summary.summary) : null;
|
|
94
|
+
const anchor = parsed ? windowStart : gateAnchor(gate);
|
|
95
|
+
const checks = summary.state === 'ok' ? summary.summary.checks : [];
|
|
96
|
+
const [rows, digest, listing] = await Promise.all([
|
|
97
|
+
Promise.all(checks.map((check) => buildRow(checkDir, check, windowStart))),
|
|
98
|
+
statArtifact(checkDir, DIGEST_FILE, anchor),
|
|
99
|
+
parsed ? Promise.resolve(null) : listArtifacts(checkDir, anchor),
|
|
100
|
+
]);
|
|
101
|
+
return { summary, windowStart, rows, digest, checkDir: listing };
|
|
102
|
+
}
|
|
103
|
+
function isVacuous(summary) {
|
|
104
|
+
return summary.state === 'ok' && summary.summary.ok && summary.summary.checks_run === 0;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Run the gate, then read what it wrote. On the broken-harness branch `doctor`
|
|
108
|
+
* is folded in first, because there the environment is the finding and the
|
|
109
|
+
* slot table is not evidence of anything.
|
|
110
|
+
*/
|
|
111
|
+
export async function triage(cwd, env) {
|
|
112
|
+
const gate = await runGate(cwd, env);
|
|
113
|
+
const doctor = isHarnessProblem(gate.verdict) ? await foldDoctor(cwd, env) : null;
|
|
114
|
+
const { summary, windowStart, rows, digest, checkDir } = await readArtifacts(cwd, gate);
|
|
115
|
+
return {
|
|
116
|
+
cwd,
|
|
117
|
+
gate,
|
|
118
|
+
doctor,
|
|
119
|
+
summary,
|
|
120
|
+
fromThisRun: writtenByThisRun(summary, gate),
|
|
121
|
+
windowStart,
|
|
122
|
+
rows,
|
|
123
|
+
failing: rows.filter((r) => r.status === 'fail'),
|
|
124
|
+
coverage: buildCoverage(cwd, rows),
|
|
125
|
+
vacuous: isVacuous(summary),
|
|
126
|
+
digest,
|
|
127
|
+
stale: collectStale(rows, digest),
|
|
128
|
+
checkDir,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=triage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.js","sourceRoot":"","sources":["../../src/triage/triage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "checkride",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "An agent harness for
|
|
5
|
-
"license": "
|
|
3
|
+
"version": "0.10.2",
|
|
4
|
+
"description": "An agent harness for code repositories: one command that is the definition of done, plus mechanically enforced module boundaries. TypeScript-first, not TypeScript-only.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
6
|
"author": "Rob McLarty",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/robmclarty/checkride.git"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://github.
|
|
11
|
+
"homepage": "https://robmclarty.github.io/checkride/",
|
|
12
12
|
"bugs": "https://github.com/robmclarty/checkride/issues",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"keywords": [
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
"dist",
|
|
41
41
|
"templates",
|
|
42
42
|
"schema",
|
|
43
|
+
".claude-plugin",
|
|
44
|
+
"skills",
|
|
43
45
|
"README.md",
|
|
44
46
|
"CHANGELOG.md",
|
|
45
47
|
"LICENSE"
|
|
@@ -62,20 +64,20 @@
|
|
|
62
64
|
"prepublishOnly": "tsc --build && vitest run"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
|
-
"@arethetypeswrong/cli": "0.18.
|
|
66
|
-
"@ast-grep/cli": "0.
|
|
67
|
+
"@arethetypeswrong/cli": "0.18.5",
|
|
68
|
+
"@ast-grep/cli": "0.45.0",
|
|
67
69
|
"@stryker-mutator/core": "9.6.1",
|
|
68
70
|
"@stryker-mutator/vitest-runner": "9.6.1",
|
|
69
|
-
"@types/node": "22.20.
|
|
70
|
-
"@vitest/coverage-v8": "4.1.
|
|
71
|
+
"@types/node": "22.20.1",
|
|
72
|
+
"@vitest/coverage-v8": "4.1.10",
|
|
71
73
|
"ajv": "8.20.0",
|
|
72
|
-
"cspell": "10.0.
|
|
73
|
-
"fallow": "3.
|
|
74
|
-
"markdownlint-cli2": "0.
|
|
75
|
-
"oxlint": "1.
|
|
76
|
-
"oxlint-tsgolint": "0.
|
|
77
|
-
"publint": "0.3.
|
|
74
|
+
"cspell": "10.0.1",
|
|
75
|
+
"fallow": "3.9.1",
|
|
76
|
+
"markdownlint-cli2": "0.23.1",
|
|
77
|
+
"oxlint": "1.74.0",
|
|
78
|
+
"oxlint-tsgolint": "0.25.0",
|
|
79
|
+
"publint": "0.3.22",
|
|
78
80
|
"typescript": "6.0.3",
|
|
79
|
-
"vitest": "4.1.
|
|
81
|
+
"vitest": "4.1.10"
|
|
80
82
|
}
|
|
81
83
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"type": "string",
|
|
11
11
|
"description": "URL of this JSON Schema, for editor validation and autocompletion."
|
|
12
12
|
},
|
|
13
|
+
"note": { "$ref": "#/definitions/note" },
|
|
13
14
|
"extends": {
|
|
14
15
|
"description": "Preset(s) to inherit — a file path (./base.json) or package specifier (@acme/preset), or an array of them. Bases merge left-to-right and the local config wins over all; objects deep-merge, arrays and scalars replace (arrays are not concatenated).",
|
|
15
16
|
"oneOf": [
|
|
@@ -22,15 +23,41 @@
|
|
|
22
23
|
"minimum": 0,
|
|
23
24
|
"description": "Default per-check timeout in seconds. Unset, checks fall back to the built-in 600s cap; 0 here or on a check disables the cap."
|
|
24
25
|
},
|
|
26
|
+
"gate": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"description": "What the agent stop-gate runs, when the full check is too slow to pay for on every turn. The gate then reports the profile in its verdict, so a narrowed green is never mistaken for a full one — keep the full check binding somewhere else (a commit hook, CI).",
|
|
30
|
+
"properties": {
|
|
31
|
+
"note": { "$ref": "#/definitions/note" },
|
|
32
|
+
"only": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "type": "string" },
|
|
35
|
+
"description": "Run only these slots in the gate."
|
|
36
|
+
},
|
|
37
|
+
"skip": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": { "type": "string" },
|
|
40
|
+
"description": "Run everything but these slots in the gate."
|
|
41
|
+
},
|
|
42
|
+
"changed": {
|
|
43
|
+
"type": "boolean",
|
|
44
|
+
"description": "Affected-only mode for the gate, as --changed."
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
25
48
|
"checks": {
|
|
26
49
|
"type": "object",
|
|
27
|
-
"description": "Per-slot configuration. A key that matches a catalogue slot (types, format, lint, struct, dead, dupes, health, test, docs, links, spell, mutation, security, publint, attw) configures that slot; any other key is a custom check that runs alongside the catalogue. Naming an opt-in slot (format, dupes, health, mutation, security, publint, attw) here also opts it into the default run.",
|
|
50
|
+
"description": "Per-slot configuration. A key that matches a catalogue slot (types, format, lint, struct, dead, dupes, health, test, docs, links, spell, mutation, security, publint, attw) configures that slot; any other key is a custom check that runs alongside the catalogue. Naming an opt-in slot (format, dupes, health, mutation, security, publint, attw) here also opts it into the default run — set optIn:true on the entry to configure it without opting in (run it only with --all/--include).",
|
|
28
51
|
"additionalProperties": {
|
|
29
52
|
"$ref": "#/definitions/slotConfig"
|
|
30
53
|
}
|
|
31
54
|
}
|
|
32
55
|
},
|
|
33
56
|
"definitions": {
|
|
57
|
+
"note": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "Internal documentation for whoever reads this config next. Never rendered in the CLI output or written to .check/summary.json — use description for the user-facing text a run prints beside the check."
|
|
60
|
+
},
|
|
34
61
|
"slotConfig": {
|
|
35
62
|
"description": "How to fill a slot: an adapter name, false to disable it, an adapter with overrides, or a custom check.",
|
|
36
63
|
"oneOf": [
|
|
@@ -58,12 +85,34 @@
|
|
|
58
85
|
},
|
|
59
86
|
"command": { "type": "string" },
|
|
60
87
|
"args": { "type": "array", "items": { "type": "string" } },
|
|
61
|
-
"description": {
|
|
88
|
+
"description": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"description": "User-facing text rendered beside this check in the CLI output. For maintainer commentary that should not render, use note."
|
|
91
|
+
},
|
|
92
|
+
"note": { "$ref": "#/definitions/note" },
|
|
62
93
|
"outputFile": { "type": ["string", "null"] },
|
|
63
94
|
"changedArgs": { "type": "array", "items": { "type": "string" } },
|
|
64
95
|
"fixArgs": { "type": "array", "items": { "type": "string" } },
|
|
65
96
|
"timeout": { "type": "number", "minimum": 0 },
|
|
66
|
-
"order": { "$ref": "#/definitions/order" }
|
|
97
|
+
"order": { "$ref": "#/definitions/order" },
|
|
98
|
+
"optIn": {
|
|
99
|
+
"type": "boolean",
|
|
100
|
+
"description": "Override the slot's opt-in status. true configures the slot without opting it into the default run (reach it with --all/--include); false forces it into the default run."
|
|
101
|
+
},
|
|
102
|
+
"exclude": {
|
|
103
|
+
"type": "array",
|
|
104
|
+
"items": { "type": "string" },
|
|
105
|
+
"description": "Links slot only: extra directory names to skip while walking for markdown, on top of the built-in exclude set (e.g. docs, research, .ridgeline)."
|
|
106
|
+
},
|
|
107
|
+
"allowlist": {
|
|
108
|
+
"type": "array",
|
|
109
|
+
"items": { "type": "string" },
|
|
110
|
+
"description": "Links slot only: regex sources for link targets to treat as always valid (deliberately illustrative links that never resolve on disk)."
|
|
111
|
+
},
|
|
112
|
+
"profile": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"description": "attw slot only: append --profile <name> (e.g. esm-only) to the attw invocation — a shortcut for retyping the full args."
|
|
115
|
+
}
|
|
67
116
|
}
|
|
68
117
|
},
|
|
69
118
|
"order": {
|
|
@@ -84,7 +133,11 @@
|
|
|
84
133
|
"description": "Executable to spawn."
|
|
85
134
|
},
|
|
86
135
|
"args": { "type": "array", "items": { "type": "string" } },
|
|
87
|
-
"description": {
|
|
136
|
+
"description": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"description": "User-facing text rendered beside this check in the CLI output. For maintainer commentary that should not render, use note."
|
|
139
|
+
},
|
|
140
|
+
"note": { "$ref": "#/definitions/note" },
|
|
88
141
|
"outputFile": { "type": ["string", "null"] },
|
|
89
142
|
"changedArgs": { "type": "array", "items": { "type": "string" } },
|
|
90
143
|
"fixArgs": { "type": "array", "items": { "type": "string" } },
|
|
@@ -95,7 +148,11 @@
|
|
|
95
148
|
"items": { "type": "string" },
|
|
96
149
|
"description": "Marker files that gate a non-catalogue custom check: it runs only when at least one listed file exists, and is skipped otherwise. Ignored on an entry that fills a catalogue slot."
|
|
97
150
|
},
|
|
98
|
-
"order": { "$ref": "#/definitions/order" }
|
|
151
|
+
"order": { "$ref": "#/definitions/order" },
|
|
152
|
+
"optIn": {
|
|
153
|
+
"type": "boolean",
|
|
154
|
+
"description": "true holds this custom check out of the default run — it runs only under --all/--include <name>. Absent runs it by default."
|
|
155
|
+
}
|
|
99
156
|
}
|
|
100
157
|
}
|
|
101
158
|
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"total_duration_ms": {
|
|
28
28
|
"type": "number",
|
|
29
29
|
"minimum": 0,
|
|
30
|
-
"description": "
|
|
30
|
+
"description": "Wall-clock duration of the whole execution phase, in milliseconds — not the sum of the per-check durations, which is larger whenever checks ran concurrently. The two are equal only when execution was sequential (including any --bail run). The run STARTED at timestamp - total_duration_ms; readers use that to judge whether an artifact belongs to this run."
|
|
31
31
|
},
|
|
32
32
|
"checks": {
|
|
33
33
|
"type": "array",
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: check
|
|
3
|
+
description: Triage a red checkride gate and name one root cause. Use whenever `pnpm check` (or `npm/yarn/bun run check`) fails, a checkride gate is red, CI is failing on the gate, or you need to know what to fix first. Runs the gate itself, reads a bounded report instead of megabytes of `.check/` artifacts, and covers the contract corners a plain summary read gets wrong — exit 2 vs exit 1, vacuous green, narrow green, baselined findings, skipped slots, spawn failures and stale artifacts.
|
|
4
|
+
argument-hint: "[repo-path]"
|
|
5
|
+
allowed-tools: Read, Grep, Glob, Bash(node *), Bash(pnpm *), Bash(npm run *), Bash(yarn *), Bash(bun run *), Bash(npx checkride*), Bash(wc *)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# checkride: triage a red gate
|
|
9
|
+
|
|
10
|
+
checkride's gate is the definition of done: exit 0 means the work is complete,
|
|
11
|
+
anything else means it is not. This skill is the procedure for the "anything
|
|
12
|
+
else" — it turns a red gate into **one named root cause** plus an explicit list
|
|
13
|
+
of what it is deliberately not reading yet.
|
|
14
|
+
|
|
15
|
+
It replaces reading `.check/summary.json` by hand. That habit is wrong in two
|
|
16
|
+
directions at once: it is unbounded (`mutation.json` runs to 2.3 MB in
|
|
17
|
+
checkride's own repo, `test.json` to 650 KB, and opening one spends the context
|
|
18
|
+
you need for the fix), and it is credulous (every run overwrites `summary.json`,
|
|
19
|
+
so an `ok: true` on disk may describe three of seventeen slots from fourteen
|
|
20
|
+
minutes ago).
|
|
21
|
+
|
|
22
|
+
## 1. Run the reader
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm exec checkride triage
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Substitute the repo's package manager (`npx checkride`, `yarn checkride`, `bunx
|
|
29
|
+
checkride`). Pass a repo path as the one optional argument to triage somewhere
|
|
30
|
+
other than the current directory.
|
|
31
|
+
|
|
32
|
+
If checkride is not a dependency of the target repo, run the copy the plugin
|
|
33
|
+
ships instead: `node "${CLAUDE_PLUGIN_ROOT}/dist/triage/cli.js"`. Both entry
|
|
34
|
+
points render the identical report.
|
|
35
|
+
|
|
36
|
+
What it does, in order: runs the repo's **own** `check` script (that script is
|
|
37
|
+
the definition of done and may carry deliberate `--only` / `--skip` / `--changed`
|
|
38
|
+
that a direct `checkride` invocation would bypass), branches on the promised
|
|
39
|
+
0/1/2 exit split, then reads what the run wrote. On exit 2 it also folds in
|
|
40
|
+
`checkride doctor --json`, so the broken-harness branch arrives with its
|
|
41
|
+
diagnosis attached.
|
|
42
|
+
|
|
43
|
+
Every artifact is measured, never opened. A green 17-slot run renders in about
|
|
44
|
+
2 KB. It exits 0 whenever it produced a report — the gate's verdict is in the
|
|
45
|
+
Markdown, not in the process status, so a red repo never looks like a broken
|
|
46
|
+
reader.
|
|
47
|
+
|
|
48
|
+
**Do not open any `.check/` file before this report tells you which one.** That
|
|
49
|
+
is the whole point: the report is the index, and you open exactly one thing from
|
|
50
|
+
it.
|
|
51
|
+
|
|
52
|
+
## 2. Read the header before you read any finding
|
|
53
|
+
|
|
54
|
+
The report opens with four lines. They are not preamble — three of the five ways
|
|
55
|
+
to be confidently wrong about a checkride run are visible only here.
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
- gate: `pnpm run check` → exit 0 (20.5s)
|
|
59
|
+
- script: `tsc --build && node dist/cli.js`
|
|
60
|
+
- summary: `.check/summary.json` — `schema_version` 1, written by this run, 19.8s
|
|
61
|
+
- covered: 17 slot(s) ran, 0 skipped
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- **`script`** — the repo's literal `check` script. If it contains `--only`,
|
|
65
|
+
`--skip` or `--changed`, this gate narrows the run on purpose and a green is
|
|
66
|
+
green *for those slots only*. The report says so under `coverage`.
|
|
67
|
+
- **`summary`** — provenance. `written by this run` is the good case. **`left by
|
|
68
|
+
an EARLIER run`** means the table below describes something else entirely and
|
|
69
|
+
every row in it is suspect. `schema_version` anything but 1 means **stop**: the
|
|
70
|
+
reader is pinned to schema 1, additive-only guarantees hold within a version
|
|
71
|
+
and promise nothing across one, so guessing is how you invent a finding. **`NOT
|
|
72
|
+
written by checkride`** (no `schema_version` at all) means this repo's gate is
|
|
73
|
+
a different tool — see below.
|
|
74
|
+
- **`covered`** — how much was verified. Compare it against the `coverage`
|
|
75
|
+
section, which names the slots `checkride.config.json` configures but this run
|
|
76
|
+
never touched. **`unknown`** is not `0`: it means no summary could be parsed,
|
|
77
|
+
so nothing about coverage was measured either way.
|
|
78
|
+
|
|
79
|
+
**Always open your report with the covered-slot count and the run's age.** A
|
|
80
|
+
finding without its coverage is an assertion about the whole repo built from a
|
|
81
|
+
fraction of it.
|
|
82
|
+
|
|
83
|
+
## 3. Branch on the verdict
|
|
84
|
+
|
|
85
|
+
| verdict | what it means | what to do |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| **harness broken** | exit 2 — checkride reserves it for "the harness broke or was misused" | Read the `doctor` section and the `gate output` tail. **No check result from this run is evidence of anything.** Report *what doctor found* — the named requirement, what was found, what was expected — never just "the harness is broken". |
|
|
88
|
+
| **off-contract exit** | not 0, 1 or 2 (a 127, a signal death, a wrapper that died before checkride ran) | Same posture as exit 2. Read the `gate output` tail: something in the `check` script failed around checkride, not inside it. |
|
|
89
|
+
| **red** | exit 1 — at least one check failed | Go to step 4. This is the normal path. |
|
|
90
|
+
| **red, but no slot explains it** | exit 1 with an empty `failing slots` section | The failure happened *outside* checkride. Read the `gate output` tail, which the report includes on this branch. See below — do not triage the table. |
|
|
91
|
+
| **red, and the summary cannot be read** | exit 1, and `.check/summary.json` exists but this reader cannot parse it | There is **no table at all**, and its absence is not evidence. Read the `gate output` tail and the `.check/ contents` listing; report *only* what those show. See below. |
|
|
92
|
+
| **green, with no index** | exit 0, same unparseable summary | The repo's own gate passed — report that, and nothing more. Attaching a slot count or a "clean" claim to it is inventing coverage. |
|
|
93
|
+
| **vacuous green** | exit 0 with `checks_run: 0` | A failure wearing a pass: nothing was verified. Find out why no check was selected (a typo'd `--only`, an empty config) before believing anything. Treat it as red. |
|
|
94
|
+
| **green, but narrow** | exit 0 over a subset | Say which slots were covered and which were not. Do not report the work as done on this evidence. |
|
|
95
|
+
| **green** | exit 0, full coverage | Still check the caveats for `baselined` and `skipped` before saying clean — see step 7. |
|
|
96
|
+
| **gate not run** | no `check` script in this repo | Nothing here defines done. `checkride init` adds it. Anything in `.check/` is from whatever last wrote it. |
|
|
97
|
+
|
|
98
|
+
### Red with an empty `failing slots` section
|
|
99
|
+
|
|
100
|
+
The verdict reads **`red, but no slot explains it`**: the gate exited 1 but
|
|
101
|
+
checkride never ran, so nothing in the table came from this run. `check` scripts
|
|
102
|
+
are compound — `tsc --build && node dist/cli.js` is the standard shape
|
|
103
|
+
`checkride init` writes — and when the command *before* checkride dies, the `&&`
|
|
104
|
+
short-circuits and no summary is written.
|
|
105
|
+
|
|
106
|
+
The `summary` header line is the second tell: **`left by an EARLIER run`**. The
|
|
107
|
+
table below it describes something else entirely, and the coverage numbers belong
|
|
108
|
+
to that other run too.
|
|
109
|
+
|
|
110
|
+
**The evidence is already in the report.** On this branch it renders a `gate
|
|
111
|
+
output` section — a capped tail of both captured streams — because that is the
|
|
112
|
+
only record of the failure that exists. Triage it there rather than re-running
|
|
113
|
+
anything.
|
|
114
|
+
|
|
115
|
+
Read **both** blocks. Which stream carries the diagnosis is the failing tool's
|
|
116
|
+
choice, not a convention you can rely on: `tsc` reports errors on **stdout**
|
|
117
|
+
while `stderr` holds nothing but pnpm's `$ tsc --build && node dist/cli.js`
|
|
118
|
+
command echo. A near-empty `stderr` block is not "no output".
|
|
119
|
+
|
|
120
|
+
Only if both blocks are absent, re-run the failing prefix directly (`pnpm exec
|
|
121
|
+
tsc --build` for the shape above) and triage what it prints. Either way: do not
|
|
122
|
+
report any slot in the table as passing.
|
|
123
|
+
|
|
124
|
+
### A summary this reader cannot parse
|
|
125
|
+
|
|
126
|
+
Distinct from the branch above, and the distinction is the whole point. There
|
|
127
|
+
the summary is **absent** — checkride never ran, so it wrote nothing. Here a
|
|
128
|
+
`.check/summary.json` exists and cannot be parsed, which says *nothing at all*
|
|
129
|
+
about what ran. The verdict reads **`red, and the summary cannot be read`** (or
|
|
130
|
+
**`green, with no index`**), and the header names which of three it is:
|
|
131
|
+
|
|
132
|
+
- **`NOT written by checkride`** — no `schema_version`. The repo's gate is a
|
|
133
|
+
homegrown script that writes a checkride-shaped `.check/`. Its artifacts follow
|
|
134
|
+
no contract, so their names and freshness are all you can trust about them.
|
|
135
|
+
- **`schema_version` is N, not 1** — checkride wrote it, but a newer one.
|
|
136
|
+
- **unreadable** — truncated, or not JSON.
|
|
137
|
+
|
|
138
|
+
On this branch the report gives you two things and no table: the `gate output`
|
|
139
|
+
tail, and a **`.check/ contents`** listing of every file with its size and age.
|
|
140
|
+
`fresh` there means written after the gate started; `stale` means a leftover that
|
|
141
|
+
describes no part of this run. Triage from those, and open at most one file.
|
|
142
|
+
|
|
143
|
+
What you must not do is fill the gap. `covered: unknown` is not `covered: 0`;
|
|
144
|
+
`baselined` and `skipped` are both **unknown**, and because a baselined slot
|
|
145
|
+
*passes* and a skipped one reports nothing, "no caveats raised" and "no caveats
|
|
146
|
+
could be raised" look identical. No slot can be reported as passing on this run.
|
|
147
|
+
|
|
148
|
+
## 4. Order the failures — this is the judgment
|
|
149
|
+
|
|
150
|
+
The report lists failing slots in **pipeline order** and says explicitly that
|
|
151
|
+
this is not importance order. Re-ranking them is the part no script can do.
|
|
152
|
+
|
|
153
|
+
When several slots fail at once, most of them are usually one cause and its
|
|
154
|
+
shadows. The cheap tell: **does the failing slot consume something an earlier
|
|
155
|
+
failing slot produces?**
|
|
156
|
+
|
|
157
|
+
| when this fails | these failures are usually its shadow | because |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| `types` | `build`, `typecheck-tests`, `test` | `build` is normally the same `tsc` invocation, and a type error is the same defect surfacing at runtime |
|
|
160
|
+
| `types` on a *syntax* error | also `lint`, `struct`, `dead`, `dupes`, `health` | unparseable source breaks every tool that parses it, which a merely semantic type error does not |
|
|
161
|
+
| `build` | `publint`, `attw`, `pack`, `smoke`, `snippets` | they all inspect `dist/`, which is now stale or absent |
|
|
162
|
+
| `test` | nothing | no slot consumes a test result |
|
|
163
|
+
|
|
164
|
+
Two rules that outrank the table:
|
|
165
|
+
|
|
166
|
+
1. **A slot with `exit_code: -1` is not a finding.** It failed to spawn or timed
|
|
167
|
+
out and reported nothing. That is a harness problem wearing a failure's
|
|
168
|
+
clothes, and it comes first.
|
|
169
|
+
2. **The prose lane is independent.** `docs`, `spell` and `links` never share a
|
|
170
|
+
cause with the code lane. `types` red *and* `spell` red is two pieces of work,
|
|
171
|
+
not one — say so rather than folding them together.
|
|
172
|
+
|
|
173
|
+
Worked shape: `types`, `build` and `test` all red, 41 test failures. That is one
|
|
174
|
+
root cause — the type error — and two shadows. Naming the 41 test failures is
|
|
175
|
+
noise; fixing the type error is the work. Say which one you picked and why the
|
|
176
|
+
others are downstream.
|
|
177
|
+
|
|
178
|
+
## 5. If everything failing is auto-fixable, say so before proposing edits
|
|
179
|
+
|
|
180
|
+
`checkride fix` runs every active adapter's fix command. The slots it can fix
|
|
181
|
+
are `format` (prettier, biome), `lint` (oxlint, biome, eslint), `docs`
|
|
182
|
+
(markdownlint) and `dead` (fallow, knip). Nothing else — `types`, `test`,
|
|
183
|
+
`spell`, `links`, `struct` and the packaging slots have no fix command.
|
|
184
|
+
|
|
185
|
+
- **Every failing slot is in that set** → propose `pnpm exec checkride fix`
|
|
186
|
+
followed by a re-run, before writing a single hand edit. Hand-editing what a
|
|
187
|
+
formatter would rewrite is wasted work.
|
|
188
|
+
- **Only some are** → the root cause is elsewhere. Name it first; mention `fix`
|
|
189
|
+
as cleanup for the rest.
|
|
190
|
+
|
|
191
|
+
Two caveats to state when you propose it: `fix` writes to files across the whole
|
|
192
|
+
repo, not just the failing slots, so it wants a clean git tree or a reviewed
|
|
193
|
+
diff; and `dead`'s fix *deletes* code it believes is unused — read that part of
|
|
194
|
+
the diff rather than trusting it.
|
|
195
|
+
|
|
196
|
+
## 6. Open exactly one file
|
|
197
|
+
|
|
198
|
+
The report's `failing slots` section names each failure's raw output with its
|
|
199
|
+
size. Open the one belonging to your chosen root cause, and nothing else.
|
|
200
|
+
|
|
201
|
+
- If `.check/digest.md` is listed and **fresh**, read it first — it is
|
|
202
|
+
checkride's own bounded excerpt of this run's failing slots, capped at 8 KB.
|
|
203
|
+
Its existence always means the run that wrote it had failures. If it is
|
|
204
|
+
labelled stale, it belongs to an earlier run; do not read it as this one's.
|
|
205
|
+
- Prefer the file the report chose. When a slot has both a `.json` and a
|
|
206
|
+
`.stdout.txt`, the reader already picked the small one (`test.stdout.txt` is
|
|
207
|
+
6 KB against `test.json`'s 650 KB) and the `(+1)` marks the one it passed over.
|
|
208
|
+
- **If the chosen file gives you a count but not a location, open the `(+1)`.**
|
|
209
|
+
The reader prefers stdout because checkride's own stream discipline puts machine
|
|
210
|
+
output there and progress on stderr — but not every tool obeys it.
|
|
211
|
+
markdownlint-cli2 inverts it outright: `docs.stdout.txt` says
|
|
212
|
+
`Summary: 1 issue in 1 file` while `docs.stderr.txt` carries the
|
|
213
|
+
`file:line:rule` you actually need. A summary line is not a finding; go get the
|
|
214
|
+
finding.
|
|
215
|
+
- **Check the size before opening.** Anything past ~50 KB gets `Grep`, not
|
|
216
|
+
`Read` — search for the error text rather than loading the file.
|
|
217
|
+
- If a failing slot's raw output is `—`, the tool wrote nothing the reader could
|
|
218
|
+
locate. Do not report "no output": re-run that slot alone
|
|
219
|
+
(`pnpm exec checkride --only <slot>`) and read what it prints.
|
|
220
|
+
|
|
221
|
+
## 7. Report
|
|
222
|
+
|
|
223
|
+
Lead with provenance, then one cause, then what you left closed:
|
|
224
|
+
|
|
225
|
+
- **Gate** — the verdict, the covered-slot count, and the run's age.
|
|
226
|
+
- **Root cause** — one slot, one sentence, grounded in the file you opened.
|
|
227
|
+
- **Downstream, not read** — the failing slots you believe are shadows of it,
|
|
228
|
+
and the one-line reason. Naming these is as much the product as the cause is.
|
|
229
|
+
- **Separate work** — failing slots that are genuinely independent (usually the
|
|
230
|
+
prose lane).
|
|
231
|
+
- **Masked** — every caveat the report raised, because each one means a green is
|
|
232
|
+
less green than it looks:
|
|
233
|
+
- `baselined: N` — that many current findings are grandfathered by
|
|
234
|
+
`checkride.baseline.json`. **A baselined slot passing is not clean, and you
|
|
235
|
+
must say the count rather than reporting clean.** Never add to a baseline to
|
|
236
|
+
make a check pass.
|
|
237
|
+
- `skipped` plus its reason — that slot verified nothing this run.
|
|
238
|
+
- stale artifacts — leftovers from an earlier run, not this one's output.
|
|
239
|
+
- uncovered slots — configured in `checkride.config.json`, absent from this run.
|
|
240
|
+
- **Next** — the fix command, or the specific hand edit.
|
|
241
|
+
|
|
242
|
+
Do not produce a fixed-size list of findings. One cause is the target; two is
|
|
243
|
+
fine when the lanes are genuinely independent; five means you re-ranked nothing.
|
|
244
|
+
|
|
245
|
+
## What this skill does not do
|
|
246
|
+
|
|
247
|
+
- **It does not fix.** It runs the gate and reads. Proposing `checkride fix` or a
|
|
248
|
+
hand edit is the deliverable; applying it is the next request.
|
|
249
|
+
- **It does not normalize tool output.** The raw file is the truth and the
|
|
250
|
+
summary is only an index — that is checkride's thesis, and reformatting a
|
|
251
|
+
tool's own bytes into something prettier is how a triage loses the detail that
|
|
252
|
+
mattered.
|
|
253
|
+
- **It does not read `.check/` contents on spec.** Sizes and locations first,
|
|
254
|
+
then exactly one file. If you find yourself opening a second artifact before
|
|
255
|
+
naming a cause, that is exploration, not triage.
|
|
256
|
+
- **It does not touch the baseline.** `checkride baseline` hides findings
|
|
257
|
+
permanently; that is the human's call, never a triage step.
|