paperlint 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (762) hide show
  1. package/.github/dependabot.yml +72 -0
  2. package/.github/workflows/ci.yml +297 -0
  3. package/.github/workflows/dependabot-automerge.yml +70 -0
  4. package/.github/workflows/pr-title.yml +59 -0
  5. package/.github/workflows/release.yml +54 -0
  6. package/CLAUDE.md +598 -0
  7. package/CONTRIBUTING.md +159 -0
  8. package/LICENSE +21 -0
  9. package/README.md +240 -0
  10. package/action.harness.mjs +287 -0
  11. package/action.mutations.mjs +162 -0
  12. package/action.yml +138 -0
  13. package/bin/rpp.mjs +43 -0
  14. package/dist/action-ref.d.ts +12 -0
  15. package/dist/action-ref.d.ts.map +1 -0
  16. package/dist/action-ref.js +16 -0
  17. package/dist/action-ref.js.map +1 -0
  18. package/dist/adapters/banal/failure.d.ts +73 -0
  19. package/dist/adapters/banal/failure.d.ts.map +1 -0
  20. package/dist/adapters/banal/failure.js +58 -0
  21. package/dist/adapters/banal/failure.js.map +1 -0
  22. package/dist/adapters/banal/index.d.ts +17 -0
  23. package/dist/adapters/banal/index.d.ts.map +1 -0
  24. package/dist/adapters/banal/index.js +56 -0
  25. package/dist/adapters/banal/index.js.map +1 -0
  26. package/dist/adapters/banal/install.d.ts +26 -0
  27. package/dist/adapters/banal/install.d.ts.map +1 -0
  28. package/dist/adapters/banal/install.js +15 -0
  29. package/dist/adapters/banal/install.js.map +1 -0
  30. package/dist/adapters/banal/invocation.d.ts +48 -0
  31. package/dist/adapters/banal/invocation.d.ts.map +1 -0
  32. package/dist/adapters/banal/invocation.js +43 -0
  33. package/dist/adapters/banal/invocation.js.map +1 -0
  34. package/dist/adapters/banal/locate.d.ts +50 -0
  35. package/dist/adapters/banal/locate.d.ts.map +1 -0
  36. package/dist/adapters/banal/locate.js +34 -0
  37. package/dist/adapters/banal/locate.js.map +1 -0
  38. package/dist/adapters/banal/output.d.ts +27 -0
  39. package/dist/adapters/banal/output.d.ts.map +1 -0
  40. package/dist/adapters/banal/output.js +112 -0
  41. package/dist/adapters/banal/output.js.map +1 -0
  42. package/dist/adapters/banal/pin.d.ts +19 -0
  43. package/dist/adapters/banal/pin.d.ts.map +1 -0
  44. package/dist/adapters/banal/pin.js +15 -0
  45. package/dist/adapters/banal/pin.js.map +1 -0
  46. package/dist/adapters/banal/probe.d.ts +12 -0
  47. package/dist/adapters/banal/probe.d.ts.map +1 -0
  48. package/dist/adapters/banal/probe.js +27 -0
  49. package/dist/adapters/banal/probe.js.map +1 -0
  50. package/dist/adapters/banal/run.d.ts +89 -0
  51. package/dist/adapters/banal/run.d.ts.map +1 -0
  52. package/dist/adapters/banal/run.js +104 -0
  53. package/dist/adapters/banal/run.js.map +1 -0
  54. package/dist/adapters/banal/settings.d.ts +18 -0
  55. package/dist/adapters/banal/settings.d.ts.map +1 -0
  56. package/dist/adapters/banal/settings.js +29 -0
  57. package/dist/adapters/banal/settings.js.map +1 -0
  58. package/dist/adapters/banal/xml.d.ts +48 -0
  59. package/dist/adapters/banal/xml.d.ts.map +1 -0
  60. package/dist/adapters/banal/xml.js +67 -0
  61. package/dist/adapters/banal/xml.js.map +1 -0
  62. package/dist/adapters/curl/download.io.d.ts +14 -0
  63. package/dist/adapters/curl/download.io.d.ts.map +1 -0
  64. package/dist/adapters/curl/download.io.js +69 -0
  65. package/dist/adapters/curl/download.io.js.map +1 -0
  66. package/dist/adapters/curl/index.d.ts +6 -0
  67. package/dist/adapters/curl/index.d.ts.map +1 -0
  68. package/dist/adapters/curl/index.js +6 -0
  69. package/dist/adapters/curl/index.js.map +1 -0
  70. package/dist/adapters/memory/index.d.ts +43 -0
  71. package/dist/adapters/memory/index.d.ts.map +1 -0
  72. package/dist/adapters/memory/index.js +79 -0
  73. package/dist/adapters/memory/index.js.map +1 -0
  74. package/dist/adapters/node/files.io.d.ts +3 -0
  75. package/dist/adapters/node/files.io.d.ts.map +1 -0
  76. package/dist/adapters/node/files.io.js +31 -0
  77. package/dist/adapters/node/files.io.js.map +1 -0
  78. package/dist/adapters/node/host.io.d.ts +3 -0
  79. package/dist/adapters/node/host.io.d.ts.map +1 -0
  80. package/dist/adapters/node/host.io.js +14 -0
  81. package/dist/adapters/node/host.io.js.map +1 -0
  82. package/dist/adapters/node/index.d.ts +25 -0
  83. package/dist/adapters/node/index.d.ts.map +1 -0
  84. package/dist/adapters/node/index.js +14 -0
  85. package/dist/adapters/node/index.js.map +1 -0
  86. package/dist/adapters/node/process.io.d.ts +14 -0
  87. package/dist/adapters/node/process.io.d.ts.map +1 -0
  88. package/dist/adapters/node/process.io.js +41 -0
  89. package/dist/adapters/node/process.io.js.map +1 -0
  90. package/dist/adapters/node/workspace.io.d.ts +4 -0
  91. package/dist/adapters/node/workspace.io.d.ts.map +1 -0
  92. package/dist/adapters/node/workspace.io.js +33 -0
  93. package/dist/adapters/node/workspace.io.js.map +1 -0
  94. package/dist/adapters/pdfjs/fill.d.ts +42 -0
  95. package/dist/adapters/pdfjs/fill.d.ts.map +1 -0
  96. package/dist/adapters/pdfjs/fill.js +91 -0
  97. package/dist/adapters/pdfjs/fill.js.map +1 -0
  98. package/dist/build-engine.d.ts +48 -0
  99. package/dist/build-engine.d.ts.map +1 -0
  100. package/dist/build-engine.js +148 -0
  101. package/dist/build-engine.js.map +1 -0
  102. package/dist/build.d.ts +163 -0
  103. package/dist/build.d.ts.map +1 -0
  104. package/dist/build.js +575 -0
  105. package/dist/build.js.map +1 -0
  106. package/dist/cli.d.ts +151 -0
  107. package/dist/cli.d.ts.map +1 -0
  108. package/dist/cli.js +951 -0
  109. package/dist/cli.js.map +1 -0
  110. package/dist/doctor.d.ts +42 -0
  111. package/dist/doctor.d.ts.map +1 -0
  112. package/dist/doctor.js +280 -0
  113. package/dist/doctor.js.map +1 -0
  114. package/dist/domain/geometry.d.ts +71 -0
  115. package/dist/domain/geometry.d.ts.map +1 -0
  116. package/dist/domain/geometry.js +35 -0
  117. package/dist/domain/geometry.js.map +1 -0
  118. package/dist/domain/host.d.ts +16 -0
  119. package/dist/domain/host.d.ts.map +1 -0
  120. package/dist/domain/host.js +8 -0
  121. package/dist/domain/host.js.map +1 -0
  122. package/dist/domain/page-layout.d.ts +34 -0
  123. package/dist/domain/page-layout.d.ts.map +1 -0
  124. package/dist/domain/page-layout.js +8 -0
  125. package/dist/domain/page-layout.js.map +1 -0
  126. package/dist/domain/paths.d.ts +5 -0
  127. package/dist/domain/paths.d.ts.map +1 -0
  128. package/dist/domain/paths.js +2 -0
  129. package/dist/domain/paths.js.map +1 -0
  130. package/dist/domain/result.d.ts +23 -0
  131. package/dist/domain/result.d.ts.map +1 -0
  132. package/dist/domain/result.js +10 -0
  133. package/dist/domain/result.js.map +1 -0
  134. package/dist/domain/sha256.d.ts +7 -0
  135. package/dist/domain/sha256.d.ts.map +1 -0
  136. package/dist/domain/sha256.js +14 -0
  137. package/dist/domain/sha256.js.map +1 -0
  138. package/dist/domain/text.d.ts +6 -0
  139. package/dist/domain/text.d.ts.map +1 -0
  140. package/dist/domain/text.js +7 -0
  141. package/dist/domain/text.js.map +1 -0
  142. package/dist/engine.d.ts +93 -0
  143. package/dist/engine.d.ts.map +1 -0
  144. package/dist/engine.js +119 -0
  145. package/dist/engine.js.map +1 -0
  146. package/dist/exit-code.d.ts +22 -0
  147. package/dist/exit-code.d.ts.map +1 -0
  148. package/dist/exit-code.js +10 -0
  149. package/dist/exit-code.js.map +1 -0
  150. package/dist/facts-file.d.ts +96 -0
  151. package/dist/facts-file.d.ts.map +1 -0
  152. package/dist/facts-file.js +134 -0
  153. package/dist/facts-file.js.map +1 -0
  154. package/dist/hooks-settings.d.ts +141 -0
  155. package/dist/hooks-settings.d.ts.map +1 -0
  156. package/dist/hooks-settings.js +306 -0
  157. package/dist/hooks-settings.js.map +1 -0
  158. package/dist/init.d.ts +201 -0
  159. package/dist/init.d.ts.map +1 -0
  160. package/dist/init.js +579 -0
  161. package/dist/init.js.map +1 -0
  162. package/dist/latex-log.d.ts +80 -0
  163. package/dist/latex-log.d.ts.map +1 -0
  164. package/dist/latex-log.js +187 -0
  165. package/dist/latex-log.js.map +1 -0
  166. package/dist/latex-loop.d.ts +129 -0
  167. package/dist/latex-loop.d.ts.map +1 -0
  168. package/dist/latex-loop.js +113 -0
  169. package/dist/latex-loop.js.map +1 -0
  170. package/dist/link-skills.d.ts +51 -0
  171. package/dist/link-skills.d.ts.map +1 -0
  172. package/dist/link-skills.js +199 -0
  173. package/dist/link-skills.js.map +1 -0
  174. package/dist/new-paper.d.ts +48 -0
  175. package/dist/new-paper.d.ts.map +1 -0
  176. package/dist/new-paper.js +110 -0
  177. package/dist/new-paper.js.map +1 -0
  178. package/dist/pdf-facts.d.ts +44 -0
  179. package/dist/pdf-facts.d.ts.map +1 -0
  180. package/dist/pdf-facts.js +239 -0
  181. package/dist/pdf-facts.js.map +1 -0
  182. package/dist/pdf-geometry.d.ts +170 -0
  183. package/dist/pdf-geometry.d.ts.map +1 -0
  184. package/dist/pdf-geometry.js +158 -0
  185. package/dist/pdf-geometry.js.map +1 -0
  186. package/dist/ports/download.d.ts +9 -0
  187. package/dist/ports/download.d.ts.map +1 -0
  188. package/dist/ports/download.js +2 -0
  189. package/dist/ports/download.js.map +1 -0
  190. package/dist/ports/files.d.ts +11 -0
  191. package/dist/ports/files.d.ts.map +1 -0
  192. package/dist/ports/files.js +2 -0
  193. package/dist/ports/files.js.map +1 -0
  194. package/dist/ports/measure-geometry.d.ts +8 -0
  195. package/dist/ports/measure-geometry.d.ts.map +1 -0
  196. package/dist/ports/measure-geometry.js +2 -0
  197. package/dist/ports/measure-geometry.js.map +1 -0
  198. package/dist/ports/process.d.ts +45 -0
  199. package/dist/ports/process.d.ts.map +1 -0
  200. package/dist/ports/process.js +2 -0
  201. package/dist/ports/process.js.map +1 -0
  202. package/dist/ports/tool-installer.d.ts +29 -0
  203. package/dist/ports/tool-installer.d.ts.map +1 -0
  204. package/dist/ports/tool-installer.js +2 -0
  205. package/dist/ports/tool-installer.js.map +1 -0
  206. package/dist/ports/workspace.d.ts +18 -0
  207. package/dist/ports/workspace.d.ts.map +1 -0
  208. package/dist/ports/workspace.js +2 -0
  209. package/dist/ports/workspace.js.map +1 -0
  210. package/dist/rules-config.d.ts +34 -0
  211. package/dist/rules-config.d.ts.map +1 -0
  212. package/dist/rules-config.js +132 -0
  213. package/dist/rules-config.js.map +1 -0
  214. package/dist/structure.d.ts +34 -0
  215. package/dist/structure.d.ts.map +1 -0
  216. package/dist/structure.js +149 -0
  217. package/dist/structure.js.map +1 -0
  218. package/dist/tex-requirements.d.ts +43 -0
  219. package/dist/tex-requirements.d.ts.map +1 -0
  220. package/dist/tex-requirements.js +127 -0
  221. package/dist/tex-requirements.js.map +1 -0
  222. package/dist/toolchain.d.ts +159 -0
  223. package/dist/toolchain.d.ts.map +1 -0
  224. package/dist/toolchain.js +542 -0
  225. package/dist/toolchain.js.map +1 -0
  226. package/dist/types.d.ts +110 -0
  227. package/dist/types.d.ts.map +1 -0
  228. package/dist/types.js +2 -0
  229. package/dist/types.js.map +1 -0
  230. package/docs/configuration.md +235 -0
  231. package/docs/e2e.md +152 -0
  232. package/docs/incidents.md +59 -0
  233. package/docs/install.md +170 -0
  234. package/docs/optional-rules.md +107 -0
  235. package/docs/package-shape-options.md +262 -0
  236. package/docs/prior-art/README.md +76 -0
  237. package/docs/prior-art/blocking-vs-advisory.md +83 -0
  238. package/docs/prior-art/content-delivery.md +124 -0
  239. package/docs/prior-art/multi-mode-tools.md +106 -0
  240. package/docs/prior-art/nondeterministic-checks.md +99 -0
  241. package/docs/prior-art/package-location.md +422 -0
  242. package/docs/prior-art/paper-folder-scaffolding.md +538 -0
  243. package/docs/prior-art/readme-structure.md +69 -0
  244. package/docs/prior-art/repro/README.md +92 -0
  245. package/docs/prior-art/repro/claim1-allowedtools.mjs +66 -0
  246. package/docs/prior-art/repro/claim1-at2.mjs +40 -0
  247. package/docs/prior-art/repro/claim1-crosschannel.mjs +54 -0
  248. package/docs/prior-art/repro/claim1-frontmatter.mjs +76 -0
  249. package/docs/prior-art/repro/claim1-hook-payload-reporter.mjs +10 -0
  250. package/docs/prior-art/repro/claim1-plugin-frontmatter.mjs +27 -0
  251. package/docs/prior-art/repro/claim1-plugin-skill.mjs +52 -0
  252. package/docs/prior-art/repro/claim1-project-skill.mjs +81 -0
  253. package/docs/prior-art/repro/claim2-marketplace-flat-asclaimed.json +1 -0
  254. package/docs/prior-art/repro/claim2-marketplace-negative-control.json +1 -0
  255. package/docs/prior-art/repro/claim2-marketplace-nested-exact.json +9 -0
  256. package/docs/prior-art/repro/claim2-marketplace-nested-noversion.json +9 -0
  257. package/docs/prior-art/repro/claim2-marketplace-nested-range.json +1 -0
  258. package/docs/prior-art/repro/claim3-imports.mjs +50 -0
  259. package/docs/prior-art/repro/claim4-find-package-json.mjs +8 -0
  260. package/docs/prior-art/repro/claim4-package-dir.mjs +39 -0
  261. package/docs/prior-art/repro/claim4-parent-arg.mjs +17 -0
  262. package/docs/prior-art/repro/claim4-resolve-apis.mjs +21 -0
  263. package/docs/prior-art/repro/claim4-setup-consumers.mjs +45 -0
  264. package/docs/prior-art/repro/claim4-yarn-pnp.mjs +70 -0
  265. package/docs/prior-art/repro/claim5-bin-launch.mjs +39 -0
  266. package/docs/prior-art/repro/claim5-exports-mutation.mjs +57 -0
  267. package/docs/prior-art/repro/claim5-resolved-location-and-bin.mjs +33 -0
  268. package/docs/prior-art/repro/claim6-candidate-ambiguity.mjs +17 -0
  269. package/docs/prior-art/repro/claim6-doc-path-candidates.mjs +27 -0
  270. package/docs/prior-art/test-tooling.md +131 -0
  271. package/docs/rules.md +58 -0
  272. package/docs/texlive-install-decision.md +230 -0
  273. package/docs/toolchain.md +152 -0
  274. package/eslint-rules/doc-fields.harness.mjs +336 -0
  275. package/eslint-rules/doc-fields.mjs +186 -0
  276. package/eslint-rules/doc-fields.mutations.mjs +96 -0
  277. package/eslint-rules/install-path-literals.harness.mjs +121 -0
  278. package/eslint-rules/install-path-literals.mjs +108 -0
  279. package/eslint-rules/install-path-literals.mutations.mjs +62 -0
  280. package/eslint-rules/latex-language.harness.mjs +599 -0
  281. package/eslint-rules/latex-language.mjs +591 -0
  282. package/eslint-rules/latex-language.mutations.mjs +196 -0
  283. package/eslint-rules/paper-research-question.harness.mjs +146 -0
  284. package/eslint-rules/paper-research-question.mjs +180 -0
  285. package/eslint-rules/paper-research-question.mutations.mjs +127 -0
  286. package/eslint-rules/paper-stages.harness.mjs +356 -0
  287. package/eslint-rules/paper-stages.mjs +455 -0
  288. package/eslint-rules/paper-stages.mutations.mjs +157 -0
  289. package/eslint-rules/paper-typography.harness.mjs +291 -0
  290. package/eslint-rules/paper-typography.mjs +313 -0
  291. package/eslint-rules/paper-typography.mutations.mjs +131 -0
  292. package/eslint-rules/papers.harness.mjs +259 -0
  293. package/eslint-rules/papers.mjs +166 -0
  294. package/eslint-rules/papers.mutations.mjs +186 -0
  295. package/eslint-rules/pdf-last-page-balance.harness.mjs +206 -0
  296. package/eslint-rules/pdf-last-page-balance.mjs +208 -0
  297. package/eslint-rules/review-findings-cause.harness.mjs +228 -0
  298. package/eslint-rules/review-findings-cause.mjs +135 -0
  299. package/eslint-rules/review-findings-cause.mutations.mjs +72 -0
  300. package/eslint-rules/temp-root-realpath.harness.mjs +176 -0
  301. package/eslint-rules/temp-root-realpath.mjs +129 -0
  302. package/eslint-rules/temp-root-realpath.mutations.mjs +99 -0
  303. package/eslint-rules/tex-build.harness.mjs +753 -0
  304. package/eslint-rules/tex-build.mjs +322 -0
  305. package/eslint-rules/tex-build.mutations.mjs +258 -0
  306. package/eslint.config.mjs +521 -0
  307. package/fixtures/build-e2e/acmart/PIPELINE-STATUS.md +3 -0
  308. package/fixtures/build-e2e/acmart/paper.tex +11 -0
  309. package/fixtures/build-e2e/acmart/venue.json +1 -0
  310. package/fixtures/build-e2e/broken/PIPELINE-STATUS.md +3 -0
  311. package/fixtures/build-e2e/broken/paper.tex +7 -0
  312. package/fixtures/build-e2e/cite/PIPELINE-STATUS.md +3 -0
  313. package/fixtures/build-e2e/cite/build.sh +5 -0
  314. package/fixtures/build-e2e/cite/paper.tex +10 -0
  315. package/fixtures/build-e2e/cite/refs.bib +9 -0
  316. package/fixtures/build-e2e/empty/PIPELINE-STATUS.md +3 -0
  317. package/fixtures/build-e2e/empty/paper.tex +6 -0
  318. package/fixtures/build-e2e/fallback/PIPELINE-STATUS.md +3 -0
  319. package/fixtures/build-e2e/fallback/paper.tex +11 -0
  320. package/fixtures/build-e2e/guards/PIPELINE-STATUS.md +3 -0
  321. package/fixtures/build-e2e/guards/paper.tex +10 -0
  322. package/fixtures/build-e2e/no-source/PIPELINE-STATUS.md +3 -0
  323. package/fixtures/build-e2e/unbalanced/PIPELINE-STATUS.md +3 -0
  324. package/fixtures/build-e2e/unbalanced/paper.tex +28 -0
  325. package/fixtures/build-e2e/unbalanced/refs.bib +269 -0
  326. package/fixtures/install-path-literals/clean.fixture.mjs +3 -0
  327. package/fixtures/install-path-literals/clean.md +15 -0
  328. package/fixtures/install-path-literals/defect.fixture.mjs +3 -0
  329. package/fixtures/install-path-literals/defect.md +14 -0
  330. package/fixtures/latex-language/clean.tex +50 -0
  331. package/fixtures/latex-language/defect.tex +52 -0
  332. package/fixtures/paper-research-question/comment-only/PIPELINE-STATUS.md +9 -0
  333. package/fixtures/paper-research-question/comment-only/paper.tex +7 -0
  334. package/fixtures/paper-research-question/declared-not-in-paper/PIPELINE-STATUS.md +10 -0
  335. package/fixtures/paper-research-question/declared-not-in-paper/paper.tex +6 -0
  336. package/fixtures/paper-research-question/draft/PIPELINE-STATUS.md +6 -0
  337. package/fixtures/paper-research-question/draft/paper.tex +2 -0
  338. package/fixtures/paper-research-question/markdown-no-rq/PIPELINE-STATUS.md +9 -0
  339. package/fixtures/paper-research-question/markdown-no-rq/paper.md +4 -0
  340. package/fixtures/paper-research-question/shipped-no-rq/PIPELINE-STATUS.md +12 -0
  341. package/fixtures/paper-research-question/shipped-no-rq/paper.tex +3 -0
  342. package/fixtures/paper-research-question/shipped-with-rq/PIPELINE-STATUS.md +10 -0
  343. package/fixtures/paper-research-question/shipped-with-rq/paper.tex +2 -0
  344. package/fixtures/paper-stages/authors-ran/PIPELINE-STATUS.md +16 -0
  345. package/fixtures/paper-stages/marker-in-prose/PIPELINE-STATUS.md +17 -0
  346. package/fixtures/paper-stages/nofile/PIPELINE-STATUS.md +8 -0
  347. package/fixtures/paper-stages/noheader/PIPELINE-STATUS.md +1 -0
  348. package/fixtures/paper-stages/noheader/versions/2026-07-22-submitted.pdf +0 -0
  349. package/fixtures/paper-stages/nothing/PIPELINE-STATUS.md +3 -0
  350. package/fixtures/paper-stages/ok/PIPELINE-STATUS.md +9 -0
  351. package/fixtures/paper-stages/ok/versions/2026-07-22-submitted.pdf +0 -0
  352. package/fixtures/paper-stages/stale/PIPELINE-STATUS.md +1 -0
  353. package/fixtures/paper-stages/stale/versions/2026-07-22-submitted.STALE-WRONG-FILE.pdf +0 -0
  354. package/fixtures/paper-stages/twice/PIPELINE-STATUS.md +14 -0
  355. package/fixtures/paper-stages/twice/versions/2026-08-06-submitted.pdf +0 -0
  356. package/fixtures/paper-stages/twice/versions/2026-10-24-submitted.pdf +0 -0
  357. package/fixtures/paper-stages/undeclared/PIPELINE-STATUS.md +8 -0
  358. package/fixtures/paper-stages/undeclared/versions/2026-07-22-submitted.pdf +0 -0
  359. package/fixtures/paper-stages/undeclared/versions/2026-08-29-camera-ready.pdf +0 -0
  360. package/fixtures/paper-stages/wrongsize/PIPELINE-STATUS.md +8 -0
  361. package/fixtures/paper-stages/wrongsize/versions/2026-07-22-submitted.pdf +0 -0
  362. package/fixtures/paper-typography/clean-paper/paper.tex +29 -0
  363. package/fixtures/paper-typography/messy-paper/paper.tex +27 -0
  364. package/fixtures/pdf-facts/README.md +22 -0
  365. package/fixtures/pdf-facts/corrupt-font.pdf +0 -0
  366. package/fixtures/pdf-facts/encrypted.pdf +0 -0
  367. package/fixtures/pdf-facts/hidden-text.pdf +0 -0
  368. package/fixtures/pdf-facts/hidden-text.tex +28 -0
  369. package/fixtures/pdf-facts/t3-all.pdf +0 -0
  370. package/fixtures/pdf-facts/t3-all.tex +8 -0
  371. package/fixtures/pdf-facts/t3-mixed.pdf +0 -0
  372. package/fixtures/pdf-facts/t3-mixed.tex +9 -0
  373. package/fixtures/pdf-facts/ttf.pdf +2240 -1
  374. package/fixtures/pdf-facts/ttf.tex +6 -0
  375. package/fixtures/real-markdown-paper/baseline.json +24 -0
  376. package/fixtures/real-markdown-paper/baseline.mjs +48 -0
  377. package/fixtures/render-paper/build-clean.sh +25 -0
  378. package/fixtures/render-paper/build-defect.sh +15 -0
  379. package/fixtures/review-findings-cause/clean.md +17 -0
  380. package/fixtures/review-findings-cause/defect.md +14 -0
  381. package/fixtures/review-findings-cause/old-debt.md +14 -0
  382. package/fixtures/review-findings-cause/quiet-in-fence.md +16 -0
  383. package/fixtures/tex-build/clean.tex +21 -0
  384. package/fixtures/tex-build/defect.tex +24 -0
  385. package/fixtures/tex-build/frontmatter-clean.tex +25 -0
  386. package/fixtures/tex-build/frontmatter-defect.tex +23 -0
  387. package/fixtures/toolchain-mirror/catalog.txt +5 -0
  388. package/fixtures/toolchain-mirror/install-tl +27 -0
  389. package/fixtures/toolchain-mirror/release-texlive.txt +3 -0
  390. package/fixtures/toolchain-mirror/release-year +1 -0
  391. package/fixtures/toolchain-mirror/stub-kpsewhich +8 -0
  392. package/fixtures/toolchain-mirror/stub-pdflatex +3 -0
  393. package/fixtures/toolchain-mirror/stub-tlmgr +44 -0
  394. package/hooks/hooks.harness.mjs +713 -0
  395. package/hooks/hooks.mutations.mjs +337 -0
  396. package/hooks/paper-edit-guard.hook.d.mts +13 -0
  397. package/hooks/paper-edit-guard.hook.mjs +457 -0
  398. package/hooks/paper-skills-nudge.hook.mjs +136 -0
  399. package/hooks/paper-status-gates.hook.mjs +156 -0
  400. package/hooks/paper-status-gates.sh +91 -0
  401. package/lib/agent-cli-version.harness.mjs +165 -0
  402. package/lib/agent-cli-version.mjs +106 -0
  403. package/lib/agent-cli-version.mutations.mjs +109 -0
  404. package/lib/markdown.mjs +386 -0
  405. package/lib/mutation-driver.harness.mjs +227 -0
  406. package/lib/mutation-driver.mjs +397 -0
  407. package/lib/mutation-driver.mutations.mjs +68 -0
  408. package/lib/paper-config.d.mts +34 -0
  409. package/lib/paper-config.harness.mjs +286 -0
  410. package/lib/paper-config.mjs +142 -0
  411. package/lib/paper-config.mutations.mjs +143 -0
  412. package/lib/skill-checks.mjs +701 -0
  413. package/lib/skill-corpus.mjs +403 -0
  414. package/lib/skill-eval-fixture.mjs +63 -0
  415. package/lib/skill-eval-kit.mjs +257 -0
  416. package/lib/skill-trigger-cases.harness.mjs +170 -0
  417. package/lib/skill-trigger-cases.mjs +446 -0
  418. package/lib/skill-trigger-cases.mutations.mjs +65 -0
  419. package/lib/trigger-ledger.mjs +215 -0
  420. package/package.json +97 -0
  421. package/plugin/.claude-plugin/plugin.json +8 -0
  422. package/plugin/hooks/hooks.json +30 -0
  423. package/scripts/check.harness.mjs +177 -0
  424. package/scripts/check.mjs +239 -0
  425. package/scripts/check.mutations.mjs +110 -0
  426. package/scripts/eslint-report-guard.mjs +82 -0
  427. package/scripts/exclusive.mjs +138 -0
  428. package/scripts/harness-api.frozen.json +76 -0
  429. package/scripts/harness-api.test.ts +175 -0
  430. package/scripts/layer-legacy-frozen.d.mts +28 -0
  431. package/scripts/layer-legacy-frozen.mjs +152 -0
  432. package/scripts/layer-legacy-frozen.test.ts +115 -0
  433. package/scripts/layer-legacy.frozen.json +50 -0
  434. package/scripts/mutation-batteries-frozen.harness.mjs +204 -0
  435. package/scripts/mutation-batteries-frozen.mjs +238 -0
  436. package/scripts/mutation-batteries.frozen.json +117 -0
  437. package/scripts/release-config.test.ts +90 -0
  438. package/scripts/rules-are-content-only.harness.mjs +113 -0
  439. package/scripts/rules-are-content-only.mjs +138 -0
  440. package/scripts/rules-are-content-only.mutations.mjs +81 -0
  441. package/scripts/rules-see-files.harness.mjs +115 -0
  442. package/scripts/rules-see-files.mjs +99 -0
  443. package/scripts/rules-see-files.mutations.mjs +131 -0
  444. package/scripts/run-mutations.mjs +100 -0
  445. package/scripts/semantic-release-plugins.d.ts +16 -0
  446. package/skills/README.md +15 -0
  447. package/skills/analyze-sibling-paper/SKILL.md +170 -0
  448. package/skills/analyze-sibling-paper/SKILL.md.spec.ts +186 -0
  449. package/skills/analyze-sibling-paper/analyze-sibling-paper.eval.mjs +19 -0
  450. package/skills/analyze-sibling-paper/analyze-sibling-paper.harness.mjs +23 -0
  451. package/skills/argument-arc/SKILL.md +177 -0
  452. package/skills/argument-arc/SKILL.md.spec.ts +192 -0
  453. package/skills/argument-arc/argument-arc.eval.mjs +19 -0
  454. package/skills/argument-arc/argument-arc.harness.mjs +23 -0
  455. package/skills/build-benchmark/SKILL.md +213 -0
  456. package/skills/build-benchmark/SKILL.md.spec.ts +220 -0
  457. package/skills/build-benchmark/build-benchmark.eval.mjs +19 -0
  458. package/skills/build-benchmark/build-benchmark.harness.mjs +23 -0
  459. package/skills/build-benchmark/references/adversarial-cold-repro.md +68 -0
  460. package/skills/camera-ready/SKILL.md +148 -0
  461. package/skills/camera-ready/SKILL.md.spec.ts +164 -0
  462. package/skills/camera-ready/camera-ready.eval.mjs +19 -0
  463. package/skills/camera-ready/camera-ready.harness.mjs +23 -0
  464. package/skills/cold-read-diff/SKILL.md +160 -0
  465. package/skills/cold-read-diff/SKILL.md.spec.ts +166 -0
  466. package/skills/cold-read-diff/cold-read-diff.eval.mjs +19 -0
  467. package/skills/cold-read-diff/cold-read-diff.harness.mjs +23 -0
  468. package/skills/draft-paper/SKILL.md +152 -0
  469. package/skills/draft-paper/SKILL.md.spec.ts +169 -0
  470. package/skills/draft-paper/draft-paper.eval.mjs +19 -0
  471. package/skills/draft-paper/draft-paper.harness.mjs +23 -0
  472. package/skills/extend-paper/SKILL.md +99 -0
  473. package/skills/extend-paper/SKILL.md.spec.ts +116 -0
  474. package/skills/extend-paper/extend-paper.eval.mjs +19 -0
  475. package/skills/extend-paper/extend-paper.harness.mjs +23 -0
  476. package/skills/find-venue/SKILL.md +128 -0
  477. package/skills/find-venue/SKILL.md.spec.ts +145 -0
  478. package/skills/find-venue/find-venue.eval.mjs +19 -0
  479. package/skills/find-venue/find-venue.harness.mjs +23 -0
  480. package/skills/grade-paper-writing/SKILL.md +436 -0
  481. package/skills/grade-paper-writing/SKILL.md.spec.ts +453 -0
  482. package/skills/grade-paper-writing/fixtures/control_gopen.txt +1 -0
  483. package/skills/grade-paper-writing/fixtures/control_human_paper.txt +1 -0
  484. package/skills/grade-paper-writing/fixtures/rewrite.txt +1 -0
  485. package/skills/grade-paper-writing/fixtures/specimen.txt +1 -0
  486. package/skills/grade-paper-writing/fixtures/structure-checks.md +22 -0
  487. package/skills/grade-paper-writing/grade-paper-writing.eval.mjs +19 -0
  488. package/skills/grade-paper-writing/grade-paper-writing.harness.mjs +23 -0
  489. package/skills/grade-paper-writing/prose-lint.mjs +713 -0
  490. package/skills/harden-paper/SKILL.md +318 -0
  491. package/skills/harden-paper/SKILL.md.spec.ts +336 -0
  492. package/skills/harden-paper/check-numbers.sh +33 -0
  493. package/skills/harden-paper/check-release-claims.sh +35 -0
  494. package/skills/harden-paper/fixtures/uncited-assertions-sample.md +43 -0
  495. package/skills/harden-paper/fixtures/uncited-assertions-sample.tex +77 -0
  496. package/skills/harden-paper/harden-paper.eval.mjs +19 -0
  497. package/skills/harden-paper/harden-paper.harness.mjs +23 -0
  498. package/skills/map-prior-work/SKILL.md +211 -0
  499. package/skills/map-prior-work/SKILL.md.spec.ts +227 -0
  500. package/skills/map-prior-work/map-prior-work.eval.mjs +19 -0
  501. package/skills/map-prior-work/map-prior-work.harness.mjs +23 -0
  502. package/skills/osf-artifact-upload/SKILL.md +52 -0
  503. package/skills/osf-artifact-upload/SKILL.md.spec.ts +59 -0
  504. package/skills/osf-artifact-upload/osf-artifact-upload.eval.mjs +22 -0
  505. package/skills/osf-artifact-upload/osf-artifact-upload.harness.mjs +103 -0
  506. package/skills/paper-adversarial-review/SKILL.md +126 -0
  507. package/skills/paper-adversarial-review/SKILL.md.spec.ts +142 -0
  508. package/skills/paper-adversarial-review/paper-adversarial-review.eval.mjs +19 -0
  509. package/skills/paper-adversarial-review/paper-adversarial-review.harness.mjs +23 -0
  510. package/skills/paper-pipeline/PIPELINE-MAP.md +371 -0
  511. package/skills/paper-pipeline/SKILL.md +499 -0
  512. package/skills/paper-pipeline/SKILL.md.spec.ts +517 -0
  513. package/skills/paper-pipeline/description-language.eval.mjs +347 -0
  514. package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +891 -0
  515. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +1254 -0
  516. package/skills/paper-pipeline/paper-pipeline.eval.mjs +22 -0
  517. package/skills/paper-pipeline/paper-pipeline.harness.mjs +143 -0
  518. package/skills/paper-pipeline/pipeline-firing.baseline.json +270 -0
  519. package/skills/paper-pipeline/pipeline-firing.eval.mjs +664 -0
  520. package/skills/paper-pipeline/pipeline-language.eval.mjs +672 -0
  521. package/skills/paper-pipeline/references/acceptance-gate.md +329 -0
  522. package/skills/paper-pipeline/references/acl-venue-rules.md +142 -0
  523. package/skills/paper-pipeline/references/anonymization.md +68 -0
  524. package/skills/paper-pipeline/references/artifact-checklist.md +93 -0
  525. package/skills/paper-pipeline/references/body-vs-appendix.md +97 -0
  526. package/skills/paper-pipeline/references/credit-criteria.md +69 -0
  527. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/README.md +35 -0
  528. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/run_retext.mjs +24 -0
  529. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/sentences.txt +11 -0
  530. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/test_sentences.py +25 -0
  531. package/skills/paper-pipeline/references/occupancy-2026-08-06-prose-checkers.md +538 -0
  532. package/skills/paper-pipeline/references/occupancy-2026-08-06-reproducible-tooling.md +431 -0
  533. package/skills/paper-pipeline/references/occupancy-2026-08-06-staleness-and-orchestration.md +592 -0
  534. package/skills/paper-pipeline/references/pipeline-status-template.md +162 -0
  535. package/skills/paper-pipeline/references/review-ratchet.md +36 -0
  536. package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +585 -0
  537. package/skills/paper-pipeline/references/writing-craft.md +448 -0
  538. package/skills/paper-pipeline/repro/2026-08-07-description-language-control.log +63 -0
  539. package/skills/paper-pipeline/repro/2026-08-07-fork-check.log +52 -0
  540. package/skills/paper-pipeline/repro/2026-08-07-fork-check2.log +33 -0
  541. package/skills/paper-pipeline/repro/2026-08-07-language-eval-pilot.log +33 -0
  542. package/skills/paper-pipeline/repro/2026-08-07-language-eval-raw.log +166 -0
  543. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.json +338 -0
  544. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.log +118 -0
  545. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-raw.log +245 -0
  546. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary.json +776 -0
  547. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-oracle.log +53 -0
  548. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-raw.log +89 -0
  549. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.json +450 -0
  550. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.log +136 -0
  551. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-raw.log +242 -0
  552. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-setupdiff.log +59 -0
  553. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation.json +1032 -0
  554. package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.json +139 -0
  555. package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.log +98 -0
  556. package/skills/paper-pipeline/repro/2026-08-08-parent-replication.mjs +92 -0
  557. package/skills/paper-pipeline/repro/README.md +129 -0
  558. package/skills/paper-pipeline/repro/analyze-language-eval.py +116 -0
  559. package/skills/paper-pipeline/scripts/README.md +344 -0
  560. package/skills/paper-pipeline/scripts/announce.mjs +67 -0
  561. package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +496 -0
  562. package/skills/paper-pipeline/scripts/artifact-coverage.mjs +397 -0
  563. package/skills/paper-pipeline/scripts/artifact-coverage.mutations.mjs +218 -0
  564. package/skills/paper-pipeline/scripts/check-provenance.mjs +184 -0
  565. package/skills/paper-pipeline/scripts/consumer.d.mts +32 -0
  566. package/skills/paper-pipeline/scripts/consumer.harness.mjs +562 -0
  567. package/skills/paper-pipeline/scripts/consumer.mjs +535 -0
  568. package/skills/paper-pipeline/scripts/consumer.mutations.mjs +190 -0
  569. package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +457 -0
  570. package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +656 -0
  571. package/skills/paper-pipeline/scripts/extract-ref-facts.mutations.mjs +54 -0
  572. package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +51 -0
  573. package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +52 -0
  574. package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +6 -0
  575. package/skills/paper-pipeline/scripts/fixtures/real-bib/refs.bib +153 -0
  576. package/skills/paper-pipeline/scripts/generated-code.harness.mjs +466 -0
  577. package/skills/paper-pipeline/scripts/generated-code.mjs +338 -0
  578. package/skills/paper-pipeline/scripts/generated-code.mutations.mjs +254 -0
  579. package/skills/paper-pipeline/scripts/ledger.mjs +623 -0
  580. package/skills/paper-pipeline/scripts/ledger.selftest.mjs +286 -0
  581. package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +389 -0
  582. package/skills/paper-pipeline/scripts/pipeline-check.mjs +737 -0
  583. package/skills/paper-pipeline/scripts/pipeline-check.mutations.mjs +54 -0
  584. package/skills/paper-pipeline/scripts/pipeline-edges.mjs +169 -0
  585. package/skills/paper-pipeline/scripts/population-map.harness.mjs +178 -0
  586. package/skills/paper-pipeline/scripts/population-map.mjs +181 -0
  587. package/skills/paper-pipeline/scripts/population-map.mutations.mjs +65 -0
  588. package/skills/paper-pipeline/scripts/population-map.selftest.mjs +122 -0
  589. package/skills/paper-pipeline/scripts/provenance.harness.mjs +240 -0
  590. package/skills/paper-pipeline/scripts/provenance.mutations.mjs +59 -0
  591. package/skills/paper-pipeline/scripts/round-diff.harness.mjs +881 -0
  592. package/skills/paper-pipeline/scripts/round-diff.mjs +576 -0
  593. package/skills/paper-pipeline/scripts/round-diff.mutations.mjs +276 -0
  594. package/skills/paper-pipeline/scripts/run-mechanical.mjs +633 -0
  595. package/skills/paper-pipeline/scripts/status.mjs +295 -0
  596. package/skills/paper-status/SKILL.md +183 -0
  597. package/skills/paper-status/SKILL.md.spec.ts +190 -0
  598. package/skills/paper-status/paper-status.eval.mjs +22 -0
  599. package/skills/paper-status/paper-status.harness.mjs +25 -0
  600. package/skills/pc-panel-review/SKILL.md +263 -0
  601. package/skills/pc-panel-review/SKILL.md.spec.ts +280 -0
  602. package/skills/pc-panel-review/pc-panel-review.eval.mjs +19 -0
  603. package/skills/pc-panel-review/pc-panel-review.harness.mjs +23 -0
  604. package/skills/plan-paper-timeline/SKILL.md +182 -0
  605. package/skills/plan-paper-timeline/SKILL.md.spec.ts +200 -0
  606. package/skills/plan-paper-timeline/fixtures/fake-google-calendar.mjs +239 -0
  607. package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +431 -0
  608. package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +65 -0
  609. package/skills/plan-paper-timeline/plan-paper-timeline.eval.mjs +19 -0
  610. package/skills/plan-paper-timeline/plan-paper-timeline.harness.mjs +23 -0
  611. package/skills/render-paper/SKILL.md +159 -0
  612. package/skills/render-paper/SKILL.md.spec.ts +166 -0
  613. package/skills/render-paper/check-render.sh +419 -0
  614. package/skills/render-paper/checkers-requirements.txt +55 -0
  615. package/skills/render-paper/ensure-checkers.sh +69 -0
  616. package/skills/render-paper/extract-pdf-facts.harness.mjs +166 -0
  617. package/skills/render-paper/extract-pdf-facts.mjs +144 -0
  618. package/skills/render-paper/render-paper.eval.mjs +19 -0
  619. package/skills/render-paper/render-paper.harness.mjs +339 -0
  620. package/skills/research-ideate/SKILL.md +136 -0
  621. package/skills/research-ideate/SKILL.md.spec.ts +152 -0
  622. package/skills/research-ideate/research-ideate.eval.mjs +19 -0
  623. package/skills/research-ideate/research-ideate.harness.mjs +23 -0
  624. package/skills/skill-contract.mutations.mjs +179 -0
  625. package/skills/study-accepted-papers/SKILL.md +206 -0
  626. package/skills/study-accepted-papers/SKILL.md.spec.ts +223 -0
  627. package/skills/study-accepted-papers/study-accepted-papers.eval.mjs +19 -0
  628. package/skills/study-accepted-papers/study-accepted-papers.harness.mjs +23 -0
  629. package/skills/submit-paper/SKILL.md +182 -0
  630. package/skills/submit-paper/SKILL.md.spec.ts +199 -0
  631. package/skills/submit-paper/check-deanon.sh +149 -0
  632. package/skills/submit-paper/references/publishers/acm.md +92 -0
  633. package/skills/submit-paper/references/venues/agenticdev.jsonc +108 -0
  634. package/skills/submit-paper/references/venues/agenticdev.md +139 -0
  635. package/skills/submit-paper/references/venues/agenticdev.tex +19 -0
  636. package/skills/submit-paper/references/venues/aisec.jsonc +101 -0
  637. package/skills/submit-paper/references/venues/aisec.md +105 -0
  638. package/skills/submit-paper/references/venues/paper-guards.tex +41 -0
  639. package/skills/submit-paper/references/venues/realm.jsonc +81 -0
  640. package/skills/submit-paper/references/venues/realm.md +155 -0
  641. package/skills/submit-paper/references/venues/tex-base.jsonc +50 -0
  642. package/skills/submit-paper/references/venues/venue-profile.schema.json +74 -0
  643. package/skills/submit-paper/submit-paper.eval.mjs +19 -0
  644. package/skills/submit-paper/submit-paper.harness.mjs +23 -0
  645. package/skills/sweep-design-space/SKILL.md +269 -0
  646. package/skills/sweep-design-space/SKILL.md.spec.ts +285 -0
  647. package/skills/sweep-design-space/sweep-design-space.eval.mjs +19 -0
  648. package/skills/sweep-design-space/sweep-design-space.harness.mjs +23 -0
  649. package/skills/tighten-paper/SKILL.md +368 -0
  650. package/skills/tighten-paper/SKILL.md.spec.ts +384 -0
  651. package/skills/tighten-paper/structure.mjs +371 -0
  652. package/skills/tighten-paper/tighten-paper.eval.mjs +19 -0
  653. package/skills/tighten-paper/tighten-paper.harness.mjs +23 -0
  654. package/skills/verify-citations/SKILL.md +328 -0
  655. package/skills/verify-citations/SKILL.md.spec.ts +345 -0
  656. package/skills/verify-citations/scripts/bib-authors.mjs +479 -0
  657. package/skills/verify-citations/scripts/bib-authors.test.mjs +175 -0
  658. package/skills/verify-citations/scripts/verify-cites.mjs +1108 -0
  659. package/skills/verify-citations/scripts/verify-cites.test.mjs +735 -0
  660. package/skills/verify-citations/verify-citations.eval.mjs +19 -0
  661. package/skills/verify-citations/verify-citations.harness.mjs +23 -0
  662. package/src/CLAUDE.md +51 -0
  663. package/src/action-ref.test.ts +26 -0
  664. package/src/action-ref.ts +15 -0
  665. package/src/adapters/banal/failure.test.ts +63 -0
  666. package/src/adapters/banal/failure.ts +118 -0
  667. package/src/adapters/banal/index.test.ts +119 -0
  668. package/src/adapters/banal/index.ts +100 -0
  669. package/src/adapters/banal/install.test.ts +20 -0
  670. package/src/adapters/banal/install.ts +41 -0
  671. package/src/adapters/banal/invocation.test.ts +74 -0
  672. package/src/adapters/banal/invocation.ts +95 -0
  673. package/src/adapters/banal/locate.test.ts +52 -0
  674. package/src/adapters/banal/locate.ts +84 -0
  675. package/src/adapters/banal/output.test.ts +140 -0
  676. package/src/adapters/banal/output.ts +141 -0
  677. package/src/adapters/banal/pin.ts +30 -0
  678. package/src/adapters/banal/probe.ts +35 -0
  679. package/src/adapters/banal/run.test.ts +191 -0
  680. package/src/adapters/banal/run.ts +244 -0
  681. package/src/adapters/banal/settings.test.ts +31 -0
  682. package/src/adapters/banal/settings.ts +55 -0
  683. package/src/adapters/banal/xml.test.ts +111 -0
  684. package/src/adapters/banal/xml.ts +112 -0
  685. package/src/adapters/curl/download.io.ts +73 -0
  686. package/src/adapters/curl/download.test.ts +55 -0
  687. package/src/adapters/curl/index.ts +5 -0
  688. package/src/adapters/memory/index.ts +131 -0
  689. package/src/adapters/node/files.io.ts +39 -0
  690. package/src/adapters/node/files.test.ts +28 -0
  691. package/src/adapters/node/host.io.ts +15 -0
  692. package/src/adapters/node/index.ts +36 -0
  693. package/src/adapters/node/process.io.ts +49 -0
  694. package/src/adapters/node/process.test.ts +46 -0
  695. package/src/adapters/node/workspace.io.ts +40 -0
  696. package/src/adapters/node/workspace.test.ts +58 -0
  697. package/src/adapters/pdfjs/fill.test.ts +111 -0
  698. package/src/adapters/pdfjs/fill.ts +141 -0
  699. package/src/build-engine.harness.mjs +314 -0
  700. package/src/build-engine.ts +219 -0
  701. package/src/build.harness.mjs +631 -0
  702. package/src/build.mutations.mjs +195 -0
  703. package/src/build.ts +793 -0
  704. package/src/cli.harness.mjs +2007 -0
  705. package/src/cli.mutations.mjs +448 -0
  706. package/src/cli.ts +1189 -0
  707. package/src/doctor.harness.mjs +396 -0
  708. package/src/doctor.mutations.mjs +175 -0
  709. package/src/doctor.ts +356 -0
  710. package/src/domain/geometry.ts +108 -0
  711. package/src/domain/host.ts +23 -0
  712. package/src/domain/page-layout.ts +32 -0
  713. package/src/domain/paths.ts +5 -0
  714. package/src/domain/result.test.ts +26 -0
  715. package/src/domain/result.ts +29 -0
  716. package/src/domain/sha256.test.ts +12 -0
  717. package/src/domain/sha256.ts +21 -0
  718. package/src/domain/text.ts +11 -0
  719. package/src/engine.harness.mjs +252 -0
  720. package/src/engine.ts +176 -0
  721. package/src/exit-code.test.ts +21 -0
  722. package/src/exit-code.ts +38 -0
  723. package/src/facts-file.test.ts +240 -0
  724. package/src/facts-file.ts +241 -0
  725. package/src/hooks-settings.harness.mjs +386 -0
  726. package/src/hooks-settings.mutations.mjs +116 -0
  727. package/src/hooks-settings.ts +434 -0
  728. package/src/init.ts +900 -0
  729. package/src/latex-log.harness.mjs +226 -0
  730. package/src/latex-log.ts +234 -0
  731. package/src/latex-loop.harness.mjs +449 -0
  732. package/src/latex-loop.ts +211 -0
  733. package/src/link-skills.harness.mjs +273 -0
  734. package/src/link-skills.mutations.mjs +136 -0
  735. package/src/link-skills.ts +258 -0
  736. package/src/new-paper.harness.mjs +216 -0
  737. package/src/new-paper.mutations.mjs +79 -0
  738. package/src/new-paper.ts +158 -0
  739. package/src/pdf-facts.harness.mjs +188 -0
  740. package/src/pdf-facts.ts +327 -0
  741. package/src/pdf-geometry.harness.mjs +254 -0
  742. package/src/pdf-geometry.ts +300 -0
  743. package/src/ports/download.ts +10 -0
  744. package/src/ports/files.ts +11 -0
  745. package/src/ports/measure-geometry.ts +8 -0
  746. package/src/ports/process.ts +46 -0
  747. package/src/ports/tool-installer.ts +33 -0
  748. package/src/ports/workspace.ts +20 -0
  749. package/src/rules-config.harness.mjs +114 -0
  750. package/src/rules-config.ts +178 -0
  751. package/src/structure.harness.mjs +179 -0
  752. package/src/structure.mutations.mjs +83 -0
  753. package/src/structure.ts +166 -0
  754. package/src/tex-requirements.harness.mjs +238 -0
  755. package/src/tex-requirements.ts +181 -0
  756. package/src/toolchain.harness.mjs +651 -0
  757. package/src/toolchain.ts +755 -0
  758. package/src/types.ts +106 -0
  759. package/templates/paper/PIPELINE-STATUS.md +72 -0
  760. package/templates/paper/paper.md +4 -0
  761. package/templates/paper/paper.tex +8 -0
  762. package/tsconfig.json +23 -0
@@ -0,0 +1,295 @@
1
+ // status.mjs — the one status view, computed. Replaces the table nobody could trust.
2
+ //
3
+ // node .claude/skills/paper-pipeline/scripts/status.mjs <papers-root>/<paper-a>
4
+ //
5
+ // Everything printed here is derived from the ledger plus the bytes currently on disk. There is
6
+ // no field a human can set, which is the entire point: the table it replaces was accurate only
7
+ // for as long as someone remembered to un-tick it, and nobody ever did.
8
+ //
9
+ // 🔴 NOTHING IN THIS VIEW SAYS A PAPER PASSED, AND THAT IS ENFORCED, NOT INTENDED.
10
+ // The ledger has no `PASS` constructor (see ledger.mjs), so this reader has nothing to render as
11
+ // an acquittal. It reports, per check: how many findings the last run recorded, or — when the run
12
+ // recorded none — the ABSTENTION reason it gave. `no-witness` means "ran, found nothing, and has
13
+ // no witness for the negative"; it is displayed as an abstention and never as green.
14
+ // `gates.harness.mjs` asserts that this file's output contains no word meaning "passed", because
15
+ // a rule about tone that nothing checks is a rule that lasts one refactor.
16
+
17
+ import {
18
+ status,
19
+ readLedger,
20
+ rowKey,
21
+ parseGate,
22
+ ABSTENTIONS,
23
+ } from "./ledger.mjs";
24
+ import { resolve, basename } from "node:path";
25
+ import { isMain } from "./consumer.mjs";
26
+
27
+ // The checks a paper is expected to have been put through. Listed explicitly so a check that has
28
+ // NEVER run shows up as a row rather than as an absence — the difference between "we looked and
29
+ // recorded nothing" and "nobody asked" is the whole failure this pipeline keeps having.
30
+ //
31
+ // 🔴 ENTRIES ARE CHECKS, NOT SKILLS. `skill` names a skill's own single pass; `skill/check` names
32
+ // one mechanical check filed under that skill. Before 2026-08-10 the key was the skill, and
33
+ // `status()` took the LAST row per skill — so two checks under one name took turns being the
34
+ // answer and a clean run of one erased a finding of the other from every derived view. Three
35
+ // checks now sit under `build-benchmark` and none of them can overwrite the others.
36
+ export const EXPECTED_GATES = [
37
+ // — before a word is written —
38
+ "research-ideate",
39
+ "sweep-design-space",
40
+ "map-prior-work",
41
+ "find-venue",
42
+ "plan-paper-timeline",
43
+ // — building the evidence —
44
+ "build-benchmark",
45
+ "build-benchmark/check-provenance",
46
+ "build-benchmark/arm-permutation",
47
+ "build-benchmark/delivered-pdf",
48
+ "build-benchmark/generated-code",
49
+ "argument-arc",
50
+ "draft-paper",
51
+ "draft-paper/population-map",
52
+ // — the loop —
53
+ "cold-read-diff",
54
+ "tighten-paper",
55
+ "tighten-paper/structure",
56
+ "tighten-paper/round-diff",
57
+ "grade-paper-writing",
58
+ "grade-paper-writing/prose-lint",
59
+ // TeXtidote. Filed here because this skill owns the paper's PROSE surface and `prose-lint` is the
60
+ // other instrument reading it — style thresholds there, spelling and grammar here.
61
+ "grade-paper-writing/textidote",
62
+ "render-paper",
63
+ "render-paper/report-submission",
64
+ // — checking against the world —
65
+ "verify-citations",
66
+ "verify-citations/verify-cites",
67
+ // checkcites, the bibliography read backwards: verify-cites asks whether an entry names a real
68
+ // work, this asks whether anything cites the entry. Same surface, opposite arrow, same skill.
69
+ "verify-citations/uncited-refs",
70
+ "analyze-sibling-paper",
71
+ "study-accepted-papers",
72
+ // — the gates —
73
+ "paper-adversarial-review",
74
+ "pc-panel-review",
75
+ "harden-paper",
76
+ "harden-paper/artifact-coverage",
77
+ "submit-paper",
78
+ // — after —
79
+ "camera-ready",
80
+ "extend-paper",
81
+ ];
82
+ // 🔴 This list is the table. A check that records a row but is absent here writes rows nobody
83
+ // ever sees — it ran, and the status view says nothing, which is the precise failure this whole
84
+ // directory was built to end. Found 2026-08-07, hours after the first version shipped with 12 of
85
+ // the 22 wired skills listed. `paper-status` is deliberately absent: it REPORTS state rather than
86
+ // producing a verdict about the paper, so a row for it would be the table grading itself.
87
+ // Any new paper skill: wire it, then add it here. Any new mechanical check in `run-mechanical.mjs`:
88
+ // add its `skill/check` key here. `unlistedGates()` below catches the omission.
89
+
90
+ /** Checks that have recorded rows for this paper but are missing from the table above. */
91
+ export function unlistedGates(rows) {
92
+ const listed = new Set(EXPECTED_GATES);
93
+ return [...new Set(rows.map(rowKey))].filter(
94
+ (k) => !listed.has(k) && parseGate(k).skill !== "paper-status",
95
+ );
96
+ }
97
+
98
+ const ICON = {
99
+ FRESH: "🟢",
100
+ "STALE-PAPER": "🟠",
101
+ "STALE-SKILL": "🟡",
102
+ "NEVER-RUN": "⬜",
103
+ };
104
+
105
+ const WHY = {
106
+ FRESH: "ran against these exact bytes",
107
+ "STALE-PAPER":
108
+ "the paper changed since it ran — its answer is about a document that is gone",
109
+ "STALE-SKILL":
110
+ "the check itself changed since it ran — that answer came from a different tool",
111
+ "NEVER-RUN": "nobody has asked this question about this paper",
112
+ };
113
+
114
+ /** What the last run of this check produced. Never a word that could be read as an acquittal. */
115
+ function produced(r) {
116
+ if (r.state === "NEVER-RUN") return "—";
117
+ if (r.findings > 0) return `${r.blocking ? "🔴" : "•"} ${r.findings} found`;
118
+ if (r.legacy) return `legacy:${r.legacy}`;
119
+ if (r.abstained) return `abstained:${r.abstained.reason}`;
120
+ return "no row";
121
+ }
122
+
123
+ function main(argv) {
124
+ const dir = resolve(argv[2] || ".");
125
+ const rows = status(dir, { gates: EXPECTED_GATES });
126
+
127
+ console.log(`\n ${basename(dir)}\n`);
128
+ const pad = (s, n) => String(s ?? "").padEnd(n);
129
+ console.log(
130
+ ` ${pad("check", 36)}${pad("freshness", 14)}${pad("last run produced", 22)}${pad("runs", 6)}when`,
131
+ );
132
+ console.log(` ${"-".repeat(92)}`);
133
+
134
+ for (const r of rows) {
135
+ const when = r.ts ? r.ts.slice(0, 16).replace("T", " ") : "—";
136
+ console.log(
137
+ ` ${ICON[r.state]} ${pad(r.key, 34)}${pad(r.state, 14)}${pad(produced(r), 22)}${pad(r.runs, 6)}${when}`,
138
+ );
139
+ }
140
+
141
+ const stale = rows.filter(
142
+ (r) => r.state === "STALE-PAPER" || r.state === "STALE-SKILL",
143
+ );
144
+ const never = rows.filter((r) => r.state === "NEVER-RUN");
145
+ const mute = rows.filter((r) => r.runs > 0 && !r.everFound);
146
+
147
+ console.log("");
148
+ for (const r of stale)
149
+ console.log(` ${ICON[r.state]} ${r.key}: ${WHY[r.state]}`);
150
+ if (never.length) {
151
+ console.log(` ⬜ never run: ${never.map((r) => r.key).join(", ")}`);
152
+ console.log(
153
+ ` ${WHY["NEVER-RUN"]} — an unasked question reads exactly like a clean one in prose.`,
154
+ );
155
+ }
156
+
157
+ // 🔴 THE ABSENCE OF FINDINGS IS NOT A RESULT, AND THIS IS WHERE THAT IS SAID OUT LOUD.
158
+ // Under the old vocabulary these checks recorded PASS and this block was a footnote about a
159
+ // suspicious gate. With PASS deleted, "recorded no finding" is ALL that a clean run ever
160
+ // produces, so this is now the primary reading of the table rather than a warning about it.
161
+ if (mute.length) {
162
+ console.log(
163
+ `\n 🔇 has run and has NEVER recorded a finding: ${mute.map((r) => r.key).join(", ")}`,
164
+ );
165
+ console.log(
166
+ ` Borrowed from mutation testing: a test that kills no mutant is not a test. This is`,
167
+ );
168
+ console.log(
169
+ ` not proof the check is broken — it is the reason to go plant a defect and watch.`,
170
+ );
171
+ console.log(
172
+ ` Precedent here: a tightening pass returned KEEP on 80 of 81 sections and a`,
173
+ );
174
+ console.log(
175
+ ` justification pass never once recommended a deletion. Both "ran".`,
176
+ );
177
+ }
178
+
179
+ const legacy = rows.filter((r) => r.legacy);
180
+ if (legacy.length) {
181
+ const acquittals = legacy.filter(
182
+ (r) => !["FINDINGS", "FAIL"].includes(r.legacy),
183
+ );
184
+ console.log(
185
+ `\n 🏷️ answered in the RETIRED vocabulary: ${legacy.map((r) => `${r.key}=${r.legacy}`).join(", ")}`,
186
+ );
187
+ console.log(
188
+ ` Rows written before 2026-08-10 are kept verbatim and are NOT translated into the`,
189
+ );
190
+ console.log(
191
+ ` current constructors — a silent reinterpretation is the class of defect this`,
192
+ );
193
+ console.log(
194
+ ` pipeline removed. A retired FINDINGS/FAIL row still shows its count above, because`,
195
+ );
196
+ console.log(
197
+ ` it carries evidence and discarding evidence is the destructive direction.`,
198
+ );
199
+ if (acquittals.length) {
200
+ console.log(
201
+ ` ${acquittals.map((r) => `${r.key}=${r.legacy}`).join(", ")} carry NOTHING forward:`,
202
+ );
203
+ console.log(
204
+ ` they recorded that nothing was wrong, with no evidence attached, which is exactly`,
205
+ );
206
+ console.log(
207
+ ` the value that was deleted. Re-run those checks for an answer in a live vocabulary.`,
208
+ );
209
+ }
210
+ }
211
+
212
+ const orphans = unlistedGates(
213
+ readLedger().filter((r) => r.paper === basename(dir)),
214
+ );
215
+ if (orphans.length) {
216
+ console.log(`\n ❗ recording but NOT IN THE TABLE: ${orphans.join(", ")}`);
217
+ console.log(
218
+ ` These ran and said something, and this view showed you nothing. Add them to`,
219
+ );
220
+ console.log(
221
+ ` EXPECTED_GATES — an invisible row is the failure this directory exists to end.`,
222
+ );
223
+ }
224
+
225
+ // 🔴 OPEN FINDINGS. The ledger has recorded a findings COUNT and a REPORT PATH on every row since
226
+ // it was written, and this view never showed either — a check could record "7 findings, report at
227
+ // <path>" and the table printed a single word. The number and the path went nowhere, so the one
228
+ // thing a check actually produces was the one thing you could not see without opening runs.jsonl
229
+ // by hand.
230
+ //
231
+ // NB this reports what the LEDGER holds. It cannot tell whether anyone acted on a finding — that
232
+ // lives in the session's task list, which is not a file and cannot be checked from the repo. So
233
+ // this makes findings VISIBLE and durable; it does not and cannot make them assigned.
234
+ const open = rows.filter((r) => r.findings > 0 && r.state !== "NEVER-RUN");
235
+ if (open.length) {
236
+ const total = open.reduce((s, r) => s + r.findings, 0);
237
+ console.log(
238
+ `\n 📌 open findings: ${total} across ${open.length} check(s)`,
239
+ );
240
+ for (const r of open) {
241
+ const where = r.report
242
+ ? ` → ${r.report}`
243
+ : " (no report path recorded — the count is all there is)";
244
+ const fresh =
245
+ r.state === "FRESH"
246
+ ? ""
247
+ : ` [${r.state}: this count describes an older text]`;
248
+ console.log(
249
+ ` ${r.blocking ? "🔴" : "•"} ${r.key}: ${r.findings}${where}${fresh}`,
250
+ );
251
+ }
252
+ console.log(
253
+ ` Nothing here proves anyone acted on these. The ledger records what a check SAID,`,
254
+ );
255
+ console.log(
256
+ ` never what was done about it — that lives in the session, not in a file.`,
257
+ );
258
+ }
259
+
260
+ const quiet = rows.filter(
261
+ (r) => r.state === "FRESH" && r.findings === 0 && r.abstained,
262
+ );
263
+ if (quiet.length) {
264
+ console.log(
265
+ `\n 🤍 ran against the current bytes and recorded nothing: ${quiet.length} check(s)`,
266
+ );
267
+ console.log(
268
+ ` ${quiet.map((r) => `${r.key} (${r.abstained.reason})`).join(", ")}`,
269
+ );
270
+ console.log(
271
+ ` Read this as the ABSENCE of a finding, which is what it is. \`no-witness\` means the`,
272
+ );
273
+ console.log(
274
+ ` check ran and has no witness for the negative answer — unlike a certifying`,
275
+ );
276
+ console.log(
277
+ ` algorithm (McConnell et al. 2011), which ships one for both answers. Our discipline`,
278
+ );
279
+ console.log(
280
+ ` is strictly weaker than theirs and this line is where that shows.`,
281
+ );
282
+ for (const [reason, meaning] of ABSTENTIONS) {
283
+ if (quiet.some((r) => r.abstained.reason === reason))
284
+ console.log(` ${reason}: ${meaning}`);
285
+ }
286
+ }
287
+
288
+ const blocking = stale.length + never.length;
289
+ console.log(
290
+ `\n ${blocking === 0 ? "🟢 every expected check answered for the current text" : `🔴 ${blocking} check(s) not answering for the current text`}\n`,
291
+ );
292
+ return 0; // advisory: this reports, it does not block
293
+ }
294
+
295
+ if (isMain(import.meta.url)) process.exit(main(process.argv));
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: paper-status
3
+ description: Answer "what's the status of the paper?" in one pass — MEASURE what is measurable (page count from the real build, git state, which gates were run against the CURRENT text), then read the judgement rows, then print blockers worst-first split into mine and the author's. Use whenever the author asks "what's up with the paper / status / what's left / is it ready", at the start of a session touching a paper, or before deciding what to work on next. Not a review skill — it reports state, it does not grade, cut, or fix.
4
+ allowed-tools: [Bash, Read, Grep, Glob]
5
+ ---
6
+
7
+ <!-- vigiles:sha256:51bc50b2485782e4 compiled from skills/paper-status/SKILL.md.spec.ts -->
8
+
9
+ # paper-status — state, measured before it is narrated
10
+
11
+ ## Run me
12
+
13
+ 🔴 FIRST, before any other step:
14
+
15
+ ```
16
+ node .claude/skills/paper-pipeline/scripts/announce.mjs paper-status <paper-dir>
17
+ ```
18
+
19
+ An advisory pass cannot be observed failing — silence is both its error state and its normal
20
+ state — so starting is an event, and events get written down.
21
+
22
+ The author asks "what's the status there?" constantly, and the answer keeps coming from the wrong place: my
23
+ memory of the session, which drifts, or a 200-line scorecard he cannot skim. Both fail the same way —
24
+ **they narrate state instead of measuring it.**
25
+
26
+ Grounding failure, 2026-08-04 (`compile-rules-2026`, day before deadline): a status line in chat said
27
+ the review panel was running. It had never been launched. Another said the paper was 8 pages while the
28
+ real build said 9 and BLOCKED — steering a whole day of cuts by the wrong instrument. Both would have
29
+ been caught by running two commands instead of recalling two facts.
30
+
31
+ ## The rule this skill exists to enforce
32
+
33
+ **Anything a command can answer is not allowed to come from memory or from prose.** Measure first,
34
+ read the scorecard second, and mark clearly which is which. A claim in `PIPELINE-STATUS.md` is a claim
35
+ about the past; the build is the present.
36
+
37
+ ## 🔴 The second rule: status is PUSHED, never waited for
38
+
39
+ The corpus owner, 2026-08-05: *"I have to constantly ask for the paper's status and direct you so you tell me what we can do next"*. Building a skill that answers when asked fixed the wrong half —
40
+ the work he was complaining about is **the asking**, and a pull-only skill leaves all of it with him.
41
+
42
+ So on any turn that touched a paper, the reply ends with **three lines, unprompted**:
43
+
44
+ 1. **where it stands** — the build's own verdict line, page count, deadline countdown;
45
+ 2. **the single next action, with an owner** — not a menu. If it is mine, it is already started or
46
+ started in the same reply. If it is his, it says exactly what to click.
47
+ 3. **what is stale** — a gate whose verdict predates the current text, named.
48
+
49
+ Three failures make this a rule rather than a preference, all in one session:
50
+ - I finished a page-fit cut and stopped, so he asked what the status was;
51
+ - I left artifact hosting on his side of the split for a day and a half while the credential to clear
52
+ it sat in the environment (see `credential-available` in `pipeline-check.mjs`);
53
+ - three consecutive panels returned Weak Accept and the ceiling they named was never the next task,
54
+ because nothing turned "here is the score" into "here is what to do about it".
55
+
56
+ **Never end a paper turn on a completed sub-task alone.** "Fits in 8 pages" is a measurement, not a
57
+ status; the status is what that measurement makes possible next.
58
+
59
+ **Enforcement leg.** `pipeline-check.mjs` prints its banner **unconditionally**, including when it has
60
+ zero findings — deadline countdown, verdict row, and `➡️ NEXT`. It runs from `paper-status-gates.sh`
61
+ on every edit to a paper source, so the state arrives without anyone pulling it. If that banner and
62
+ this section ever disagree, the banner is a measurement and this is prose: believe the banner.
63
+
64
+ ## How to run it
65
+
66
+ ### 1. Measure (no reading yet)
67
+
68
+ ```bash
69
+ cd <paper-dir>
70
+ bash repro/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
71
+ git status --porcelain # uncommitted work
72
+ git log --oneline @{u}..HEAD # unpushed commits
73
+ ```
74
+
75
+ - **The build is the only page-count authority.** If the repo has an approximate measurer, do not use
76
+ it and say so. In this project `measure.sh` was gutted on 2026-08-04 for exactly this reason.
77
+ - Report the build's own verdict line verbatim. Do not paraphrase `BLOCKED` into "nearly there".
78
+
79
+ ### 2. Detect stale gates — the part memory always gets wrong
80
+
81
+ A gate is stale if the paper changed after the gate ran. Check it mechanically, not by recall:
82
+
83
+ ```bash
84
+ git log -1 --format=%cd --date=short -- paper.md # when the text last moved
85
+ ls -la reviews/ | tail -20 # when each gate last reported
86
+ ```
87
+
88
+ Compare against the dates in `PIPELINE-STATUS.md`. If the paper moved after a gate's date, that
89
+ gate's verdict **does not describe the current paper** — say so explicitly, and say what changed since.
90
+ An accept-probability from a superseded draft is not evidence about this one; carrying it forward is
91
+ the single most common way a status report lies.
92
+
93
+ If the project ships a checker (`.claude/skills/paper-pipeline/scripts/pipeline-check.mjs`), run it.
94
+
95
+ ### 3. Read the judgement rows — from BOTH checklists, they answer different questions
96
+
97
+ The project already carries the checklists this skill should report against. Do not invent a new list
98
+ and do not report from one of them alone:
99
+
100
+ | source | the question it answers | what to pull |
101
+ |---|---|---|
102
+ | **`<paper-dir>/PIPELINE-STATUS.md`** | were the QUALITY stages run, and what did they conclude | per-stage `☑`/`◐`/`☐`/`⚠`, dates, the one-line submit-ready verdict |
103
+ | **`<paper-dir>/SUBMIT-CHECKLIST.md`** | does it comply with the VENUE's format, and is the submission mechanics understood | page limit, template, blind model, mandatory sections, portal URL, whether a supplementary-upload field exists, the deadline converted to the author's own zone |
104
+ | **`.claude/hooks/paper-skills-nudge.hook.ts`** | which gates EXIST at all | the canonical pre-submit gate list — use it to spot a gate nobody has ever run, which no scorecard row will show because the row was never added |
105
+ | `<paper-dir>/CLAIMS.md` | what may still be claimed | 🔴 retired claims — flag if the current text asserts one |
106
+ | `<paper-dir>/CLAUDE.md` | what this venue rewards | only when it changes what to do next |
107
+
108
+ 🔴 **Both checklists must be green before upload, and they fail differently.** A paper can pass every
109
+ quality gate and still be unsubmittable (no active account, no supplementary field so the artifact
110
+ needs external hosting, deadline misconverted from AoE). Reporting only the quality side is how a
111
+ "ready" paper misses its deadline. The compliance side usually contains the blockers that are *his*,
112
+ which is exactly why they belong at the top of the output.
113
+
114
+ ### 4. Print it, in this shape and this order
115
+
116
+ Short. He is asking because he wants to decide what to do next, not to read a report.
117
+
118
+ 1. **One line: can it be submitted right now?** The build verdict plus the hard blockers, nothing else.
119
+ 2. **Blockers, worst first, split by owner** — 🔴 his (accounts, hosting, anything needing a human or a
120
+ login) vs 🔵 mine (text, gates, artifacts). His come first: he can start them while I work.
121
+ 3. **Gates** (`PIPELINE-STATUS.md`), each marked ✅ ran against current text · ⚠️ ran against an older
122
+ text (name what changed) · ☐ never run. Cross-check against the hook's canonical gate list so a
123
+ gate with no row at all shows up as ☐ rather than vanishing.
124
+ 4. **Format compliance** (`SUBMIT-CHECKLIST.md`) — one line: green, or the specific item that is not.
125
+ Page limit and blind model come from the measured build, not from the checklist's memory of them.
126
+ 5. **What moved since he last asked**, three lines maximum.
127
+ 6. **The deadline, in his timezone**, and what is on the critical path to it.
128
+
129
+ ## Record the verdict
130
+
131
+ 🔴 LAST step, once the deliverable exists:
132
+
133
+ ```
134
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> FINDING <count> <report-path>
135
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> ABSTAINED <reason> "<one line>"
136
+ ```
137
+
138
+ This skill reports state and does not judge the paper, so what it records is about the **status run**:
139
+ **FINDING** — `<count>` blockers printed, `<report-path>` the status output.
140
+ **ABSTAINED** — `no-witness`: the status run measured everything it can and printed zero blockers.
141
+ `crashed`: the build did not run, so nothing was measured.
142
+
143
+ 🔴 `crashed` is the one outcome that must never be narrated as a status. This skill exists because
144
+ state was being narrated instead of measured; a status report built on a build that did not happen
145
+ is that same failure with a fresh timestamp on it. Under the old vocabulary this was `ERROR`, which
146
+ sat in the same column as a verdict about the paper — it does not any more.
147
+
148
+ 🔴 **There is no PASS**, so "zero blockers" cannot be stored. Print it, and let the reader draw the
149
+ conclusion from an empty blocker list they can see.
150
+
151
+ ## Rules
152
+
153
+ - **Never report a gate as run because I intended to run it.** Predicting a background agent's result,
154
+ or calling a queued task "running" when nothing was launched, is the failure this skill was written
155
+ after. If a task was not launched, the honest line is "not started".
156
+ - **Owner-split is not decoration.** A blocker only he can clear (an account, an upload, a phone call)
157
+ belongs at the top, because every hour it sits is an hour of pure schedule loss.
158
+ - **Numbers, not adjectives.** "8/8 pages, fits" not "about right"; "78 stalls over 8 pages against a
159
+ threshold of 2" not "readable enough".
160
+ - **Say what is NOT known.** A gate never run is a real answer and more useful than an optimistic one.
161
+ - 🔴 **Send the built PDF with the report, every time, without being asked** (`SendUserFile`, from the
162
+ outdir the report's page count came from — never an older copy). The corpus owner, 2026-08-05: *"and I often ask for the PDF to be delivered"*. He reads the paper, not the scorecard; a status report that makes him ask for the
163
+ artifact costs a round trip for nothing. The caption states the build time and the page count, so
164
+ the file cannot be mistaken for an earlier one.
165
+ - 🔴 **Never let "the gates are stale" be heard as "the measurements are stale."** They are different
166
+ objects and conflating them destroys trust in real data: a *measurement* is an experiment on the
167
+ tool or corpus and stays valid until the tool changes; a *gate* is a judgement of the paper text and
168
+ expires the moment the text moves. Name which one you mean, every time. On 2026-08-05 a one-word
169
+ slip here made a four-hour experiment sound like wasted work.
170
+ - Do not fix anything while reporting. Status and work are different turns — mixing them is how the
171
+ status stops being trustworthy.
172
+
173
+ ## Compose with
174
+
175
+ - `paper-pipeline` — owns the stage contract this reads.
176
+ - `harden-paper` — the decision to submit; this only reports the inputs to it.
177
+ - `handoff` — end-of-session preservation; this is the start-of-session counterpart.
178
+
179
+ ## Provenance
180
+
181
+ Built 2026-08-04, the day before the `compile-rules-2026` deadline, after the author asked for paper status
182
+ for the fourth time in one session and pointed out it should be a command: *"I ask this so often... there should be a skill"*. He was right, and the two things the skill measures first are the two
183
+ things chat had most recently gotten wrong.
@@ -0,0 +1,190 @@
1
+ // Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
2
+ //
3
+ // Adopted 2026-08-17 as part of the second batch. The body is the previous SKILL.md
4
+ // VERBATIM, so the compiled diff shows only what the compiler adds. No `disallowedTools`
5
+ // fence yet: the field exists on `SkillSpec` as of the branch `claude/skill-disallowed-tools`
6
+ // but is not in a release `mine` installs, so adding it here would not compile.
7
+ import { experimental_skill } from "vigiles/spec";
8
+
9
+ export default experimental_skill({
10
+ name: "paper-status",
11
+ description:
12
+ "Answer \"what's the status of the paper?\" in one pass — MEASURE what is measurable (page count from the real build, git state, which gates were run against the CURRENT text), then read the judgement rows, then print blockers worst-first split into mine and the author's. Use whenever the author asks \"what's up with the paper / status / what's left / is it ready\", at the start of a session touching a paper, or before deciding what to work on next. Not a review skill — it reports state, it does not grade, cut, or fix.",
13
+ tools: ["Bash", "Read", "Grep", "Glob"],
14
+ body: `
15
+ # paper-status — state, measured before it is narrated
16
+
17
+ ## Run me
18
+
19
+ 🔴 FIRST, before any other step:
20
+
21
+ \`\`\`
22
+ node .claude/skills/paper-pipeline/scripts/announce.mjs paper-status <paper-dir>
23
+ \`\`\`
24
+
25
+ An advisory pass cannot be observed failing — silence is both its error state and its normal
26
+ state — so starting is an event, and events get written down.
27
+
28
+ The author asks "what's the status there?" constantly, and the answer keeps coming from the wrong place: my
29
+ memory of the session, which drifts, or a 200-line scorecard he cannot skim. Both fail the same way —
30
+ **they narrate state instead of measuring it.**
31
+
32
+ Grounding failure, 2026-08-04 (\`compile-rules-2026\`, day before deadline): a status line in chat said
33
+ the review panel was running. It had never been launched. Another said the paper was 8 pages while the
34
+ real build said 9 and BLOCKED — steering a whole day of cuts by the wrong instrument. Both would have
35
+ been caught by running two commands instead of recalling two facts.
36
+
37
+ ## The rule this skill exists to enforce
38
+
39
+ **Anything a command can answer is not allowed to come from memory or from prose.** Measure first,
40
+ read the scorecard second, and mark clearly which is which. A claim in \`PIPELINE-STATUS.md\` is a claim
41
+ about the past; the build is the present.
42
+
43
+ ## 🔴 The second rule: status is PUSHED, never waited for
44
+
45
+ The corpus owner, 2026-08-05: *"I have to constantly ask for the paper's status and direct you so you tell me what we can do next"*. Building a skill that answers when asked fixed the wrong half —
46
+ the work he was complaining about is **the asking**, and a pull-only skill leaves all of it with him.
47
+
48
+ So on any turn that touched a paper, the reply ends with **three lines, unprompted**:
49
+
50
+ 1. **where it stands** — the build's own verdict line, page count, deadline countdown;
51
+ 2. **the single next action, with an owner** — not a menu. If it is mine, it is already started or
52
+ started in the same reply. If it is his, it says exactly what to click.
53
+ 3. **what is stale** — a gate whose verdict predates the current text, named.
54
+
55
+ Three failures make this a rule rather than a preference, all in one session:
56
+ - I finished a page-fit cut and stopped, so he asked what the status was;
57
+ - I left artifact hosting on his side of the split for a day and a half while the credential to clear
58
+ it sat in the environment (see \`credential-available\` in \`pipeline-check.mjs\`);
59
+ - three consecutive panels returned Weak Accept and the ceiling they named was never the next task,
60
+ because nothing turned "here is the score" into "here is what to do about it".
61
+
62
+ **Never end a paper turn on a completed sub-task alone.** "Fits in 8 pages" is a measurement, not a
63
+ status; the status is what that measurement makes possible next.
64
+
65
+ **Enforcement leg.** \`pipeline-check.mjs\` prints its banner **unconditionally**, including when it has
66
+ zero findings — deadline countdown, verdict row, and \`➡️ NEXT\`. It runs from \`paper-status-gates.sh\`
67
+ on every edit to a paper source, so the state arrives without anyone pulling it. If that banner and
68
+ this section ever disagree, the banner is a measurement and this is prose: believe the banner.
69
+
70
+ ## How to run it
71
+
72
+ ### 1. Measure (no reading yet)
73
+
74
+ \`\`\`bash
75
+ cd <paper-dir>
76
+ bash repro/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
77
+ git status --porcelain # uncommitted work
78
+ git log --oneline @{u}..HEAD # unpushed commits
79
+ \`\`\`
80
+
81
+ - **The build is the only page-count authority.** If the repo has an approximate measurer, do not use
82
+ it and say so. In this project \`measure.sh\` was gutted on 2026-08-04 for exactly this reason.
83
+ - Report the build's own verdict line verbatim. Do not paraphrase \`BLOCKED\` into "nearly there".
84
+
85
+ ### 2. Detect stale gates — the part memory always gets wrong
86
+
87
+ A gate is stale if the paper changed after the gate ran. Check it mechanically, not by recall:
88
+
89
+ \`\`\`bash
90
+ git log -1 --format=%cd --date=short -- paper.md # when the text last moved
91
+ ls -la reviews/ | tail -20 # when each gate last reported
92
+ \`\`\`
93
+
94
+ Compare against the dates in \`PIPELINE-STATUS.md\`. If the paper moved after a gate's date, that
95
+ gate's verdict **does not describe the current paper** — say so explicitly, and say what changed since.
96
+ An accept-probability from a superseded draft is not evidence about this one; carrying it forward is
97
+ the single most common way a status report lies.
98
+
99
+ If the project ships a checker (\`.claude/skills/paper-pipeline/scripts/pipeline-check.mjs\`), run it.
100
+
101
+ ### 3. Read the judgement rows — from BOTH checklists, they answer different questions
102
+
103
+ The project already carries the checklists this skill should report against. Do not invent a new list
104
+ and do not report from one of them alone:
105
+
106
+ | source | the question it answers | what to pull |
107
+ |---|---|---|
108
+ | **\`<paper-dir>/PIPELINE-STATUS.md\`** | were the QUALITY stages run, and what did they conclude | per-stage \`☑\`/\`◐\`/\`☐\`/\`⚠\`, dates, the one-line submit-ready verdict |
109
+ | **\`<paper-dir>/SUBMIT-CHECKLIST.md\`** | does it comply with the VENUE's format, and is the submission mechanics understood | page limit, template, blind model, mandatory sections, portal URL, whether a supplementary-upload field exists, the deadline converted to the author's own zone |
110
+ | **\`.claude/hooks/paper-skills-nudge.hook.ts\`** | which gates EXIST at all | the canonical pre-submit gate list — use it to spot a gate nobody has ever run, which no scorecard row will show because the row was never added |
111
+ | \`<paper-dir>/CLAIMS.md\` | what may still be claimed | 🔴 retired claims — flag if the current text asserts one |
112
+ | \`<paper-dir>/CLAUDE.md\` | what this venue rewards | only when it changes what to do next |
113
+
114
+ 🔴 **Both checklists must be green before upload, and they fail differently.** A paper can pass every
115
+ quality gate and still be unsubmittable (no active account, no supplementary field so the artifact
116
+ needs external hosting, deadline misconverted from AoE). Reporting only the quality side is how a
117
+ "ready" paper misses its deadline. The compliance side usually contains the blockers that are *his*,
118
+ which is exactly why they belong at the top of the output.
119
+
120
+ ### 4. Print it, in this shape and this order
121
+
122
+ Short. He is asking because he wants to decide what to do next, not to read a report.
123
+
124
+ 1. **One line: can it be submitted right now?** The build verdict plus the hard blockers, nothing else.
125
+ 2. **Blockers, worst first, split by owner** — 🔴 his (accounts, hosting, anything needing a human or a
126
+ login) vs 🔵 mine (text, gates, artifacts). His come first: he can start them while I work.
127
+ 3. **Gates** (\`PIPELINE-STATUS.md\`), each marked ✅ ran against current text · ⚠️ ran against an older
128
+ text (name what changed) · ☐ never run. Cross-check against the hook's canonical gate list so a
129
+ gate with no row at all shows up as ☐ rather than vanishing.
130
+ 4. **Format compliance** (\`SUBMIT-CHECKLIST.md\`) — one line: green, or the specific item that is not.
131
+ Page limit and blind model come from the measured build, not from the checklist's memory of them.
132
+ 5. **What moved since he last asked**, three lines maximum.
133
+ 6. **The deadline, in his timezone**, and what is on the critical path to it.
134
+
135
+ ## Record the verdict
136
+
137
+ 🔴 LAST step, once the deliverable exists:
138
+
139
+ \`\`\`
140
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> FINDING <count> <report-path>
141
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> ABSTAINED <reason> "<one line>"
142
+ \`\`\`
143
+
144
+ This skill reports state and does not judge the paper, so what it records is about the **status run**:
145
+ **FINDING** — \`<count>\` blockers printed, \`<report-path>\` the status output.
146
+ **ABSTAINED** — \`no-witness\`: the status run measured everything it can and printed zero blockers.
147
+ \`crashed\`: the build did not run, so nothing was measured.
148
+
149
+ 🔴 \`crashed\` is the one outcome that must never be narrated as a status. This skill exists because
150
+ state was being narrated instead of measured; a status report built on a build that did not happen
151
+ is that same failure with a fresh timestamp on it. Under the old vocabulary this was \`ERROR\`, which
152
+ sat in the same column as a verdict about the paper — it does not any more.
153
+
154
+ 🔴 **There is no PASS**, so "zero blockers" cannot be stored. Print it, and let the reader draw the
155
+ conclusion from an empty blocker list they can see.
156
+
157
+ ## Rules
158
+
159
+ - **Never report a gate as run because I intended to run it.** Predicting a background agent's result,
160
+ or calling a queued task "running" when nothing was launched, is the failure this skill was written
161
+ after. If a task was not launched, the honest line is "not started".
162
+ - **Owner-split is not decoration.** A blocker only he can clear (an account, an upload, a phone call)
163
+ belongs at the top, because every hour it sits is an hour of pure schedule loss.
164
+ - **Numbers, not adjectives.** "8/8 pages, fits" not "about right"; "78 stalls over 8 pages against a
165
+ threshold of 2" not "readable enough".
166
+ - **Say what is NOT known.** A gate never run is a real answer and more useful than an optimistic one.
167
+ - 🔴 **Send the built PDF with the report, every time, without being asked** (\`SendUserFile\`, from the
168
+ outdir the report's page count came from — never an older copy). The corpus owner, 2026-08-05: *"and I often ask for the PDF to be delivered"*. He reads the paper, not the scorecard; a status report that makes him ask for the
169
+ artifact costs a round trip for nothing. The caption states the build time and the page count, so
170
+ the file cannot be mistaken for an earlier one.
171
+ - 🔴 **Never let "the gates are stale" be heard as "the measurements are stale."** They are different
172
+ objects and conflating them destroys trust in real data: a *measurement* is an experiment on the
173
+ tool or corpus and stays valid until the tool changes; a *gate* is a judgement of the paper text and
174
+ expires the moment the text moves. Name which one you mean, every time. On 2026-08-05 a one-word
175
+ slip here made a four-hour experiment sound like wasted work.
176
+ - Do not fix anything while reporting. Status and work are different turns — mixing them is how the
177
+ status stops being trustworthy.
178
+
179
+ ## Compose with
180
+
181
+ - \`paper-pipeline\` — owns the stage contract this reads.
182
+ - \`harden-paper\` — the decision to submit; this only reports the inputs to it.
183
+ - \`handoff\` — end-of-session preservation; this is the start-of-session counterpart.
184
+
185
+ ## Provenance
186
+
187
+ Built 2026-08-04, the day before the \`compile-rules-2026\` deadline, after the author asked for paper status
188
+ for the fourth time in one session and pointed out it should be a command: *"I ask this so often... there should be a skill"*. He was right, and the two things the skill measures first are the two
189
+ things chat had most recently gotten wrong.`,
190
+ });