paperlint 3.2.0 → 4.1.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 (442) hide show
  1. package/.github/workflows/ci.yml +16 -23
  2. package/CLAUDE.md +33 -13
  3. package/CONTRIBUTING.md +23 -7
  4. package/README.md +11 -8
  5. package/dist/adapters/banal/failure.d.ts +1 -7
  6. package/dist/adapters/banal/failure.d.ts.map +1 -1
  7. package/dist/adapters/banal/failure.js +5 -7
  8. package/dist/adapters/banal/failure.js.map +1 -1
  9. package/dist/adapters/banal/index.d.ts.map +1 -1
  10. package/dist/adapters/banal/index.js +8 -11
  11. package/dist/adapters/banal/index.js.map +1 -1
  12. package/dist/adapters/banal/install.d.ts.map +1 -1
  13. package/dist/adapters/banal/install.js +4 -3
  14. package/dist/adapters/banal/install.js.map +1 -1
  15. package/dist/adapters/banal/invocation.d.ts +10 -5
  16. package/dist/adapters/banal/invocation.d.ts.map +1 -1
  17. package/dist/adapters/banal/invocation.js +13 -1
  18. package/dist/adapters/banal/invocation.js.map +1 -1
  19. package/dist/adapters/banal/locate.d.ts +12 -9
  20. package/dist/adapters/banal/locate.d.ts.map +1 -1
  21. package/dist/adapters/banal/locate.js +19 -12
  22. package/dist/adapters/banal/locate.js.map +1 -1
  23. package/dist/adapters/banal/run.d.ts +10 -1
  24. package/dist/adapters/banal/run.d.ts.map +1 -1
  25. package/dist/adapters/banal/run.js +8 -4
  26. package/dist/adapters/banal/run.js.map +1 -1
  27. package/dist/adapters/banal/settings.d.ts +1 -1
  28. package/dist/adapters/banal/settings.d.ts.map +1 -1
  29. package/dist/adapters/banal/settings.js +2 -1
  30. package/dist/adapters/banal/settings.js.map +1 -1
  31. package/dist/adapters/latex/document-class.d.ts +22 -0
  32. package/dist/adapters/latex/document-class.d.ts.map +1 -0
  33. package/dist/adapters/latex/document-class.js +102 -0
  34. package/dist/adapters/latex/document-class.js.map +1 -0
  35. package/dist/adapters/latex/hidden.d.ts +16 -0
  36. package/dist/adapters/latex/hidden.d.ts.map +1 -0
  37. package/dist/adapters/latex/hidden.js +49 -0
  38. package/dist/adapters/latex/hidden.js.map +1 -0
  39. package/dist/adapters/latex/index.d.ts +29 -0
  40. package/dist/adapters/latex/index.d.ts.map +1 -0
  41. package/dist/adapters/latex/index.js +18 -0
  42. package/dist/adapters/latex/index.js.map +1 -0
  43. package/dist/adapters/latex/nodes.d.ts +54 -0
  44. package/dist/adapters/latex/nodes.d.ts.map +1 -0
  45. package/dist/adapters/latex/nodes.js +93 -0
  46. package/dist/adapters/latex/nodes.js.map +1 -0
  47. package/dist/adapters/latex/outline.d.ts +10 -0
  48. package/dist/adapters/latex/outline.d.ts.map +1 -0
  49. package/dist/adapters/latex/outline.js +39 -0
  50. package/dist/adapters/latex/outline.js.map +1 -0
  51. package/dist/adapters/latex/parse.d.ts +42 -0
  52. package/dist/adapters/latex/parse.d.ts.map +1 -0
  53. package/dist/adapters/latex/parse.js +94 -0
  54. package/dist/adapters/latex/parse.js.map +1 -0
  55. package/dist/adapters/latex/rendered.d.ts +10 -0
  56. package/dist/adapters/latex/rendered.d.ts.map +1 -0
  57. package/dist/adapters/latex/rendered.js +39 -0
  58. package/dist/adapters/latex/rendered.js.map +1 -0
  59. package/dist/adapters/memory/index.d.ts.map +1 -1
  60. package/dist/adapters/memory/index.js +8 -2
  61. package/dist/adapters/memory/index.js.map +1 -1
  62. package/dist/adapters/node/process.io.d.ts +6 -3
  63. package/dist/adapters/node/process.io.d.ts.map +1 -1
  64. package/dist/adapters/node/process.io.js.map +1 -1
  65. package/dist/adapters/node/workspace.io.d.ts.map +1 -1
  66. package/dist/adapters/node/workspace.io.js +4 -2
  67. package/dist/adapters/node/workspace.io.js.map +1 -1
  68. package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
  69. package/dist/adapters/pdfjs/fill.js +12 -12
  70. package/dist/adapters/pdfjs/fill.js.map +1 -1
  71. package/dist/adapters/references/index.d.ts.map +1 -1
  72. package/dist/adapters/references/index.js +4 -2
  73. package/dist/adapters/references/index.js.map +1 -1
  74. package/dist/build-engine.d.ts +1 -1
  75. package/dist/build-engine.d.ts.map +1 -1
  76. package/dist/build-engine.js +8 -1
  77. package/dist/build-engine.js.map +1 -1
  78. package/dist/build.d.ts +2 -3
  79. package/dist/build.d.ts.map +1 -1
  80. package/dist/build.js +9 -10
  81. package/dist/build.js.map +1 -1
  82. package/dist/caller-path.d.ts +3 -0
  83. package/dist/caller-path.d.ts.map +1 -0
  84. package/dist/caller-path.js +13 -0
  85. package/dist/caller-path.js.map +1 -0
  86. package/dist/cli.d.ts +10 -17
  87. package/dist/cli.d.ts.map +1 -1
  88. package/dist/cli.js +91 -17
  89. package/dist/cli.js.map +1 -1
  90. package/dist/doctor.d.ts +12 -3
  91. package/dist/doctor.d.ts.map +1 -1
  92. package/dist/doctor.js +2 -1
  93. package/dist/doctor.js.map +1 -1
  94. package/dist/domain/paths.d.ts +8 -2
  95. package/dist/domain/paths.d.ts.map +1 -1
  96. package/dist/domain/paths.js +12 -1
  97. package/dist/domain/paths.js.map +1 -1
  98. package/dist/domain/ready.d.ts +24 -0
  99. package/dist/domain/ready.d.ts.map +1 -0
  100. package/dist/domain/ready.js +11 -0
  101. package/dist/domain/ready.js.map +1 -0
  102. package/dist/domain/record.d.ts +8 -0
  103. package/dist/domain/record.d.ts.map +1 -0
  104. package/dist/domain/record.js +8 -0
  105. package/dist/domain/record.js.map +1 -0
  106. package/dist/domain/sha256.d.ts.map +1 -1
  107. package/dist/domain/sha256.js +4 -2
  108. package/dist/domain/sha256.js.map +1 -1
  109. package/dist/domain/tex-document.d.ts +84 -0
  110. package/dist/domain/tex-document.d.ts.map +1 -0
  111. package/dist/domain/tex-document.js +43 -0
  112. package/dist/domain/tex-document.js.map +1 -0
  113. package/dist/engine.d.ts +23 -22
  114. package/dist/engine.d.ts.map +1 -1
  115. package/dist/engine.js.map +1 -1
  116. package/dist/eslint-rules/bib-reachable-entry.d.ts +1 -1
  117. package/dist/eslint-rules/bib-reachable-entry.js.map +1 -1
  118. package/dist/eslint-rules/install-path-literals.d.ts +2 -2
  119. package/dist/eslint-rules/install-path-literals.js.map +1 -1
  120. package/dist/eslint-rules/paper-research-question.d.ts +1 -1
  121. package/dist/eslint-rules/paper-research-question.js.map +1 -1
  122. package/dist/eslint-rules/paper-stages.d.ts +2 -2
  123. package/dist/eslint-rules/paper-stages.js.map +1 -1
  124. package/dist/eslint-rules/paper-typography.d.ts +6 -6
  125. package/dist/eslint-rules/paper-typography.js.map +1 -1
  126. package/dist/eslint-rules/pdf-last-page-balance.d.ts +1 -1
  127. package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -1
  128. package/dist/eslint-rules/review-frontmatter.d.ts +2 -2
  129. package/dist/eslint-rules/review-frontmatter.js.map +1 -1
  130. package/dist/eslint-rules/sibling-frontmatter.d.ts +1 -1
  131. package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -1
  132. package/dist/eslint-rules/temp-root-realpath.d.ts +1 -1
  133. package/dist/eslint-rules/temp-root-realpath.js.map +1 -1
  134. package/dist/eslint-rules/tex-build.d.ts +2 -2
  135. package/dist/eslint-rules/tex-build.js.map +1 -1
  136. package/dist/facts-file.d.ts.map +1 -1
  137. package/dist/facts-file.js +31 -28
  138. package/dist/facts-file.js.map +1 -1
  139. package/dist/hooks-settings.d.ts.map +1 -1
  140. package/dist/hooks-settings.js +17 -2
  141. package/dist/hooks-settings.js.map +1 -1
  142. package/dist/init.d.ts +3 -4
  143. package/dist/init.d.ts.map +1 -1
  144. package/dist/init.js +18 -8
  145. package/dist/init.js.map +1 -1
  146. package/dist/lib/paper-config.d.ts.map +1 -1
  147. package/dist/lib/paper-config.js +1 -5
  148. package/dist/lib/paper-config.js.map +1 -1
  149. package/dist/new-paper.d.ts +5 -0
  150. package/dist/new-paper.d.ts.map +1 -1
  151. package/dist/new-paper.js +8 -1
  152. package/dist/new-paper.js.map +1 -1
  153. package/dist/package-dirs.d.ts +5 -0
  154. package/dist/package-dirs.d.ts.map +1 -0
  155. package/dist/package-dirs.js +14 -0
  156. package/dist/package-dirs.js.map +1 -0
  157. package/dist/paper-files.d.ts +4 -4
  158. package/dist/paper-files.d.ts.map +1 -1
  159. package/dist/paper-files.js +6 -6
  160. package/dist/paper-files.js.map +1 -1
  161. package/dist/paper-settings.js +3 -3
  162. package/dist/paper-settings.js.map +1 -1
  163. package/dist/pdf-facts.d.ts +51 -1
  164. package/dist/pdf-facts.d.ts.map +1 -1
  165. package/dist/pdf-facts.js +23 -15
  166. package/dist/pdf-facts.js.map +1 -1
  167. package/dist/pdf-geometry.d.ts.map +1 -1
  168. package/dist/pdf-geometry.js +2 -3
  169. package/dist/pdf-geometry.js.map +1 -1
  170. package/dist/ports/latex.d.ts +24 -0
  171. package/dist/ports/latex.d.ts.map +1 -0
  172. package/dist/ports/latex.js +2 -0
  173. package/dist/ports/latex.js.map +1 -0
  174. package/dist/ports/tool-installer.d.ts +2 -14
  175. package/dist/ports/tool-installer.d.ts.map +1 -1
  176. package/dist/presets.d.ts +15 -2
  177. package/dist/presets.d.ts.map +1 -1
  178. package/dist/presets.js +35 -10
  179. package/dist/presets.js.map +1 -1
  180. package/dist/references.d.ts.map +1 -1
  181. package/dist/references.js +4 -4
  182. package/dist/references.js.map +1 -1
  183. package/dist/rules-config.d.ts +26 -1
  184. package/dist/rules-config.d.ts.map +1 -1
  185. package/dist/rules-config.js +9 -9
  186. package/dist/rules-config.js.map +1 -1
  187. package/dist/tex-requirements.d.ts +15 -0
  188. package/dist/tex-requirements.d.ts.map +1 -1
  189. package/dist/tex-requirements.js +28 -10
  190. package/dist/tex-requirements.js.map +1 -1
  191. package/dist/tex-venue-rules.d.ts +83 -0
  192. package/dist/tex-venue-rules.d.ts.map +1 -0
  193. package/dist/tex-venue-rules.js +254 -0
  194. package/dist/tex-venue-rules.js.map +1 -0
  195. package/dist/types.d.ts +5 -3
  196. package/dist/types.d.ts.map +1 -1
  197. package/dist/venue-rules.d.ts +1 -1
  198. package/dist/venue-rules.d.ts.map +1 -1
  199. package/dist/venue-rules.js +20 -7
  200. package/dist/venue-rules.js.map +1 -1
  201. package/docs/configuration.md +5 -4
  202. package/docs/e2e.md +69 -40
  203. package/docs/install.md +1 -1
  204. package/docs/prior-art/README.md +1 -1
  205. package/docs/prior-art/package-location.md +5 -5
  206. package/docs/prior-art/repro/README.md +1 -1
  207. package/docs/prior-art/test-tooling.md +21 -10
  208. package/docs/rules/tex/required-section.md +73 -0
  209. package/docs/rules/tex/template.md +62 -0
  210. package/docs/rules/tex/venue-leftover.md +71 -0
  211. package/docs/rules.md +70 -48
  212. package/docs/testing.md +17 -4
  213. package/docs/texlive-install-decision.md +1 -1
  214. package/docs/toolchain.md +2 -2
  215. package/eslint-rules/bib-reachable-entry.ts +1 -1
  216. package/eslint-rules/install-path-literals.ts +2 -2
  217. package/eslint-rules/paper-research-question.ts +1 -1
  218. package/eslint-rules/paper-stages.ts +2 -2
  219. package/eslint-rules/paper-typography.ts +2 -2
  220. package/eslint-rules/pdf-last-page-balance.ts +1 -1
  221. package/eslint-rules/review-frontmatter.ts +1 -1
  222. package/eslint-rules/temp-root-realpath.ts +1 -1
  223. package/eslint-rules/tex-build.ts +2 -2
  224. package/eslint.config.mjs +162 -15
  225. package/fixtures/build-e2e/acmart/expect.json +26 -0
  226. package/fixtures/build-e2e/aidc/PIPELINE-STATUS.md +3 -0
  227. package/fixtures/build-e2e/aidc/expect.json +14 -0
  228. package/fixtures/build-e2e/aidc/paper.tex +46 -0
  229. package/fixtures/build-e2e/aidc/paperlint.json +1 -0
  230. package/fixtures/build-e2e/broken/expect.json +11 -0
  231. package/fixtures/build-e2e/cite/expect.json +27 -0
  232. package/fixtures/build-e2e/empty/expect.json +12 -0
  233. package/fixtures/build-e2e/fallback/expect.json +53 -0
  234. package/fixtures/build-e2e/guards/expect.json +6 -0
  235. package/fixtures/build-e2e/no-source/expect.json +10 -0
  236. package/fixtures/build-e2e/unbalanced/expect.json +60 -0
  237. package/fixtures/install-path-literals/clean.fixture.mjs +1 -1
  238. package/fixtures/install-path-literals/clean.md +2 -2
  239. package/fixtures/install-path-literals/defect.fixture.mjs +1 -1
  240. package/fixtures/install-path-literals/defect.md +2 -2
  241. package/fixtures/pdf-facts/README.md +1 -1
  242. package/fixtures/real-markdown-paper/baseline.ts +1 -1
  243. package/fixtures/render-paper/build-clean.sh +3 -5
  244. package/hooks/paper-status-gates.sh +9 -19
  245. package/lib/paper-config.harness.mjs +1 -1
  246. package/lib/paper-config.ts +1 -5
  247. package/lib/skill-checks.mjs +24 -381
  248. package/lib/skill-checks.test.mjs +63 -115
  249. package/lib/skill-corpus.mjs +10 -251
  250. package/lib/skill-corpus.test.mjs +2 -13
  251. package/lib/skill-trigger-cases.mjs +1 -1
  252. package/package.json +13 -2
  253. package/{skills/submit-paper/references/venues → presets}/acm-sigconf.jsonc +4 -1
  254. package/{skills/submit-paper/references/venues → presets}/agenticdev.jsonc +4 -0
  255. package/presets/aidc.jsonc +73 -0
  256. package/{skills/submit-paper/references/venues → presets}/aisec.jsonc +4 -0
  257. package/presets/ieee-conference.jsonc +66 -0
  258. package/{skills/submit-paper/references/venues → presets}/realm.jsonc +8 -1
  259. package/{skills/submit-paper/references/venues → presets/tex}/paper-guards.tex +1 -1
  260. package/{skills/submit-paper/references/venues → presets}/venue-profile.schema.json +30 -2
  261. package/scripts/check.harness.ts +64 -10
  262. package/scripts/check.test.ts +60 -13
  263. package/scripts/check.ts +83 -30
  264. package/scripts/coverage-config.test.ts +0 -1
  265. package/scripts/harness-api.frozen.json +0 -1
  266. package/scripts/test.test.ts +1 -1
  267. package/scripts/test.ts +1 -1
  268. package/skills/analyze-sibling-paper/SKILL.md +1 -39
  269. package/skills/analyze-sibling-paper/SKILL.md.spec.ts +0 -38
  270. package/skills/argument-arc/SKILL.md +2 -36
  271. package/skills/argument-arc/SKILL.md.spec.ts +1 -43
  272. package/skills/build-benchmark/SKILL.md +1 -41
  273. package/skills/build-benchmark/SKILL.md.spec.ts +0 -40
  274. package/skills/camera-ready/SKILL.md +1 -34
  275. package/skills/camera-ready/SKILL.md.spec.ts +0 -33
  276. package/skills/cold-read-diff/SKILL.md +1 -35
  277. package/skills/cold-read-diff/SKILL.md.spec.ts +0 -34
  278. package/skills/draft-paper/SKILL.md +2 -41
  279. package/skills/draft-paper/SKILL.md.spec.ts +1 -50
  280. package/skills/extend-paper/SKILL.md +2 -33
  281. package/skills/extend-paper/SKILL.md.spec.ts +1 -42
  282. package/skills/find-venue/SKILL.md +2 -38
  283. package/skills/find-venue/SKILL.md.spec.ts +1 -47
  284. package/skills/grade-paper-writing/SKILL.md +3 -38
  285. package/skills/grade-paper-writing/SKILL.md.spec.ts +2 -47
  286. package/skills/grade-paper-writing/prose-lint.mjs +2 -3
  287. package/skills/grade-paper-writing/prose-lint.test.ts +1 -1
  288. package/skills/harden-paper/SKILL.md +1 -39
  289. package/skills/harden-paper/SKILL.md.spec.ts +0 -38
  290. package/skills/map-prior-work/SKILL.md +1 -35
  291. package/skills/map-prior-work/SKILL.md.spec.ts +0 -34
  292. package/skills/osf-artifact-upload/osf-artifact-upload.harness.ts +3 -4
  293. package/skills/paper-adversarial-review/SKILL.md +2 -35
  294. package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -43
  295. package/skills/paper-pipeline/PIPELINE-MAP.md +2 -2
  296. package/skills/paper-pipeline/SKILL.md +3 -29
  297. package/skills/paper-pipeline/SKILL.md.spec.ts +2 -28
  298. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +1 -1
  299. package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
  300. package/skills/paper-pipeline/references/acceptance-gate.md +1 -6
  301. package/skills/paper-pipeline/references/pipeline-status-template.md +8 -35
  302. package/skills/paper-pipeline/scripts/README.md +30 -225
  303. package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +4 -8
  304. package/skills/paper-pipeline/scripts/consumer.d.mts +0 -2
  305. package/skills/paper-pipeline/scripts/consumer.harness.mjs +6 -104
  306. package/skills/paper-pipeline/scripts/consumer.mjs +24 -119
  307. package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
  308. package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
  309. package/skills/paper-status/SKILL.md +2 -42
  310. package/skills/paper-status/SKILL.md.spec.ts +1 -41
  311. package/skills/pc-panel-review/SKILL.md +2 -46
  312. package/skills/pc-panel-review/SKILL.md.spec.ts +1 -45
  313. package/skills/plan-paper-timeline/SKILL.md +2 -36
  314. package/skills/plan-paper-timeline/SKILL.md.spec.ts +0 -36
  315. package/skills/render-paper/SKILL.md +2 -38
  316. package/skills/render-paper/SKILL.md.spec.ts +1 -37
  317. package/skills/render-paper/check-render.sh +16 -63
  318. package/skills/render-paper/render-paper.harness.mjs +17 -59
  319. package/skills/research-ideate/SKILL.md +2 -39
  320. package/skills/research-ideate/SKILL.md.spec.ts +1 -47
  321. package/skills/study-accepted-papers/SKILL.md +1 -34
  322. package/skills/study-accepted-papers/SKILL.md.spec.ts +0 -33
  323. package/skills/submit-paper/SKILL.md +1 -33
  324. package/skills/submit-paper/SKILL.md.spec.ts +0 -32
  325. package/skills/sweep-design-space/SKILL.md +1 -38
  326. package/skills/sweep-design-space/SKILL.md.spec.ts +0 -37
  327. package/skills/tighten-paper/SKILL.md +2 -39
  328. package/skills/tighten-paper/SKILL.md.spec.ts +1 -47
  329. package/skills/tighten-paper/structure.mjs +4 -11
  330. package/skills/verify-citations/SKILL.md +2 -38
  331. package/skills/verify-citations/SKILL.md.spec.ts +1 -37
  332. package/src/adapters/banal/failure.ts +9 -10
  333. package/src/adapters/banal/index.test.ts +3 -3
  334. package/src/adapters/banal/index.ts +8 -10
  335. package/src/adapters/banal/install.ts +9 -4
  336. package/src/adapters/banal/invocation.test.ts +20 -8
  337. package/src/adapters/banal/invocation.ts +24 -9
  338. package/src/adapters/banal/locate.test.ts +2 -2
  339. package/src/adapters/banal/locate.ts +27 -21
  340. package/src/adapters/banal/output.test.ts +1 -1
  341. package/src/adapters/banal/run.test.ts +3 -3
  342. package/src/adapters/banal/run.ts +16 -10
  343. package/src/adapters/banal/settings.ts +2 -2
  344. package/src/adapters/banal/xml.test.ts +1 -1
  345. package/src/adapters/curl/download.test.ts +4 -4
  346. package/src/adapters/latex/document-class.ts +147 -0
  347. package/src/adapters/latex/hidden.ts +70 -0
  348. package/src/adapters/latex/index.test.ts +361 -0
  349. package/src/adapters/latex/index.ts +55 -0
  350. package/src/adapters/latex/nodes.ts +141 -0
  351. package/src/adapters/latex/outline.ts +64 -0
  352. package/src/adapters/latex/parse.ts +136 -0
  353. package/src/adapters/latex/rendered.ts +59 -0
  354. package/src/adapters/memory/index.ts +4 -3
  355. package/src/adapters/node/files.test.ts +5 -3
  356. package/src/adapters/node/process.io.ts +9 -2
  357. package/src/adapters/node/process.test.ts +4 -4
  358. package/src/adapters/node/workspace.io.ts +9 -4
  359. package/src/adapters/pdfjs/fill.test.ts +1 -1
  360. package/src/adapters/pdfjs/fill.ts +18 -10
  361. package/src/adapters/references/index.ts +7 -2
  362. package/src/build-engine.test.ts +11 -6
  363. package/src/build-engine.ts +10 -5
  364. package/src/build.harness.mjs +5 -7
  365. package/src/build.test.ts +10 -11
  366. package/src/build.ts +12 -13
  367. package/src/caller-path.ts +13 -0
  368. package/src/cli.harness.mjs +1 -3
  369. package/src/cli.test.ts +21 -16
  370. package/src/cli.ts +115 -33
  371. package/src/doctor.test.ts +1 -1
  372. package/src/doctor.ts +14 -5
  373. package/src/domain/paths.test.ts +15 -0
  374. package/src/domain/paths.ts +20 -1
  375. package/src/domain/ready.ts +31 -0
  376. package/src/domain/record.test.ts +20 -0
  377. package/src/domain/record.ts +12 -0
  378. package/src/domain/sha256.ts +5 -3
  379. package/src/domain/tex-document.test.ts +80 -0
  380. package/src/domain/tex-document.ts +110 -0
  381. package/src/engine.harness.mjs +1 -1
  382. package/src/engine.ts +30 -2
  383. package/src/facts-file.test.ts +4 -7
  384. package/src/facts-file.ts +45 -30
  385. package/src/hooks-settings.harness.ts +17 -0
  386. package/src/hooks-settings.ts +28 -4
  387. package/src/init.test.ts +25 -5
  388. package/src/init.ts +26 -12
  389. package/src/latex-loop.harness.ts +1 -1
  390. package/src/new-paper.harness.mjs +7 -23
  391. package/src/new-paper.test.ts +28 -3
  392. package/src/new-paper.ts +15 -3
  393. package/src/package-dirs.ts +17 -0
  394. package/src/paper-files.test.ts +22 -19
  395. package/src/paper-files.ts +16 -27
  396. package/src/paper-settings-commands.test.ts +6 -1
  397. package/src/paper-settings.test.ts +2 -2
  398. package/src/paper-settings.ts +5 -5
  399. package/src/pdf-facts.test.ts +16 -5
  400. package/src/pdf-facts.ts +79 -22
  401. package/src/pdf-geometry.ts +5 -3
  402. package/src/ports/latex.ts +29 -0
  403. package/src/ports/tool-installer.ts +2 -17
  404. package/src/presets.test.ts +65 -4
  405. package/src/presets.ts +65 -28
  406. package/src/references.test.ts +25 -19
  407. package/src/references.ts +4 -5
  408. package/src/rule-cases.test.ts +474 -0
  409. package/src/rule-docs.test.ts +159 -0
  410. package/src/rules-config.ts +40 -11
  411. package/src/tex-requirements.harness.ts +13 -23
  412. package/src/tex-requirements.test.ts +21 -0
  413. package/src/tex-requirements.ts +64 -14
  414. package/src/tex-venue-rules.test.ts +659 -0
  415. package/src/tex-venue-rules.ts +429 -0
  416. package/src/toolchain.harness.mjs +1 -1
  417. package/src/toolchain.test.ts +9 -5
  418. package/src/toolchain.ts +2 -2
  419. package/src/types.ts +5 -3
  420. package/src/venue-rules.test.ts +104 -8
  421. package/src/venue-rules.ts +22 -12
  422. package/templates/paper/paper.tex +2 -1
  423. package/skills/paper-pipeline/scripts/announce.mjs +0 -67
  424. package/skills/paper-pipeline/scripts/announce.test.mjs +0 -102
  425. package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +0 -51
  426. package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +0 -52
  427. package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +0 -6
  428. package/skills/paper-pipeline/scripts/fixtures/scorecard.ts +0 -100
  429. package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +0 -302
  430. package/skills/paper-pipeline/scripts/ledger.mjs +0 -623
  431. package/skills/paper-pipeline/scripts/ledger.test.mjs +0 -254
  432. package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +0 -474
  433. package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +0 -328
  434. package/skills/paper-pipeline/scripts/pipeline-check.mjs +0 -750
  435. package/skills/paper-pipeline/scripts/pipeline-edges.mjs +0 -169
  436. package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +0 -73
  437. package/skills/paper-pipeline/scripts/run-mechanical.mjs +0 -648
  438. package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +0 -468
  439. package/skills/paper-pipeline/scripts/status.mjs +0 -295
  440. package/skills/paper-pipeline/scripts/status.test.mjs +0 -232
  441. /package/{skills/submit-paper/references/venues → presets/tex}/agenticdev.tex +0 -0
  442. /package/{skills/submit-paper/references/venues → presets}/tex-base.jsonc +0 -0
@@ -0,0 +1,71 @@
1
+ # tex/venue-leftover
2
+
3
+ **Level:** warn · **Reads:** `paper.tex`, and the shipped venue presets
4
+
5
+ ## What it catches
6
+
7
+ The paper mentions a venue other than the one set in its `paperlint.json`. Usually that is text
8
+ left over from an earlier submission: "Submission to VenueA 2026" in the author block of a paper
9
+ now going to VenueB.
10
+
11
+ It only knows the venues paperlint ships a preset for, by each preset's `name` and `aliases`. A
12
+ venue with no preset is not recognized.
13
+
14
+ It looks at what a reader sees — prose, the author block, captions, footnotes, a citation's note in
15
+ square brackets, and front-matter macros such as `\acmConference` — and ignores comments, citation
16
+ keys, labels, URLs (a `\url`, and the address of an `\href` — its link text is read), math, code and
17
+ the bibliography. Names are matched as whole words, case-sensitive.
18
+
19
+ A macro definition that names another venue — `\newcommand{\oldvenue}{VenueA}` — is reported at the
20
+ definition, whether or not the macro is used: the rule does not expand macros, so a use such as
21
+ `Submitted to \oldvenue` has no text of its own, and the definition is where the old name lives.
22
+
23
+ ## Why
24
+
25
+ A reviewer reads the author block before the abstract. A line naming the previous venue tells them
26
+ the paper was written for somewhere else, and at a double-blind venue it can say more than that.
27
+ Nothing else compares what the source says about the venue with what the settings say.
28
+
29
+ ## Examples
30
+
31
+ Under `"extends": "paperlint:realm"`, where the `agenticdev` preset's alias is `AgenticDev`:
32
+
33
+ ```latex
34
+ \acmConference[AgenticDev '26]{Workshop on Agentic Development} % warns: «AgenticDev»
35
+ As shown~\cite{agenticdev2025}. % silent: a citation key
36
+ % AgenticDev draft % silent: a comment
37
+ ```
38
+
39
+ The first line reports:
40
+
41
+ > «AgenticDev» names agenticdev, and this paper extends realm — a leftover from an earlier
42
+ > submission? A reviewer reads it before the abstract. Comments and citation keys are not
43
+ > reported; a sentence that names the other venue on purpose can keep it with a disable directive
44
+
45
+ The same line passes under `"extends": "paperlint:agenticdev"`: it names the paper's own venue.
46
+
47
+ ## Preset fields
48
+
49
+ No rule options. It reads every shipped preset's `name` and `aliases`, collected along `extends`:
50
+
51
+ ```jsonc
52
+ "aliases": ["AgenticDev"]
53
+ ```
54
+
55
+ A name the paper's own chain also declares (two workshops of one parent conference) is never
56
+ reported.
57
+
58
+ ## What it does not check
59
+
60
+ - A venue no shipped preset describes.
61
+ - A name split by markup (`\textbf{AI}Sec`), and text pulled in with `\input`.
62
+
63
+ ## How to fix
64
+
65
+ Remove or replace the old venue's name. A sentence that names another venue on purpose keeps it
66
+ with ESLint's directive and the reason:
67
+
68
+ ```latex
69
+ % eslint-disable-next-line tex/venue-leftover -- comparing with the venue that published [3]
70
+ Unlike AgenticDev, this workshop …
71
+ ```
package/docs/rules.md CHANGED
@@ -3,30 +3,37 @@
3
3
  The README lists what each check catches in one line. This page says exactly which file each one
4
4
  reads and when it fails. Errors fail `paperlint lint`; warnings print and do not.
5
5
 
6
- | Rule | Level | Reads | Fails when |
7
- | ------------------------------ | ----- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
- | `paper/stages` | error | `PIPELINE-STATUS.md` | a declared stage's PDF is missing, or the `bytes:` it names does not match the file's real size, or a frozen PDF exists that no stage declares |
9
- | `paper/source` | error | `PIPELINE-STATUS.md` | a declared stage has no frozen `.tex` beside its PDF (a commit hash does not count — squash and gc destroy it) |
10
- | `paper/author-list` | error | `paper.tex` → `_build/references.json` | an entry's authors are not those of the version it cites — typically the arXiv preprint's list under a published venue. Checked online by `paperlint build` (DBLP), reported on the entry's own line |
11
- | `paper/research-question` | warn | `paper.tex`, `paper.md`, `PIPELINE-STATUS.md` | a stage is declared and either the scorecard has no `researchQuestion` field, or it has one the paper does not contain. The declared sentence is compared against the source with whitespace collapsed — your words, not a pattern. Advisory, because nothing here can judge whether what you declared _is_ a research question |
12
- | `paper/section-word` | warn | `paper.tex`, `paper.md` | `§` or `\S\ref` instead of the word Section. **Fixable:** `--fix` writes `Section~\ref{…}` / `Section 5` |
13
- | `paper/leading-zero` | warn | `paper.tex`, `paper.md` | a decimal below 1 without its leading zero (`.05` instead of `0.05`, IEEE / ISO 80000-1 style), counted only where the reader sees it — prose, math and table cells, not macro options, column specs, comments, code or tikz. A number right after `¶` or `§` (`¶¶.42`) is a paragraph designator and is not reported; in a paragraph that cites numbers that way, another bare decimal is reported without a fix, with the zero as a suggestion. **Fixable** |
14
- | `paper/figure-ref-style` | warn | `paper.tex` | `Fig.~\ref` and `Figure~\ref` mixed in one document; each minority occurrence is reported. **Fixable:** `--fix` writes the majority form |
15
- | `bib/reachable-entry` | warn | `paper.tex` (its `filecontents` bibliography) | an entry has no doi, url or arXiv id — a reader has nothing to follow. Reported on the entry; no fix, the link has to be looked up |
16
- | `paper/cite-exists` | error | `paper.tex` → `_build/references.json` | an entry's doi or arXiv id resolves to nothing, or to a different work. Checked online by `paperlint build`; a work that was merely not found is not a finding |
17
- | `paper/refs-fresh` | error | `paper.tex` → `_build/references.json` | the bibliography changed since the build checked it (its SHA-256 differs) — run `npx paperlint build` |
18
- | `paper/refs-checked` | warn | `paper.tex` → `_build/references.json` | the paper has a bibliography and no build has checked it, or the last build could not (no network) — so the two rules above did not run |
19
- | `tex/future-promise` | warn | `paper.tex` | a camera-ready build still says "will be released" about something already handed over |
20
- | `tex/acm-frontmatter-override` | error | `paper.tex` | an `acmart` build overrides ACM's front-matter commands and drops template elements from page 1 |
21
- | `review/frontmatter` | error | `reviews/*.md` | the review's frontmatter fails paperlint's JSON Schema — a `findings` record without `id`/`status`, an unknown field, or an **open** finding with no `cause` (`skill-defect` · `missing-skill` · `hook` · `rule`). A review with no `findings` key is not checked for findings |
22
- | `sibling/frontmatter` | warn | `siblings/*.md` (not `README.md`) | a sibling card's frontmatter has no `read:` saying how much of the competing paper was read (`full` · `abstract` · `none`) |
23
- | `pdf/fresh` | error | `paper.tex` → `_build/paper.facts.json` | the paper names a venue and the facts cannot be judged: not JSON, a schema other than 2, or they describe a PDF that is gone or differs from the one on disk (its SHA-256) |
24
- | `pdf/profile` | error | `paper.tex` → `paperlint.json` | `paperlint.json` is not JSON or has an unknown key, its `extends` does not resolve (not found, a cycle, a chain longer than four, a preset that fails the schema, an npm name), it names no `kind` while the preset has kinds, or names a kind the preset does not have |
25
- | `pdf/fonts` | error | `paper.tex` → `_build/paper.facts.json` | a font the pages draw is Type 3 or not embedded, or no font starts with the family the venue preset names for body text (`fonts_text`) or headings (`fonts_title`) |
26
- | `pdf/geometry` | error | `paper.tex` → `_build/paper.facts.json` | the page width or height is more than `dimTol` (default 0.05 in) off the preset's, or the column count differs |
27
- | `pdf/limits` | error | `paper.tex` → `_build/paper.facts.json` | body or reference pages exceed the limit of the paper's kind, or the reference font size is outside the preset's range widened by `body_pt_tol` |
28
- | `pdf/body-size` | warn | `paper.tex` → `_build/paper.facts.json` | the body font size is more than `body_pt_tol` off the preset's. A warning: banal measures the mode of the rendered text, not the declared size (9.30 pt measured at a declared 9) |
29
- | `pdf/measured` | warn | `paper.tex` → `_build/paper.facts.json` | the paper's `paperlint.json` names no venue preset yet; or it names one and there are no facts (it was not built), or the facts carry no page geometry (banal was not found) — so the checks above did not run |
6
+ | Rule | Level | Reads | Fails when |
7
+ | ------------------------------------------------------- | ----- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
+ | `paper/stages` | error | `PIPELINE-STATUS.md` | a declared stage's PDF is missing, or the `bytes:` it names does not match the file's real size, or a frozen PDF exists that no stage declares |
9
+ | `paper/source` | error | `PIPELINE-STATUS.md` | a declared stage has no frozen `.tex` beside its PDF (a commit hash does not count — squash and gc destroy it) |
10
+ | `paper/author-list` | error | `paper.tex` → `_build/references.json` | an entry's authors are not those of the version it cites — typically the arXiv preprint's list under a published venue. Checked online by `paperlint build` (DBLP), reported on the entry's own line |
11
+ | `paper/research-question` | warn | `paper.tex`, `paper.md`, `PIPELINE-STATUS.md` | a stage is declared and either the scorecard has no `researchQuestion` field, or it has one the paper does not contain. The declared sentence is compared against the source with whitespace collapsed — your words, not a pattern. Advisory, because nothing here can judge whether what you declared _is_ a research question |
12
+ | `paper/section-word` | warn | `paper.tex`, `paper.md` | `§` or `\S\ref` instead of the word Section. **Fixable:** `--fix` writes `Section~\ref{…}` / `Section 5` |
13
+ | `paper/leading-zero` | warn | `paper.tex`, `paper.md` | a decimal below 1 without its leading zero (`.05` instead of `0.05`, IEEE / ISO 80000-1 style), counted only where the reader sees it — prose, math and table cells, not macro options, column specs, comments, code or tikz. A number right after `¶` or `§` (`¶¶.42`) is a paragraph designator and is not reported; in a paragraph that cites numbers that way, another bare decimal is reported without a fix, with the zero as a suggestion. **Fixable** |
14
+ | `paper/figure-ref-style` | warn | `paper.tex` | `Fig.~\ref` and `Figure~\ref` mixed in one document; each minority occurrence is reported. **Fixable:** `--fix` writes the majority form |
15
+ | `bib/reachable-entry` | warn | `paper.tex` (its `filecontents` bibliography) | an entry has no doi, url or arXiv id — a reader has nothing to follow. Reported on the entry; no fix, the link has to be looked up |
16
+ | `paper/cite-exists` | error | `paper.tex` → `_build/references.json` | an entry's doi or arXiv id resolves to nothing, or to a different work. Checked online by `paperlint build`; a work that was merely not found is not a finding |
17
+ | `paper/refs-fresh` | error | `paper.tex` → `_build/references.json` | the bibliography changed since the build checked it (its SHA-256 differs) — run `npx paperlint build` |
18
+ | `paper/refs-checked` | warn | `paper.tex` → `_build/references.json` | the paper has a bibliography and no build has checked it, or the last build could not (no network) — so the two rules above did not run |
19
+ | `tex/future-promise` | warn | `paper.tex` | a camera-ready build still says "will be released" about something already handed over |
20
+ | `tex/acm-frontmatter-override` | error | `paper.tex` | an `acmart` build overrides ACM's front-matter commands and drops template elements from page 1 |
21
+ | [`tex/template`](rules/tex/template.md) | error | `paper.tex` → `paperlint.json` | the `\documentclass` is not the preset's `template` class, or lacks an option it names — [page](rules/tex/template.md) |
22
+ | [`tex/required-section`](rules/tex/required-section.md) | error | `paper.tex` → `paperlint.json` | a section the preset requires (AIDC: «LLM Usage Statement», last) is missing or not where it must be — [page](rules/tex/required-section.md) |
23
+ | [`tex/venue-leftover`](rules/tex/venue-leftover.md) | warn | `paper.tex` → `paperlint.json` | the text names another shipped venue than the one the paper extends («Submission to VenueA 2026» in a paper now set for VenueB) — [page](rules/tex/venue-leftover.md) |
24
+ | `review/frontmatter` | error | `reviews/*.md` | the review's frontmatter fails paperlint's JSON Schema — a `findings` record without `id`/`status`, an unknown field, or an **open** finding with no `cause` (`skill-defect` · `missing-skill` · `hook` · `rule`). A review with no `findings` key is not checked for findings |
25
+ | `sibling/frontmatter` | warn | `siblings/*.md` (not `README.md`) | a sibling card's frontmatter has no `read:` saying how much of the competing paper was read (`full` · `abstract` · `none`) |
26
+ | `pdf/fresh` | error | `paper.tex` → `_build/paper.facts.json` | the paper names a venue and the facts cannot be judged: not JSON, a schema other than 2, or they describe a PDF that is gone or differs from the one on disk (its SHA-256) |
27
+ | `pdf/profile` | error | `paper.tex` → `paperlint.json` | `paperlint.json` is not JSON or has an unknown key, its `extends` does not resolve (not found, a cycle, a chain longer than four, a preset that fails the schema, an npm name), it names no `kind` while the preset has kinds, or names a kind the preset does not have |
28
+ | `pdf/fonts` | error | `paper.tex` → `_build/paper.facts.json` | a font the pages draw is Type 3 or not embedded, or no font starts with the family the venue preset names for body text (`fonts_text`) or headings (`fonts_title`) |
29
+ | `pdf/geometry` | error | `paper.tex` → `_build/paper.facts.json` | the page width or height is more than `dimTol` (default 0.05 in) off the preset's, or the column count differs |
30
+ | `pdf/limits` | error | `paper.tex` → `_build/paper.facts.json` | body or reference pages exceed the limit of the paper's kind, or the reference font size is outside the preset's range widened by `body_pt_tol` |
31
+ | `pdf/body-size` | warn | `paper.tex` → `_build/paper.facts.json` | the body font size is more than `body_pt_tol` off the preset's. A warning: banal measures the mode of the rendered text, not the declared size (9.30 pt measured at a declared 9) |
32
+ | `pdf/measured` | warn | `paper.tex` → `_build/paper.facts.json` | the paper's `paperlint.json` names no venue preset yet; or it names one and there are no facts (it was not built), or the facts carry no page geometry (banal was not found) — so the checks above did not run |
33
+
34
+ `tex/required-section` requires AIDC's «LLM Usage Statement» **always**. ACSAC asks for it «if
35
+ LLMs are used», which no rule can know; an author who used none says so in the section
36
+ ([page](rules/tex/required-section.md)).
30
37
 
31
38
  Optional rules — off unless you turn them on in the `rules` setting, because only some venues need
32
39
  them — are on their own page: [`optional-rules.md`](optional-rules.md). Today there is one,
@@ -79,21 +86,34 @@ for papers, each with the quote it came from, the TeX packages its template need
79
86
  the venue implies. A preset may itself extend another: the ACM venues extend the `acm-sigconf`
80
87
  family, which holds everything the ACM template decides.
81
88
 
82
- | preset | extends | template | kinds | page limit checked | rules it turns on |
83
- | ----------------------- | ----------------------- | -------------------- | -------------------------------------------------------- | ------------------ | ----------------------- |
84
- | `paperlint:acm-sigconf` | — | ACM `acmart` sigconf | none | no (no kinds) | — |
85
- | `paperlint:agenticdev` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `short` (5 + 2 refs), `full` (10 + 2), `demo` (5 + 2) | yes | `pdf/last-page-balance` |
86
- | `paperlint:aisec` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `research`, `benchmark`, `position`, `sok` (10 + 2 each) | yes | — |
87
- | `paperlint:realm` | — | ACL | `long`, `short` | no — see below | — |
88
-
89
- That is all that ships today. There is no IEEE, NeurIPS, USENIX or Springer preset. A paper for an
90
- ACM venue nobody has profiled can extend `paperlint:acm-sigconf` directly: page size, columns and
91
- fonts are checked, and `pdf/profile` says the page limit is not. For anything else, write your own
92
- preset ([below](#writing-your-own-venue-preset)). REALM's preset sets no page limit on purpose:
93
- banal counts the Limitations and Ethics sections as body, ACL does not, and a limit on banal's
94
- number would fail a correct paper. AgenticDev's turns on `pdf/last-page-balance` because its
95
- proceedings are produced by Conference Publishing Consulting, which sends back an unbalanced last
96
- page; AISec's does not, because nothing in hand says who produces the AISec proceedings.
89
+ | preset | extends | template | kinds | page limit checked | rules it turns on |
90
+ | --------------------------- | --------------------------- | ------------------------------------- | -------------------------------------------------------- | ------------------ | ----------------------- |
91
+ | `paperlint:acm-sigconf` | — | ACM `acmart` sigconf | none | no (no kinds) | — |
92
+ | `paperlint:agenticdev` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `short` (5 + 2 refs), `full` (10 + 2), `demo` (5 + 2) | yes | `pdf/last-page-balance` |
93
+ | `paperlint:aisec` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `research`, `benchmark`, `position`, `sok` (10 + 2 each) | yes | — |
94
+ | `paperlint:realm` | — | ACL | `long`, `short` | no — see below | — |
95
+ | `paperlint:ieee-conference` | — | IEEE `IEEEtran` conference | none | no (no kinds) | — |
96
+ | `paperlint:aidc` | `paperlint:ieee-conference` | IEEE `IEEEtran` conference, `compsoc` | `regular` (12), `short` (6) | no — see below | — |
97
+
98
+ That is all that ships today. There is no NeurIPS, USENIX or Springer preset. A paper for an ACM or
99
+ IEEE conference venue nobody has profiled can extend `paperlint:acm-sigconf` or
100
+ `paperlint:ieee-conference` directly: page size, columns and fonts are checked, and `pdf/profile`
101
+ says the page limit is not. For anything else, write your own preset
102
+ ([below](#writing-your-own-venue-preset)). REALM's preset sets no page limit on purpose: banal
103
+ counts the Limitations and Ethics sections as body, ACL does not, and a limit on banal's number
104
+ would fail a correct paper. AIDC's sets none for the same reason, measured: banal counts a page as
105
+ body when an appendix or the LLM Usage Statement sits on it before the bibliography, and AIDC counts
106
+ neither, so a correct 12-page paper measured 13. AgenticDev's turns on `pdf/last-page-balance`
107
+ because its proceedings are produced by Conference Publishing Consulting, which sends back an
108
+ unbalanced last page; AISec's does not, because nothing in hand says who produces the AISec
109
+ proceedings.
110
+
111
+ **How presets are named.** A template family — the preset venues extend, owning the template,
112
+ the format and the TeX packages — is `<publisher>-<template variant>`: `acm-sigconf`, `ieee-conference`. A venue
113
+ is its own short name, lowercase, with no publisher and no parent-conference prefix: `aisec`,
114
+ `agenticdev`, `realm`, `aidc`. Which template a venue uses is said by its `extends`, not by its
115
+ name — a name repeating it would be wrong the day the venue changes template — and the parent
116
+ conference (CCS, ASE, ACSAC) goes into the preset's comment and its `aliases`.
97
117
 
98
118
  **Build, then lint.** The rules judge what `paperlint build` measured and wrote to
99
119
  `_build/paper.facts.json` — page count, fonts, and, through banal, page size, columns, font sizes
@@ -130,7 +150,7 @@ To skip a check for one paper — a finding you accept — set it to `"off"` in
130
150
 
131
151
  A preset is a JSONC file (JSON with comments — keep the call-for-papers quote beside each number)
132
152
  of the same shape as the shipped ones, validated by
133
- [`venue-profile.schema.json`](../skills/submit-paper/references/venues/venue-profile.schema.json).
153
+ [`venue-profile.schema.json`](../presets/venue-profile.schema.json).
134
154
  Put it in your repository and extend it by a path relative to the file that names it:
135
155
 
136
156
  ```
@@ -170,14 +190,16 @@ papers/
170
190
 
171
191
  The numbers and packages above illustrate the shape; take yours from the venue's own call for papers and template.
172
192
 
173
- | key | what it is |
174
- | ---------- | --------------------------------------------------------------------------------------------------- |
175
- | `extends` | the preset this one builds on: `paperlint:<name>` or `./path` / `../path`, relative to this file |
176
- | `name` | how messages name the venue; the file name otherwise |
177
- | `template` | the `\documentclass` the venue's template uses |
178
- | `format` | page size, columns, fonts, font sizes, and `kinds` (page limits per kind of paper) |
179
- | `tex` | TeX Live packages, each with the files that prove it is installed. Required unless `extends` is set |
180
- | `rules` | rules the venue implies, rule id → severity or `[severity, options]` |
193
+ | key | what it is |
194
+ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
195
+ | `extends` | the preset this one builds on: `paperlint:<name>` or `./path` / `../path`, relative to this file |
196
+ | `name` | how messages name the venue; the file name otherwise |
197
+ | `template` | the `\documentclass` the venue's template uses — a whole line (`\documentclass[conference,compsoc]{IEEEtran}`) or a bare class name; `tex/template` requires the paper's class and every option named here |
198
+ | `aliases` | other names the venue goes by in a paper's text — its acronym, its parent conference: `["AISec", "ACM CCS"]`. Collected along `extends`, with `name`. Read by `tex/venue-leftover` |
199
+ | `required_sections` | sections the venue requires, `[{ "title": "LLM Usage Statement", "position": "last" }]`: the exact title, and `last` when it must close the paper. Read by `tex/required-section`; a child's list replaces its parent's |
200
+ | `format` | page size, columns, fonts, font sizes, and `kinds` (page limits per kind of paper) |
201
+ | `tex` | TeX Live packages, each with the files that prove it is installed. Required unless `extends` is set |
202
+ | `rules` | rules the venue implies, rule id → severity or `[severity, options]` |
181
203
 
182
204
  How a chain merges, from the root preset to the paper: `tex` is the union — a child never removes a
183
205
  package; `format` keys are replaced one by one, and a child's kind replaces that kind whole;
package/docs/testing.md CHANGED
@@ -40,6 +40,11 @@ When in doubt between unit and integration: if the function takes a port (`Files
40
40
  - **Example:** `src/adapters/references/index.test.ts` — the reference checker over a fake
41
41
  `fetch`: a cold run stores every answer, a warm run makes no request at all (the recorded list of
42
42
  requests is empty), an edited entry asks only for itself.
43
+ - **A rule through real ESLint is integration, not e2e:** `src/rule-cases.test.ts` reads every rule
44
+ the registry holds (`rulePlugins`) and runs each through `paperlint lint --json` in-process on a
45
+ small paper tree — the CLI's own config, the `tex/latex` language, `loc`, message templating. Each
46
+ rule needs a case that reports (id, severity, line) and one that stays silent; a registered rule
47
+ without cases fails the test by name. A `_build/` file a rule reads is planted, not built.
43
48
 
44
49
  ## Harness — vigiles, the agent-facing surface only
45
50
 
@@ -56,14 +61,20 @@ When in doubt between unit and integration: if the function takes a port (`Files
56
61
  - **Skills are tested through vigiles**, not a bespoke runner: a home-grown runner here once printed
57
62
  byte-identical "clean" verdicts for three skills that had never loaded.
58
63
 
59
- ## End-to-end — `test/e2e/*.ts`
64
+ ## End-to-end — `test/e2e/<area>/*.e2e.ts`
60
65
 
61
66
  - **Answers:** does the package work once it is somewhere else? The tarball installed into another
62
67
  tree, a real `pdflatex` build, the PDF's fonts measured.
63
68
  - **May touch:** everything a user's machine has, except the network: a citation service is a
64
- counting fake `fetch` even here (`test/e2e/build.ts`).
69
+ counting fake `fetch` even here (`test/e2e/tex/build.e2e.ts`).
65
70
  - **Types:** the runs import the built modules from `dist/` (the shipped path is the point), so
66
71
  their types are the declarations `tsc` emits — `npm run build` before type-checking them.
72
+ - **Where:** a directory per environment the tests need — `test/e2e/install/` (npm and pnpm),
73
+ `test/e2e/tex/` (TeX Live) — each a vitest project that finds `*.e2e.ts` by its glob. A new e2e
74
+ file needs no list anywhere. Helpers beside them are named without `.e2e.ts`.
75
+ - **A missing tool:** `missing(what, present)` from `test/e2e/need.ts` → `describe.skipIf`. Locally
76
+ the tests are reported skipped; with `CI` set they fail.
77
+ - **A build fixture:** a folder in `fixtures/build-e2e/` with its own `expect.json`; no test code.
67
78
  - **What each run proves, and when a change owes one:** [`e2e.md`](e2e.md).
68
79
 
69
80
  ## Running
@@ -71,9 +82,11 @@ When in doubt between unit and integration: if the function takes a port (`Files
71
82
  ```bash
72
83
  npx vitest run <file or folder> # unit and integration tests
73
84
  npx vigiles test <file> # one harness
74
- npm test # everything: vitest, then every harness
85
+ npm test # unit and integration (vitest project `unit`), then every harness
75
86
  npm run coverage # the same under c8, failing below the thresholds in .c8rc.json
76
- npm run test:e2e # the end-to-end runs
87
+ npm run test:e2e # every end-to-end run
88
+ npm run test:e2e:install # the package packed and installed under npm and pnpm
89
+ npm run test:e2e:tex # real TeX Live: toolchain, builds of every fixture, banal
77
90
  npm run check # every gate CI runs, and the list of what it does not reproduce
78
91
  ```
79
92
 
@@ -18,7 +18,7 @@ another"_.
18
18
  > **Where this ended up (2026-09-24).** Method 5 below won, and it is no longer a CI script: it is
19
19
  > `paperlint toolchain` (`src/toolchain.ts`), the command users run and the `build-e2e` job runs on Linux
20
20
  > and macOS. The package list and the file contract (`REQUIRED_FILES` in the deleted
21
- > `ensure-toolchain.sh`) moved into the venue profiles — each `skills/submit-paper/references/venues/*.jsonc`
21
+ > `ensure-toolchain.sh`) moved into the venue profiles — each `presets/*.jsonc`
22
22
  > declares a `tex` block of CTAN package → proof files, and `tex-base.jsonc` the set every paper
23
23
  > gets. This file stays as the record of why tlmgr and not apt or a container; the scripts it names
24
24
  > (`ensure-toolchain.sh`, `ci-install-texlive.sh`) were deleted in the same change.
package/docs/toolchain.md CHANGED
@@ -58,7 +58,7 @@ that has every declared package, so a new-year install that was interrupted neve
58
58
  complete older one.
59
59
 
60
60
  **Where the package list lives:** in the venue profiles, not here and not in a script.
61
- `skills/submit-paper/references/venues/<venue>.jsonc` carries a `tex` block — CTAN package → the
61
+ `presets/<venue>.jsonc` carries a `tex` block — CTAN package → the
62
62
  files that prove it is installed — and `tex-base.jsonc` carries what every paper gets, and all a
63
63
  paper with an unknown venue gets. The shape is `venue-profile.schema.json` in the same directory.
64
64
  A venue that needs a new package gets one line there.
@@ -97,7 +97,7 @@ accepts as input. Measured on 50 PDFs / 598 pages (2026-09-25): banal on paperli
97
97
  real `pdftohtml` agree on every field the facts file keeps, with no venue verdict changed. They
98
98
  agree only because paperlint leaves out rotated and invisible text (as `pdftohtml` does), writes each
99
99
  text's colour so banal drops light text by its own rule, and writes sizes and coordinates at the
100
- zoom and precision banal expects. `test/e2e/banal.ts` checks each of those against the real banal
100
+ zoom and precision banal expects. `test/e2e/tex/banal.e2e.ts` checks each of those against the real banal
101
101
  on the committed fixtures.
102
102
 
103
103
  **How it is installed — and the licence boundary.** banal is **GPL-2.0-or-later**; paperlint is MIT. paperlint
@@ -33,7 +33,7 @@ export default {
33
33
  rules: {
34
34
  "reachable-entry": {
35
35
  meta: {
36
- type: "suggestion",
36
+ type: "suggestion" as const,
37
37
  docs: {
38
38
  description:
39
39
  "a bibliography entry carries a doi, a url or an arXiv id — something a reader can follow",
@@ -55,7 +55,7 @@ const MESSAGES: Readonly<Record<string, string>> = {
55
55
  /** Markdown: a skill's own prose, its fenced commands, and its YAML frontmatter. */
56
56
  const mdInstallPath = {
57
57
  meta: {
58
- type: "problem",
58
+ type: "problem" as const,
59
59
  docs: {
60
60
  description:
61
61
  "a skill must not name its scripts by an install-specific path — rule 10, the port owns where",
@@ -78,7 +78,7 @@ const mdInstallPath = {
78
78
  /** JavaScript: the modules this package ships. */
79
79
  const jsInstallPath = {
80
80
  meta: {
81
- type: "problem",
81
+ type: "problem" as const,
82
82
  docs: {
83
83
  description:
84
84
  "a shipped module must not carry an install-specific path literal — rule 10, the port owns where",
@@ -131,7 +131,7 @@ export default {
131
131
  rules: {
132
132
  "research-question": {
133
133
  meta: {
134
- type: "suggestion",
134
+ type: "suggestion" as const,
135
135
  docs: {
136
136
  description:
137
137
  "a paper that declares a stage states its research question explicitly — otherwise the reviewer reconstructs it themselves, and says so",
@@ -130,7 +130,7 @@ export default {
130
130
  rules: {
131
131
  stages: {
132
132
  meta: {
133
- type: "problem",
133
+ type: "problem" as const,
134
134
  docs: {
135
135
  description:
136
136
  "a paper's stage is declared as a FIELD, and every declaration is checked against the bytes on disk in both directions",
@@ -300,7 +300,7 @@ export default {
300
300
  */
301
301
  source: {
302
302
  meta: {
303
- type: "problem",
303
+ type: "problem" as const,
304
304
  docs: {
305
305
  description:
306
306
  "a declared stage freezes its source beside the pdf and is checked by bytes — not by a commit reference",
@@ -467,8 +467,8 @@ const rule = (
467
467
  meta: { readonly hasSuggestions?: boolean } = {},
468
468
  ) => ({
469
469
  meta: {
470
- type: "suggestion",
471
- fixable: "code",
470
+ type: "suggestion" as const,
471
+ fixable: "code" as const,
472
472
  docs: { description },
473
473
  schema: [],
474
474
  messages,
@@ -218,7 +218,7 @@ function verdict(paperDir: string, tolerancePt: number): Finding | null {
218
218
 
219
219
  const rule = {
220
220
  meta: {
221
- type: "problem",
221
+ type: "problem" as const,
222
222
  docs: {
223
223
  description:
224
224
  "the last page's two columns end at about the same height (optional; for venues that require it)",
@@ -90,7 +90,7 @@ export function frontmatterRule(schemaUrl: URL | string, description: string) {
90
90
  const validate = new Ajv({ allErrors: true }).compile(schema);
91
91
  return {
92
92
  meta: {
93
- type: "problem",
93
+ type: "problem" as const,
94
94
  docs: { description },
95
95
  schema: [],
96
96
  messages: {
@@ -112,7 +112,7 @@ export default {
112
112
  rules: {
113
113
  "temp-root-realpath": {
114
114
  meta: {
115
- type: "problem",
115
+ type: "problem" as const,
116
116
  docs: {
117
117
  description:
118
118
  "a temp root taken from tmpdir() is resolved to its realpath at the moment it is created",
@@ -137,7 +137,7 @@ const FRONTMATTER_OVERRIDES = [
137
137
  // checks stop being read too.
138
138
  const futurePromise = {
139
139
  meta: {
140
- type: "problem",
140
+ type: "problem" as const,
141
141
  docs: {
142
142
  description:
143
143
  "the build is not in review mode, yet the text promises a future release of something already handed over",
@@ -241,7 +241,7 @@ const futurePromise = {
241
241
  // miss is a rejection with no content review. In a consumer that is `error`.
242
242
  const acmFrontmatterOverride = {
243
243
  meta: {
244
- type: "problem",
244
+ type: "problem" as const,
245
245
  docs: {
246
246
  description:
247
247
  "an acmart build overrides ACM's front-matter commands, removing template elements from page 1",