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.
Files changed (278) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +15 -13
  3. package/dist/cli-core.js +19 -2
  4. package/dist/lib/check.js +46 -13
  5. package/dist/lib/intent.js +1 -1
  6. package/dist/lib/latch.js +3 -3
  7. package/dist/lib/reentry.js +70 -0
  8. package/dist/verbs/agent.js +2 -2
  9. package/dist/verbs/doctor.js +4 -4
  10. package/dist/verbs/finish.js +1 -1
  11. package/dist/verbs/recover.js +297 -0
  12. package/dist/verbs/revert.js +2 -2
  13. package/dist/verbs/spike.js +8 -2
  14. package/hooks/post-edit.sh +4 -4
  15. package/hooks/pre-bash-commit.sh +3 -3
  16. package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
  17. package/node_modules/checkride/CHANGELOG.md +1003 -0
  18. package/node_modules/checkride/LICENSE +201 -21
  19. package/node_modules/checkride/README.md +171 -30
  20. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
  21. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
  22. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
  23. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
  24. package/node_modules/checkride/dist/adapters.d.ts +18 -6
  25. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  26. package/node_modules/checkride/dist/adapters.js +42 -23
  27. package/node_modules/checkride/dist/adapters.js.map +1 -1
  28. package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
  29. package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
  30. package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
  31. package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
  32. package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
  33. package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
  34. package/node_modules/checkride/dist/agent-setup/command.js +77 -0
  35. package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
  36. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +61 -0
  37. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
  38. package/node_modules/checkride/dist/agent-setup/cursor.js +189 -0
  39. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
  40. package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
  41. package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
  42. package/node_modules/checkride/dist/agent-setup/files.js +80 -0
  43. package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
  44. package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
  45. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
  46. package/node_modules/checkride/dist/agent-setup/harness.js +84 -0
  47. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
  48. package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
  49. package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
  50. package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
  51. package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
  52. package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
  53. package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
  54. package/node_modules/checkride/dist/agent-setup/index.js +9 -4
  55. package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
  56. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +58 -0
  57. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
  58. package/node_modules/checkride/dist/agent-setup/scripts.js +299 -0
  59. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
  60. package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
  61. package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
  62. package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
  63. package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
  64. package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
  65. package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
  66. package/node_modules/checkride/dist/artifacts/configured.js +45 -0
  67. package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
  68. package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
  69. package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
  70. package/node_modules/checkride/dist/artifacts/format.js +56 -0
  71. package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
  72. package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
  73. package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
  74. package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
  75. package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
  76. package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
  77. package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
  78. package/node_modules/checkride/dist/artifacts/index.js +19 -0
  79. package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
  80. package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
  81. package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
  82. package/node_modules/checkride/dist/artifacts/json.js +47 -0
  83. package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
  84. package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
  85. package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
  86. package/node_modules/checkride/dist/artifacts/raw.js +91 -0
  87. package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
  88. package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
  89. package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
  90. package/node_modules/checkride/dist/artifacts/summary.js +108 -0
  91. package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
  92. package/node_modules/checkride/dist/atomic.d.ts +16 -1
  93. package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
  94. package/node_modules/checkride/dist/atomic.js +25 -3
  95. package/node_modules/checkride/dist/atomic.js.map +1 -1
  96. package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
  97. package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
  98. package/node_modules/checkride/dist/baseline/fallow.js +161 -58
  99. package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
  100. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +7 -7
  101. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  102. package/node_modules/checkride/dist/baseline/fingerprint.js +16 -19
  103. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  104. package/node_modules/checkride/dist/baseline/index.d.ts +4 -4
  105. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  106. package/node_modules/checkride/dist/baseline/index.js +4 -4
  107. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  108. package/node_modules/checkride/dist/baseline/store.d.ts +12 -4
  109. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  110. package/node_modules/checkride/dist/baseline/store.js +16 -9
  111. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  112. package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
  113. package/node_modules/checkride/dist/baseline-command.js +7 -7
  114. package/node_modules/checkride/dist/baseline-command.js.map +1 -1
  115. package/node_modules/checkride/dist/cli.d.ts +17 -4
  116. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  117. package/node_modules/checkride/dist/cli.js +259 -18
  118. package/node_modules/checkride/dist/cli.js.map +1 -1
  119. package/node_modules/checkride/dist/config.d.ts +84 -8
  120. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  121. package/node_modules/checkride/dist/config.js +122 -18
  122. package/node_modules/checkride/dist/config.js.map +1 -1
  123. package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
  124. package/node_modules/checkride/dist/digest/digest.js +5 -5
  125. package/node_modules/checkride/dist/digest/index.d.ts +2 -2
  126. package/node_modules/checkride/dist/digest/index.js +2 -2
  127. package/node_modules/checkride/dist/doctor.d.ts +25 -6
  128. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  129. package/node_modules/checkride/dist/doctor.js +193 -27
  130. package/node_modules/checkride/dist/doctor.js.map +1 -1
  131. package/node_modules/checkride/dist/gate.d.ts +135 -0
  132. package/node_modules/checkride/dist/gate.d.ts.map +1 -0
  133. package/node_modules/checkride/dist/gate.js +490 -0
  134. package/node_modules/checkride/dist/gate.js.map +1 -0
  135. package/node_modules/checkride/dist/init.d.ts +72 -12
  136. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  137. package/node_modules/checkride/dist/init.js +324 -81
  138. package/node_modules/checkride/dist/init.js.map +1 -1
  139. package/node_modules/checkride/dist/json.d.ts +21 -0
  140. package/node_modules/checkride/dist/json.d.ts.map +1 -0
  141. package/node_modules/checkride/dist/json.js +21 -0
  142. package/node_modules/checkride/dist/json.js.map +1 -0
  143. package/node_modules/checkride/dist/links.d.ts +31 -5
  144. package/node_modules/checkride/dist/links.d.ts.map +1 -1
  145. package/node_modules/checkride/dist/links.js +141 -32
  146. package/node_modules/checkride/dist/links.js.map +1 -1
  147. package/node_modules/checkride/dist/node-pin.d.ts +129 -0
  148. package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
  149. package/node_modules/checkride/dist/node-pin.js +211 -0
  150. package/node_modules/checkride/dist/node-pin.js.map +1 -0
  151. package/node_modules/checkride/dist/orchestrator.d.ts +40 -10
  152. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  153. package/node_modules/checkride/dist/orchestrator.js +196 -102
  154. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  155. package/node_modules/checkride/dist/pack.d.ts +8 -9
  156. package/node_modules/checkride/dist/pack.d.ts.map +1 -1
  157. package/node_modules/checkride/dist/pack.js +53 -17
  158. package/node_modules/checkride/dist/pack.js.map +1 -1
  159. package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
  160. package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
  161. package/node_modules/checkride/dist/pm/detect.js +6 -1
  162. package/node_modules/checkride/dist/pm/detect.js.map +1 -1
  163. package/node_modules/checkride/dist/pm/index.d.ts +6 -2
  164. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  165. package/node_modules/checkride/dist/pm/index.js +6 -2
  166. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  167. package/node_modules/checkride/dist/pm/launch.d.ts +51 -0
  168. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
  169. package/node_modules/checkride/dist/pm/launch.js +92 -0
  170. package/node_modules/checkride/dist/pm/launch.js.map +1 -0
  171. package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
  172. package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
  173. package/node_modules/checkride/dist/pm/tools.js +124 -0
  174. package/node_modules/checkride/dist/pm/tools.js.map +1 -0
  175. package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
  176. package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
  177. package/node_modules/checkride/dist/pm/translate.js +78 -18
  178. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  179. package/node_modules/checkride/dist/proc.d.ts +30 -0
  180. package/node_modules/checkride/dist/proc.d.ts.map +1 -0
  181. package/node_modules/checkride/dist/proc.js +42 -0
  182. package/node_modules/checkride/dist/proc.js.map +1 -0
  183. package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
  184. package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
  185. package/node_modules/checkride/dist/qa/cli.js +24 -0
  186. package/node_modules/checkride/dist/qa/cli.js.map +1 -0
  187. package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
  188. package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
  189. package/node_modules/checkride/dist/qa/dead.js +88 -0
  190. package/node_modules/checkride/dist/qa/dead.js.map +1 -0
  191. package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
  192. package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
  193. package/node_modules/checkride/dist/qa/dupes.js +62 -0
  194. package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
  195. package/node_modules/checkride/dist/qa/health.d.ts +85 -0
  196. package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
  197. package/node_modules/checkride/dist/qa/health.js +109 -0
  198. package/node_modules/checkride/dist/qa/health.js.map +1 -0
  199. package/node_modules/checkride/dist/qa/index.d.ts +23 -0
  200. package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
  201. package/node_modules/checkride/dist/qa/index.js +22 -0
  202. package/node_modules/checkride/dist/qa/index.js.map +1 -0
  203. package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
  204. package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
  205. package/node_modules/checkride/dist/qa/mutation.js +195 -0
  206. package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
  207. package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
  208. package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
  209. package/node_modules/checkride/dist/qa/qa.js +158 -0
  210. package/node_modules/checkride/dist/qa/qa.js.map +1 -0
  211. package/node_modules/checkride/dist/qa/read.d.ts +40 -0
  212. package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
  213. package/node_modules/checkride/dist/qa/read.js +47 -0
  214. package/node_modules/checkride/dist/qa/read.js.map +1 -0
  215. package/node_modules/checkride/dist/qa/render.d.ts +26 -0
  216. package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
  217. package/node_modules/checkride/dist/qa/render.js +310 -0
  218. package/node_modules/checkride/dist/qa/render.js.map +1 -0
  219. package/node_modules/checkride/dist/security.d.ts +45 -0
  220. package/node_modules/checkride/dist/security.d.ts.map +1 -0
  221. package/node_modules/checkride/dist/security.js +86 -0
  222. package/node_modules/checkride/dist/security.js.map +1 -0
  223. package/node_modules/checkride/dist/smoke.d.ts +5 -5
  224. package/node_modules/checkride/dist/smoke.js +5 -5
  225. package/node_modules/checkride/dist/snippets.d.ts +26 -29
  226. package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
  227. package/node_modules/checkride/dist/snippets.js +26 -30
  228. package/node_modules/checkride/dist/snippets.js.map +1 -1
  229. package/node_modules/checkride/dist/tool-json.d.ts +33 -0
  230. package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
  231. package/node_modules/checkride/dist/tool-json.js +58 -0
  232. package/node_modules/checkride/dist/tool-json.js.map +1 -0
  233. package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
  234. package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
  235. package/node_modules/checkride/dist/triage/cli.js +26 -0
  236. package/node_modules/checkride/dist/triage/cli.js.map +1 -0
  237. package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
  238. package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
  239. package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
  240. package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
  241. package/node_modules/checkride/dist/triage/env.d.ts +54 -0
  242. package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
  243. package/node_modules/checkride/dist/triage/env.js +81 -0
  244. package/node_modules/checkride/dist/triage/env.js.map +1 -0
  245. package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
  246. package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
  247. package/node_modules/checkride/dist/triage/gate.js +121 -0
  248. package/node_modules/checkride/dist/triage/gate.js.map +1 -0
  249. package/node_modules/checkride/dist/triage/index.d.ts +22 -0
  250. package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
  251. package/node_modules/checkride/dist/triage/index.js +20 -0
  252. package/node_modules/checkride/dist/triage/index.js.map +1 -0
  253. package/node_modules/checkride/dist/triage/render.d.ts +19 -0
  254. package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
  255. package/node_modules/checkride/dist/triage/render.js +419 -0
  256. package/node_modules/checkride/dist/triage/render.js.map +1 -0
  257. package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
  258. package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
  259. package/node_modules/checkride/dist/triage/triage.js +131 -0
  260. package/node_modules/checkride/dist/triage/triage.js.map +1 -0
  261. package/node_modules/checkride/package.json +17 -15
  262. package/node_modules/checkride/schema/checkride.config.schema.json +62 -5
  263. package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
  264. package/node_modules/checkride/skills/check/SKILL.md +257 -0
  265. package/node_modules/checkride/skills/qa/SKILL.md +231 -0
  266. package/node_modules/checkride/templates/shared/cspell.json +1 -0
  267. package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
  268. package/package.json +2 -2
  269. package/skills/build/SKILL.md +23 -19
  270. package/skills/finish/SKILL.md +3 -1
  271. package/skills/harvest/SKILL.md +2 -1
  272. package/skills/plan/SKILL.md +8 -7
  273. package/skills/recover/SKILL.md +28 -0
  274. package/skills/refine/SKILL.md +5 -4
  275. package/skills/spike/SKILL.md +1 -1
  276. package/skills/step/SKILL.md +4 -4
  277. package/skills/verify/SKILL.md +19 -14
  278. package/templates/intent.md +8 -7
@@ -0,0 +1,231 @@
1
+ ---
2
+ name: qa
3
+ description: Read checkride's quality artifacts — surviving mutants, dead code, duplication and the health score — and say what the test suite actually proves. Use when asked how healthy the codebase is, whether the tests are any good, where the risk or the tech debt is, what mutation testing found, or which files need better coverage. Reads a bounded report instead of megabytes of `.check/` artifacts, runs nothing, and reports which quality dimensions were never measured rather than guessing at them.
4
+ argument-hint: "[repo-path]"
5
+ allowed-tools: Read, Grep, Glob, Bash(node *), Bash(pnpm *), Bash(npx checkride*), Bash(yarn *), Bash(bunx *), Bash(wc *), Bash(git log *)
6
+ ---
7
+
8
+ # checkride: read the quality signal
9
+
10
+ checkride's gate answers one question — is the work done? — and answers it
11
+ pass/fail. These four artifacts answer a different one: **is the suite actually
12
+ testing anything, and where is the risk?** Nothing here is red or green. No
13
+ threshold fires. That is exactly why this is the easiest report in the repo to
14
+ hallucinate: with no failure to anchor to, a plausible-sounding list of eight
15
+ issues costs nothing to write and means nothing.
16
+
17
+ So the discipline is inverted from triage. The triage skill starts from a
18
+ failure and narrows to one cause. This skill starts from evidence and stops when
19
+ the evidence stops — which is sometimes after one finding, and sometimes after
20
+ none.
21
+
22
+ For a red gate, use the triage skill instead (`/checkride:check` under the
23
+ plugin, `/checkride-check` in Cursor, or `checkride triage` directly). This skill
24
+ reads what a *past* run left behind and never runs the gate itself.
25
+
26
+ ## 1. Run the reader
27
+
28
+ ```bash
29
+ pnpm exec checkride qa
30
+ ```
31
+
32
+ Substitute the repo's package manager (`npx checkride`, `yarn checkride`, `bunx
33
+ checkride`). Pass a repo path as the one optional argument to read somewhere
34
+ other than the current directory.
35
+
36
+ If checkride is not a dependency of the target repo, run the copy the plugin
37
+ ships instead: `node "${CLAUDE_PLUGIN_ROOT}/dist/qa/cli.js"`. Both entry points
38
+ render the identical report.
39
+
40
+ It **runs nothing** — no stryker, no fallow, not the gate. It opens `.check/`,
41
+ folds each artifact to a ranked short list, and renders under 8 KB (the same
42
+ ceiling `--digest` uses). In checkride's own repo that is 2.3 MB of
43
+ `mutation.json` reduced to a page, which is the only reason a mutation finding
44
+ is affordable at all.
45
+
46
+ **Do not open any `.check/` file before this report names one.** Every count
47
+ below comes from a full pass over the artifact; the lists are ranked, not
48
+ truncated at random.
49
+
50
+ ## 2. The ledger is the answer, not the preamble
51
+
52
+ Because the reader runs nothing, its first job is to say what it is actually
53
+ holding. Two head lines, then a table — and in a default consumer repo that is
54
+ very nearly the *whole* report.
55
+
56
+ ```text
57
+ - summary: `.check/summary.json` — `schema_version` 1, 1.5m ago, 1.5s
58
+ - covered: 3 slot(s) ran — links, docs, spell
59
+ ```
60
+
61
+ - **`summary`** — what the artifacts beside it belong to, and how long ago. If it
62
+ reads `` `schema_version` is 2, not 1; STOP ``, then **stop**: the reader is
63
+ pinned to schema 1, and guessing across a version is how you invent a finding.
64
+ - **`covered`** — the slots that run actually touched. Three of seventeen means
65
+ the artifacts on disk mostly belong to *some other* run, and the ledger's
66
+ staleness column is the only thing standing between you and reporting them as
67
+ current. `covered: nothing` means there is no readable summary at all, so no
68
+ artifact here can be dated and none of them is evidence.
69
+
70
+ **Open your report with that covered count and the run's age**, the same way
71
+ the triage skill does. A quality claim without its coverage is an assertion
72
+ about the whole repo built from a fraction of it.
73
+
74
+ | state | what it means | what it licenses you to say |
75
+ | --- | --- | --- |
76
+ | `read` | fresh — written by the run whose summary sits beside it | evidence, present tense |
77
+ | `STALE` | on disk, but older than that run's start | a fact about the past, with the age always attached |
78
+ | `not opted in` | the slot is absent from `checkride.config.json`, so no run produces it | **nothing about this dimension** — name the remedy instead |
79
+ | `absent` | opted in, but no file — the slot has not run, or produced nothing | nothing; name the command |
80
+ | `too-large` / `unreadable` / `unrecognized` | the bytes are there but not usable | nothing; say which, because each has a different cause |
81
+
82
+ Two rules follow, and they are the ones that make this skill honest.
83
+
84
+ **A gap is a finding, not an edge case.** Three of the four artifacts come from
85
+ opt-in slots, and checkride's own gate never runs `mutation` at all. In a fresh
86
+ consumer repo you will find `dead.json` and nothing else. The honest report
87
+ there is the ledger plus the two commands that would produce data — *not* a page
88
+ of quality assessment extrapolated from one artifact. The reader already prints
89
+ the exact command or config entry for each gap; quote it rather than inventing
90
+ one.
91
+
92
+ **Never launder a stale number into a present-tense claim.** "Mutation score is
93
+ 71%" is wrong when the file is 7.6 days old. "As of a stryker run 7.6 days ago,
94
+ 71%" is right, and it carries its own warning. When a stale artifact is
95
+ load-bearing for a finding, check whether the code moved under it:
96
+
97
+ ```bash
98
+ git log -1 --format=%cr -- src/init.ts
99
+ ```
100
+
101
+ If the file changed more recently than the artifact, the artifact describes code
102
+ that no longer exists. Say so and stop — do not report its findings as current.
103
+
104
+ ## 3. Read in evidence order — strongest proof first
105
+
106
+ The reader emits its sections in the order you should reason about them, and
107
+ that order is not arbitrary. It ranks by **how much of the claim the artifact
108
+ already proved for you**:
109
+
110
+ 1. **Surviving mutants** — the strongest evidence in the repo. Stryker *changed
111
+ the code* and the suite still passed. That is a demonstrated hole, not an
112
+ opinion, and no amount of coverage percentage can contradict it.
113
+ 2. **Dead code** — a static claim about reachability. Usually right; wrong
114
+ exactly where entry points are dynamic, which is why `fallow.toml`'s `entry`
115
+ list exists.
116
+ 3. **Structure** (`dupes`, `health`) — measurements against thresholds somebody
117
+ configured. A hotspot is a place to look, not a defect.
118
+ 4. **Your own reading of the source** — last, and only when it names a file and
119
+ a line.
120
+
121
+ Work down that list and stop where the evidence stops. That is the whole
122
+ anti-hallucination device: findings are sorted by proof, so a short report is a
123
+ *strong* one.
124
+
125
+ ### Mutation: survived and no-coverage want different fixes
126
+
127
+ The two undetected states look alike in a table and mean opposite things.
128
+
129
+ - **No-coverage** — no test reaches the line at all. The fix is a test that
130
+ executes it.
131
+ - **Survived** — a test *does* reach it and asserts nothing that would notice
132
+ the change. The fix is a stronger assertion in the test that already runs.
133
+ Adding another test that also does not look is the standard wrong answer, and
134
+ it raises line coverage while changing nothing.
135
+
136
+ The mutator name tells you what kind of hole it is:
137
+
138
+ | mutator | what its survival proves |
139
+ | --- | --- |
140
+ | `ConditionalExpression` | a branch condition can be forced true or false and nothing notices — usually one side of the branch is decorative. The most common survivor almost everywhere (359 of them in checkride's own repo) and the most informative |
141
+ | `BlockStatement` | an entire function body was emptied and the suite passed. The loudest signal in the table |
142
+ | `EqualityOperator` | a comparison flipped undetected — a boundary case nothing exercises |
143
+ | `LogicalOperator` | one arm of an `&&` / `\|\|` is never the deciding one in any test |
144
+ | `ArrayDeclaration`, `ObjectLiteral` | a literal was emptied unnoticed — the *contents* of that data are unasserted. Common on config tables, and often low-value (see below) |
145
+ | `Regex`, `StringLiteral` | the pattern or text is unasserted; frequently a message nobody should assert on |
146
+
147
+ **Not every survivor is worth killing.** Equivalent mutants — ones with no
148
+ observable behavior difference — are real and common: log text, a default
149
+ immediately overwritten, a `??` on a value that is never null. A suite driven to
150
+ 100% mutation score is a suite full of assertions on things nobody cares about.
151
+ Rank survivors by **what the mutant proves about a path a user can reach**, and
152
+ say when you are dismissing one and why.
153
+
154
+ **Rank is not priority.** The reader ranks files by undetected count, which
155
+ tracks file *size* at least as much as risk — `src/init.ts` tops checkride's own
156
+ table largely because it is the biggest file with the most mutants. Read what
157
+ the survivors are before treating the top row as the most important work.
158
+
159
+ ## 4. Ground the finding, or drop it
160
+
161
+ A finding must be able to name three things: **the artifact it came from, the
162
+ file and line, and — for a mutation finding — the test that should have caught
163
+ it and did not.** If you cannot name the test file you would edit, you have a
164
+ metric, not a finding.
165
+
166
+ So for the one or two survivors that look genuinely load-bearing:
167
+
168
+ 1. Open the source at the sample line the report gave you (`Read` with an
169
+ `offset`, not the whole file).
170
+ 2. Find the test that covers it — `src/__tests__/<name>.test.ts`, or `Grep` for
171
+ the function name.
172
+ 3. Read what that test asserts. The finding is the sentence that comes out:
173
+ *"`resolveOrder` is called in three tests and all three assert only the
174
+ length of the result, so flipping its `<=` to `<` changes nothing they
175
+ check."*
176
+
177
+ "Coverage could be improved here" is not that sentence.
178
+
179
+ **Open at most two or three files.** If the report ranks eight, read the top one
180
+ properly rather than all eight badly — the same economy the triage skill uses
181
+ when it opens exactly one artifact.
182
+
183
+ ## 5. Report
184
+
185
+ - **Evidence** — the covered-slot count, the run's age, then the ledger in a
186
+ line or two: what is fresh, what is stale and by how much, what was never
187
+ produced. Always first. A report that opens with a finding is a report that hid
188
+ its own uncertainty.
189
+ - **What the artifacts prove** — findings in evidence order, each grounded per
190
+ step 4. As many as the evidence supports, and no more.
191
+ - **What would produce the missing evidence** — the reader's own command or
192
+ config line for each gap. This is often the single most useful thing you can
193
+ say.
194
+ - **Judgment** — clearly labelled as yours, last, and only where it names a
195
+ file.
196
+
197
+ ### The failure mode this skill exists to prevent
198
+
199
+ **Produce no fixed-size list.** Not "top 5 issues", not eight findings, not one
200
+ per artifact. The count is whatever the evidence supports, and **zero is a
201
+ legitimate answer** — a repo with a fresh, empty `dead.json` and three
202
+ unmeasured dimensions has exactly one honest thing to report: that three of four
203
+ quality dimensions are unmeasured. Padding that to five means inventing four.
204
+
205
+ Three specific ways it goes wrong:
206
+
207
+ - **Restating the metric as a finding.** "Health score is 80.9/B" is the ledger.
208
+ A finding names which function costs the points and why.
209
+ - **Grading the grade.** No number in `health.json` is a defect; the thresholds
210
+ are a configured opinion, and the score is 100 minus the penalties. When
211
+ nothing is over any threshold and the whole penalty is hotspots and unit size,
212
+ say that — do not manufacture violations to explain a B.
213
+ - **Turning a ranked list into a to-do list.** The tables are ranked so you know
214
+ where to *look*. Copying the top five rows into "recommendations" is
215
+ transcription wearing analysis's clothes.
216
+
217
+ ## What this skill does not do
218
+
219
+ - **It runs nothing.** Not stryker (minutes to hours, and it rewrites your
220
+ source while it works), not fallow, not the gate. Naming the command is the
221
+ deliverable; running it is the human's call.
222
+ - **It does not gate.** None of these four dimensions has a pass/fail line, and
223
+ inventing one — "mutation score should be above 80" — turns a measurement into
224
+ a target, which is how it stops being a measurement.
225
+ - **It does not write tests.** Naming the unasserted branch is the deliverable.
226
+ Writing the test is the next request, and it should start from the named
227
+ mutant.
228
+ - **It does not triage a red gate.** That is the triage skill, which runs the
229
+ gate and reads different artifacts entirely.
230
+ - **It does not touch the baseline.** `checkride baseline` hides findings
231
+ permanently; that is never a reading step.
@@ -10,6 +10,7 @@
10
10
  "package.json",
11
11
  "CHANGELOG.md"
12
12
  ],
13
+ "ignoreRegExpList": ["/v1[0-9a-f]{16}/g"],
13
14
  "words": [
14
15
  "checkride",
15
16
  "baselined",
@@ -29,5 +29,5 @@
29
29
  }
30
30
  }
31
31
  ],
32
- "ignorePatterns": ["dist/**", ".check/**", ".claude/**", "node_modules/**"]
32
+ "ignorePatterns": ["dist/**", ".check/**", ".claude/**", ".cursor/**", "node_modules/**"]
33
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plumbbob",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "Attention-first build process: 12 skills + a CLI that keep you the decider — guidance on the work, a latch on the record.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -59,7 +59,7 @@
59
59
  "vitest": "4.1.9"
60
60
  },
61
61
  "dependencies": {
62
- "checkride": "0.5.2"
62
+ "checkride": "0.10.2"
63
63
  },
64
64
  "bundleDependencies": [
65
65
  "checkride"
@@ -16,14 +16,14 @@ another harness and go straight to `/plumbbob:verify` instead — plumbbob does
16
16
  the diff appeared. When you do run it, it reads the plan, writes the step, and
17
17
  carries straight through to the verify pause.
18
18
 
19
- Since `/plumbbob:plan` lays down the whole step list up front, the happy path is to fire
19
+ Since `/plumbbob:plan` lays down the whole step list up front, the happy path is to run
20
20
  `/plumbbob:build` once per step until done — each run builds the next undone step and stops
21
- at the pause for your approval. **Re-firing `/plumbbob:build` is itself the clock tick.**
21
+ at the pause for your approval. **Running `/plumbbob:build` again is itself the clock tick.**
22
22
 
23
23
  A model note: this skill **inherits the session model** — nothing pins or switches
24
24
  it. If the step you're about to build carries a `- model:` recommendation that
25
25
  differs from the model you're running as, say so before implementing — the human can
26
- `/model` and re-fire to honor it, or wave you on. Advisory, never a gate.
26
+ switch with `/model` and rerun to honor it, or wave you on. Advisory, never a gate.
27
27
 
28
28
  ## What this skill does, in order
29
29
 
@@ -42,7 +42,8 @@ differs from the model you're running as, say so before implementing — the hum
42
42
  `spike-NN-<slug>.md` in the build folder, stamped `via: step <n>`), then work the
43
43
  experiment and record your **Findings** and **Verdict** there. A recorded verdict is
44
44
  what the step's done-when should check — the report, not just the code, is the
45
- deliverable. This is the same artifact `/plumbbob:spike` produces for a mid-build fork (D70).
45
+ deliverable. This is the same artifact `/plumbbob:spike` produces for a mid-build fork
46
+ — D70 (spike-reports).
46
47
  3. **Read the plan.** Read the step's **done-when**, its **seam**, and the
47
48
  **Decisions** and **Constraints** in `intent.md`. Build to *that* — the deciding
48
49
  already happened, off the chat.
@@ -66,7 +67,8 @@ differs from the model you're running as, say so before implementing — the hum
66
67
  raw output under `.check/` for the actual diagnostics; while iterating on a fix,
67
68
  narrow the loop with `plumbbob check --bail --only <slots>` — the checkpoint gate
68
69
  still runs everything) → self-review the diff against the done-when, the Decisions,
69
- and the Constraints (a single structured read) → validate → **PAUSE
70
+ and the Constraints (a single structured read; cite each with its slug from
71
+ `intent.md` — `C1 (no-new-deps)`, never a bare `C1`) → validate → **PAUSE
70
72
  for the human's approval** → only on approval, checkpoint with
71
73
  `plumbbob checkpoint <n> --body <<'BODY' … BODY` — a commit body **proportional to the
72
74
  step** (a line for a trivial change, a short paragraph for a meatier one; no TIL scan,
@@ -74,13 +76,14 @@ differs from the model you're running as, say so before implementing — the hum
74
76
  build-log's `## Log`, so the history writes itself — you only supply the body (or omit
75
77
  `--body` for the deterministic done-when + seam + diffstat fallback). Do **not** bump
76
78
  the version or changelog — that is the human's `/version` call.
77
- - **A drifted subject is reconciled at the pause, never silently (D5/D6).** The planned
78
- title *is* the checkpoint subject (D1). If the diff drifted from it, **present** a
79
- corrected subject at the pause — `planned title → proposed subject`, one line — for
80
- explicit approval, and only on approval land it by adding `-m "<subject>"` to the
81
- checkpoint. Present nothing and the deterministic title-derived subject lands
82
- untouched: the reconcile is the human-approved exception, not a quiet `-m` swap (which
83
- is the agent-authored subject D68 refuses).
79
+ - **A drifted subject is reconciled at the pause, never silently.** The planned
80
+ title *is* the checkpoint subject — D68 (conventional-subjects). If the diff drifted
81
+ from it, **present** a corrected subject at the pause — `planned title → proposed
82
+ subject`, one line — for explicit approval, and only on approval land it by adding
83
+ `-m "<subject>"` to the checkpoint. Present nothing and the deterministic
84
+ title-derived subject lands untouched: the reconcile is the human-approved exception,
85
+ not a quiet `-m` swap (which is the agent-authored subject D68 (conventional-subjects)
86
+ refuses).
84
87
  - **If `plumbbob status` shows a `harness bindings:` block**, fold any bound
85
88
  `after`-agents into that self-review as advisory input — see **§ Running bound
86
89
  agents**.
@@ -110,7 +113,7 @@ differs from the model you're running as, say so before implementing — the hum
110
113
  run `plumbbob handoff` again and relay its boundary block — with the step gone from
111
114
  in-flight it renders "step N checkpointed" and points at the next undone step, carrying
112
115
  that step's `- model:` recommendation (the plan's smallest-model-that-fits call) so the
113
- human knows which `/model` to select before firing `/plumbbob:build` again. It is what
116
+ human knows which `/model` to select before running `/plumbbob:build` again. It is what
114
117
  carries the plan's suggestion across a fresh context window, which inherits the session
115
118
  model, not the plan's. No `- model:` line means any model will do. Guidance, never a
116
119
  gate.
@@ -131,10 +134,10 @@ harness *is* bound, this is what each affected step gains, in lifecycle order.
131
134
  `plumbbob agent run --step <n> --mode build` and let that agent author the step's code
132
135
  instead of writing it yourself; its envelope reports what it did. You still own the verify
133
136
  tick — the diff is reviewed the same way whoever wrote it.
134
- - **A manifest's `when` prose is your cue to fire an agent mid-build (step 4).** The three
137
+ - **A manifest's `when` prose is your cue to run an agent mid-build (step 4).** The three
135
138
  slots are the only *declarative* lifecycle points; there is no config for "a salient
136
139
  moment in the middle." That is judgment, and you are the frontier model in the room: when
137
- the work reaches the situation a bound agent's `when` (or a step `note`) describes, fire
140
+ the work reaches the situation a bound agent's `when` (or a step `note`) describes, run
138
141
  `plumbbob agent run <name> --step <n>` yourself. Prose is the orchestration language; you
139
142
  are the workflow engine.
140
143
  - **Route a non-`done` envelope by its status (step 4).** An agent that returns `blocked`
@@ -146,8 +149,8 @@ harness *is* bound, this is what each affected step gains, in lifecycle order.
146
149
  - **`after` — advisory input to the verify tick (step 5).** After `plumbbob check`, run any
147
150
  bound `after`-agents (`plumbbob agent run --step <n> --mode after`) and fold their
148
151
  envelopes into the self-review as **advisory input** — they inform, they never gate
149
- (checkride gates, the human is the clock; an `after`-agent that could fail a step is the
150
- lock in autonomy's costume).
152
+ (checkride gates, the human is the clock; an `after`-agent that could fail a step would
153
+ be the old lock back in another form).
151
154
 
152
155
  ## `--auto` — let the agent be the clock (opt-in)
153
156
 
@@ -220,8 +223,9 @@ just the one more entry already in the halt list above.
220
223
  Never route around it with a raw `git commit`. An explicit `/plumbbob:build --auto` or a typed
221
224
  step range in the human's own prompt are the only self-approvals — **never write `auto`
222
225
  into a settings file yourself to unlock a checkpoint. A grant you mint is no grant (the
223
- latch ignores it since D67); ask the human to re-fire `/plumbbob:build --auto` instead.**
226
+ latch ignores it — D67 (auto-not-a-grant)); ask the human to type
227
+ `/plumbbob:build --auto` again instead.**
224
228
  - **Close with the next model.** When a step lands, run `plumbbob handoff` and relay its
225
229
  block — it cites the completed step and the next undone step, and names that next step's
226
230
  `- model:` recommendation if it has one, which is what a fresh context window needs to
227
- pick the right `/model` before re-firing. Guidance, never a gate.
231
+ pick the right `/model` before the next run. Guidance, never a gate.
@@ -23,7 +23,9 @@ record.
23
23
  wrote a dated line for every step as it landed. **Read it as the spine; do not
24
24
  re-narrate it.** The report adds only what the log does not already carry:
25
25
  - **What shipped** — summarize from the `## Log` timeline; don't rebuild it step by step.
26
- - **Decisions and why** — the settled calls that shaped the build (the *why* behind the log).
26
+ - **Decisions and why** — the settled calls that shaped the build (the *why* behind
27
+ the log). Copy each one's `D# (slug)` from `intent.md` — never a bare `D#` — so
28
+ the report reads without flipping back to the intent.
27
29
  - **Parked & harvested** — what was captured and how each was classified.
28
30
  - **Final status** — done or partial, and what is left.
29
31
  - **Deferred tangents** — the harvested items that become future work.
@@ -42,6 +42,7 @@ one line of reasoning, then **wait for the human to confirm or override**. Write
42
42
  - Record each confirmed class in `build-log.md`'s `## Harvest` section.
43
43
  - **Flip the harvested item** from `- [ ]` to `- [x]` in the Park list, so `/plumbbob:status`
44
44
  stops counting it as open.
45
- - A confirmed **blocker** also folds its decision into `intent.md`.
45
+ - A confirmed **blocker** also folds its decision into `intent.md` — slugged at birth
46
+ like any Decision (`D5 (retry-cap): <the call> — *because* <why>`), never a bare `D5`.
46
47
  - Never reclassify or resolve an item the human hasn't confirmed, and default every
47
48
  uncertain item to **tangent**, never to blocker.
@@ -84,23 +84,24 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
84
84
  sharpened just-in-time when you reach them with `/plumbbob:step`. Keep each small enough to
85
85
  verify in one review pass.
86
86
 
87
- **The title *is* the commit subject — author it as one** *(D1)*: write each
87
+ **The title *is* the commit subject — author it as one**
88
+ ([D68 (conventional-subjects)](../../docs/decisions.md#d68)): write each
88
89
  `<title>` as a plain, single-line Conventional-Commit subject,
89
90
  `type(scope): description`, and it lands in `git log` verbatim (its breaking `!`
90
91
  honored) — this is how each step lands a *real* `feat`/`fix`/`chore` in the history.
91
92
  Keep load-bearing detail — file paths, module names — in `seam` and `done-when`; it is
92
- **never jammed into the title** (D2), which has to read as plain English and as a clean
93
+ **never jammed into the title**, which has to read as plain English and as a clean
93
94
  subject at once. Aim for **≤72 characters** (GitHub's subject convention) — soft
94
- guidance you eyeball at plan time, no lint, no gate (D9).
95
+ guidance you eyeball at plan time, no lint, no gate.
95
96
 
96
- **Set the build's default scope, then let steps override it** *(D8)*: fill the
97
+ **Set the build's default scope, then let steps override it**: fill the
97
98
  `**Scope:**` header once with a short feature-level name — the catch-all every step
98
99
  inherits — and give a step its own `(scope)` when it touches a distinct code area
99
100
  (`plan`, `commitmsg`, `docs`). A step's `(scope)` names the *code area*; the header
100
101
  names the *feature*, so scopes stay consistent and greppable across builds. Scope
101
102
  resolves title-scope → `**Scope:**` default → build slug → bare, and type resolves
102
103
  title-type → `feat`, so a scopeless plain title still yields a clean
103
- `feat(<slug>): <title>` unchanged ([D68](../../docs/decisions.md#d68), D3).
104
+ `feat(<slug>): <title>` unchanged.
104
105
 
105
106
  **Recommend a model per step where the signal is clear** *(optional)*: the
106
107
  `- model:` sub-line names the **smallest model that can carry the step**, with the
@@ -129,7 +130,7 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
129
130
 
130
131
  Keep it **bindings + prose only, never a conditional**: the file says *which*
131
132
  agent, not *when* — the host model reads each manifest's `when` prose and a step's
132
- `note` and decides when to fire one mid-build. Skip the file entirely when no step
133
+ `note` and decides when to run one mid-build. Skip the file entirely when no step
133
134
  uses an agent — the loop runs identically without it. The plan commit picks it
134
135
  up automatically (it lives in the build folder).
135
136
  6. **Commit the plan.** Once the human approves the frame and steps, run
@@ -143,7 +144,7 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
143
144
  - **The plan commit is latched too.** Once the turn ledger exists, `checkpoint
144
145
  --plan` refuses to land in the same turn `start` stamped it: present the plan,
145
146
  **end the turn**, and the human's approving message is the tick that lets it
146
- commit on re-fire — the refusal *is* the plan pause. Never route around it with a
147
+ commit on the next run — the refusal *is* the plan pause. Never route around it with a
147
148
  raw `git commit`. (One documented seam: the very first plan of a brand-new
148
149
  session runs `start` *before* the turn hook has ever ticked, so that single
149
150
  commit predates the ledger and stays guidance-governed — it lands without a
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: recover
3
+ description: Human-triggered driver for `plumbbob recover` — reconcile the control plane when the session looks wrong: a cursor pointing at a build that is gone, a step marked in flight that the plan no longer has, leftovers from an interrupted spike. Reports by default; `--fix` repairs the stale files it can.
4
+ argument-hint: "[--fix]"
5
+ disable-model-invocation: true
6
+ model: haiku
7
+ allowed-tools: Bash(plumbbob status:*), Bash(plumbbob recover:*)
8
+ ---
9
+
10
+ # PlumbBob — reconcile the control plane (driver)
11
+
12
+ Current session state (injected when this skill runs): !`plumbbob status 2>/dev/null || echo "plumbbob CLI not on PATH in this session. Marketplace install: confirm the plugin is enabled in /plugin, then /reload-plugins. Skills-dir/global install: npm i -g plumbbob && plumbbob init."`
13
+
14
+ This is a **driver skill** — a chat-side trigger for the mechanical `plumbbob recover` verb, so the whole workflow runs from the agent window instead of a terminal. It is `disable-model-invocation: true`: only the human fires it. It carries **no Edit and no Write tool** — its only action is to shell the verb and report the verb's output verbatim, including any refusal. The CLI is the source of truth: never retry a refused transition, and never edit a file to work around one.
15
+
16
+ Reach for it when the dashboard and reality disagree: `status` shows a build you thought you finished, or an empty plan for a build you know you wrote, or a step in flight you have no memory of starting. Those are the shapes a crashed session, a lost context window, or a mid-step build switch leaves behind. `/plumbbob:doctor` answers "is plumbbob installed correctly"; this answers "is this session's own state telling the truth".
17
+
18
+ ## What it does
19
+
20
+ 1. Run `plumbbob recover` via Bash. It reads the control plane — the active-build cursor, the step and spike markers, the latch's stamp, the agent handoff ledger, and any leftover spike worktrees — and prints one line per check.
21
+ 2. Report that output verbatim, `✓` and `✗` lines alike. Every problem carries a `→` line naming the fix; relay those as written rather than paraphrasing them into your own advice.
22
+ 3. **Only if the human asks for the repair**, run `plumbbob recover --fix`. It clears stale untracked control files and re-points a cursor when exactly one build survives. It never touches intent.md, the build log, the checkpoints ledger, a report, or git history — and it never lands or advances a step.
23
+
24
+ ## What it will not do for you
25
+
26
+ - **Spike leftovers are reported, never removed.** Those worktrees sit outside the repo and may hold the only copy of what a spike learned, so the verb prints the exact `git worktree remove` / `git branch -D` commands and stops. Relay them; do not run them yourself.
27
+ - **A contradictory phase is yours to settle.** A spike and a step both marked in flight, or a step number the plan no longer contains, need a decision about which one is real — `--fix` deliberately leaves them alone.
28
+ - **It is not a rewind.** Recovering reconciles bookkeeping; it never restores lost work. Discarding a half-done step is `/plumbbob:revert`, and that is a different, destructive move the human asks for by name.
@@ -44,10 +44,11 @@ is fine — refining is always available.
44
44
  by what you built, a Constraint changed, a Step no longer matches the seam, or a
45
45
  **step's title no longer describes what the diff actually does** — propose the edits
46
46
  that bring `intent.md` back in line with the truth. A step title *is* its checkpoint
47
- commit subject (D1), so bringing a drifted one back in line means keeping it a plain,
48
- single-line `type(scope): description` subject, with load-bearing detail (file paths,
49
- module names) in `seam` and `done-when`, **never jammed into the title** (D2) — the
50
- checkpoint body pass then reconciles and lands that subject at the verify pause (D5).
47
+ commit subject — D68 (conventional-subjects) — so bringing a drifted one back in line
48
+ means keeping it a plain, single-line `type(scope): description` subject, with
49
+ load-bearing detail (file paths, module names) in `seam` and `done-when`,
50
+ **never jammed into the title** — the checkpoint body pass then reconciles and lands
51
+ that subject at the verify pause.
51
52
  Show the before/after for each, and **write only what the human approves**.
52
53
 
53
54
  ## The hard contracts
@@ -19,7 +19,7 @@ This is a **driver skill** — a chat-side trigger for the mechanical `plumbbob
19
19
  2. Run `plumbbob spike "<slug>"`, `plumbbob spike report "<slug>"`, or `plumbbob spike done` via Bash.
20
20
  3. Report the verb's output verbatim — the worktree it created or removed, the spike report it scaffolded, or any refusal. When the verb names a `spike-NN-<slug>.md` report, point the human at it; when `spike done` nudges that a verdict is unrecorded, relay that nudge verbatim.
21
21
 
22
- ## The spike report (D70)
22
+ ## The spike report — D70 (spike-reports)
23
23
 
24
24
  Every spike leaves a durable `spike-NN-<slug>.md` in the build folder, beside `intent.md`/`report.md`, so the fork's verdict rides the branch into the PR instead of evaporating. The CLI scaffolds it from a template and numbers it — you never create or number the file:
25
25
 
@@ -16,7 +16,7 @@ build has actually taught you, right before you `/plumbbob:build` it. (Framing t
16
16
  is the separate `/plumbbob:plan` move.) It can also add or re-cut a step when scope genuinely
17
17
  grew — but its everyday job is to sharpen, not to invent.
18
18
 
19
- ## Two ways to fire it
19
+ ## Two ways to run it
20
20
 
21
21
  - **`/plumbbob:step` (no input) → automatic sharpen.** Re-examine the next undone step
22
22
  against the completed code, the Decisions, the Constraints, and the build-log, then
@@ -43,11 +43,11 @@ grew — but its everyday job is to sharpen, not to invent.
43
43
  sharpened `<title>` a plain, single-line Conventional-Commit subject,
44
44
  `type(scope): description` — it lands in `git log` verbatim, so as the step tightens
45
45
  keep load-bearing detail (file paths, module names) in `seam` and `done-when`,
46
- **never jammed into the title** (D1/D2). A sharpened step carries its own `(scope)`
46
+ **never jammed into the title**. A sharpened step carries its own `(scope)`
47
47
  when it touches a distinct code area — one that **overrides the build-default**
48
48
  `**Scope:**` header; drop the scope and it falls back to that default → build slug →
49
- bare, and the type to `feat` ([D68](../../docs/decisions.md#d68), D8). Aim for a soft
50
- ≤72 chars, no gate (D9). Revise the existing step in place; only append when you are
49
+ bare, and the type to `feat` ([D68 (conventional-subjects)](../../docs/decisions.md#d68)). Aim for a soft
50
+ ≤72 chars, no gate. Revise the existing step in place; only append when you are
51
51
  genuinely adding an increment.
52
52
  4. **Revise the step's harness bindings if they drifted too** *(optional)*. If the
53
53
  build carries a `harness.json` (beside `intent.md`) and the reality that moved the
@@ -11,7 +11,8 @@ Current session state (injected when this skill runs): !`plumbbob status 2>/dev/
11
11
 
12
12
  This is the **tick** — the one beat where the human is the clock. Whatever produced
13
13
  the current diff — `/plumbbob:build`, your own hands, a vibe session, another harness —
14
- this skill verifies it the same way: **it reads the diff, not the author**.
14
+ this skill verifies it the same way: **it reads the diff, not the author** — D3
15
+ (author-blind-executor).
15
16
 
16
17
  ## What this skill does, in order
17
18
 
@@ -27,7 +28,7 @@ this skill verifies it the same way: **it reads the diff, not the author**.
27
28
  binds agents to this step's `after` slot, run `plumbbob agent run --step <n> --mode
28
29
  after`. Their envelopes are **advisory input to the self-review, never a gate** —
29
30
  `plumbbob check` already gated in step 1, and an `after`-agent that could fail a step
30
- is the lock returning in autonomy's costume. Fold a `done` envelope's
31
+ would be the old lock back in another form. Fold a `done` envelope's
31
32
  `summary`/`body` into the review below; route a non-`done` one by its status: a
32
33
  `blocked` agent couldn't finish — surface its `notes`, let the human unblock, re-run;
33
34
  a `drift` agent found the plan no longer matches reality — stop and send the human to
@@ -39,20 +40,23 @@ this skill verifies it the same way: **it reads the diff, not the author**.
39
40
  - the **Decisions** — does anything contradict a settled call?
40
41
  - the **Constraints** — are any violated?
41
42
  - any **`after`-agent findings** from step 2 — advisory, weigh them, don't defer to them.
42
- Surface every mismatch plainly. You are reviewing, not building — do not fix anything.
43
+ Surface every mismatch plainly, and when you cite a Decision or Constraint, carry its
44
+ slug from `intent.md` — `C1 (no-new-deps)`, never a bare `C1` — so each finding reads
45
+ on its own. You are reviewing, not building — do not fix anything.
43
46
  4. **Validate.** State, yes or no, whether the step's done-when is met, with the evidence.
44
47
  5. **PAUSE.** Present the check result, the self-review (with any `after`-agent
45
48
  findings), and the validation, then
46
49
  **stop and wait for the human's explicit approval.** This is the convergence beat;
47
50
  the human is the clock. Never checkpoint without it.
48
- - **Reconcile a drifted subject here, in the open (D5).** The planned title *is* the
49
- checkpoint subject (D1). If the diff drifted from it — the step landed something the
50
- title no longer describes — the body pass may propose a corrected subject, but it
51
- **presents** it at this pause for explicit approval: show `planned title → proposed
52
- subject`, one line, as part of what the human OKs. This is the exception, not the
53
- default (D6): with **nothing presented**, the deterministic title-derived subject
54
- lands untouched. A silent `-m` swap is exactly the agent-authored subject D68 refuses
55
- — so a reconcile is *only ever* the visible, approved kind.
51
+ - **Reconcile a drifted subject here, in the open.** The planned title *is* the
52
+ checkpoint subject — D68 (conventional-subjects). If the diff drifted from it — the
53
+ step landed something the title no longer describes — the body pass may propose a
54
+ corrected subject, but it **presents** it at this pause for explicit approval: show
55
+ `planned title → proposed subject`, one line, as part of what the human OKs. This is
56
+ the exception, not the default: with **nothing presented**, the deterministic
57
+ title-derived subject lands untouched. A silent `-m` swap is exactly the
58
+ agent-authored subject D68 (conventional-subjects) refuses — so a reconcile is
59
+ *only ever* the visible, approved kind.
56
60
  6. **Checkpoint** *(only after approval)*. Run `plumbbob checkpoint`: it makes the WIP
57
61
  commit, records the SHA, flips the step to done, appends the step to the build-log's
58
62
  `## Log`, and returns to DESIGN. The CLI owns the commit **subject** — a Conventional
@@ -79,7 +83,7 @@ this skill verifies it the same way: **it reads the diff, not the author**.
79
83
  step gone from in-flight it renders `step N checkpointed — back at the boundary` and
80
84
  points at the **next undone step**, carrying that step's `- model:` recommendation (the
81
85
  plan's smallest-model-that-fits call) so the human knows which `/model` to select before
82
- firing `/plumbbob:build` again. This matters most across a context boundary: a fresh window
86
+ running `/plumbbob:build` again. This matters most across a context boundary: a fresh window
83
87
  inherits the *session's* model, not the plan's suggestion, so this line is what carries
84
88
  the recommendation over. The CLI owns the block, so it can't drift from what `plumbbob
85
89
  status` reports; no `- model:` line means any model will do. Guidance, never a gate.
@@ -91,13 +95,14 @@ land a step in the same turn it was entered** — and that refusal **is** this p
91
95
  an error to route around. If the checkpoint prints *"checkpoint refused — no human turn
92
96
  since this step began,"* you have reached the pause the hard way: present the diff and
93
97
  the self-review, **end the turn**, and the human's next message is the tick that lets
94
- the checkpoint land when you re-fire. **Never reach for a raw `git commit` to force the
98
+ the checkpoint land when you run it again. **Never reach for a raw `git commit` to force the
95
99
  land** — that forges the very record the latch exists to keep honest, and the
96
100
  commit-ask hook asks the human about it anyway. The refusal is a healthy latch doing its
97
101
  job on the *record* while the *work* plane stays free; a `/plumbbob:build --auto` or
98
102
  a typed step range in the human's own prompt is the only self-approval — **never write
99
103
  `auto` into a settings file to unlock the land; the latch ignores a model-minted grant
100
- (D67), so ask the human to re-fire `/plumbbob:build --auto` instead.**
104
+ — D67 (auto-not-a-grant) — so ask the human to type `/plumbbob:build --auto` again
105
+ instead.**
101
106
 
102
107
  ## The hard contracts
103
108