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,499 @@
1
+ ---
2
+ name: paper-pipeline
3
+ description: The orchestrator for writing a research paper end-to-end, from idea to accepted-and-extended, with every stage graded for the credit it earns a body of work. START HERE when writing/hardening a paper (AgenticDev, AISec, and future ones) and want the whole lifecycle driven, not one step. Routes to the stage skills — research-ideate, find-venue, plan-paper-timeline, build-benchmark, draft-paper, render-paper, verify-citations, the review skills, submit-paper (+ venue cards), camera-ready, extend-paper — and owns the shared references.
4
+ allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, WebSearch, WebFetch, Agent, Skill]
5
+ ---
6
+
7
+ <!-- vigiles:sha256:6ec7cc1d25db0a0f compiled from skills/paper-pipeline/SKILL.md.spec.ts -->
8
+
9
+ # paper-pipeline — the conductor for the whole organism
10
+
11
+ This is the entry point. Each lifecycle stage is its own skill; this routes through them in order and
12
+ owns the shared reference docs the others cite. **These papers are written to COUNT as credentials** —
13
+ every stage is graded against `references/credit-criteria.md`, not abstract "impact." The personal half
14
+ of that — who is filing what, and when — stays in the author's own private notes, never in a public repo.
15
+
16
+ ## Shared references (single source of truth — all skills cite these)
17
+ - `references/credit-criteria.md` — which criteria a paper feeds; where venue quality bites; the
18
+ decisions credit value forces on the pipeline.
19
+ - `references/artifact-checklist.md` — the self-checking reproduction artifact.
20
+ - `references/anonymization.md` — the double-blind deny-list + hygiene (and its reverse at camera-ready).
21
+ - `references/writing-craft.md` — how well-written papers read (craft rules + exemplar lessons + the
22
+ gradeable 9-dim writing rubric); cited by `draft-paper`, `grade-paper-writing`, and `harden-paper`.
23
+ - `references/review-ratchet.md` — how to fix a caught overclaim (tighten → cut → Threats → hedge)
24
+ and why every review round must be paid back with a `tighten-paper` pass; cited by
25
+ `paper-adversarial-review`, `pc-panel-review`, `harden-paper`.
26
+ - `references/pipeline-status-template.md` — the per-paper **readiness scorecard** (which stages ran,
27
+ grades, open findings, submit-ready verdict). Copied into `<paper-dir>/PIPELINE-STATUS.md`.
28
+ - `references/acl-venue-rules.md` — what holds at **every** ACL-family venue and workshop: the
29
+ page-limit map, the appendix rule and the trap inside it, Limitations/Ethics as free-but-restricted
30
+ space, anonymity, OpenReview mechanics. Fetch once, not per paper. Venue-specific facts stay in
31
+ `submit-paper/references/venues/<venue>.md`. (No equivalent yet for ACM or IEEE — write one when
32
+ the next paper goes there.)
33
+
34
+ ## The readiness scorecard (which boxes are checked)
35
+ Stages run in subagents and report into chat, which evaporates — so "did everything run?" becomes
36
+ unanswerable. Fix: every paper carries a **`<paper-dir>/PIPELINE-STATUS.md`** (template in
37
+ `references/pipeline-status-template.md`), the durable colocated source-of-truth for *which stages ran,
38
+ their grade/result, what's open,* and a one-line **submit-ready verdict**. Rules:
39
+ - **When any stage runs (here or in a subagent), update its row in the same commit** — status, date,
40
+ result, open findings, artifact link. The scorecard is only trustworthy if it's kept live.
41
+ - **Never inflate:** a stage not run *this* cycle is `☐`, even if a prior submission ran it — don't
42
+ borrow credit you can't point to. Approximate/from-memory grades get `≈`.
43
+ - **"Is paper X ready / what's checked?"** = read this file (verdict + any `☐`/`◐`/`⚠` rows), don't
44
+ reconstruct from chat.
45
+ - Distinct from `SUBMIT-CHECKLIST.md` (venue-format compliance); both must be green before upload.
46
+ - 🔴 **Enforcement leg (prose-isn't-policy), and it is a script, not a paragraph.**
47
+ `scripts/pipeline-check.mjs` reads this file on every paper edit and reports the failures that
48
+ actually happened on real papers: a CONTINUOUS check whose last run predates the current text, a GATE
49
+ that ran without its required input, **a `Requires` cell that omits an edge the pipeline declares**
50
+ (the canonical set is `scripts/pipeline-edges.mjs`, with the admitting sentence per edge), a study
51
+ that ran with no stated claim, the `access` row not green inside the moderation window, and a verdict
52
+ line that is just an accept probability. Run it directly
53
+ with `node .claude/skills/paper-pipeline/scripts/pipeline-check.mjs <paper-dir>`; it is wired into
54
+ `.claude/hooks/paper-status-gates.sh` and asserted in `.claude/hooks/hooks.harness.mjs`.
55
+ **The grading itself stays judgment** (that is the skills' job) — only the mechanically checkable
56
+ parts are compiled. *Added 2026-08-03, the day three hooks in this repo were found to have been dead
57
+ for weeks: an advisory that is never exercised is indistinguishable from one that works.*
58
+
59
+ 🔴 **As of 2026-08-26, this file is read by TWO things.** Sixteen checks over it live as
60
+ `@eslint/markdown` rules in `eslint-rules/pipeline-status.mjs` (run:
61
+ `npx eslint <paper-dir>/PIPELINE-STATUS.md`; five of them are `error`), while
62
+ `scripts/pipeline-check.mjs` holds six whose input lies OUTSIDE the file — git, the clock, the
63
+ `reviews/` directory, `process.env`. The classification of all 22 lives in the
64
+ author's private notes (`<papers-root>/research/2026-08-26-klassifikatsiya-pipeline-check.md`).
65
+
66
+ ⚠️ The paragraph above lived for a day NOT HERE but directly in `SKILL.md` — i.e. in the
67
+ generated file. The very first `vigiles compile` (27.08) ate it, and it was not a human who
68
+ noticed but an agent whose compile had just erased someone else's edit. **An edit to `SKILL.md`
69
+ without `.spec.ts` is an edit with an expiration date: the next compile.**
70
+
71
+ ## 🗺️ Where every check actually runs — and where it can be walked around
72
+
73
+ ```
74
+ YOU EDIT YOU COMMIT YOU BUILD YOU PUSH
75
+ │ │ │ │
76
+ ▼ ▼ ▼ ▼
77
+ ┌──────────────┐ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐
78
+ │ PostToolUse │ │ .githooks/ │ │ build- │ │ GitHub Actions │
79
+ │ paper-lint │ BLOCKS │ pre-commit │REFUSES│ submission.sh │ │ paper-gates │
80
+ │ pre >55 wds │ │ │ │ │ │ │
81
+ │ paper-lint │ nudges │ numbers gate │ │ numbers gate │REFUSES numbers+self│
82
+ │ post │ │ │ │ │ │ │
83
+ │ prose-lint │ │ prose-lint │ nudge │ page count │ │ prose-lint │
84
+ │ SHAVE │ │ self-test if │ │ overfull │ │ check-anon │
85
+ │ numbers │ │ you touched │ │ unresolved │ │ verify-cites │
86
+ │ paper-edit- │ BLOCKS │ a gate │ │ refs │ │ provenance │
87
+ │ guard │ bash │ harness if │ │ dropped glyphs│ │ scorecard │
88
+ └──────────────┘ │ you touched │ │ anon grep │ │ harness │
89
+ │ │ a hook │ └────────────────┘ │ LaTeX build │
90
+ │ │ RAW DNA │REFUSES │ └────────────────┘
91
+ │ └────────────────┘ │ │
92
+ │ │ │ │
93
+ watches EVENTS watches STATE watches OUTPUT watches EVERYTHING
94
+ (Edit/Write fired) (what is staged) (the actual PDF) (after the fact)
95
+ │ │
96
+ │ │
97
+ 🕳 BYPASSABLE: 🛡 NOT bypassable by that route: it does not care
98
+ write from Bash and HOW the bytes got there. However you wrote the
99
+ no event fires, so file, you still have to commit it.
100
+ every PostToolUse
101
+ check silently
102
+ does not run.
103
+ ```
104
+
105
+ **Read the bottom row, it is the whole point.** Each column watches a different KIND of thing, and
106
+ that is why they are not three copies of one check:
107
+
108
+ - **Editor hooks watch events.** Fast, and the only layer that can stop a bad edit *before* it lands.
109
+ Bypassable by construction — an event that never fires cannot be checked, and writing the file from
110
+ Bash produces no event. Documented in `papers/CLAUDE.md`, open since 2026-08-04.
111
+ - **The git hook watches state.** Immune to that whole class, because it reads what is staged and has
112
+ no opinion about how it got staged. This is the layer that was missing, and the one to reach for
113
+ when an editor check turns out to be walkable-around.
114
+ - **The build watches output.** Only it can see page count, overfull boxes, and glyphs pdflatex
115
+ silently dropped — none of which exist until the PDF does.
116
+ - **CI watches everything, but after the fact.** Its real job is the slow checks nobody will wait for
117
+ locally (the anonymity self-test copies a 24 MB bundle per leak category) and the self-tests, which
118
+ are what catch a gate that has quietly stopped catching things.
119
+
120
+ 🔴 **A fifth kind, and none of the four columns can see it: does the MODEL call these skills at all?**
121
+ Every column above watches something the repository produced — an event, staged bytes, a PDF, a commit.
122
+ None watches *selection*: whether a real model, reading 37 competing descriptions, picks `tighten-paper`
123
+ over `grade-paper-writing` when the draft is bloated. A harness test proves a skill works once invoked;
124
+ it cannot prove it gets invoked. That needs the real CLI and it costs money, so it is a measurement, not
125
+ a gate — `.claude/skills/paper-pipeline/pipeline-firing.eval.mjs`, run manually or by the weekly
126
+ `skill-firing` job (`workflow_dispatch` + `schedule`, deliberately NOT on push). It installs every skill
127
+ in this repo natively so selection is *competitive*, feeds each skill 4 prompts it should fire on plus 4
128
+ its colliding sibling owns, and reports recall / false-positive / precision per skill against a committed
129
+ baseline. **What it measures drifts without a commit here** — a model update can change routing while
130
+ every file stays byte-identical, which is exactly the regression no check in the diagram can see.
131
+ Prior art is named in the file header (`adewale/skill-eval-harness` does this too); the idea is not ours.
132
+
133
+ 🔴 **Still manual, and no mechanism has been found for it:** the **cold read** — a reader with no
134
+ context restating each sentence — is the only check that catches a sentence that is short, true,
135
+ threshold-passing and meaningless. It needs a fresh subagent, so no hook can run it. What IS
136
+ mechanised is noticing that it is *overdue*: `pipeline-check.mjs` reports `stale-cold-read` when the
137
+ prose changed after the last one.
138
+
139
+ Install the git hook once per clone: `git config core.hooksPath .githooks`.
140
+
141
+ ## 🔴 There is no stage 7. Four kinds of work, four shapes.
142
+
143
+ **This section replaced a single numbered list running 0 → 12, on 2026-08-03.** That list had a
144
+ paragraph on top explaining that the numbers were dependencies rather than turns — and underneath it,
145
+ a table numbered straight through, which every reader (including this pipeline's own author) read as a
146
+ waterfall. The paragraph was the tell: a document that needs a disclaimer explaining how not to read
147
+ it is mis-shaped, and the fix is to change the shape, not to add a second disclaimer. That is the
148
+ argument `compile-rules-2026` makes about instruction files, applied here.
149
+
150
+ Three concrete errors the numbering produced, all real:
151
+
152
+ - **`verify-citations` sat at 7**, looking like a one-shot step, while the project rule is that it runs
153
+ every cycle — an edit on the last day adds a `\cite` that "we checked last cycle" does not cover.
154
+ - **`render-paper` sat at 6**, as a stage. It is a command you run twenty times a day.
155
+ - **`map-prior-work` sat at 1.5** and its own description told you to re-run it as a cheap delta before
156
+ submit — so it was simultaneously a stage and a continuous check, and the table could only show one.
157
+
158
+ Work is now grouped by **how it runs**, and only the groups that are genuinely ordered carry an order.
159
+
160
+ | kind | shape | how to read it |
161
+ |---|---|---|
162
+ | **SETUP** | ordered | Each genuinely gates the next. Runs once, before the study is malleable. |
163
+ | **LOOP** | unordered cycle | Draft ↔ study ↔ arc ↔ review. No numbers, because there are no turns. |
164
+ | **CONTINUOUS** | trigger table | Fires when the thing it checks changes. Never "done". |
165
+ | **GATES** | ordered by input | Late, expensive, each hard-blocked on a named input. |
166
+
167
+ ---
168
+
169
+ ## SETUP — once, before anything is expensive to change
170
+
171
+ Ordered, because each really does gate the next. Two pairs run in parallel; that is marked.
172
+
173
+ | Step | Skill | What it settles |
174
+ |---|---|---|
175
+ | **Orient** | — | Read `<papers-root>/HANDOFF.md` + `<papers-root>/research/README.md`. Never restart from scratch. |
176
+ | **Validate the idea** | **`research-ideate`** | Is it a reusable method (survives review) in your lane, and does it feed the credit criteria? Go/no-go + the MVP finding. |
177
+ | **Map the competition** ‖ | **`map-prior-work`** | 🔴 **Who already did this?** Multi-angle sweep; date each hit against your submission (5 months = prior, not concurrent); triage by which layer of your claim it threatens; deep-read the dangerous ones. Output: **what you can still claim** + a related-work skeleton. *Added 2026-07-27 after a five-month-older paper surfaced at T−10 days on a finished draft.* |
178
+ | **Pick the venue** ‖ | **`find-venue`** | Rank by credit-weight (peer-reviewed + indexed) × fit × accept-odds × deadline × remote. |
179
+ | **Learn the venue's bar** | **`study-accepted-papers`** | 🔴 **What does an ACCEPTED paper look like HERE?** Measure the venue's whole accepted volume, deep-read 8–12 of your contribution type, and extract what made them strong: evidence scale, figures, artifact release, how the abstract is built. File the venue card (`submit-paper/references/venues/<venue>.md`) and confirm family rules (`references/acl-venue-rules.md`). *Promoted to its own step 2026-08-03: on `compile-rules-2026` every judgement of the paper's quality — rubric, persona, simulated panel, accept probability — came from instruments this pipeline itself generated, with no external grounding, and the author had to say so at T−3 days. A closed loop optimises against its own model of a reviewer.* |
180
+ | 🔴 **Can you physically submit?** | **`plan-paper-timeline`** | **The step that owns the question no stage used to own.** Create the portal account NOW; drive the profile to **ACTIVE**, not "pending moderation"; confirm the form's fields and the artifact-hosting requirement. OpenReview moderation runs **up to two weeks**, and an author with no institutional email has no expedite route. Scorecard row `access`. *Added 2026-08-03, when this was the sole critical-path item on a finished paper at T−4 days: the science was done and there was nowhere to put it.* |
181
+ | **Schedule it** | **`plan-paper-timeline`** | Deadlines → calendar with buffers, in the author's own zone (AoE − 12h ≠ your clock). Space papers apart. |
182
+ | 🔴 **State the claim** | **`argument-arc`** (frame mode) | **One paragraph: what will this paper claim, and what would have to be true?** Before any run. The frame decides which results matter, and reframing after the data is collected is how experiments get thrown away — observed on `compile-rules-2026`, and the reason `argument-arc` has a rebuild mode at all. Costs a paragraph; saves a study. Scorecard row `frame`. |
183
+
184
+ ## LOOP — iterates until it settles
185
+
186
+ No numbers. Nothing here happens once, and nothing here is "next".
187
+
188
+ ```
189
+ study ──────────► draft
190
+ build-benchmark draft-paper
191
+ ▲ │
192
+ │ ▼
193
+ argument-arc ◄──── the arc
194
+ (rebuild mode) 5.5 verdict
195
+ ```
196
+
197
+ - **`build-benchmark`** — a design that inverts the pitfall; honest stats; a self-checking artifact
198
+ (`references/artifact-checklist.md`).
199
+ - **`draft-paper`** — section skeleton + the accept-and-get-cited properties
200
+ (`references/writing-craft.md`).
201
+ - **`argument-arc`** — 🔴 **does the draft carry the reader to ONE conclusion?** One sentence per
202
+ section (*what does the reader now believe*), then a bottom-up pass asking whether each section makes
203
+ the conclusion harder to escape. Owns **rebuild mode**: the only protocol here for *the frame is
204
+ wrong, start the arc over*. Every other gate assumes a settled draft and patches it. *Added
205
+ 2026-07-30 after a full-day rewrite in which the author said five times that the paper threw ideas at
206
+ him and got five local edits back.*
207
+
208
+ **Leaving the loop** means the arc holds and the numbers are in. Not that the prose is pretty — that
209
+ is what the gates are for.
210
+
211
+ ## CONTINUOUS — fires when its input changes, never "done"
212
+
213
+ These have no position, because a position is what made them look finished. Each is a trigger.
214
+
215
+ | When this changes | Run | Why it cannot be a stage |
216
+ |---|---|---|
217
+ | any `\cite` added or moved | **`verify-citations`** | An edit on the last day adds a citation the last run never saw. "We checked last cycle" does not count — the project rule, and it was numbered as a one-shot anyway. |
218
+ | a genuine sibling surfaces | **`analyze-sibling-paper`** | Deep-read, scoop/delta, saved in `<paper-dir>/siblings/`. |
219
+ | the contribution's framing moves | **`map-prior-work`** (delta mode) | A cheap re-sweep. ⚠️ If a rival first surfaces during citation checking, the SETUP sweep was skipped and you are reshaping the contribution under deadline. |
220
+ | any `.tex` / `paper.md` edit | **`render-paper`** + page count | **Not a stage — a command.** Render, then eyeball pages 1–2 before believing anything about the paper. 🔴 **Rendering is continuous; ACTING on the page count is not** — see the rule below. |
221
+ | the deadline approaches | the `access` row | Re-check that the profile is still ACTIVE and the portal still opens. External state rots without telling you. |
222
+
223
+ ## GATES — late, expensive, each blocked on a named input
224
+
225
+ Ordered, and the order is real: every one refuses to run without the output of the one before it.
226
+
227
+ | Gate | Skill | Requires (hard) |
228
+ |---|---|---|
229
+ | **Structure** | **`tighten-paper`** | A rendered PDF and a page count. Produces the cut plan + structural verdict. *Before 2026-07-30 this appeared only INSIDE the harden stage — i.e. after the gate that requires it — so a literal reading sent you into a hard-blocked gate.* |
230
+ | **Writing craft** | **`grade-paper-writing`** | The current draft. Produces the **persona stall inventory**, which the panel cannot run without. |
231
+ | **Review decision** | **`pc-panel-review`** | 🔴 **Both of the above.** N independent lenses (incl. an artifact-runner that executes the artifact) + a chair meta-review — predicts the PC's accept/reject. Its venue-fit mode is the one-reviewer CFP-fit spot-check. |
232
+ | **Claim preservation** | Fable diff (`claims`) | The pre-pass baseline. Run after **every** aggressive rewrite, before committing. |
233
+ | **Harden** | **`harden-paper`** | The panel's verdict. Closes the desk-reject axes a reviewer-sim misses: threat-model, ethics/dual-use, page-fit, citability, double-blind hygiene, artifact-runs-clean. Its structure and writing axes are the **re-run/confirm** pass, not the first invocation. |
234
+ | **Submit** | **`submit-paper`** (+ the venue card) | 🔴 **The `access` row green.** Portal mechanics, PDF-only, artifact hosted anonymously, "ready for review" marked. |
235
+
236
+ ## AFTER — only reachable by acceptance
237
+
238
+ **`camera-ready`** — de-anonymize; public repo + archival DOI; complete disclosure. Then
239
+ **`extend-paper`** — extend (≥30% new) to a higher-prestige venue, the "second, stronger publication."
240
+
241
+ **Which review skill?** `paper-adversarial-review` = one hostile reviewer, fast defect hunt;
242
+ `pc-panel-review` = the full panel + meta-review that makes the accept/reject **decision** (its
243
+ **venue-fit mode** is the one-reviewer CFP-fit spot-check — formerly the standalone `venue-review-sim`).
244
+ Use an atom for a quick spot-check; **run the panel for the decision.**
245
+
246
+ **Four grading axes — don't confuse them.** A draft is judged on four independent axes, each its own
247
+ skill: 🔴 **argument architecture** — does the whole thing carry the reader to one conclusion
248
+ (`argument-arc`, in the LOOP; the axis that failed on `compile-rules-2026` precisely because it was
249
+ nobody's) · **content strength** — does the contribution clear *this venue's* bar (`study-accepted-papers`,
250
+ mines the accepted corpus for Accept→Strong levers; in SETUP, before the prose is set) ·
251
+ **scientific defects** — what a hostile reviewer attacks (`paper-adversarial-review` / `pc-panel-review`)
252
+ · **writing craft** — does it read like a human wrote it (`grade-paper-writing`, the 9-dim rubric in
253
+ `references/writing-craft.md`; called by `harden-paper`). A paper can ace one and fail another — grade all four.
254
+ **The arc axis comes first**, because tightening length and polishing sentences inside a broken arc is
255
+ how a day disappears and the same paper ships.
256
+
257
+ **Panel vs harden — not rival gates, they're sequential.** `pc-panel-review` is the review DECISION
258
+ gate: it predicts what the PC does. `harden-paper` is the pre-submit ORCHESTRATOR: it *calls* the review
259
+ skills and then closes the desk-reject axes a reviewer-sim doesn't systematically hit (threat-model,
260
+ ethics/dual-use, page-fit, citability, double-blind hygiene). Order is **review (decide) → harden (close
261
+ every other axis) → submit** — neither is "the one final gate" alone.
262
+
263
+ ## The review round (a cycle inside GATES)
264
+ Review → **apply the consensus fixes → re-run the panel to confirm**. The artifact-runner re-executes
265
+ the artifact each round. Stop when the panel converges to accept and the artifact reproduces clean —
266
+ **don't loop past one confirming round**, and don't chase the last notch into the deadline. A defensible
267
+ **Accept shipped on time beats a risky Strong that misses it**.
268
+
269
+ ## 📝 Text pass vs evidence pass — two independent axes, ask which one you want
270
+
271
+ The author, 2026-08-05 (translated from Russian): *"can we just run the gate on the text? we just
272
+ checked the numbers, and now I want to grade the text — assume the numbers are fine."* He is right that these are separable, and
273
+ running both when only one is wanted burns an hour for nothing.
274
+
275
+ Every gate belongs to exactly one axis. **Sort by what invalidates it**, not by what it reads:
276
+
277
+ | axis | invalidated by | gates |
278
+ |---|---|---|
279
+ | **TEXT** — does the argument land? | a change to the **prose**: any edit, cut, reorder | `structure` tighten-paper · `writing` grade-paper-writing · `arc` argument-arc · the prose lenses of `panel` pc-panel-review |
280
+ | **EVIDENCE** — is it true? | a change to the **data, code, or artifact** | `claims` claim-preservation · `cites` verify-citations · `artifact` the artifact-runner lens · the numeric half of `harden` harden-paper |
281
+
282
+ **Why this matters more than it looks.** The two axes expire on completely different clocks. Rewriting
283
+ a paragraph invalidates every TEXT gate and no EVIDENCE gate. Re-running an experiment does the exact
284
+ reverse. Conflating them produces both classic wastes: re-verifying numbers nobody touched, and — worse
285
+ — trusting a readability verdict on prose that has since been rewritten.
286
+
287
+ **Text-only pass** (the common request, and the right default after a cut, a reorder, or a rewrite where
288
+ the numbers did not move): run `structure` and `writing` in parallel, then `panel` with its artifact lens **explicitly
289
+ disabled**, and hand each agent the sentence *"assume every number is correct and already verified — do
290
+ not re-derive anything; judge the writing, the structure and the argument."* Roughly halves the wall
291
+ clock and removes the single most expensive stage.
292
+
293
+ **Evidence-only pass** is the mirror: a new experiment landed, the prose around it is stable. Run `claims`
294
+ and the artifact-runner; skip readability entirely.
295
+
296
+ 🔴 **State which pass you ran, in the scorecard row and in the reply.** A gate row that does not say
297
+ which axis it covered will be read as covering both — which is how a paper ends up believed to be
298
+ checked on a dimension nobody looked at.
299
+
300
+ ### 🔢 The one defect neither axis can see: a number correct on both axes and wrong anyway
301
+
302
+ **Observed 2026-08-05, on page 1, 29 hours before a deadline.** The abstract read *"147 real rules
303
+ files exactly as their projects committed them, 22 fail admission"*. The data has two arms over the
304
+ same 147 files: **strict** (files byte-for-byte as committed — nothing fails) and **annotated** (the
305
+ same files with the tool's proposed pointers written in — 22 fail). The 22 was from the annotated arm
306
+ and was described in the strict arm's words. Five more numbers had the same defect; a sixth was found
307
+ later in an appendix by machine, after two people had searched by hand.
308
+
309
+ **Every gate passed, and each for a good reason.** `cites` checks the reference is real. `claims` checks the
310
+ claim did not grow — and it did not, 22 was always 22. The artifact-runner recomputes the number from
311
+ the data and it reconciles, *because the number is correct*. The reading panel takes "unmodified" as a
312
+ fact about the world, which is what a reader does. **The defect lives only in the join between a
313
+ sentence and a field path, and nothing was holding both.** It is not a TEXT defect and not an EVIDENCE
314
+ defect; it is a defect of the edge between them, so no pass on either axis can be made to see it.
315
+
316
+ **The construction, not another pass.** A registered quantity is not written as digits at all:
317
+
318
+ ```
319
+ Over {{corpus.n}} real rules files, with the extractor's proposed mapping
320
+ taken as if an author had written it, {{annotated.failedContradicted}} fail admission.
321
+ ```
322
+
323
+ `<paper>/repro/numbers.tsv` gives each name its value, the JSON path or **formula** that recomputes
324
+ it, and two guards. The build refuses a PDF unless: the name resolves · the value still matches the
325
+ data · the **paragraph** names the arm (`requires`) · the **sentence** does not claim a different one
326
+ (`forbids`). Requires and forbids are separate on purpose — the pairing is auditing's, where a control
327
+ is tested once for *design* and once for *operating effectiveness*.
328
+
329
+ **Why paragraph for one and sentence for the other.** *"Every figure in this paragraph is the
330
+ counterfactual arm"* is good writing, and a sentence-scoped `requires` would forbid it. But *"exactly
331
+ as committed"* nine words from the number is the defect itself, so `forbids` has to be tight.
332
+
333
+ **Coverage without a migration.** `numbers-grandfathered.txt` lists every quantity that predates the
334
+ gate; adding a new raw one fails the build. This is `ADD CONSTRAINT ... NOT VALID` — the constraint
335
+ binds every row from now on, and the existing rows are *enumerated rather than exempted*, so the file
336
+ says out loud how many figures still have no machine-checked path to data. On the paper that has it:
337
+ 7 guarded, 248 grandfathered. That ratio is a finding, not a score.
338
+
339
+ **Adopting it in another paper:** copy `repro/paper_numbers.py`, `repro/paper_numbers.selftest.py` and
340
+ the three lines in `md2submission.py` that call `expand()`; generate the grandfather list from the
341
+ current draft; register the numbers a reviewer will actually check first. `check-provenance.mjs`
342
+ reports `no-numbers-gate` for any paper that has not.
343
+
344
+ 🔴 **Do not write the substitution half — it is `jinja2`, and `{{name}}` is already its syntax.**
345
+ Eleven candidates were installed and run on a real markdown-source ACL paper on 2026-08-05. The
346
+ result is not a matter of taste:
347
+
348
+ | candidate | verdict, from an actual run |
349
+ |---|---|
350
+ | **jinja2** | **adopt.** Our `{{annotated.failRate}}` was already valid Jinja2; dotted names are attribute access. Zero characters changed in the paper, byte-identical `.tex`. This is Manubot's mechanism, taken without Manubot. Use `StrictUndefined`, and move the block/comment delimiters off `{%`/`{#` if the paper might ever quote a config file |
351
+ | **knitr** | equally proven, also byte-identical. Rejected only for putting an R runtime into an artifact that otherwise needs `python3` + `pdflatex` |
352
+ | `\newcommand` + `numbers.tex` | works (1 line in the converter); the folk convention, ~12 GitHub hits, all hand-rolled. No package exists |
353
+ | **Quarto**, **pandoc lua filters** | ❌ **destroy the paper.** Markdown→markdown is a pandoc AST round-trip: HTML comments become raw blocks and `[58]` becomes `\[58\]`, so every citation renders as literal `\textbackslash{}[58]`. 3,120 diff lines on the real source. No ACL format exists for Quarto either |
354
+ | **cog.py** | ❌ line-oriented; cannot substitute mid-sentence |
355
+ | **pythontex** | ❌ not in Ubuntu TeX Live at any level, not on PyPI; CTAN zip + `.ins` build |
356
+ | **showyourwork** | ❌ LaTeX-only, and it manages *figures*, not in-text numbers |
357
+ | **Pweave** | ❌ dead — the one candidate with a markdown native format, broken against modern IPython |
358
+ | DVC · datalad · papermill | orthogonal and **worth adding**: they pin the data file to the pipeline that made it, a layer below anything here |
359
+
360
+ **🔴 Computing the value DISSOLVES the freshness problem — do not build a checker for it.** With no
361
+ recorded value there is nothing that can go stale, so there is nothing to verify. Adopting jinja2
362
+ deleted 137 lines of ours outright: a hand-rolled expression language with an `eval()` sandbox, a
363
+ renderer guessing which of six formattings the paper meant, a JSON-path walker and the comparison.
364
+ Recording-plus-verifying is the trap; computing is the wheel.
365
+
366
+ **Binding a number to its CONDITION is genuinely unoccupied**, and the reason is structural rather
367
+ than an accident of packaging: **every literate-programming tool models the paper as a program that
368
+ prints text**, so the prose is opaque *output*, not an input to a check. None of them has a hook
369
+ where you could say "and the sentence around this must say *counterfactual* and must not say *as
370
+ committed*". The near-misses read the manuscript but never the data — `statcheck` recomputes
371
+ p-values from statistics printed in the same sentence; `RegCheck` compares a paper to a study
372
+ registration with an LLM and reports to a human instead of failing a build. Searched and empty:
373
+ GitHub repo search (0 results), the Actions marketplace, the pre-commit hook ecosystem, PyPI, and
374
+ the Claude skill marketplaces.
375
+
376
+ 🔴 **And it is not a number-keyed table**: the first version keyed rules on the digits, and a paper
377
+ printing two unrelated 22s broke it the same hour. Key on the occurrence.
378
+
379
+ 🔴 **Hand the gate to a red team the same day you build it.** This one was, and seven holes came
380
+ back, the worst being that the original defect could simply be **retyped as digits** — its value was
381
+ grandfathered, so the guard applied to the macro and not to the claim. Every hole is now a case in
382
+ `repro/paper_numbers.selftest.py` (18/18, including three that must stay **quiet** — a gate that
383
+ fires on ordinary writing gets muted, and then its silence reads as coverage).
384
+
385
+ ## 🔴 The page limit is a SUBMISSION gate, not an EDIT gate
386
+
387
+ **Observed failure, `compile-rules-2026`, 2026-08-02/03.** The body oscillated 8 ↔ 9 pages for roughly
388
+ fifty iterations. Each time content went in, the page count read 9, and prose came out to get back to
389
+ 8 — sixty characters at a time. Every individual cut looked harmless. Their sum is the unanimous 2/5
390
+ for clarity: the first compression took real repetition, the second had none left and took
391
+ transitions, antecedents and the conclusion's honest half. The structural pass named the arithmetic —
392
+ 780 words of genuine repetition removed, then 880 words in and 480 out, leaving the paper 51 words
393
+ *heavier* than before the pass that cut 780.
394
+
395
+ **The rule.** Content work runs OVER the limit on purpose. Compression is **one pass, at the end**,
396
+ when the content has settled — with a whole-draft view, so it can move a section instead of shaving a
397
+ clause. Going over during drafting is not a problem to fix; it is the normal state of a paper that is
398
+ still growing.
399
+
400
+ **The trigger to catch yourself:** you just added something, ran the page count, saw it over, and
401
+ started looking for words to remove **in the section you were just editing**. That is the failure, in
402
+ progress. The page count is information for the end of the work, not an alarm during it. (The author's
403
+ own words on catching it, translated from Russian: *"you're cutting the text right away — dunno if that really needs doing immediately."*)
404
+
405
+ **What is still continuous:** rendering, and looking at pages 1–2. Seeing the number is fine. Acting
406
+ on it is what waits.
407
+
408
+ 🔴 **Every round adds text; pay it back — in ONE pass.** Review is a ratchet — fixes are additive, so a
409
+ paper that survives three rounds is longer and denser than the one that entered them. On `compile-rules-2026` the
410
+ body oscillated 8 ↔ 9 pages for ~50 iterations, and the squeezing is what produced the unanimous 2/5 on
411
+ clarity: the first compression took real repetition, the second had none left and took transitions,
412
+ antecedents and the conclusion's honest half. After each round's fixes, run `tighten-paper` — and if the
413
+ page limit is binding, **move** rather than delete (Limitations and Ethics do not count toward ACL page
414
+ limits). The trap in that move is real and named in `references/acl-venue-rules.md`: relocating a caveat
415
+ while its flattering number stays in the body is exactly the asymmetry reviewers punish.
416
+
417
+ **Anti-churn ≠ skipping unrun gates.** "Don't loop past one confirming round" forbids *re-polishing prose
418
+ that already passed a gate* — it does NOT license *skipping a gate that never ran*. A `☐` row in
419
+ `PIPELINE-STATUS.md` for **study-accepted-papers, pc-panel-review, or full harden-paper** is an unrun
420
+ quality gate, not churn: **if capacity exists, run it before calling the paper done.** (This session
421
+ skipped those three under an "anti-churn" rationalization on a submitted paper; when the user forced them,
422
+ the pc-panel caught real must-fixes — a release overclaim and an unsupported number — that the skip would
423
+ have shipped.) Churn is re-touching FINE prose; a never-run gate is a hole. If a real
424
+ objection is out of scope, name it in Threats to Validity (adversarial reviewers read Threats first; an
425
+ honest limitation reads as strength).
426
+
427
+ **A `☐` in GATES is a hole. A `☐` in CONTINUOUS is worse** — it means the check exists, ran once, and
428
+ has been silently stale ever since. That is the shape of every failure this pipeline has actually had.
429
+
430
+ ## ⏱️ What each stage actually costs — MEASURED, not estimated
431
+
432
+ The author, 2026-08-05, watching a run he could not size (translated from Russian): *"is it worth
433
+ writing the timing problem into the pipeline skill?"*. Yes — because the project already forbids guessing here. The rule in the papers tree's own `CLAUDE.md`
434
+ says an estimate must be decomposed into labour / calendar / result-risk / access and **spiked
435
+ rather than guessed**, and the same session it was written I still launched an experiment with no
436
+ upper bound and had to cut it four hours later.
437
+
438
+ Every number below is subagent **wall clock, measured on 2026-08-04/05** while finishing
439
+ `compile-rules-2026`. They are one machine, one paper, one day — treat them as an order of
440
+ magnitude, not a promise. Re-measure rather than inherit.
441
+
442
+ | stage | measured | note |
443
+ |---|--:|---|
444
+ | `verify-citations`, one reference | **3 min** | sonnet; a fetch and a comparison |
445
+ | `verify-citations`, eight references | **3 min** | the fetches parallelise; count barely matters |
446
+ | a single reconciliation ("do these two numbers agree?") | **4 min** | sonnet, over committed data |
447
+ | a second-rater pass over ~20 rows | **8 min** | opens every cited file |
448
+ | a process/mechanism research pass (docs + source + issue tracker) | **10 min** | |
449
+ | `pc-panel-review`, full panel + chair | **17 min** | unchanged for the confirming round |
450
+ | `grade-paper-writing` incl. the persona cold read | **20 min** | |
451
+ | bundling an experiment into the artifact + gate + re-zip | **24–39 min** | scales with directories, not bytes |
452
+ | a design/measurement **spike** (feasibility, a handful of cells) | **27 min** | |
453
+ | `tighten-paper` applied, with a loss letter | **34 min** | includes several build round-trips |
454
+ | `harden-paper` | **36 min** | the widest gate; it runs the artifact |
455
+ | **an experiment with real checkouts and installed dependencies** | **≈4 h for 143 cells** | median cell **76 s**; the outlier by an order of magnitude |
456
+
457
+ **What the shape tells you, which matters more than the rows.**
458
+
459
+ - **A full gate cycle — `tighten` → `grade` → `panel` — is about 1.2 hours.** That is cheap enough
460
+ to run after any substantial edit, and there is no excuse for a stale gate on a paper you are
461
+ still touching.
462
+ - **Reading, checking and reviewing are all minutes.** Anything whose cost is dominated by fetching,
463
+ parsing or judging text lands in the 3–40 minute band regardless of how important it feels.
464
+ - 🔴 **Anything that installs dependencies and runs an agent inside a real checkout is hours, and
465
+ that is the only class that is.** Its cost is *per cell*: rows × arms × seeds × ~76 s. Compute
466
+ that product **before launching**, and say it out loud. 6 rows × 5 arms × 4 seeds = 120 cells ≈
467
+ 2.5 h; carrying the same design to 21 rows would have been ≈ 9 h.
468
+ - **Therefore: bound experiments by a cell budget, never by "run it and see".** Pick the number of
469
+ rows from the time available, decide up front what a complete balanced design is, and stop at the
470
+ last complete row. A design closed at six rows is a result; a design abandoned at eleven is a mess.
471
+
472
+ ## Model policy (which model runs which stage)
473
+ Single home for the whole suite — stage skills point here instead of each re-deciding. Default:
474
+ - **Adversarial / red-team / verify a claim** → **Fable** (a separate model; never the author grading
475
+ itself): `paper-adversarial-review`, `pc-panel-review` reviewers, `harden-paper` threat-model +
476
+ citability red-team, disputed `verify-citations` verdicts.
477
+ - **Heavy generation / synthesis** → the session's main model (**Opus**): `draft-paper`,
478
+ `build-benchmark` design, `extend-paper`, `research-ideate`.
479
+ - **Cheap bulk fetch / extraction** → **Haiku** (or Sonnet): `study-accepted-papers` corpus pull,
480
+ `plan-paper-timeline`.
481
+ - **No model at all (mechanical)** → `verify-citations`'s `../verify-citations/scripts/verify-cites.mjs` reducer,
482
+ `harden-paper`'s `check-*.sh` linters, `render-paper` toolchain.
483
+ - **Judge panels use DIVERSE models, not N copies of one** → `grade-paper-writing`, `pc-panel-review`:
484
+ mix Opus + Fable + Sonnet so independent lenses catch what redundancy can't.
485
+
486
+ Override per call when a stage clearly needs otherwise; this is the default, not a straitjacket.
487
+
488
+ ## Rules
489
+ - **Fable (a separate model) is always the reviewer** — never let the author grade itself.
490
+ - **Never fabricate** a citation, number, or result. Mark `% VERIFY` and check (`verify-citations`).
491
+ - **Commit + push after each stage**, keep the tree clean (resume-safe across `/compact`); update
492
+ `<papers-root>/research/README.md` in the same commit as any new research file (its CLAUDE.md enforces this).
493
+ - **Two roles, never double-counted:** authoring = the *authorship* criterion; reviewing others at the
494
+ venue (the organizer review-offer email) = the *judging* criterion — a separate credential.
495
+
496
+ ## Provenance
497
+ Two real papers this session ran this pipeline end-to-end: **AgenticDev 2026 @ ASE** ("Measuring the
498
+ Wrong Number," ~90%, submitted #20) and **AISec 2026 @ ACM CCS** ("Safety Theater," Weak-Accept→~87–88%
499
+ after a panel round + confirm). The stage skills and shared refs are distilled from exactly those runs.