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
@@ -1,328 +0,0 @@
1
- /**
2
- * pipeline-check.harness.mjs — one planted defect at a time, on an otherwise-clean scorecard.
3
- *
4
- * 🔴 Since 2026-08-26 HERE ARE SIX CHECKS, NOT TWENTY-TWO. Sixteen, whose input is the document itself,
5
- * moved to `eslint-rules/pipeline-status.mjs`, and their cases — to `eslint-rules/pipeline-status.harness.mjs`.
6
- * `npx vigiles test .claude/skills/paper-pipeline/scripts/pipeline-check.harness.mjs`.
7
- *
8
- * WHY THIS EXISTS ALONGSIDE THE FIXTURE TEST IN hooks.harness.ts. That one runs the checker over
9
- * `scripts/fixtures/dirty/`, a scorecard carrying every defect at once, and asserts each kind
10
- * appears somewhere in the output. It cannot answer the question that matters when a check breaks:
11
- * WHICH defect produced WHICH finding. A checker that reports `stale-continuous` for the wrong
12
- * reason — say, because the date parser returns null and every row looks undated — passes that test
13
- * forever. So each case below plants exactly ONE defect on a scorecard that is otherwise silent, and
14
- * asserts the FULL SET of kinds, not merely that the expected one is present. Collateral findings
15
- * are written into the expectation on purpose: they are part of the contract, and an unlisted one is
16
- * a change in behaviour nobody asked for.
17
- *
18
- * 🔴 Assertions run at MODULE TOP LEVEL. `vigiles test` imports the file and treats "did not throw"
19
- * as a pass — an earlier harness here exported a `tests` object, nothing ran, and the runner printed
20
- * ✓ on a file whose only assertion was `assert.equal(1, 2)`.
21
- *
22
- * 🔴 The subprocess environment is SCRUBBED of OSF_TOKEN and GITHUB_TOKEN. The `credential-available`
23
- * check fires when the session holds a credential that could clear a parked blocker, so with either
24
- * token exported this suite would pass on a laptop and fail in CI, or the reverse. A test whose
25
- * verdict depends on who is running it is not a test.
26
- *
27
- * Fixtures are throwaways in a temp dir; no real scorecard is read or written.
28
- */
29
- import assert from "node:assert/strict";
30
- import { parseStatus } from "./pipeline-check.mjs";
31
- import { execFileSync } from "node:child_process";
32
- import {
33
- mkdtempSync,
34
- mkdirSync,
35
- writeFileSync,
36
- rmSync,
37
- realpathSync,
38
- } from "node:fs";
39
- import { tmpdir } from "node:os";
40
- import { join, dirname } from "node:path";
41
- import { fileURLToPath } from "node:url";
42
- import { consumerRoot } from "./consumer.mjs";
43
- import { scorecard as makeScorecard } from "./fixtures/scorecard.ts";
44
- const HERE = dirname(fileURLToPath(import.meta.url));
45
-
46
- const ROOT = consumerRoot();
47
- const SCRIPT = join(HERE, "pipeline-check.mjs");
48
- const tmp = realpathSync(mkdtempSync(join(tmpdir(), "pipecheck-harness-")));
49
-
50
- // The paper source is written NOW, so `newestSourceDate` returns today and the staleness comparison
51
- // has something real to compare against. Every clean row therefore carries today's date: hard-coding
52
- // a date would make this suite start failing on its own the following morning.
53
- const TODAY = new Date().toISOString().slice(0, 10);
54
-
55
- const ENV = { ...process.env };
56
- delete ENV.OSF_TOKEN;
57
- delete ENV.GITHUB_TOKEN;
58
-
59
- const scorecard = (over = {}) => makeScorecard(over, TODAY);
60
-
61
- /** Write a fixture and return the findings pipeline-check reports, verbatim. */
62
- function findings(name, over = {}, today = TODAY) {
63
- const d = join(tmp, name);
64
- mkdirSync(d, { recursive: true });
65
- writeFileSync(join(d, "PIPELINE-STATUS.md"), scorecard(over));
66
- writeFileSync(join(d, "paper.md"), "## 1. Heading\n\nProse.\n");
67
- const out = execFileSync("node", [SCRIPT, d, "--json", `--today=${today}`], {
68
- cwd: ROOT,
69
- encoding: "utf8",
70
- env: ENV,
71
- stdio: ["ignore", "pipe", "pipe"],
72
- });
73
- return JSON.parse(out);
74
- }
75
-
76
- /** …and just the kinds, sorted. */
77
- const kinds = (name, over = {}, today = TODAY) =>
78
- findings(name, over, today)
79
- .map((f) => f.kind)
80
- .sort();
81
-
82
- /** A SETUP-shaped (7-column) table head. */
83
- const PLAIN_HEAD = [
84
- "| id | Work | Skill | Status | Date | Result | Open |",
85
- "|----|------|-------|--------|------|--------|------|",
86
- ];
87
-
88
- /** Assert the EXACT set of kinds, so a check firing for the wrong reason cannot hide. */
89
- const expect = (name, over, want, today = TODAY) =>
90
- assert.deepEqual(
91
- kinds(name, over, today),
92
- [...want].sort(),
93
- `${name}: wrong finding set`,
94
- );
95
-
96
- // ═══════════════════════════════════════════════════════════════════════════════════════
97
- // 🔴 2026-08-26 — SIXTEEN CASES MOVED OUT ALONG WITH THEIR CHECKS.
98
- //
99
- // Checks whose input is ONE markdown document moved to `eslint-rules/pipeline-status.mjs`,
100
- // and their cases — to the colocated `eslint-rules/pipeline-status.harness.mjs`. They were NOT
101
- // left behind even "just in case": a test running a check that is not in the file is always green
102
- // and therefore lies worse than its absence.
103
- //
104
- // undated-continuous · gate-missing-input · gate-stale-input · unknown-input ·
105
- // unattributed-verdict · single-family-jury (+ mixed-family / non-judging / widened) ·
106
- // scalar-verdict (+ owned) · study-before-frame · undeclared-input (+ superset) ·
107
- // unrun-gate · no-verdict · weak-accept-unowned · ceiling-unplanned ·
108
- // unattributed-row · unreadable-row · duplicate-id
109
- //
110
- // Six checks remain, and all six read input FROM OUTSIDE the file: git, clock, `reviews/`,
111
- // `process.env`. Exactly those are checked below.
112
- //
113
- // ⚠️ TWO CASES ABOUT PARSING WERE REWRITTEN, NOT DELETED, and this is more important than keeping them.
114
- // "Heading with trailing text" and "line `| Id |`" — parser regressions, found live
115
- // on 2026-08-09, and before they were observed through `unrun-gate`, which no longer exists here. If they
116
- // had simply been left expecting `[]`, they would have turned green BY CONSTRUCTION: empty set
117
- // of findings appears both when the parser is right and when it silently ate the table. So both
118
- // were rewritten to be observed through `stale-continuous` — the check that stayed here:
119
- // parser did not see section ⇒ no line ⇒ no finding ⇒ assertion is red.
120
- // ═══════════════════════════════════════════════════════════════════════════════════════
121
-
122
- // ── 0. the baseline says nothing ───────────────────────────────────────────────────────
123
- // Asserted first and asserted hard. Every case below is "the baseline plus one thing", so a noisy
124
- // baseline would make all of them meaningless — and a checker that fires on a clean scorecard is
125
- // muted within a day, which is worse than one that misses.
126
- expect("clean", {}, []);
127
-
128
- // ── 1. stale-continuous — a ☑ about text that has since been rewritten ─────────────────
129
- // verify-citations was numbered like a one-shot step, so a citation added after the last run counted
130
- // as verified. The project rule "we checked last cycle does not count" was already written down.
131
- // INPUT FROM OUTSIDE THE FILE: the date of the last commit that touched the paper's text — that is why the check stayed.
132
- expect("stale-continuous", { cites: { date: "2020-01-01" } }, [
133
- "stale-continuous",
134
- ]);
135
-
136
- // ── 2. submit-access — no portal account inside somebody else's moderation window ──────
137
- // Found at T−4 days on a finished paper, as the sole item on the critical path: OpenReview profiles
138
- // are moderated for up to two weeks and there is no expedite route without an institutional email.
139
- // INPUT FROM OUTSIDE THE FILE: the clock.
140
- expect(
141
- "submit-access",
142
- { access: { status: "☐" }, deadline: "2026-09-01" },
143
- ["submit-access"],
144
- "2026-08-20",
145
- );
146
-
147
- // ── 3. …and a far deadline with the same blank row is NOT urgent ───────────────────────
148
- expect("submit-access-not-yet", { access: { status: "☐" } }, []);
149
-
150
- // ── 4. a history section is evidence, not status ──────────────────────────────────────
151
- // A superseded 2026-08-02 row saying the artifact was unhosted re-triggered the credential check on
152
- // 2026-08-05, hours after the artifact went up. This project appends rather than rewrites, so every
153
- // scorecard accumulates old rows, and parsing them makes every past state live again.
154
- // Observed through `stale-continuous`: a row in history is dated 2020, and if the history
155
- // slice did not work, it would have given it.
156
- expect(
157
- "history-is-not-status",
158
- {
159
- tail: [
160
- "## History",
161
- "",
162
- "### CONTINUOUS",
163
- ...PLAIN_HEAD,
164
- "| cites | any cite | verify-citations | ☑ | 2020-01-01 | old | — |",
165
- ].join("\n"),
166
- },
167
- [],
168
- );
169
-
170
- // ── 5. a heading may carry trailing text — the RELAXATION, still observable ────────────
171
- // The old pattern was `/^###\s+([A-Z]+)\s*$/`: an all-caps Latin word and NOTHING after it. Papers
172
- // annotate their headings (`### GATES (re-run 06.08)`), so the pattern failed on the real document
173
- // and the section simply stayed unset — SILENTLY. Planted here as a CONTINUOUS row with an old date:
174
- // the finding exists only if the annotated heading was recognised as a section.
175
- expect(
176
- "heading-with-trailing-text",
177
- {
178
- tail: [
179
- "### CONTINUOUS (re-run 2026-08-09, after the cut)",
180
- ...PLAIN_HEAD,
181
- "| refs | any ref moved | verify-refs | ☑ | 2020-01-01 | ok | — |",
182
- ].join("\n"),
183
- },
184
- ["stale-continuous"],
185
- );
186
-
187
- // ── 6. the row `| Id |` is a ROW, and the header is whatever `thead` says it is ────────
188
- // The old parser guessed the header with `/^\|\s*id\s*\|/i`, so the DATA row `| Id | …` — the
189
- // research-ideate row, before the words-not-codes rename — matched the guess and was eaten on every
190
- // scorecard in the repo, for as long as the template had existed. A row that parses as nothing, on
191
- // every paper, forever. Planted as a stale CONTINUOUS row so its absence is visible: if the row were
192
- // still being swallowed, the finding set would be EMPTY.
193
- {
194
- const f = findings("header-lookalike-row", {
195
- tail: [
196
- "### CONTINUOUS",
197
- ...PLAIN_HEAD,
198
- "| Id | Header-lookalike | research-ideate | ☑ | 2020-01-01 | — | — |",
199
- ].join("\n"),
200
- });
201
- assert.deepEqual(
202
- f.map((x) => x.kind),
203
- ["stale-continuous"],
204
- "header-lookalike-row: wrong finding set",
205
- );
206
- assert.match(
207
- f[0].msg,
208
- /\bId\b/,
209
- "header-lookalike-row: the swallowed row is not named in the finding",
210
- );
211
- }
212
-
213
- // ── 17. the cold-read report's filename: BOTH live spellings must count ───────────────────────────
214
- // 2026-08-24: this gate announced "nobody without context has read this text" about a paper that had
215
- // been cold-read TWICE that day. The report was filed as `…-coldread-worksheet.md`; the pattern knew
216
- // only `cold-read`. Neither spelling is a typo — the skill is `cold-read-diff` while the scorecard
217
- // row id, in the very file this checker parses, is `coldread` — so a gate keyed to one of two live
218
- // spellings is guaranteed to miss. Its failure mode is the expensive one: a hole announced where
219
- // none exists is how a gate stops being read, and then a real hole walks past it.
220
- for (const fname of [
221
- "2026-08-24-cold-read-report.md",
222
- "2026-08-24-coldread-worksheet.md",
223
- ]) {
224
- const name = "coldread-" + fname.replace(/[^a-z]/gi, "");
225
- const d = join(tmp, name);
226
- mkdirSync(join(d, "reviews"), { recursive: true });
227
- writeFileSync(join(d, "PIPELINE-STATUS.md"), scorecard());
228
- writeFileSync(join(d, "paper.md"), "## 1. Heading\n\nProse.\n");
229
- writeFileSync(join(d, "reviews", fname), "# a reader with no context\n");
230
- const out = execFileSync("node", [SCRIPT, d, "--json", `--today=${TODAY}`], {
231
- cwd: ROOT,
232
- encoding: "utf8",
233
- env: ENV,
234
- stdio: ["ignore", "pipe", "pipe"],
235
- });
236
- const ks = JSON.parse(out).map((f) => f.kind);
237
- assert.ok(
238
- !ks.includes("no-cold-read"),
239
- `a real cold-read report named ${fname} was reported as missing — the pattern does not know this spelling`,
240
- );
241
- }
242
- // …and the half that proves the check still works: reviews/ exists and holds nothing cold-read.
243
- {
244
- const d = join(tmp, "coldread-absent");
245
- mkdirSync(join(d, "reviews"), { recursive: true });
246
- writeFileSync(join(d, "PIPELINE-STATUS.md"), scorecard());
247
- writeFileSync(join(d, "paper.md"), "## 1. Heading\n\nProse.\n");
248
- writeFileSync(
249
- join(d, "reviews", "2026-08-24-hotcrp-reviews.md"),
250
- "# not a cold read\n",
251
- );
252
- const out = execFileSync("node", [SCRIPT, d, "--json", `--today=${TODAY}`], {
253
- cwd: ROOT,
254
- encoding: "utf8",
255
- env: ENV,
256
- stdio: ["ignore", "pipe", "pipe"],
257
- });
258
- assert.ok(
259
- JSON.parse(out)
260
- .map((f) => f.kind)
261
- .includes("no-cold-read"),
262
- "reviews/ with no cold-read report was NOT reported — widening the pattern silenced the gate",
263
- );
264
- }
265
-
266
- rmSync(tmp, { recursive: true, force: true });
267
- console.log(
268
- "✓ pipeline-check: 6 cases + two spellings of the cold-read report — one planted defect at a time, on six checks whose input is OUTSIDE the file (git · clock · reviews/ · env). The other sixteen moved to eslint-rules/pipeline-status.harness.mjs",
269
- );
270
-
271
- // ── THE HISTORY CUT ──────────────────────────────────────────────────────────
272
- // Added 2026-09-19, and the reason it was added is the finding: `currentPart` had NO test at
273
- // all. The word "History" appeared nowhere in this file, so the function that decides which
274
- // half of a scorecard counts as current was running unwatched.
275
- //
276
- // 🔴 That is also why the cleanup it guards was unsafe until now. `HISTORY_MARK_RE` — a regex
277
- // over the raw sentence «Всё, что ниже, — история» — was deleted in favour of the heading path
278
- // alone, and neither the old branch nor the new one could be shown to work. Two attempts at a
279
- // discriminator through the CLI returned the same answer for both inputs, which says nothing
280
- // about the subject: same answer for different inputs means the probe is measuring itself.
281
- // Going through the exported parser instead separates them in one call.
282
- //
283
- // Both halves: the buried row is gone under a marker heading, and PRESENT under one that is not
284
- // a marker. Without the second, a parser that dropped every second section would pass.
285
- {
286
- const body = (heading) => `# Scorecard
287
-
288
- ### CONTINUOUS
289
- | id | Trigger | Skill | Status | Date | Result | Open |
290
- |----|---------|-------|--------|------|--------|------|
291
- | live | x | s | ☑ | 2026-09-01 | current | — |
292
-
293
- ## ${heading}
294
-
295
- ### CONTINUOUS
296
- | id | Trigger | Skill | Status | Date | Result | Open |
297
- |----|---------|-------|--------|------|--------|------|
298
- | buried | x | s | ☑ | 2001-01-01 | superseded snapshot | — |
299
- `;
300
- const ids = (t) =>
301
- Object.values(parseStatus(t).sections)
302
- .flat()
303
- .map((r) => r.id);
304
-
305
- for (const marker of [
306
- "History",
307
- "Archive",
308
- "history",
309
- "Archive of superseded rows",
310
- ]) {
311
- const got = ids(body(marker));
312
- assert.deepEqual(
313
- got,
314
- ["live"],
315
- `a row under the «${marker}» marker is still counted as current — a superseded snapshot ` +
316
- `reads as today's status, which is the exact failure the cut exists to prevent: ${JSON.stringify(got)}`,
317
- );
318
- }
319
-
320
- // The other half. A heading that merely mentions neither word must NOT cut, or the check
321
- // silently stops seeing whole sections and reports a clean scorecard it never read.
322
- const kept = ids(body("Notes"));
323
- assert.deepEqual(
324
- kept,
325
- ["live", "buried"],
326
- `an ordinary heading cut the document — sections after it vanish unnoticed: ${JSON.stringify(kept)}`,
327
- );
328
- }