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,431 @@
1
+ ---
2
+ title: "Occupancy research — reproducible-article and paper-QA tooling (does it already exist?)"
3
+ created: 2026-08-06
4
+ tags:
5
+ [
6
+ paper-pipeline,
7
+ occupancy-research,
8
+ reproducibility,
9
+ latex-tooling,
10
+ citation-verification,
11
+ tool-survey,
12
+ ]
13
+ ---
14
+
15
+ # Occupancy research — reproducible-article and paper-QA tooling
16
+
17
+ **Question asked:** the homegrown pipeline does page-limit counting, anonymity grep, a
18
+ number-provenance registry, citation verification, prose linting, section-justification
19
+ notes, and artifact-URL checks. Before continuing to maintain it by hand — what already
20
+ ships, from whom, and does it actually close these gaps?
21
+
22
+ **Method:** every claim below was fetched live (WebSearch + WebFetch on 2026-08-06), not
23
+ recalled from training. Dates/stars/versions are what the source showed on that date and
24
+ will drift — re-check before trusting a specific number months later. This is a survey,
25
+ not a recommendation — no design proposed here.
26
+
27
+ ---
28
+
29
+ ## 1. Reproducible-article pipelines (figure/number ↔ code+data)
30
+
31
+ ### showyourwork (rodluger/showyourwork)
32
+
33
+ - **What it is:** an open-source scientific-article workflow built on **Snakemake** +
34
+ the **tectonic** typesetting engine + **GitHub Actions**. A repo holds LaTeX
35
+ manuscript files, figure-generating scripts, an environment file, and dataset-download
36
+ instructions; on every push, a GitHub Action rebuilds the article from scratch so "the
37
+ compiled article PDF is always in sync with all of the code used to generate it."
38
+ - **The exact mechanism that matches the hand-built number-provenance registry:**
39
+ the `\variable{...}` command. Quoting the docs (`show-your.work/en/latest/latex/`):
40
+ `\variable` is an alias for `\input` that "explicitly marks the file as a dependency
41
+ of the manuscript in the workflow graph, which automatically generates the file if it
42
+ is missing **and re-builds the article whenever the script or rule that generates that
43
+ file is modified**." A number in prose is never hand-typed — it lives in a
44
+ Snakemake-tracked output file, and the build DAG regenerates it whenever the
45
+ generating script or its inputs change.
46
+ - **Caveat, read carefully:** this does NOT implement "type a number, then verify it
47
+ against a fresh computation and fail if it drifted." It implements something
48
+ stronger — the number literally cannot be hand-typed at all; it is always the
49
+ freshly generated file content. There is no drift-detection step because there is no
50
+ manual value to drift from. If your pipeline's actual pattern is "author types `47%`
51
+ in prose, CI recomputes `47%` from data and diffs" — showyourwork doesn't do that
52
+ diff; it removes the need for it by construction, which requires migrating every
53
+ such number into a `\variable{}`-managed script output.
54
+ - **Is it alive?** Yes, confirmed by checking commit history directly: **most recent
55
+ commit August 4, 2026**, 30+ commits July–August 2026, multiple contributors. Note the
56
+ docs site itself carries a stale scare-banner ("the last release is 2+ years old") —
57
+ that banner is outdated relative to actual GitHub activity; don't trust the docs
58
+ banner over the commit log. 662 GitHub stars.
59
+ - **What it explicitly does NOT cover:** citation verification, anonymity, prose
60
+ linting, page limits — confirmed absent from the docs; it's scoped to computational
61
+ reproducibility of figures/values, nothing else in your list.
62
+ - **Adoption cost:** high. It's not a linter you bolt on — it replaces your build with a
63
+ Snakemake DAG (rules per figure/table/variable), pins a conda/pip environment, and
64
+ wants tectonic instead of pdflatex. Migrating an existing homegrown Python-to-LaTeX
65
+ script into this model is a rewrite, not an install.
66
+ - **Fetched:** https://show-your.work/en/latest/ , https://show-your.work/en/latest/latex/ ,
67
+ https://github.com/showyourwork/showyourwork/commits/main
68
+
69
+ ### Quarto / knitr–R Markdown (the "inline code" mechanism)
70
+
71
+ - **What it is:** literate-document engines where prose and code interleave; at render
72
+ time the code executes and its return value is spliced into text.
73
+ - **Quarto inline code** (docs quote, `quarto.org/docs/computations/inline-code.html`):
74
+ `` `r mean(x)` `` style inline expressions — _"Inline expressions are **always
75
+ evaluated** when rendering and previewing `.qmd` files."_ Same idea in R
76
+ Markdown/knitr: `` `r format(1234567, big.mark=",")` `` inline in the prose, evaluated
77
+ on every knit.
78
+ - **This is the closest shipped analogue to "a number in text must be recomputed from
79
+ data at render time."** Same structural move as showyourwork's `\variable`: the number
80
+ is never manually typed, so there's nothing to drift. Difference from showyourwork:
81
+ Quarto/knitr compute inline in the same document (lighter-weight, no separate
82
+ Snakemake DAG); showyourwork tracks values as separate build-graph artifacts (heavier,
83
+ but works across a whole multi-figure paper with explicit dependency edges).
84
+ - **Caveat:** Quarto's **freeze** feature (caching computed output so CI doesn't
85
+ re-execute code every time) can reintroduce exactly the staleness this mechanism is
86
+ meant to prevent, if a data file changes but the freeze cache isn't invalidated —
87
+ that's a real footgun to watch for if adopting Quarto for this reason. The docs
88
+ fetched didn't cover freeze-vs-inline-code interaction explicitly; treat as an open
89
+ question, not a resolved caveat.
90
+ - **MyST / Jupyter Book 2:** same executable-document family (built on the MyST Document
91
+ Engine, a full rewrite replacing the old Sphinx-based Jupyter Book). Status as of
92
+ 2026: **Jupyter Book 2 is an active subproject of Project Jupyter**, myst-parser sees
93
+ continued activity; some components (MyST-NB specifically) are explicitly called out
94
+ as "in maintenance mode" — not the whole stack. It provides the same "code executes,
95
+ value gets embedded" mechanism as Quarto/knitr, aimed more at books/docs than
96
+ camera-ready conference PDFs; ACL/ACM/IEEE LaTeX-class output is not its native path.
97
+ - **papermill:** parameterizes and executes **Jupyter notebooks** programmatically (tag a
98
+ `parameters` cell, pass values, execute headlessly, save the output notebook). This is
99
+ a batch-execution tool, not a text/number-embedding tool — it doesn't put numbers into
100
+ LaTeX prose. Relevant only as plumbing if your pipeline's "recompute" step is itself a
101
+ notebook.
102
+ - **Pweave:** older Python literate-programming tool (Sweave/knitr equivalent for
103
+ Python). Search turned up **no clear current maintenance signal** — recent search
104
+ results returned unrelated "Weave" products (Weaveworks GitOps, weave.ai), not Pweave
105
+ itself. Treat as likely dormant/superseded by Quarto for new work; did not find
106
+ positive evidence of 2025–2026 activity either way — flagging as **unverified**, not
107
+ "confirmed dead," per the retry-before-declaring-dead rule.
108
+ - **Adoption cost:** Quarto — moderate (new toolchain, `.qmd` format, but has LaTeX/PDF
109
+ output including some conference templates); knitr/R Markdown — moderate if already
110
+ in the R ecosystem, awkward if the pipeline is Python-native; MyST/Jupyter
111
+ Book — moderate-high, not conference-template-native.
112
+ - **Fetched:** https://quarto.org/docs/computations/inline-code.html ,
113
+ R Markdown/knitr inline-code docs (rmarkdown.rstudio.com, rstudio.github.io/rmarkdown),
114
+ https://github.com/jupyter-book/mystmd , https://executablebooks.org/en/latest/blog/2024-05-20-jupyter-book-myst/
115
+
116
+ ---
117
+
118
+ ## 2. Publisher-side format checkers
119
+
120
+ ### aclpubcheck (acl-org/aclpubcheck)
121
+
122
+ - **What it checks** (README, quoted): "automatically detects **font errors, author
123
+ formatting errors, margin violations, outdated citations** as well as many other
124
+ common formatting errors in papers that are using the LaTeX sty file associated with
125
+ ACL venues." Also: page-numbering/bottom-margin checks, paper-type-specific rules
126
+ (`--paper_type {long,short,other}`).
127
+ - **Operates on the built PDF**, not the LaTeX source — you run
128
+ `python3 aclpubcheck/formatchecker.py --paper_type long paper.pdf`.
129
+ - **Known false positives** (README, quoted): _"some of the warnings generated for
130
+ citations may be spurious and inaccurate, due to parsing and indexing errors"_; margin
131
+ checks generate spurious errors on line-numbered review-mode PDFs.
132
+ - Citation checking uses the **Scholarcy API** against ACL Anthology/DBLP/arXiv — this
133
+ is the same general shape of check as the citation-verification tools in §4, but
134
+ scoped to "is this citation outdated" (e.g., cite the workshop version when a
135
+ conference version now exists), not "does this citation exist at all / does the title
136
+ match."
137
+ - **Used by ACL pub chairs themselves** for camera-ready checks, and is explicitly
138
+ recommended for **pre-submission** self-checking too.
139
+ - **Superset tooling from other publishers, confirmed to exist:**
140
+ - **IEEE PDF eXpress** — free online service; converts source to PDF or validates an
141
+ author-created PDF against Xplore's compatibility spec, "check author-created PDFs
142
+ and report whether or not they are IEEE Xplore-compatible."
143
+ - **IEEE also ships**: the **IEEE LaTeX Analyzer** (validates LaTeX source) and the
144
+ **IEEE Reference Preparation Assistant** (checks reference-list formatting) —
145
+ separate tools from PDF eXpress.
146
+ - **ACM TAPS** (The ACM Production System, homepage fetched directly): converts
147
+ LaTeX/Word source into PDF+HTML5+XML for the Digital Library. Fetched page confirms
148
+ it checks: LaTeX package-allowlist compliance, required rights-commands presence,
149
+ figure/image file-path validity, citation-style conformance (SIGGRAPH/SIGPLAN
150
+ variants), Word-doc validation status. **Quoted directly: "If the program to which
151
+ you are submitting your content has a page limit associated with the final
152
+ documentation, it is YOUR responsibility to make sure that the generated PDF version
153
+ of your content meets that requirement."** — TAPS explicitly disclaims page-limit
154
+ enforcement, and the page makes no mention of URL-resolution or font-embedding
155
+ checks; a human production editor reviews after the fact for what TAPS misses.
156
+ - **Springer tooling:** not found as a distinct public automated checker in this
157
+ search pass — Springer's LaTeX class + submission portal exist, but no
158
+ Springer-branded pdfcheck/analyzer equivalent to IEEE's or ACM TAPS's surfaced.
159
+ Flagging as **not found**, not confirmed absent (would need a deeper Springer-portal-specific
160
+ pass to call this empty with confidence).
161
+ - **Is there a maintained superset of aclpubcheck?** Not found as a single tool — the
162
+ "superset" is really the union of aclpubcheck (ACL-specific) + IEEE's three tools +
163
+ ACM TAPS, each scoped to its own publisher's house style; no cross-publisher
164
+ format-checker exists.
165
+ - **Fetched:** https://github.com/acl-org/aclpubcheck ,
166
+ https://homes.cs.washington.edu/~spencer/taps/taps.html ,
167
+ IEEE Author Center pages (journals.ieeeauthorcenter.ieee.org)
168
+
169
+ ---
170
+
171
+ ## 3. LaTeX-source QA tools
172
+
173
+ | Tool | What it does | Anonymity strip? | Comment strip? | Status |
174
+ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
175
+ | **chktex** | Semantic/style linter — "Lint for LaTeX," catches typographic/spacing mistakes (e.g. unescaped space after abbreviation, `...` vs `\ldots`) | No | No | **Alive** — v1.7.10 released 2026-02-26, "6 - Mature" on Savannah, in TeXLive/CTAN |
176
+ | **lacheck** | Older, narrower style checker, similar class of checks to chktex | No | No | Still shipped in TeX distros; no independent recent-release signal found |
177
+ | **textidote** (sylvainhalle/textidote) | Wraps LanguageTool for grammar/spelling (12+ languages) over de-macro'd LaTeX text; **also does structural sanity checks**: every figure referenced?, section-title capitalization, `\cite`/`\citep` mixing, hard-coded numbers vs `\ref` | No — explicitly confirmed: does not check anonymity or citation _accuracy_ | No | 1.1k stars, has a maintained GitHub Action (`textidote-action`) |
178
+ | **latexdiff** | Produces a marked-up diff between two LaTeX versions (word-level, not line-level) | N/A (diff tool) | N/A | Standard, shipped in TeX distros |
179
+ | **rubber** / **latexmk** | Build wrappers (dependency-aware recompilation, bibtex/biber re-runs) | N/A | N/A | Both alive — rubber has an active GitLab with 3 maintainers; latexmk ships in TeXLive, "not deprecated," more widely used |
180
+ | **CheckMyTex** (d-krupke/CheckMyTex) | **Aggregator**: bundles aspell/pyspellchecker (spelling), LanguageTool (grammar), chktex (LaTeX smells), proselint (prose advice), plus siunitx-usage and cleveref-usage checks, into one CLI walkthrough | No | No | Alive, PyPI-published, Unix-only |
181
+ | **arxiv-latex-cleaner** (google-research) | Strips `%`-comments, `\iffalse...\fi`/`\if0...\fi`/`\begin{comment}` blocks, removes unused `.tex`/image files, compresses images/PDFs, deletes user-specified commands, externalizes TikZ | **No** — confirmed no author-name/affiliation/acknowledgment stripping in docs | **Yes**, for actual `%` comments and `\iffalse`-style blocks | Alive, v1.0.11, 176 commits |
182
+ | **ALC-NG** (COMSYS/ALC-NG) | Extends arxiv-latex-cleaner: handles custom `\if` conditionals, strips EXIF metadata from images/PDFs via exiftool, validates cleaned output is pixel-identical to the original PDF | **No** — confirmed no anonymization feature | Enhanced (custom conditionals) | Backed by a 2026 IEEE S&P paper (arXiv:2604.20927), 45 stars, "experimental, use at your own risk" |
183
+
184
+ **Directly answering the two specific asks:**
185
+
186
+ - **"He shipped a PDF with working editorial comments typeset into it" — does any tool
187
+ catch this?** Not found. `todonotes`/`mnotes`-style LaTeX packages exist to
188
+ _hide_ comments in a "final" build mode (`mnotes` explicitly has a
189
+ no-comments-in-camera-ready option), but that's an authoring convention the author
190
+ must remember to invoke — **no tool was found that detects a `\todo{}`/margin-note
191
+ macro that rendered visibly into the compiled PDF.** This is a real gap.
192
+ - **"He separately shipped a broken `\url`" — does any tool catch this?** chktex/lacheck
193
+ check LaTeX _syntax_ of `\url{}`, not whether the URL _resolves_. That's a distinct,
194
+ network-dependent check — see §4 below (pdf-link-checker) for the tool that actually
195
+ does this, which works on the built PDF, not the LaTeX source.
196
+
197
+ **Anonymity specifically:** searched directly for automated leak-detection. What exists
198
+ is **toggle packages** (`anonymous-acm.sty`, `anonymize.sty`, AAAI's anonymous-submission
199
+ instructions) that let an author flip an `\ifAnonCondition` to hide the author block —
200
+ these are _authoring conventions_, not _detectors_. **No automated tool was found that
201
+ greps a compiled paper's body/acknowledgments/footnotes for identity leaks** (self-cites
202
+ in first person, institutional URLs, funded-by statements) — best practice found was a
203
+ manual checklist (Nature's double-blind checklist PDF). **This is a genuinely empty
204
+ category** — see ranked table.
205
+
206
+ **Fetched:** https://www.nongnu.org/chktex/ , https://github.com/sylvainhalle/textidote ,
207
+ https://github.com/petrhosek/rubber , https://github.com/d-krupke/CheckMyTex ,
208
+ https://github.com/google-research/arxiv-latex-cleaner , https://github.com/COMSYS/ALC-NG
209
+
210
+ ---
211
+
212
+ ## 4. Built-PDF-level checks
213
+
214
+ | Tool | What it does | Status |
215
+ | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
216
+ | **pdfx** (metachris/pdfx) | Extracts text/metadata/references (embedded PDF refs, URLs, DOIs, arXiv IDs) from a PDF; **"can find broken hyperlinks"**; optional parallel download of every referenced PDF | Established Python/CLI tool, works as library or CLI |
217
+ | **pdf-link-checker** (bootlin) | Parses a PDF, extracts hyperlinks, sends HTTP requests to each, reports broken ones | GPLv2, free software |
218
+ | **pdf-link-checker** (a-nau) | Same idea, packaged as both a **CLI and a GitHub Action** (`v0.2.0`) — this is the one to actually wire into CI | MIT, 8 stars, 21 commits — small but does the specific job and is CI-ready |
219
+ | **qpdf** | Structural PDF transform/inspect tool (linearize, decrypt, page manipulation) — general PDF plumbing, not a paper-QA-specific checker | Standard, mature |
220
+ | **veraPDF** | Industry-standard **PDF/A / PDF/UA validator** — checks standards conformance including embedded-font compliance via Schematron assertions against a validation profile | Actively maintained (PDF Association-backed); note a filed issue where **veraPDF flags a LaTeX `pdfx`-package PDF/A output as non-compliant while Adobe Preflight passes it** — i.e. even the standards validators disagree with each other on LaTeX-generated PDFs, worth knowing before trusting a single verdict |
221
+
222
+ **Directly answers "does font-embedding get checked":** yes — veraPDF does this, but
223
+ it's a PDF/A-conformance tool, so adopting it means also caring about (or filtering
224
+ around) all the _other_ PDF/A rules that have nothing to do with your paper (color
225
+ spaces, XMP metadata, etc.) — it's not a scoped "just check my fonts" tool.
226
+
227
+ **Fetched:** https://github.com/metachris/pdfx , https://github.com/a-nau/pdf-link-checker ,
228
+ https://docs.verapdf.org/validation/ , https://github.com/veraPDF/veraPDF-library/issues/957
229
+
230
+ ---
231
+
232
+ ## 5. Citation / reference verification
233
+
234
+ This is the section that matters most for **"nine fabricated citation titles with
235
+ correct arXiv IDs"** — the specific failure mode where the identifier resolves but the
236
+ title/authors attached to it are hallucinated.
237
+
238
+ | Tool | Verifies title-vs-DOI/arXiv match? | Detects fabrication? | Status |
239
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
240
+ | **rebiber** (yuchenlin/rebiber) | **No.** Normalizes bib entries against DBLP/ACL-Anthology official records and replaces stale arXiv-only cites with published-venue info. Confirmed via docs: it does _not_ verify title accuracy or detect fabrication — it assumes the entry is legitimate and just standardizes/upgrades it. | No | Alive — v1.2.0 (July 2024), 3,000 stars |
241
+ | **bibtex-tidy** (FlamingTempura/bibtex-tidy) | No — pure formatting/dedup tool, no DOI/Crossref lookup | No | Alive — 1.1k stars, 626 commits, v1.14.0-era, has pre-commit hook + Docker |
242
+ | **doi2bib** (multiple independent implementations) | Converts a known-good DOI/arXiv-ID into a BibTeX entry via Crossref — this is generation, not verification of an entry you already have | No | Multiple small, independently maintained clones (PauCasanova, vandroogenbroeckmarc, pazner, mseri, bibcure, OpenByteDev) — all narrow single-purpose scripts |
243
+ | **fixbibtex** (jaimergp/fixbibtex) | **Partial yes.** Queries Crossref with author+title, computes a similarity score; **below 0.75 similarity it falls back to a DOI-based query and updates the entry if the DOI-fetched title matches ≥0.75** — this is a real "does the title match what the identifier actually points to" check | Partial (via the similarity-threshold fallback) | Found via search, smaller/less-established than the others |
244
+ | **BibTeX Verifier** (merfanian.github.io/Bibtex-Verifier) | **Yes, explicitly.** Quoted: _"flags entries whose titles don't match any known publication — catching fabricated references from AI-generated bibliographies — by querying both Semantic Scholar and CrossRef."_ Runs client-side in-browser (no upload of the whole .bib, only titles sent to public APIs) | **Yes, this is its stated purpose** | Open source, MIT-licensed, GitHub-hosted, but a **hosted web app / manual drag-and-drop tool — no CLI or CI integration found**, and its own FAQ admits "arXiv preprints, workshop papers, theses, and very recent publications may not be found" |
245
+ | **citecheck** (jhlee0619/citecheck) | **Yes.** MCP server + TypeScript CLI; extracts refs from `.bib`/`.tex`/`.md`/`.txt`/`.docx`, validates against **PubMed, Crossref, arXiv, Semantic Scholar**, returns structured correction proposals with "replacement-safety diagnostics." Companion software paper on arXiv (2603.17339), submitted to **JOSS** (under review as of March 2026, tracked at `openjournals/joss-reviews#10224`) | **Yes, core purpose** ("citation hallucinations" from LLMs named explicitly in the paper abstract) | v0.1.12, installed via `npx -y @jhlee0619/citecheck`, no Python toolchain needed — **light adoption cost**. Young project (JOSS review still pending in-progress as of the fetch) — treat as promising but not battle-tested |
246
+ | **sciwrite-lint** (authentic-research-partners/sciwrite-lint) | **Yes**, and goes further — see below | **Yes** | See detailed writeup below |
247
+ | **Crossref / OpenAlex / Semantic Scholar APIs directly** | These are the data sources every tool above queries. You could write your own thin verifier directly against them (which is arguably what the homegrown pipeline already half-does) | N/A — raw APIs, no verification logic of their own | All three actively maintained public APIs |
248
+
249
+ ### sciwrite-lint — closest single match to the whole described pipeline
250
+
251
+ This is the most direct occupant of the described problem space, and worth reading in
252
+ detail rather than summarizing away.
253
+
254
+ - **What it is**, quoting its own framing: applies "the linting paradigm from software
255
+ engineering to citation verification: it runs entirely on the researcher's machine,"
256
+ using free public databases, a single consumer GPU, and open-weight local LLMs (no
257
+ cloud API calls).
258
+ - **23 automated checks**, spanning categories that map almost one-to-one onto the
259
+ homegrown pipeline:
260
+ - **Reference verification** — existence across CrossRef/OpenAlex/Semantic
261
+ Scholar/Open Library/Library of Congress; metadata accuracy (title/authors/year/venue);
262
+ **retraction detection** against 60,000+ Retraction Watch entries (this is a check
263
+ the homegrown pipeline almost certainly does NOT have); fuzzy matching when no DOI
264
+ present.
265
+ - **Claim support** — downloads full text from 14 open-access sources (arXiv, PMC,
266
+ bioRxiv, NBER, etc.), runs GROBID parsing + section-level embeddings, classifies
267
+ _why_ each citation is used (evidence / contrast / method / attribution / context),
268
+ and checks whether the cited paper's own claims actually support what you say it
269
+ supports. This is a genuinely different, deeper check than any other tool found —
270
+ closer to "does this citation actually say what I claim it says" than "does this
271
+ citation exist."
272
+ - **Manuscript consistency** — cross-section contradiction detection, **number/table
273
+ disagreement checks**, arithmetic and percentage validation, sample-size (N)
274
+ tracking across the paper, causal-language-in-correlational-study flagging,
275
+ abstract-vs-body alignment, p-value-vs-interpretation consistency, "structure
276
+ promises" (does the intro promise something the body doesn't deliver), prose-quality
277
+ scoring per sentence.
278
+ - **Figure analysis** — caption-to-content matching, text-to-figure accuracy, axis
279
+ labels, figure/table cross-agreement.
280
+ - **Deterministic text checks** — dangling `\cite{}` (no matching `.bib` entry),
281
+ dangling `\ref{}` (no matching `\label{}`), unreferenced figures.
282
+ - **Explicitly does NOT do** (confirmed absent from its own scope): **page limits,
283
+ anonymity/double-blind stripping, artifact-URL validation** (only in-text footnote
284
+ URLs get verified, not a general "does every URL resolve" sweep), and prose linting
285
+ is limited to grammar/word-choice, not the deeper structural prose work.
286
+ - **Adoption cost is real and non-trivial:** requires an **NVIDIA GPU with 16+ GB VRAM**,
287
+ Docker/Podman, CUDA drivers, NVIDIA Container Toolkit, plus a GROBID container for PDF
288
+ parsing. Install via `uv tool install sciwrite-lint --python 3.13` or a manual
289
+ pip+editable-install path. This is not a `pip install` weekend add — it's a local
290
+ ML-inference stack.
291
+ - **Status:** MIT license, 24 stars, 3 forks — small, young (arXiv:2604.08501, submitted
292
+ April 2026, author Sergey V. Samsonau). Not battle-tested at scale; the deterministic
293
+ checks (dangling cites/refs) are cheap and safe to adopt regardless of the GPU-heavy
294
+ LLM checks; the claim-support/consistency checks are the valuable-but-expensive part.
295
+ - **Fetched:** https://github.com/authentic-research-partners/sciwrite-lint (full README),
296
+ https://arxiv.org/abs/2604.08501
297
+
298
+ ### Adjacent research (not adoptable tools, but worth knowing the field exists)
299
+
300
+ - **ScientistOne** (arXiv:2605.26340) — a "Numerical Claim Provenance Rate (CPR)"
301
+ concept: an LLM-authoring system annotates every number-bearing sentence with a source
302
+ log-line tag, then a claim verifier checks the written number against the log within a
303
+ 5% tolerance. This is architecturally the closest published concept to "number
304
+ provenance registry with drift detection" in the entire search — but it's a research
305
+ paper describing an internal component of an autonomous-research-agent system, **not
306
+ a standalone tool you can install**.
307
+ - **PaperTrail** (CHI 2026, arXiv:2602.21045) — a claim-evidence UI for grounding LLM
308
+ scholarly Q&A answers in source documents; adjacent field, not a paper-QA pipeline
309
+ tool.
310
+
311
+ ---
312
+
313
+ ## 6. Whole "paper CI" pipelines
314
+
315
+ - **latex-action** (xu-cheng/latex-action) — GitHub Action that compiles LaTeX to PDF in
316
+ a full TeXLive Docker container, multiple engines supported. This is **compilation
317
+ only** — no QA checks bundled.
318
+ - **paper-maker** (andycasey/paper-maker) — builds a LaTeX manuscript via GitHub Actions
319
+ and pushes the compiled PDF back into the repo. Same scope: build automation, not QA.
320
+ - **paperaj** (dermatologist/paperaj) — standalone script or GitHub Action, similar
321
+ build-only scope.
322
+ - **No maintained "paper-ci" template repo was found that bundles a battery of QA checks
323
+ (format + anonymity + citations + page-limit + link-check) into one composable CI
324
+ workflow.** The GitHub topics `reproducible-paper` and `academic-paper-template`
325
+ surfaced RMarkdown/Quarto reproducibility templates and generic paper-writing
326
+ templates, but nothing that already wires together aclpubcheck + chktex + a citation
327
+ verifier + a link checker + a page-limit check as one pipeline. **This is the clearest
328
+ fully-empty category in the whole survey** — closest you get is manually chaining
329
+ latex-action (build) → aclpubcheck (format) → a-nau/pdf-link-checker (links) →
330
+ citecheck or sciwrite-lint's deterministic checks (citations) yourself, which is
331
+ functionally what the homegrown pipeline already is.
332
+ - **Fetched:** https://github.com/xu-cheng/latex-action , https://github.com/andycasey/paper-maker ,
333
+ GitHub topic pages for `reproducible-paper`, `academic-paper`, `citation-verification`
334
+
335
+ ---
336
+
337
+ ## 7. Page-limit counting
338
+
339
+ - **texcount** (CTAN package, Perl script) — mature, shipped in every TeX distribution.
340
+ Directly answers the page-limit-counting need: `-char`/`-charws` for character-limit
341
+ venues, `-1` flag prints a bare number for scripting a hard-limit check, `-inc` to
342
+ recurse across included files, `-total` to combine. Drives VS Code LaTeX Workshop's
343
+ status-bar count and TeXstudio/TeXmaker's built-in counters.
344
+ - This is squarely **ADOPT** — it's exactly the deterministic check already being
345
+ hand-rolled, already packaged, already in the TeX distro you're already using.
346
+ - **Fetched:** CTAN texcount page, app.uio.no/ifi/texcount/
347
+
348
+ ---
349
+
350
+ ## 8. Section-justification notes
351
+
352
+ Searched directly for any tool/convention matching "a note attached to each section
353
+ justifying why it exists, checked mechanically." Found only generic academic-writing
354
+ advice (Editage, Duke/UCLA library guides on "how to write a research justification
355
+ section") — this is writing-craft advice about a _type of section content_, not a
356
+ mechanical process/tool for the _author's own notes about structure_. **Confirmed
357
+ genuinely empty** — no shipped tool occupies this at all; it appears to be a bespoke
358
+ process invention specific to this pipeline.
359
+
360
+ ---
361
+
362
+ ## Ranked table
363
+
364
+ | # | Problem we hand-built | Shipped tool that already does it | Adoption cost | Verdict |
365
+ | --- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
366
+ | 1 | Page-limit / word-limit counting | **texcount** | Already in your TeX distro; one CLI flag | **ADOPT** |
367
+ | 2 | Number-in-text must be recomputed from data, build fails on drift | **showyourwork `\variable{}`** (Snakemake-tracked) or **Quarto/knitr inline code** (`` `r expr` ``) — both eliminate drift by construction rather than detecting it | High (showyourwork = Snakemake rewrite) / Moderate (Quarto = new doc format, partial LaTeX/conference-template support) | **ADOPT-PARTIAL** — real mechanism exists but requires migrating numeric claims into script-output files or inline code cells; won't slot into the existing Python-to-LaTeX script unmodified |
368
+ | 3 | Citation exists / metadata accurate / not fabricated | **citecheck** (MCP+CLI, npx install, checks Crossref/arXiv/PubMed/S2) or **sciwrite-lint**'s deterministic + reference-verification layer | Low (citecheck) / High for the GPU-based claim-support layer (sciwrite-lint) | **ADOPT** (citecheck for the light case) / **ADOPT-PARTIAL** (sciwrite-lint for the deep case) |
369
+ | 4 | Fabricated citation: correct arXiv ID, wrong/hallucinated title | **BibTeX Verifier** (web tool, explicit stated purpose) + **fixbibtex** (similarity-threshold DOI fallback) + **citecheck**/**sciwrite-lint** (same via API cross-check) | Low–Moderate (no single CLI is dominant; BibTeX Verifier is browser-only, no CI hook) | **ADOPT-PARTIAL** — the check exists in multiple independent tools, none is a clean CI-native single answer yet |
370
+ | 5 | ACL/venue format compliance (fonts, margins, page numbers, outdated cites) | **aclpubcheck** | Low — `pip install`, run on built PDF | **ADOPT** (if ACL-family venue) |
371
+ | 6 | Publisher PDF/Xplore/DL compatibility | **IEEE PDF eXpress** / **ACM TAPS** | Low, but venue-specific and often manual/portal-based, not CI-scriptable | **ADOPT-PARTIAL** — exists but not automatable into your own CI, and TAPS explicitly disclaims page-limit checking |
372
+ | 7 | LaTeX style/semantic lint (typos, spacing, macro misuse) | **chktex**, **lacheck**, or the aggregator **CheckMyTex** | Low | **ADOPT** |
373
+ | 8 | Prose quality / grammar | **textidote** or **CheckMyTex**'s LanguageTool+proselint bundle | Low–Moderate (needs LanguageTool + Aspell installed) | **ADOPT** |
374
+ | 9 | Comment/anonymity-relevant content stripped before arXiv submission | **arxiv-latex-cleaner** (comments only) / **ALC-NG** (comments + EXIF) | Low | **ADOPT-PARTIAL** — strips comments, does NOT anonymize |
375
+ | 10 | Anonymity leak grep (self-cites, institutional URLs, funded-by lines, author names in body) | _(only toggle-packages: `anonymous-acm.sty`, `anonymize.sty` — hide-on-render, not detect)_ | N/A | **GENUINELY EMPTY** |
376
+ | 11 | Editorial comment/`\todo` macro accidentally left visible in shipped PDF | _(none found)_ | N/A | **GENUINELY EMPTY** |
377
+ | 12 | Broken `\url` / dead links in the built PDF | **a-nau/pdf-link-checker** (CLI + GitHub Action) or **bootlin/pdf-link-checker** or **pdfx** | Low — `pip install`, or drop-in GitHub Action | **ADOPT** |
378
+ | 13 | Font embedding / PDF standards conformance | **veraPDF** | Low–Moderate (install + pick a validation profile; verdicts can disagree with Adobe Preflight on LaTeX output) | **ADOPT-PARTIAL** |
379
+ | 14 | Artifact-URL checks (does the linked OSF/Zenodo/GitHub artifact actually resolve and is it archived properly) | **pdf-link-checker** covers URL-resolves; **artifact-evaluation committee checklists** (Zenodo/Software Heritage DOI requirements per-venue) cover the archival-quality bar, but that's a human checklist, not automated tooling | Low (link-resolves part) / N/A (archival-quality part is manual per-venue) | **ADOPT-PARTIAL** |
380
+ | 15 | Section-justification notes (why does this section exist, mechanically checked) | _(none found — only generic "how to write a justification section" writing advice)_ | N/A | **GENUINELY EMPTY** |
381
+ | 16 | One CI pipeline that bundles all of the above ("paper-ci") | _(none found — closest are build-only Actions like latex-action/paper-maker, with zero QA bundled)_ | N/A — would have to be assembled by hand from rows 1–14 | **GENUINELY EMPTY** |
382
+
383
+ ### Bottom line for the "don't reinvent the wheel" instinct
384
+
385
+ The instinct was **partly right and partly wrong**. Right: page-limit counting (texcount),
386
+ LaTeX linting (chktex/CheckMyTex), link-checking (pdf-link-checker), venue-format
387
+ checking (aclpubcheck), and citation-existence/fabrication checking (citecheck,
388
+ BibTeX Verifier, sciwrite-lint) are all real, shipped, and should replace the equivalent
389
+ homegrown pieces outright. Wrong: the **number-provenance-registry mechanism** the
390
+ pipeline hand-built has no drop-in replacement — the shipped equivalents
391
+ (showyourwork, Quarto/knitr) solve the same underlying problem but by a structurally
392
+ different, more invasive route (own the whole document-generation pipeline) rather than
393
+ a bolt-on verifier; and **three pieces of the pipeline — anonymity-leak grep,
394
+ typeset-comment detection, and section-justification notes — are not occupied by
395
+ anyone**, confirmed by direct search, not just by failing to find them. Those three are
396
+ the only parts actually worth continuing to hand-build; everything else in the ranked
397
+ table above is a wheel that already exists somewhere in this survey.
398
+
399
+ ---
400
+
401
+ ## 🔴 Verified by running it, 2026-08-24 — the note surveyed 7 tools, adopted 0
402
+
403
+ Measured on the day of the check: `rebiber · citecheck · sciwrite-lint · fixbibtex · bibtex-tidy ·
404
+ aclpubcheck` — **zero mentions** outside this file (no skill, no script, no hook). The file itself
405
+ is cited only by other research notes. So the research was good and **never once turned into a
406
+ decision**.
407
+
408
+ **And three of the facts above did not survive being run.** This is not a jab at the note's
409
+ author — it is about method: the table was built by reading READMEs and APIs, not by executing
410
+ anything.
411
+
412
+ | row above | what running it on 24.08 showed |
413
+ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
414
+ | `betterbib` — **missing from the table entirely** | and it is the most obvious candidate (`sync` against Crossref/**DBLP**/PubMed/arXiv). And it is **NO LONGER OPEN-SOURCE**: `pip install` installs a compiled `.sfc` bundle + `stonefish_license_manager`, the import fails; the vendor's site (texworld) requires buying a license. Not adopting it — but this should have been known beforehand, not after |
415
+ | `citecheck` — "v0.1.12", "MCP server **+ TypeScript CLI**" | npm registry: version **0.1.0**, published 2026-04-11, the only `bin` is `citecheck-mcp`. **There is no CLI, it is an MCP server only.** `npx … --help` prints nothing and exits 0 |
416
+ | `rebiber` — "does not verify title accuracy → No" | the verdict is **right about its stated purpose and wrong in practice**: it does not verify by itself, but **diffing its output against ours** found two real defects on 24.08. A tool should be judged by what its OUTPUT gives you, not by how it advertises itself |
417
+
418
+ ⚠️ Plus a measured limit of `rebiber` itself: its **local DBLP dump** missed
419
+ `raji2021benchmark`, which the live DBLP API found immediately. For cross-checking, hit the API.
420
+
421
+ **What follows from this for our venue (AgenticDev @ ASE = ACM, DOI `10.1145/…`,
422
+ ISBN `979-8-4007-…`):** there is no community offline checker for ACM **by design** — the check is
423
+ done publisher-side (the HotCRP format checker + TAPS), which lines 138–158 above already
424
+ established. The ready-made author-side mechanism for an ACM paper is **`acmart` itself**: on
425
+ 24.08 it honestly printed three camera-ready blockers to `paper.log` (wrong fonts → silent
426
+ Computer Modern; figures missing `\Description`; missing CCS), and none of them was read. Wired
427
+ into `render-paper/check-render.sh` — twenty lines of grep, not a new tool.
428
+
429
+ **The rule this block was added for:** an occupancy note is not closed until every row has a
430
+ recorded **ADOPT / REJECT + reason** verdict, and until at least the ADOPT rows have been **run**.
431
+ A table of stars and version numbers is not an occupancy check yet — it is its draft.