paperlint 7.2.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/CLAUDE.md +9 -25
  2. package/CONTRIBUTING.md +5 -4
  3. package/README.md +4 -3
  4. package/dist/adapters/bibtex/index.d.ts +3 -0
  5. package/dist/adapters/bibtex/index.d.ts.map +1 -0
  6. package/dist/adapters/bibtex/index.js +103 -0
  7. package/dist/adapters/bibtex/index.js.map +1 -0
  8. package/dist/adapters/latex/filecontents.d.ts +33 -0
  9. package/dist/adapters/latex/filecontents.d.ts.map +1 -0
  10. package/dist/adapters/latex/filecontents.js +65 -0
  11. package/dist/adapters/latex/filecontents.js.map +1 -0
  12. package/dist/adapters/latex/includes.d.ts +3 -3
  13. package/dist/adapters/latex/includes.d.ts.map +1 -1
  14. package/dist/adapters/latex/includes.js +18 -10
  15. package/dist/adapters/latex/includes.js.map +1 -1
  16. package/dist/adapters/latex/index.d.ts.map +1 -1
  17. package/dist/adapters/latex/index.js +2 -0
  18. package/dist/adapters/latex/index.js.map +1 -1
  19. package/dist/adapters/latex/nodes.d.ts +12 -0
  20. package/dist/adapters/latex/nodes.d.ts.map +1 -1
  21. package/dist/adapters/latex/nodes.js +39 -0
  22. package/dist/adapters/latex/nodes.js.map +1 -1
  23. package/dist/adapters/latex/parse.d.ts +7 -1
  24. package/dist/adapters/latex/parse.d.ts.map +1 -1
  25. package/dist/adapters/latex/parse.js +55 -6
  26. package/dist/adapters/latex/parse.js.map +1 -1
  27. package/dist/adapters/memory/index.d.ts +3 -0
  28. package/dist/adapters/memory/index.d.ts.map +1 -1
  29. package/dist/adapters/memory/index.js +9 -0
  30. package/dist/adapters/memory/index.js.map +1 -1
  31. package/dist/adapters/references/index.d.ts.map +1 -1
  32. package/dist/adapters/references/index.js +27 -24
  33. package/dist/adapters/references/index.js.map +1 -1
  34. package/dist/adapters/sources-record/index.d.ts +9 -0
  35. package/dist/adapters/sources-record/index.d.ts.map +1 -0
  36. package/dist/adapters/sources-record/index.js +68 -0
  37. package/dist/adapters/sources-record/index.js.map +1 -0
  38. package/dist/adapters/tex-output/blg.d.ts +9 -0
  39. package/dist/adapters/tex-output/blg.d.ts.map +1 -0
  40. package/dist/adapters/tex-output/blg.js +20 -0
  41. package/dist/adapters/tex-output/blg.js.map +1 -0
  42. package/dist/adapters/tex-output/fls.d.ts +8 -0
  43. package/dist/adapters/tex-output/fls.d.ts.map +1 -0
  44. package/dist/adapters/tex-output/fls.js +16 -0
  45. package/dist/adapters/tex-output/fls.js.map +1 -0
  46. package/dist/adapters/tex-output/index.d.ts +7 -0
  47. package/dist/adapters/tex-output/index.d.ts.map +1 -0
  48. package/dist/adapters/tex-output/index.js +7 -0
  49. package/dist/adapters/tex-output/index.js.map +1 -0
  50. package/dist/bib-rules.d.ts +47 -0
  51. package/dist/bib-rules.d.ts.map +1 -0
  52. package/dist/bib-rules.js +127 -0
  53. package/dist/bib-rules.js.map +1 -0
  54. package/dist/build.d.ts +29 -1
  55. package/dist/build.d.ts.map +1 -1
  56. package/dist/build.js +41 -30
  57. package/dist/build.js.map +1 -1
  58. package/dist/claim-provenance.d.ts +2 -2
  59. package/dist/cli.d.ts +9 -5
  60. package/dist/cli.d.ts.map +1 -1
  61. package/dist/cli.js +43 -68
  62. package/dist/cli.js.map +1 -1
  63. package/dist/domain/paper-source.d.ts +1 -10
  64. package/dist/domain/paper-source.d.ts.map +1 -1
  65. package/dist/domain/paper-source.js +34 -24
  66. package/dist/domain/paper-source.js.map +1 -1
  67. package/dist/domain/paper-sources.d.ts +72 -0
  68. package/dist/domain/paper-sources.d.ts.map +1 -0
  69. package/dist/domain/paper-sources.js +18 -0
  70. package/dist/domain/paper-sources.js.map +1 -0
  71. package/dist/domain/sources-record.d.ts +102 -0
  72. package/dist/domain/sources-record.d.ts.map +1 -0
  73. package/dist/domain/sources-record.js +38 -0
  74. package/dist/domain/sources-record.js.map +1 -0
  75. package/dist/domain/tex-run.d.ts +25 -0
  76. package/dist/domain/tex-run.d.ts.map +1 -0
  77. package/dist/domain/tex-run.js +79 -0
  78. package/dist/domain/tex-run.js.map +1 -0
  79. package/dist/eslint-rules/latex-language.d.ts.map +1 -1
  80. package/dist/eslint-rules/latex-language.js +10 -13
  81. package/dist/eslint-rules/latex-language.js.map +1 -1
  82. package/dist/eslint-rules/paper-context.d.ts.map +1 -1
  83. package/dist/eslint-rules/paper-context.js +6 -5
  84. package/dist/eslint-rules/paper-context.js.map +1 -1
  85. package/dist/eslint-rules/paper-typography.d.ts +0 -9
  86. package/dist/eslint-rules/paper-typography.d.ts.map +1 -1
  87. package/dist/eslint-rules/paper-typography.js +34 -96
  88. package/dist/eslint-rules/paper-typography.js.map +1 -1
  89. package/dist/eslint-rules/papers.d.ts +1 -3
  90. package/dist/eslint-rules/papers.d.ts.map +1 -1
  91. package/dist/eslint-rules/papers.js +2 -4
  92. package/dist/eslint-rules/papers.js.map +1 -1
  93. package/dist/eslint-rules/tex-build.d.ts.map +1 -1
  94. package/dist/eslint-rules/tex-build.js +8 -25
  95. package/dist/eslint-rules/tex-build.js.map +1 -1
  96. package/dist/init.d.ts +1 -4
  97. package/dist/init.d.ts.map +1 -1
  98. package/dist/init.js +3 -9
  99. package/dist/init.js.map +1 -1
  100. package/dist/latex-log.d.ts +10 -0
  101. package/dist/latex-log.d.ts.map +1 -1
  102. package/dist/latex-log.js +10 -0
  103. package/dist/latex-log.js.map +1 -1
  104. package/dist/latex-loop.d.ts +2 -0
  105. package/dist/latex-loop.d.ts.map +1 -1
  106. package/dist/latex-loop.js.map +1 -1
  107. package/dist/lib/markdown.d.ts +5 -81
  108. package/dist/lib/markdown.d.ts.map +1 -1
  109. package/dist/lib/markdown.js +5 -116
  110. package/dist/lib/markdown.js.map +1 -1
  111. package/dist/lib/paper-config.d.ts.map +1 -1
  112. package/dist/lib/paper-config.js +0 -2
  113. package/dist/lib/paper-config.js.map +1 -1
  114. package/dist/lib/skill-eval-fixture.d.ts +6 -4
  115. package/dist/lib/skill-eval-fixture.d.ts.map +1 -1
  116. package/dist/lib/skill-eval-fixture.js +25 -18
  117. package/dist/lib/skill-eval-fixture.js.map +1 -1
  118. package/dist/new-paper.d.ts +5 -11
  119. package/dist/new-paper.d.ts.map +1 -1
  120. package/dist/new-paper.js +12 -23
  121. package/dist/new-paper.js.map +1 -1
  122. package/dist/package-dirs.d.ts.map +1 -1
  123. package/dist/package-dirs.js +3 -2
  124. package/dist/package-dirs.js.map +1 -1
  125. package/dist/paper-files.d.ts +4 -4
  126. package/dist/paper-includes.d.ts +4 -7
  127. package/dist/paper-includes.d.ts.map +1 -1
  128. package/dist/paper-includes.js +29 -21
  129. package/dist/paper-includes.js.map +1 -1
  130. package/dist/paper-prose.d.ts +17 -0
  131. package/dist/paper-prose.d.ts.map +1 -0
  132. package/dist/paper-prose.js +46 -0
  133. package/dist/paper-prose.js.map +1 -0
  134. package/dist/paper-record.d.ts +25 -0
  135. package/dist/paper-record.d.ts.map +1 -0
  136. package/dist/paper-record.js +39 -0
  137. package/dist/paper-record.js.map +1 -0
  138. package/dist/paper-sources.d.ts +66 -0
  139. package/dist/paper-sources.d.ts.map +1 -0
  140. package/dist/paper-sources.js +92 -0
  141. package/dist/paper-sources.js.map +1 -0
  142. package/dist/ports/bib-reader.d.ts +18 -0
  143. package/dist/ports/bib-reader.d.ts.map +1 -0
  144. package/dist/ports/bib-reader.js +2 -0
  145. package/dist/ports/bib-reader.js.map +1 -0
  146. package/dist/ports/check-references.d.ts +9 -4
  147. package/dist/ports/check-references.d.ts.map +1 -1
  148. package/dist/ports/latex.d.ts +15 -0
  149. package/dist/ports/latex.d.ts.map +1 -1
  150. package/dist/ports/sources-codec.d.ts +11 -0
  151. package/dist/ports/sources-codec.d.ts.map +1 -0
  152. package/dist/ports/sources-codec.js +2 -0
  153. package/dist/ports/sources-codec.js.map +1 -0
  154. package/dist/ports/tex-output.d.ts +17 -0
  155. package/dist/ports/tex-output.d.ts.map +1 -0
  156. package/dist/ports/tex-output.js +2 -0
  157. package/dist/ports/tex-output.js.map +1 -0
  158. package/dist/recorded-bibliography.d.ts +89 -0
  159. package/dist/recorded-bibliography.d.ts.map +1 -0
  160. package/dist/recorded-bibliography.js +136 -0
  161. package/dist/recorded-bibliography.js.map +1 -0
  162. package/dist/reference-rules.d.ts +5 -5
  163. package/dist/reference-rules.d.ts.map +1 -1
  164. package/dist/reference-rules.js +150 -77
  165. package/dist/reference-rules.js.map +1 -1
  166. package/dist/references.d.ts +71 -16
  167. package/dist/references.d.ts.map +1 -1
  168. package/dist/references.js +110 -26
  169. package/dist/references.js.map +1 -1
  170. package/dist/register-bands.d.ts +3 -3
  171. package/dist/register-bands.d.ts.map +1 -1
  172. package/dist/register-bands.js.map +1 -1
  173. package/dist/register.d.ts +2 -2
  174. package/dist/sources-record.d.ts +38 -0
  175. package/dist/sources-record.d.ts.map +1 -0
  176. package/dist/sources-record.js +123 -0
  177. package/dist/sources-record.js.map +1 -0
  178. package/dist/sources-rules.d.ts +44 -0
  179. package/dist/sources-rules.d.ts.map +1 -0
  180. package/dist/sources-rules.js +76 -0
  181. package/dist/sources-rules.js.map +1 -0
  182. package/dist/structure.d.ts.map +1 -1
  183. package/dist/structure.js +4 -3
  184. package/dist/structure.js.map +1 -1
  185. package/dist/tex-paper.d.ts +10 -15
  186. package/dist/tex-paper.d.ts.map +1 -1
  187. package/dist/tex-paper.js +24 -40
  188. package/dist/tex-paper.js.map +1 -1
  189. package/dist/tex-venue-rules.d.ts +3 -3
  190. package/dist/tex-venue-rules.d.ts.map +1 -1
  191. package/dist/tex-venue-rules.js.map +1 -1
  192. package/dist/types.d.ts +0 -2
  193. package/dist/types.d.ts.map +1 -1
  194. package/docs/configuration.md +18 -12
  195. package/docs/design/paper-sources.md +197 -0
  196. package/docs/e2e.md +4 -6
  197. package/docs/package-shape-options.md +1 -1
  198. package/docs/prior-art/paper-folder-scaffolding.md +24 -29
  199. package/docs/references.md +34 -8
  200. package/docs/rules/bib/reachable-entry.md +64 -0
  201. package/docs/rules/paper/sources-fresh.md +81 -0
  202. package/docs/rules/tex/claim-provenance.md +0 -1
  203. package/docs/rules.md +62 -61
  204. package/eslint-rules/latex-language.harness.mjs +3 -3
  205. package/eslint-rules/latex-language.ts +10 -13
  206. package/eslint-rules/paper-context.ts +6 -5
  207. package/eslint-rules/paper-typography.test.mjs +29 -157
  208. package/eslint-rules/paper-typography.ts +35 -104
  209. package/eslint-rules/papers.harness.mjs +1 -1
  210. package/eslint-rules/papers.ts +2 -4
  211. package/eslint-rules/tex-build.harness.mjs +2 -2
  212. package/eslint-rules/tex-build.ts +8 -25
  213. package/eslint.config.mjs +22 -1
  214. package/fixtures/build-e2e/aidc/paper.tex +1 -1
  215. package/fixtures/build-e2e/anon-ack/paper.tex +1 -1
  216. package/fixtures/build-e2e/anon-author/paper.tex +1 -1
  217. package/fixtures/build-e2e/anon-bib/paper.tex +1 -1
  218. package/fixtures/build-e2e/anon-href/paper.tex +1 -1
  219. package/fixtures/build-e2e/anon-macro/paper.tex +1 -1
  220. package/fixtures/build-e2e/anon-pdfauthor/paper.tex +1 -1
  221. package/fixtures/paper-sources/p1/paper.tex +30 -0
  222. package/fixtures/paper-sources/p1/refs.bib +6 -0
  223. package/fixtures/paper-sources/p1/sections/dead.tex +6 -0
  224. package/fixtures/paper-sources/p1/sections/intro.tex +7 -0
  225. package/fixtures/paper-sources/p1/sections/parked.tex +6 -0
  226. package/fixtures/paper-sources/p1/tex-truth.json +37 -0
  227. package/fixtures/paper-sources/p1/versions/2026-01-01-review.tex +4 -0
  228. package/fixtures/paper-sources/v1-stale/paper.tex +14 -0
  229. package/fixtures/paper-sources/v1-stale/refs.bib +6 -0
  230. package/fixtures/paper-sources/v1-stale/tex-truth.json +32 -0
  231. package/fixtures/paper-sources/v10-ifthenelse/anon.bib +1 -0
  232. package/fixtures/paper-sources/v10-ifthenelse/paper.tex +9 -0
  233. package/fixtures/paper-sources/v10-ifthenelse/real.bib +1 -0
  234. package/fixtures/paper-sources/v10-ifthenelse/tex-truth.json +28 -0
  235. package/fixtures/paper-sources/v11-two-blocks/paper.tex +12 -0
  236. package/fixtures/paper-sources/v11-two-blocks/tex-truth.json +30 -0
  237. package/fixtures/paper-sources/v13-percent-text/paper.tex +6 -0
  238. package/fixtures/paper-sources/v13-percent-text/refs.bib +3 -0
  239. package/fixtures/paper-sources/v13-percent-text/tex-truth.json +30 -0
  240. package/fixtures/paper-sources/v15-after-end/paper.tex +6 -0
  241. package/fixtures/paper-sources/v15-after-end/refs.bib +1 -0
  242. package/fixtures/paper-sources/v15-after-end/tex-truth.json +17 -0
  243. package/fixtures/paper-sources/v16-included-block/bibblock.tex +3 -0
  244. package/fixtures/paper-sources/v16-included-block/paper.tex +7 -0
  245. package/fixtures/paper-sources/v16-included-block/refs.bib +1 -0
  246. package/fixtures/paper-sources/v16-included-block/tex-truth.json +35 -0
  247. package/fixtures/paper-sources/v17-include-order/bibsetup.tex +1 -0
  248. package/fixtures/paper-sources/v17-include-order/first.bib +1 -0
  249. package/fixtures/paper-sources/v17-include-order/later.bib +1 -0
  250. package/fixtures/paper-sources/v17-include-order/paper.tex +7 -0
  251. package/fixtures/paper-sources/v17-include-order/tex-truth.json +40 -0
  252. package/fixtures/paper-sources/v2-overwrite/paper.tex +14 -0
  253. package/fixtures/paper-sources/v2-overwrite/refs.bib +6 -0
  254. package/fixtures/paper-sources/v2-overwrite/tex-truth.json +30 -0
  255. package/fixtures/paper-sources/v22-parked-thebibliography/paper.tex +7 -0
  256. package/fixtures/paper-sources/v22-parked-thebibliography/tex-truth.json +17 -0
  257. package/fixtures/paper-sources/v23-parked-include/old.bib +1 -0
  258. package/fixtures/paper-sources/v23-parked-include/paper.tex +7 -0
  259. package/fixtures/paper-sources/v23-parked-include/parked.tex +1 -0
  260. package/fixtures/paper-sources/v23-parked-include/refs.bib +1 -0
  261. package/fixtures/paper-sources/v23-parked-include/tex-truth.json +28 -0
  262. package/fixtures/paper-sources/v24-quoted-fields/paper.tex +6 -0
  263. package/fixtures/paper-sources/v24-quoted-fields/refs.bib +5 -0
  264. package/fixtures/paper-sources/v24-quoted-fields/tex-truth.json +32 -0
  265. package/fixtures/paper-sources/v25-string-differs/paper.tex +10 -0
  266. package/fixtures/paper-sources/v25-string-differs/refs.bib +2 -0
  267. package/fixtures/paper-sources/v25-string-differs/tex-truth.json +32 -0
  268. package/fixtures/paper-sources/v26-comment-in-names/one.bib +1 -0
  269. package/fixtures/paper-sources/v26-comment-in-names/paper.tex +7 -0
  270. package/fixtures/paper-sources/v26-comment-in-names/tex-truth.json +32 -0
  271. package/fixtures/paper-sources/v26-comment-in-names/two.bib +1 -0
  272. package/fixtures/paper-sources/v27-shared-string/abbreviations.bib +2 -0
  273. package/fixtures/paper-sources/v27-shared-string/paper.tex +6 -0
  274. package/fixtures/paper-sources/v27-shared-string/references.bib +6 -0
  275. package/fixtures/paper-sources/v27-shared-string/tex-truth.json +31 -0
  276. package/fixtures/paper-sources/v28-shared-string-block/abbreviations.bib +2 -0
  277. package/fixtures/paper-sources/v28-shared-string-block/paper.tex +14 -0
  278. package/fixtures/paper-sources/v28-shared-string-block/tex-truth.json +33 -0
  279. package/fixtures/paper-sources/v29-generated-input/paper.tex +9 -0
  280. package/fixtures/paper-sources/v29-generated-input/tex-truth.json +24 -0
  281. package/fixtures/paper-sources/v3-declared/paper.bib +6 -0
  282. package/fixtures/paper-sources/v3-declared/paper.tex +6 -0
  283. package/fixtures/paper-sources/v3-declared/tex-truth.json +28 -0
  284. package/fixtures/paper-sources/v30-name-next-line/paper.tex +14 -0
  285. package/fixtures/paper-sources/v30-name-next-line/tex-truth.json +30 -0
  286. package/fixtures/paper-sources/v4-commented/paper.tex +14 -0
  287. package/fixtures/paper-sources/v4-commented/refs.bib +6 -0
  288. package/fixtures/paper-sources/v4-commented/tex-truth.json +28 -0
  289. package/fixtures/paper-sources/v5-percent-entry/paper.tex +20 -0
  290. package/fixtures/paper-sources/v5-percent-entry/tex-truth.json +37 -0
  291. package/fixtures/paper-sources/v6-unclosed/paper.tex +6 -0
  292. package/fixtures/paper-sources/v6-unclosed/refs.bib +5 -0
  293. package/fixtures/paper-sources/v6-unclosed/tex-truth.json +37 -0
  294. package/fixtures/paper-sources/v8-jobname/paper.tex +9 -0
  295. package/fixtures/paper-sources/v8-jobname/tex-truth.json +30 -0
  296. package/fixtures/paper-sources/v9-two-bibliographies/one.bib +1 -0
  297. package/fixtures/paper-sources/v9-two-bibliographies/paper.tex +7 -0
  298. package/fixtures/paper-sources/v9-two-bibliographies/tex-truth.json +35 -0
  299. package/fixtures/paper-sources/v9-two-bibliographies/two.bib +1 -0
  300. package/fixtures/paper-typography/clean-paper/paper.tex +1 -1
  301. package/fixtures/paper-typography/messy-paper/paper.tex +1 -1
  302. package/hooks/hooks.harness.ts +15 -15
  303. package/hooks/paper-edit-guard.hook.mjs +5 -8
  304. package/hooks/paper-edit-guard.test.ts +12 -3
  305. package/hooks/paper-skills-nudge.hook.mjs +2 -3
  306. package/hooks/paper-skills-nudge.test.ts +13 -3
  307. package/hooks/paper-status-gates.hook.mjs +2 -2
  308. package/hooks/paper-status-gates.test.ts +14 -2
  309. package/lib/markdown.test.mjs +5 -60
  310. package/lib/markdown.ts +9 -136
  311. package/lib/paper-config.ts +0 -2
  312. package/lib/skill-checks.test.mjs +4 -1
  313. package/lib/skill-eval-fixture.ts +25 -18
  314. package/package.json +2 -12
  315. package/presets/realm.jsonc +1 -1
  316. package/scripts/check.test.ts +23 -1
  317. package/scripts/check.ts +7 -3
  318. package/scripts/coverage-config.test.ts +19 -10
  319. package/scripts/harness-api.frozen.json +0 -5
  320. package/scripts/layer-legacy-frozen.test.ts +41 -2
  321. package/scripts/layer-legacy-frozen.ts +31 -2
  322. package/skills/cold-read-diff/SKILL.md +3 -3
  323. package/skills/cold-read-diff/SKILL.md.spec.ts +2 -2
  324. package/skills/grade-paper-writing/SKILL.md +15 -22
  325. package/skills/grade-paper-writing/SKILL.md.spec.ts +14 -21
  326. package/skills/grade-paper-writing/__snapshots__/prose-lint.test.ts.snap +40 -26
  327. package/skills/grade-paper-writing/prose-lint.mjs +117 -278
  328. package/skills/grade-paper-writing/prose-lint.test.ts +230 -79
  329. package/skills/paper-adversarial-review/SKILL.md +2 -2
  330. package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -1
  331. package/skills/paper-pipeline/SKILL.md +9 -12
  332. package/skills/paper-pipeline/SKILL.md.spec.ts +8 -11
  333. package/skills/paper-pipeline/description-language.eval.mjs +25 -15
  334. package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +25 -15
  335. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +25 -15
  336. package/skills/paper-pipeline/pipeline-firing.eval.mjs +27 -16
  337. package/skills/paper-pipeline/pipeline-language.eval.mjs +25 -15
  338. package/skills/paper-pipeline/references/acceptance-gate.md +16 -20
  339. package/skills/paper-pipeline/references/artifact-checklist.md +4 -5
  340. package/skills/paper-pipeline/references/pipeline-status-template.md +1 -1
  341. package/skills/paper-pipeline/scripts/README.md +0 -4
  342. package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +91 -105
  343. package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +85 -241
  344. package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +166 -153
  345. package/skills/paper-pipeline/scripts/generated-code.harness.mjs +3 -3
  346. package/skills/paper-status/SKILL.md +2 -2
  347. package/skills/paper-status/SKILL.md.spec.ts +1 -1
  348. package/skills/render-paper/SKILL.md +2 -2
  349. package/skills/render-paper/SKILL.md.spec.ts +1 -1
  350. package/skills/render-paper/extract-pdf-facts.mjs +2 -2
  351. package/skills/tighten-paper/SKILL.md +29 -42
  352. package/skills/tighten-paper/SKILL.md.spec.ts +28 -41
  353. package/skills/verify-citations/SKILL.md +7 -4
  354. package/skills/verify-citations/SKILL.md.spec.ts +6 -3
  355. package/skills/verify-citations/scripts/bib-authors.check.test.mjs +17 -32
  356. package/skills/verify-citations/scripts/bib-authors.cli.test.ts +138 -43
  357. package/skills/verify-citations/scripts/bib-authors.d.mts +22 -2
  358. package/skills/verify-citations/scripts/bib-authors.mjs +54 -193
  359. package/skills/verify-citations/scripts/bib-authors.test.mjs +1 -44
  360. package/skills/verify-citations/scripts/verify-cites.cli.test.ts +16 -0
  361. package/skills/verify-citations/scripts/verify-cites.d.mts +19 -3
  362. package/skills/verify-citations/scripts/verify-cites.mjs +42 -108
  363. package/skills/verify-citations/scripts/verify-cites.test.mjs +23 -36
  364. package/src/adapters/bibtex/index.test.ts +163 -0
  365. package/src/adapters/bibtex/index.ts +155 -0
  366. package/src/adapters/latex/filecontents.ts +114 -0
  367. package/src/adapters/latex/includes.ts +18 -10
  368. package/src/adapters/latex/index.test.ts +73 -0
  369. package/src/adapters/latex/index.ts +2 -0
  370. package/src/adapters/latex/nodes.ts +64 -0
  371. package/src/adapters/latex/parse.test.ts +38 -0
  372. package/src/adapters/latex/parse.ts +67 -6
  373. package/src/adapters/memory/index.ts +17 -0
  374. package/src/adapters/references/index.test.ts +75 -21
  375. package/src/adapters/references/index.ts +37 -32
  376. package/src/adapters/sources-record/index.test.ts +87 -0
  377. package/src/adapters/sources-record/index.ts +82 -0
  378. package/src/adapters/tex-output/blg.ts +27 -0
  379. package/src/adapters/tex-output/fls.ts +24 -0
  380. package/src/adapters/tex-output/index.test.ts +171 -0
  381. package/src/adapters/tex-output/index.ts +12 -0
  382. package/src/bib-rules.test.ts +356 -0
  383. package/src/bib-rules.ts +228 -0
  384. package/src/bibliography-at.test.ts +286 -0
  385. package/src/build.harness.mjs +2 -2
  386. package/src/build.test.ts +211 -1
  387. package/src/build.ts +101 -41
  388. package/src/claim-provenance.test.ts +33 -7
  389. package/src/claim-provenance.ts +2 -2
  390. package/src/cli.harness.mjs +46 -56
  391. package/src/cli.test.ts +44 -48
  392. package/src/cli.ts +51 -82
  393. package/src/domain/paper-source.test.ts +58 -20
  394. package/src/domain/paper-source.ts +38 -42
  395. package/src/domain/paper-sources.ts +94 -0
  396. package/src/domain/sources-record.test.ts +71 -0
  397. package/src/domain/sources-record.ts +136 -0
  398. package/src/domain/tex-run.test.ts +228 -0
  399. package/src/domain/tex-run.ts +139 -0
  400. package/src/folder-venue-rule.test.ts +1 -1
  401. package/src/heading-case.test.ts +24 -10
  402. package/src/init.test.ts +6 -7
  403. package/src/init.ts +3 -22
  404. package/src/latex-log.ts +20 -0
  405. package/src/latex-loop.harness.ts +1 -0
  406. package/src/latex-loop.ts +2 -0
  407. package/src/lint-fix.test.ts +10 -4
  408. package/src/linted-set.test.ts +9 -1
  409. package/src/new-paper.harness.mjs +12 -30
  410. package/src/new-paper.test.ts +15 -11
  411. package/src/new-paper.ts +11 -30
  412. package/src/package-dirs.ts +3 -2
  413. package/src/paper-files.test.ts +5 -4
  414. package/src/paper-files.ts +4 -4
  415. package/src/paper-includes.test.ts +157 -38
  416. package/src/paper-includes.ts +39 -35
  417. package/src/paper-prose.test.ts +78 -0
  418. package/src/paper-prose.ts +67 -0
  419. package/src/paper-record.test.ts +173 -0
  420. package/src/paper-record.ts +66 -0
  421. package/src/paper-settings-commands.test.ts +5 -2
  422. package/src/paper-sources.ts +151 -0
  423. package/src/parse-args.test.ts +0 -1
  424. package/src/ports/bib-reader.ts +27 -0
  425. package/src/ports/check-references.ts +7 -3
  426. package/src/ports/latex.ts +19 -0
  427. package/src/ports/sources-codec.ts +11 -0
  428. package/src/ports/tex-output.ts +17 -0
  429. package/src/recorded-bibliography.ts +297 -0
  430. package/src/reference-rules.ts +217 -104
  431. package/src/references.test.ts +520 -177
  432. package/src/references.ts +185 -37
  433. package/src/register-bands.test.ts +5 -1
  434. package/src/register-bands.ts +3 -5
  435. package/src/register.test.ts +6 -1
  436. package/src/register.ts +2 -2
  437. package/src/rule-cases.test.ts +68 -12
  438. package/src/rule-docs.test.ts +0 -1
  439. package/src/sources-record.test.ts +308 -0
  440. package/src/sources-record.ts +231 -0
  441. package/src/sources-rules.test.ts +152 -0
  442. package/src/sources-rules.ts +117 -0
  443. package/src/structure.harness.ts +5 -11
  444. package/src/structure.ts +4 -3
  445. package/src/tex-paper.test.ts +148 -78
  446. package/src/tex-paper.ts +31 -61
  447. package/src/tex-venue-rules.test.ts +36 -8
  448. package/src/tex-venue-rules.ts +3 -5
  449. package/src/types.ts +0 -2
  450. package/dist/eslint-rules/bib-reachable-entry.d.ts +0 -22
  451. package/dist/eslint-rules/bib-reachable-entry.d.ts.map +0 -1
  452. package/dist/eslint-rules/bib-reachable-entry.js +0 -75
  453. package/dist/eslint-rules/bib-reachable-entry.js.map +0 -1
  454. package/eslint-rules/bib-reachable-entry.ts +0 -76
  455. package/fixtures/real-markdown-paper/baseline.json +0 -22
  456. package/fixtures/real-markdown-paper/baseline.ts +0 -70
  457. package/skills/paper-pipeline/PIPELINE-MAP.md +0 -381
  458. package/skills/paper-pipeline/pipeline-firing.baseline.json +0 -270
  459. package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +0 -585
  460. package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +0 -492
  461. package/skills/paper-pipeline/scripts/artifact-coverage.mjs +0 -397
  462. package/skills/paper-pipeline/scripts/artifact-coverage.test.ts +0 -86
  463. package/skills/paper-pipeline/scripts/check-provenance.mjs +0 -184
  464. package/skills/paper-pipeline/scripts/population-map.harness.mjs +0 -135
  465. package/skills/paper-pipeline/scripts/population-map.mjs +0 -188
  466. package/skills/paper-pipeline/scripts/population-map.test.mjs +0 -154
  467. package/skills/paper-pipeline/scripts/provenance.harness.mjs +0 -266
  468. package/skills/paper-pipeline/scripts/round-diff.harness.ts +0 -907
  469. package/skills/paper-pipeline/scripts/round-diff.mjs +0 -583
  470. package/skills/paper-pipeline/scripts/round-diff.test.mjs +0 -159
  471. package/skills/tighten-paper/__snapshots__/structure.test.ts.snap +0 -133
  472. package/skills/tighten-paper/structure.mjs +0 -364
  473. package/skills/tighten-paper/structure.test.ts +0 -117
  474. package/templates/paper/paper.md +0 -4
@@ -1,381 +0,0 @@
1
- ---
2
- title: "Paper pipeline map — what runs where"
3
- created: 2026-08-26
4
- updated: 2026-08-26
5
- tags: [paper-pipeline, ci, hooks, map]
6
- ---
7
-
8
- # What runs where: the pipeline map
9
-
10
- Assembled 2026-08-26 **from facts** — `.claude/settings.json` and
11
- `.github/workflows/paper-gates.yml` — not from memory. Occasion (translated from Russian): "I have
12
- no fucking idea how the pipeline works right now."
13
-
14
- > ⭐ **How to build checks** (the ladder, occupancy across 14 tools, measurements) —
15
- > in the author's private notes: `<papers-root>/research/2026-08-26-sessiya-arhitektura-payplayna.md`
16
-
17
- ## Four tiers, and they fire at different times
18
-
19
- ```
20
- ┌─ TIER 1: WHILE WRITING ────────────────────── instant, in-session ──┐
21
- │ │
22
- │ you edit paper.md / paper.tex │
23
- │ │ │
24
- │ ├─ PreToolUse → paper-lint pre 🛑 THE ONLY BLOCKER │
25
- │ │ paragraph >200 words · ≥9 numbers · │
26
- │ │ sentence >55 words · refuses the edit │
27
- │ │ outright │
28
- │ │ │
29
- │ ├─ PreToolUse → paper-edit-guard 🛑 a write from Bash │
30
- │ │ (bypassing PostToolUse gates) → deny │
31
- │ │ │
32
- │ └─ PostToolUse → paper-lint post ⚠️ nudges only │
33
- │ plain-language · carries: · SHAVE │
34
- │ prose-lint · the numbers gate │
35
- │ │
36
- │ end of response → Stop → paper-lint stop (throttled to 1 hour) │
37
- │ 15 checks across all papers │
38
- │ + kb-lint stop: 12 checks across the base │
39
- └──────────────────────────────────────────────────────────────────────┘
40
- │
41
- ▼
42
- ┌─ TIER 2: BUILD ───────────────────── when you run pdflatex ─────────┐
43
- │ │
44
- │ paper.tex │
45
- │ │ │
46
- │ ▼ │
47
- │ pdflatex ──┬─→ INSIDE, acmart runs (the document class) │
48
- │ │ it's the same thing that complains in the log: │
49
- │ │ no CCS · no libertine · │
50
- │ │ «ACM reference format is mandatory» │
51
- │ │ │
52
- │ ├─→ paper.pdf ← the final artifact, fonts EMBEDDED │
53
- │ ├─→ paper.log ← acmart writes its warnings here │
54
- │ └─→ paper.blg ← bibtex writes bibliography errors here│
55
- │ │
56
- │ check-render.sh reads ALL THREE: │
57
- │ log → overfull · undefined refs · class warnings │
58
- │ blg → dropped entries · cited-but-absent │
59
- │ pdf → fonts (LinLibertine/LinBiolinum) ← added 25.08 │
60
- │ + chktex on the .tex, if installed (advisory) │
61
- └──────────────────────────────────────────────────────────────────────┘
62
- │
63
- ▼
64
- ┌─ TIER 3: CI ─────────────── on push/PR, 7 jobs ──────────────────────┐
65
- │ │
66
- │ changes ──┐ a path classifier, ~10s, WITHOUT a checkout │
67
- │ │ decides which jobs even run │
68
- │ ▼ │
69
- │ ┌─────────────────────────────────────────────────────────────┐ │
70
- │ │ prose eslint(md) · paper-lint --gate 🛑 · bib-authors │ │
71
- │ │ prose-lint · artifact coverage · population map │ │
72
- │ │ structure · provenance · verify-cites · scorecard│ │
73
- │ ├─────────────────────────────────────────────────────────────┤ │
74
- │ │ numbers paper_numbers selftest → gate │ │
75
- │ │ artifact/reproduce.py ← wired in 26.08 │ │
76
- │ ├─────────────────────────────────────────────────────────────┤ │
77
- │ │ anonymity check-anon over the bundle + every *.selftest.{sh,mjs} │
78
- │ ├─────────────────────────────────────────────────────────────┤ │
79
- │ │ build texlive/texlive:latest container ← FONTS LIVE HERE│ │
80
- │ │ aclpubcheck (optional) · builds · check-render │ │
81
- │ ├─────────────────────────────────────────────────────────────┤ │
82
- │ │ hooks vigiles lint 🛑 · every harness on disk │ │
83
- │ │ TeXtidote (pinned jar) · ledger selftest │ │
84
- │ ├─────────────────────────────────────────────────────────────┤ │
85
- │ │ skill-firing once a week, a real model │ │
86
- │ └─────────────────────────────────────────────────────────────┘ │
87
- └──────────────────────────────────────────────────────────────────────┘
88
- │
89
- ▼
90
- ┌─ TIER 4: THE VENUE ──────── the one verdict that actually decides ──┐
91
- │ │
92
- │ eRights (ACM) ──→ issues a block of copyright commands │
93
- │ │ ↓ paste into paper.tex, REBUILD │
94
- │ ▼ │
95
- │ upload goes to TWO PLACES: │
96
- │ • conference-publishing.com ← goes to typesetting and ACM DL │
97
- │ • HotCRP paper/20/edit ← a copy for the workshop chairs │
98
- │ │ │
99
- │ ▼ │
100
- │ their checker (TAPS / the portal's format checker) — closed-source │
101
- └──────────────────────────────────────────────────────────────────────┘
102
- ```
103
-
104
- ## What only runs by hand
105
-
106
- Skills (`grade-paper-writing`, `tighten-paper`, `pc-panel-review`, `cold-read-diff`,
107
- `verify-citations`, `argument-arc`, `harden-paper`…) are **not invoked by any event**. A human calls
108
- them. This is the judgment layer; its mechanical parts should keep getting pushed down into tiers
109
- 1–3.
110
-
111
- ## Where each tier catches the same thing
112
-
113
- | defect | caught by |
114
- | ------------------------------------- | ---------------------------------------------------------------------------- |
115
- | a wall-of-text paragraph on insertion | tier 1, blocks |
116
- | a number that doesn't match the data | tier 1 (post) and tier 3 (numbers) |
117
- | a reference dropped by bibtex | tier 2 (`.blg`) → tier 3 (build) |
118
- | **wrong font** | tier 2 (the facts' font list) — but it's PREVENTED by tier 3 (the container) |
119
- | a stage declared with no PDF | tier 3, `paper-lint --gate` 🛑 |
120
- | ACM format compliance | **tier 4, and only tier 4** |
121
-
122
- ---
123
-
124
- # 🗺️ Roadmap: what is NOT built
125
-
126
- ## 1. 🔴 A requirement as a BUILD FAILURE, not a check afterward (the author's idea, 26.08)
127
-
128
- Right now almost everything is caught **after** the build. But `acmart` already knows how to fail
129
- the build — it does exactly that on missing CCS concepts (_"CCS concepts are mandatory for papers
130
- over two pages"_). So the mechanism exists, and we're not using it.
131
-
132
- **Rung 2 of the ladder instead of rung 3:** there's nothing to check in something that can't even be
133
- built.
134
-
135
- | requirement | how to turn it into a build failure |
136
- | --------------------- | ---------------------------------------------------------------------------------------------------------------- |
137
- | **fonts** | `fontspec` + a font by path → file missing → the build fails instead of silently falling back to Computer Modern |
138
- | page limit | `\AtEndDocument` + a check on `\thepage` → `\PackageError` |
139
- | text-block dimensions | the class sets these; catch the fact that they were overridden |
140
- | no page numbers | check `\thepage` in the output |
141
-
142
- 🔴 **MEASURED on 2026-08-26, not assumed: `fontspec` with `pdflatex` DOES NOT WORK.** A minimal
143
- document, a `pdflatex` run, exit code 1, verbatim from the log:
144
-
145
- ```
146
- Package: fontspec Font selection for XeLaTeX and LuaLaTeX
147
- ! Fatal Package fontspec Error: The fontspec package requires either XeTeX or LuaTeX.
148
- ```
149
-
150
- ⇒ The whole chain: only `fontspec` can load a font by path → `fontspec` requires XeLaTeX or LuaLaTeX
151
- → we run `pdflatex` → **the construction requires SWITCHING THE BUILD ENGINE**, not adding a
152
- package. That moves the item from "add a line" to "change the program that builds the paper."
153
-
154
- ⚠️ **Three unverified things that decide whether the first row is even feasible** (these are
155
- unknowns, not objections): `fontspec` requires XeLaTeX/LuaLaTeX instead of pdflatex · `acmart`
156
- assigns its own fonts and might conflict · whether the TAPS pipeline will even accept a LuaLaTeX
157
- source. Plus a risk: switching engines changes how microtype is handled, and there's no page-count
158
- slack.
159
-
160
- **Checked by a cheap spike** — build a copy in scratch, see whether the class fights back and
161
- whether the layout shifts. Do this AFTER the 29.08 submission.
162
-
163
- ## 2. Mechanical camera-ready compliance — 1 requirement out of ~25 is checked
164
-
165
- ACM's instructions list ~25 mechanical requirements. Checked: fonts. The rest — text-block geometry,
166
- 9pt/8pt type size, column balance, DOIs on references, captions above tables and below figures,
167
- capitalization, section ordering — **nothing checks any of it**.
168
-
169
- **A construction found and verified against source (26.08):**
170
-
171
- ```
172
- banal -json + pdf.js → paper.facts.json → @eslint/json
173
- (geometry) (fonts) (plain JSON) (the official plugin)
174
- ```
175
-
176
- - **`banal`** — [kohler/hotcrp/src/banal](https://github.com/kohler/hotcrp/blob/master/src/banal),
177
- 1901 lines of Perl, dependencies are core Perl + `pdftohtml`. Standalone, alive (commits on
178
- 03.08.2026). paperlint feeds it pdftohtml-style XML written from pdf.js instead, so poppler is not
179
- needed (`src/adapters/banal/`: `xml.ts` writes it, `run.ts` runs banal; issue #61). Gives you `papersize`, `margin`, `bodyfontsize`, `leading`, `columns`, `npages`,
180
- `reffontsize`. It **doesn't know about fonts by construction** — the words `type3`/`embed` don't
181
- appear in the file at all.
182
- - **banal does not accept a spec** — the comparison lives in `checkformat.php`, the profile grammar
183
- is `papersize;pagelimit;columns;textblock;bodyfontsize;bodylineheight`. For ACM ≈
184
- `letter;;2;18x23.5cm;9`.
185
- - **Why through JSON and not an ESLint language plugin:** `fileType: "binary"` in ESLint is **not
186
- implemented**, the docs say verbatim — _"should be 'text' (in the future, we will also support
187
- 'binary')"_, and the runtime reads the file unconditionally as UTF-8 (`eslint-helpers.js:1281`),
188
- irreversibly mangling PDF bytes into U+FFFD. A hack is possible (`parse()` reads the disk itself),
189
- but it breaks `--fix`, the cache, and `eslint-disable` — there's nowhere to put a directive inside
190
- a PDF.
191
- - **veraPDF is built the same way** — the one PDF validator with user-defined rules: _"doesn't parse
192
- PDF documents directly. Instead it processes the machine readable report output"_. Matching the
193
- architecture of an industrial tool is a sign the construction is right.
194
-
195
- **Occupancy checked:** `eslint-plugin-pdf` → E404 · `textlint` accepts its own format but requires
196
- conversion to text first (precedent: `textlint-plugin-pptx`) · `Vale` won't take a custom parser ·
197
- `MegaLinter`/`super-linter`/`reviewdog` are orchestrators, they won't give us a rule registry for our
198
- format.
199
-
200
- ## 3. Venue constants belong in a card, not in code
201
-
202
- > **Done (#79, 2.1.0), in a different shape than planned below.** The constants live in **venue
203
- > presets**, JSONC files in the package's `presets/`: `acm-sigconf.jsonc` is the ACM
204
- > family (the `format` block — page size, columns, fonts, font sizes — plus the `tex` packages),
205
- > `agenticdev.jsonc` and `aisec.jsonc` extend it and add their `kinds` (page limits) and `rules`,
206
- > `realm.jsonc` stands alone. A paper picks one in `<paper>/paperlint.json`
207
- > (`{ "extends": "paperlint:<venue>", "kind": "…" }`); the `pdf/*` lint rules judge the built PDF
208
- > against it. The `.md` cards stay as prose. What follows is the plan as it was written.
209
-
210
- Right now `LinLibertine`, `LinBiolinum`, `acmart` are hardcoded into `check-render.sh`. This is
211
- **venue data**, and it belongs in
212
- `.claude/skills/submit-paper/references/venues/<venue>.md`:
213
-
214
- ```yaml
215
- venue:
216
- template: acmart
217
- page_size: letter
218
- fonts: { text: LinLibertine, title: LinBiolinum }
219
- textblock: 18x23.5cm
220
- body_pt: 9
221
- body_limit: 5
222
- extra_ref_pages: 2
223
- ```
224
-
225
- The second consumer of this block is the comparison against `banal`'s output (six numbers). The
226
- first is the page limit, which currently exists in **four copies**, and they have already drifted
227
- apart (`venues/realm.md` says 8, `build-submission.sh` hardcodes 8, `PIPELINE-STATUS` writes "body
228
- 8/8," and the build prints 9).
229
-
230
- ## 4. `check-render.sh` — 244 lines of bash full of greps
231
-
232
- The place is right (nothing else reads the build artifacts, and no offline ACM checker exists),
233
- **the form isn't**: no check registry, no config, no severity, thresholds are hardcoded. Bolting 25
234
- more greps onto it is the path we're getting off of. Deal with it together with items 2 and 3.
235
-
236
- ## 5. Check occupancy BEFORE writing — the rule exists, it's rung 4
237
-
238
- Written down twice (05.08, 24.08), and the `sweep-design-space` skill exists. **It was violated
239
- three times overnight on 25/26.08** — meaning prose and a skill don't work, both are rung 4.
240
-
241
- **Proposed construction:** a new check-file must carry an `occupancy:` line — what was searched and
242
- why it didn't fit; the linter requires its presence. Same form as `carries:` for sections and
243
- `Cause:` for re-check findings. To be honest: this is rung 3, not 2 — it doesn't stop you from
244
- skipping the search, but it makes **the absence of evidence visible**.
245
-
246
- ---
247
-
248
- # 🧊 FREEZE on the current ad hoc state (the author's decision, 2026-08-26)
249
-
250
- Verbatim (translated from Russian): _"mark the current pipeline as shit by rule — don't expand it as
251
- it is, only allow new, proper stuff."_
252
-
253
- > **Fixes — yes. New checks — no.**
254
- > A new check goes only in the new form — but **only where the new form already exists.**
255
-
256
- Without the second half the rule is incoherent, and I slipped on it that same evening: announced the
257
- freeze and, two messages later, proposed bolting a check onto `paper-lint`.
258
-
259
- | check category | new form | where a new one goes |
260
- | ------------------------------- | --------------------------------------- | -------------------------------------------------------------- |
261
- | a single document: markdown, JS | **exists** — ESLint | 🛑 not allowed into the old form |
262
- | an artifact: PDF | **exists** — venue profile + checker | 🛑 not allowed into the old form |
263
- | cross-file, filesystem-shaped | **doesn't exist and isn't expected to** | stays a script — that is the rule's boundary, not a workaround |
264
-
265
- **Enforcement:** `paper-lint.mjs` currently has exactly **18** check functions. The "there are 18"
266
- test fails on the nineteenth and forces an answer to "why isn't this in the new form." Small and
267
- readable, unlike a 27-entry debt ledger that would get muted within a day.
268
-
269
- 🔴 **The order is mandatory: freeze AFTER at least half is in the new form.** Right now it's one
270
- rule out of fifteen. Freezing before the new form becomes more convenient than the old one means
271
- getting a workaround and a dead rule. That has already happened in this repo three times.
272
-
273
- ---
274
-
275
- # 📋 Work queue, cheapest to most expensive
276
-
277
- ## 1. A marker instead of a blocklist — one line
278
-
279
- `paperDirs()` today: `.filter((e) => e.name !== "research" && e.name !== "drafts")`. A hand-written
280
- list of two names; everything else under `papers/` is automatically counted as a paper.
281
-
282
- **Measured 2026-08-26:**
283
-
284
- | folder | `PIPELINE-STATUS.md` | counted as a paper today |
285
- | --------------------------------------------------- | -------------------- | ------------------------ |
286
- | `agenticdev-2026` `aisec-2026` `compile-rules-2026` | ✅ | ✅ correctly |
287
- | `scored-2026` | — | 🔴 **yes, wrongly** |
288
- | `extension-shell-ifc` | — | 🔴 **yes, wrongly** |
289
- | `research` `drafts` | — | no (on the blocklist) |
290
-
291
- **The marker: a paper folder is one that has a `PIPELINE-STATUS.md`.** This has already been our
292
- convention since 22.07 ("every paper carries a PIPELINE-STATUS.md"), the code just doesn't use it.
293
- Self-declaration instead of a list: a new paper enters the checks the day it gets a scorecard.
294
-
295
- ⚠️ **Do NOT move the three papers into a separate subfolder.** The marker solves the same problem in
296
- one line, while a move breaks every form of reference — when `.claude/pipeline/` was resettled there
297
- were 134 literal ones, and that wasn't even the whole count (paths built from segments, relative
298
- imports, paths inside regexes).
299
-
300
- ## 2. One build entry point for all papers, not one per paper
301
-
302
- > **Done (#59, 2026-09-24).** `paperlint build <paper>` is the entry point, and `paperlint toolchain` installs
303
- > TeX Live with the packages the venue presets declare; `ensure-toolchain.sh` and
304
- > `ci-install-texlive.sh` are deleted. What follows is the plan as it was written.
305
-
306
- **The hole:** `compile-rules` has `repro/build-submission.sh`, which calls `ensure-toolchain.sh`.
307
- **`agenticdev` has no entry point at all** — it's built by hand with `pdflatex`, and nothing
308
- guarantees the fonts except the CI container. That's how the submitted `aisec` went out wrong.
309
-
310
- **The fix — generalize the existing script to any paper folder**, instead of giving each one its own
311
- Makefile. It decides how to build from the files present: `paper.tex` exists → `pdflatex`;
312
- `paper.md` exists → the jinja2 pipeline. Three Makefiles would drift apart the same way the four
313
- copies of the page limit and the five copies of the package list already have.
314
-
315
- **Don't conflate the layers:**
316
-
317
- ```
318
- packages and fonts exist ← the texlive container or ensure-toolchain.sh (apt)
319
- the compile cycle ← latexmk (not in the toolchain yet, add it)
320
- fail if fonts are missing ← \IfFileExists in paper.tex (done 26.08)
321
- ```
322
-
323
- `latexmk` replaces **only the middle layer** — it does not install fonts.
324
-
325
- **There's then no need to check "does this folder have a Makefile"** — there's one shared entry
326
- point. Nothing to check.
327
-
328
- ## 3. Remove duplicated constants
329
-
330
- | fact | how many copies | where they diverge |
331
- | -------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
332
- | page limit | **4** | `venues/realm.md` 8 · `build-submission.sh` 8 · `PIPELINE-STATUS` "8/8" · the build prints **9** |
333
- | the TeX package list | **5** | `ensure-toolchain.sh` (executable) · `SKILL.md` · `render-paper.harness.mjs` (pins it ✅) · `build-submission.sh` · `PIPELINE-STATUS` |
334
-
335
- The canonical source is the venue preset (`presets/<name>.jsonc`, resolved through its `extends`
336
- chain): its `format` block for the numbers (page size, columns, fonts, font sizes, and `kinds` for
337
- page limits), its `tex` block (plus `tex-base.jsonc`) for packages — since 2026-09-24;
338
- `ensure-toolchain.sh` held them until then — and its `rules` block for the checks the venue
339
- implies. The `.md` card is prose about the venue. Everything else is a pointer.
340
-
341
- ## 3-ter. Drop the font gate from `check-render.sh` once the rules run in CI
342
-
343
- The `pdffonts` block was added to `check-render.sh` on 25.08, and once the judgment moves into rules
344
- it becomes **a second source of truth about the same fonts**. Removing it shrinks the frozen script
345
- rather than extending it, so it does not break the freeze.
346
-
347
- ⚠️ **But not before the rules are actually running in CI.** Today `check-render.sh` is the only
348
- thing in CI that even looks at `agenticdev-2026` (the `build` job only builds papers that have
349
- `repro/build-submission.sh`, and that's one out of five). Removing it before the replacement is in
350
- place means trading a duplicate for a hole.
351
-
352
- ## 3-bis. 🔴 Remove the venue-profile duplicate by GENERATING it, not guarding it with an assert
353
-
354
- The venue numbers live in two places: `<venue>.yaml` (read by the rules) and `<venue>.tex` (read by
355
- LaTeX itself, which can't do YAML). On 26.08 `texMismatch()` inside `check-geometry.mjs` guarded
356
- against the drift — **the script was torn out on 26.08, along with it**, because the whole thing was
357
- rung 5.
358
-
359
- **The assert was the wrong answer from the start.** It guards a duplicate instead of there being no
360
- duplicate. The right form is the same one we arrived at for the PDF facts: **`<venue>.tex` IS
361
- GENERATED from `<venue>.yaml` in the same step that builds the paper**, lives in `_build/`, and
362
- never enters git. Then the drift is unrepresentable, and there's nothing to guard — rung 1, not rung 5.
363
-
364
- ⚠️ The objection "a generated file goes stale silently" **does not apply** here, and the distinction
365
- matters: what goes stale is a file that's committed and regenerated only occasionally. This one
366
- regenerates on every build, like the PDF facts do. Silent staleness requires that someone be able to
367
- read the OLD copy — and there is nowhere to get one.
368
-
369
- **Until this is done, NOBODY guards the duplicate.** Recorded deliberately: the cost is a mismatch
370
- between the preamble guards and the rules; the odds are low — profile edits happen about once per
371
- venue.
372
-
373
- ## 4. Tools: what's been checked and decided
374
-
375
- | | verdict |
376
- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
377
- | **`eslint-plugin-project-structure`** | **can do** conditional "if A then B" (`enforceExistence`, via a real `fs.existsSync`), and it ships a dummy parser + `files: ["**"]`, so it sees folders with not a single JS file. **But there's no OR semantics** — "Makefile OR justfile" is not expressible. We don't need it after item 2; a candidate for other structural rules |
378
- | **`steiger`** | ❌ dropped — its own README says _"not extendable with more rules"_, plus it's about FSD in JS |
379
- | **an ESLint config inside a paper folder** | ❌ **doesn't work in this repository**: there are **233** configs here, **2** of them ours — the other 231 sit inside `compile-rules-2026/repro/` (other people's repos, pulled in). A nested lookup would pick up every one of them, which is exactly why we run with `--no-config-lookup`. The same result comes from a `files: ["<papers-root>/<paper>/**"]` section in the root config |
380
- | **`banal`** | ✅ adopted — fetched by `paperlint toolchain` at a pinned HotCRP commit (GPL; not vendored into paperlint), run on pdf.js-written XML by `paperlint build` and `extract-pdf-facts.mjs` (measurement only; the ESLint rules do the judging) |
381
- | **`latexmk`** | superseded: `paperlint build` runs its own loop (`src/latex-loop.ts`) |
@@ -1,270 +0,0 @@
1
- {
2
- "version": 1,
3
- "recordedAt": "2026-08-07T01:07:09.341Z",
4
- "reports": {
5
- "pipeline-firing": {
6
- "name": "pipeline-firing",
7
- "trials": 1,
8
- "arms": {
9
- "tighten-paper": {
10
- "runs": 8,
11
- "metrics": {
12
- "recall": 0.75,
13
- "falsePositiveRate": 0
14
- },
15
- "stats": {
16
- "recall": {
17
- "mean": 0.75,
18
- "std": 0.5,
19
- "se": 0.25,
20
- "n": 4,
21
- "passK": 0
22
- },
23
- "falsePositiveRate": {
24
- "mean": 0,
25
- "std": 0,
26
- "se": 0,
27
- "n": 4,
28
- "passK": 0
29
- }
30
- },
31
- "usage": {
32
- "totalCostUsd": 0.9953834000000001,
33
- "meanCostUsd": 0.12442292500000002,
34
- "meanDurationMs": 10830.5,
35
- "totalInputTokens": 36,
36
- "totalOutputTokens": 3983,
37
- "totalCacheCreationTokens": 119008,
38
- "totalCacheReadTokens": 721678
39
- }
40
- },
41
- "grade-paper-writing": {
42
- "runs": 8,
43
- "metrics": {
44
- "recall": 0.5,
45
- "falsePositiveRate": 0
46
- },
47
- "stats": {
48
- "recall": {
49
- "mean": 0.5,
50
- "std": 0.5773502691896257,
51
- "se": 0.28867513459481287,
52
- "n": 4,
53
- "passK": 0
54
- },
55
- "falsePositiveRate": {
56
- "mean": 0,
57
- "std": 0,
58
- "se": 0,
59
- "n": 4,
60
- "passK": 0
61
- }
62
- },
63
- "usage": {
64
- "totalCostUsd": 1.0452466,
65
- "meanCostUsd": 0.130655825,
66
- "meanDurationMs": 13598.25,
67
- "totalInputTokens": 38,
68
- "totalOutputTokens": 5884,
69
- "totalCacheCreationTokens": 120445,
70
- "totalCacheReadTokens": 763892
71
- }
72
- },
73
- "argument-arc": {
74
- "runs": 8,
75
- "metrics": {
76
- "recall": 0.75,
77
- "falsePositiveRate": 0
78
- },
79
- "stats": {
80
- "recall": {
81
- "mean": 0.75,
82
- "std": 0.5,
83
- "se": 0.25,
84
- "n": 4,
85
- "passK": 0
86
- },
87
- "falsePositiveRate": {
88
- "mean": 0,
89
- "std": 0,
90
- "se": 0,
91
- "n": 4,
92
- "passK": 0
93
- }
94
- },
95
- "usage": {
96
- "totalCostUsd": 1.062707,
97
- "meanCostUsd": 0.132838375,
98
- "meanDurationMs": 11936.25,
99
- "totalInputTokens": 43,
100
- "totalOutputTokens": 4402,
101
- "totalCacheCreationTokens": 120427,
102
- "totalCacheReadTokens": 896590
103
- }
104
- },
105
- "paper-adversarial-review": {
106
- "runs": 8,
107
- "metrics": {
108
- "recall": 0.75,
109
- "falsePositiveRate": 0
110
- },
111
- "stats": {
112
- "recall": {
113
- "mean": 0.75,
114
- "std": 0.5,
115
- "se": 0.25,
116
- "n": 4,
117
- "passK": 0
118
- },
119
- "falsePositiveRate": {
120
- "mean": 0,
121
- "std": 0,
122
- "se": 0,
123
- "n": 4,
124
- "passK": 0
125
- }
126
- },
127
- "usage": {
128
- "totalCostUsd": 1.3513067,
129
- "meanCostUsd": 0.1689133375,
130
- "meanDurationMs": 21940.125,
131
- "totalInputTokens": 68,
132
- "totalOutputTokens": 10272,
133
- "totalCacheCreationTokens": 126522,
134
- "totalCacheReadTokens": 1442859
135
- }
136
- },
137
- "pc-panel-review": {
138
- "runs": 8,
139
- "metrics": {
140
- "recall": 0.75,
141
- "falsePositiveRate": 0
142
- },
143
- "stats": {
144
- "recall": {
145
- "mean": 0.75,
146
- "std": 0.5,
147
- "se": 0.25,
148
- "n": 4,
149
- "passK": 0
150
- },
151
- "falsePositiveRate": {
152
- "mean": 0,
153
- "std": 0,
154
- "se": 0,
155
- "n": 4,
156
- "passK": 0
157
- }
158
- },
159
- "usage": {
160
- "totalCostUsd": 1.4467628,
161
- "meanCostUsd": 0.18084535,
162
- "meanDurationMs": 26701,
163
- "totalInputTokens": 642,
164
- "totalOutputTokens": 12323,
165
- "totalCacheCreationTokens": 128442,
166
- "totalCacheReadTokens": 1614556
167
- }
168
- },
169
- "cold-read-diff": {
170
- "runs": 8,
171
- "metrics": {
172
- "recall": 0.5,
173
- "falsePositiveRate": 0
174
- },
175
- "stats": {
176
- "recall": {
177
- "mean": 0.5,
178
- "std": 0.5773502691896257,
179
- "se": 0.28867513459481287,
180
- "n": 4,
181
- "passK": 0
182
- },
183
- "falsePositiveRate": {
184
- "mean": 0,
185
- "std": 0,
186
- "se": 0,
187
- "n": 4,
188
- "passK": 0
189
- }
190
- },
191
- "usage": {
192
- "totalCostUsd": 1.1799009,
193
- "meanCostUsd": 0.1474876125,
194
- "meanDurationMs": 16845.875,
195
- "totalInputTokens": 53,
196
- "totalOutputTokens": 7500,
197
- "totalCacheCreationTokens": 123048,
198
- "totalCacheReadTokens": 1079763
199
- }
200
- },
201
- "verify-citations": {
202
- "runs": 8,
203
- "metrics": {
204
- "recall": 1,
205
- "falsePositiveRate": 0
206
- },
207
- "stats": {
208
- "recall": {
209
- "mean": 1,
210
- "std": 0,
211
- "se": 0,
212
- "n": 4,
213
- "passK": 1
214
- },
215
- "falsePositiveRate": {
216
- "mean": 0,
217
- "std": 0,
218
- "se": 0,
219
- "n": 4,
220
- "passK": 0
221
- }
222
- },
223
- "usage": {
224
- "totalCostUsd": 1.2063428999999999,
225
- "meanCostUsd": 0.15079286249999999,
226
- "meanDurationMs": 17178.25,
227
- "totalInputTokens": 52,
228
- "totalOutputTokens": 7682,
229
- "totalCacheCreationTokens": 124837,
230
- "totalCacheReadTokens": 1123033
231
- }
232
- },
233
- "map-prior-work": {
234
- "runs": 8,
235
- "metrics": {
236
- "recall": 0.75,
237
- "falsePositiveRate": 0
238
- },
239
- "stats": {
240
- "recall": {
241
- "mean": 0.75,
242
- "std": 0.5,
243
- "se": 0.25,
244
- "n": 4,
245
- "passK": 0
246
- },
247
- "falsePositiveRate": {
248
- "mean": 0,
249
- "std": 0,
250
- "se": 0,
251
- "n": 4,
252
- "passK": 0
253
- }
254
- },
255
- "usage": {
256
- "totalCostUsd": 1.2584402000000001,
257
- "meanCostUsd": 0.15730502500000001,
258
- "meanDurationMs": 19536.25,
259
- "totalInputTokens": 55,
260
- "totalOutputTokens": 9461,
261
- "totalCacheCreationTokens": 126289,
262
- "totalCacheReadTokens": 1178704
263
- }
264
- }
265
- },
266
- "totalCostUsd": 9.5460905,
267
- "aborted": false
268
- }
269
- }
270
- }