paperlint 5.0.0 → 6.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 (147) hide show
  1. package/CLAUDE.md +13 -0
  2. package/CONTRIBUTING.md +3 -0
  3. package/README.md +8 -8
  4. package/bin/paperlint.mjs +5 -1
  5. package/dist/adapters/latex/index.d.ts +1 -0
  6. package/dist/adapters/latex/index.d.ts.map +1 -1
  7. package/dist/adapters/latex/index.js +3 -0
  8. package/dist/adapters/latex/index.js.map +1 -1
  9. package/dist/adapters/latex/layout.d.ts +27 -0
  10. package/dist/adapters/latex/layout.d.ts.map +1 -0
  11. package/dist/adapters/latex/layout.js +62 -0
  12. package/dist/adapters/latex/layout.js.map +1 -0
  13. package/dist/adapters/latex/nodes.d.ts.map +1 -1
  14. package/dist/adapters/latex/nodes.js +11 -1
  15. package/dist/adapters/latex/nodes.js.map +1 -1
  16. package/dist/adapters/latex/parse.d.ts.map +1 -1
  17. package/dist/adapters/latex/parse.js +5 -1
  18. package/dist/adapters/latex/parse.js.map +1 -1
  19. package/dist/cli.d.ts.map +1 -1
  20. package/dist/cli.js +25 -5
  21. package/dist/cli.js.map +1 -1
  22. package/dist/domain/anonymity.d.ts +68 -0
  23. package/dist/domain/anonymity.d.ts.map +1 -0
  24. package/dist/domain/anonymity.js +94 -0
  25. package/dist/domain/anonymity.js.map +1 -0
  26. package/dist/domain/body-pages.d.ts +69 -0
  27. package/dist/domain/body-pages.d.ts.map +1 -0
  28. package/dist/domain/body-pages.js +141 -0
  29. package/dist/domain/body-pages.js.map +1 -0
  30. package/dist/domain/tex-document.d.ts +9 -0
  31. package/dist/domain/tex-document.d.ts.map +1 -1
  32. package/dist/eslint-rules/pdf-last-page-balance.d.ts +1 -1
  33. package/dist/eslint-rules/pdf-last-page-balance.js +2 -2
  34. package/dist/facts-file.d.ts +28 -2
  35. package/dist/facts-file.d.ts.map +1 -1
  36. package/dist/facts-file.js +54 -9
  37. package/dist/facts-file.js.map +1 -1
  38. package/dist/lib/paper-config.d.ts.map +1 -1
  39. package/dist/lib/paper-config.js +2 -1
  40. package/dist/lib/paper-config.js.map +1 -1
  41. package/dist/paper-settings.d.ts +11 -0
  42. package/dist/paper-settings.d.ts.map +1 -1
  43. package/dist/paper-settings.js +38 -4
  44. package/dist/paper-settings.js.map +1 -1
  45. package/dist/pdf-content.d.ts +40 -0
  46. package/dist/pdf-content.d.ts.map +1 -0
  47. package/dist/pdf-content.js +97 -0
  48. package/dist/pdf-content.js.map +1 -0
  49. package/dist/pdf-facts.d.ts +30 -0
  50. package/dist/pdf-facts.d.ts.map +1 -1
  51. package/dist/pdf-facts.js +37 -1
  52. package/dist/pdf-facts.js.map +1 -1
  53. package/dist/ports/latex.d.ts +3 -1
  54. package/dist/ports/latex.d.ts.map +1 -1
  55. package/dist/presets.d.ts +2 -0
  56. package/dist/presets.d.ts.map +1 -1
  57. package/dist/presets.js +4 -0
  58. package/dist/presets.js.map +1 -1
  59. package/dist/tex-requirements.d.ts +4 -0
  60. package/dist/tex-requirements.d.ts.map +1 -1
  61. package/dist/tex-requirements.js +3 -0
  62. package/dist/tex-requirements.js.map +1 -1
  63. package/dist/tex-venue-rules.d.ts +7 -1
  64. package/dist/tex-venue-rules.d.ts.map +1 -1
  65. package/dist/tex-venue-rules.js +40 -0
  66. package/dist/tex-venue-rules.js.map +1 -1
  67. package/dist/types.d.ts +2 -0
  68. package/dist/types.d.ts.map +1 -1
  69. package/dist/venue-rules.d.ts +38 -8
  70. package/dist/venue-rules.d.ts.map +1 -1
  71. package/dist/venue-rules.js +179 -41
  72. package/dist/venue-rules.js.map +1 -1
  73. package/docs/configuration.md +18 -16
  74. package/docs/e2e.md +32 -11
  75. package/docs/rules/anonymity/identity.md +111 -0
  76. package/docs/rules/format/layout-override.md +61 -0
  77. package/docs/rules/format/page-limit.md +108 -0
  78. package/docs/rules/pdf/body-size.md +87 -0
  79. package/docs/rules.md +44 -39
  80. package/eslint-rules/pdf-last-page-balance.harness.mjs +6 -1
  81. package/eslint-rules/pdf-last-page-balance.ts +2 -2
  82. package/fixtures/build-e2e/aidc/expect.json +1 -1
  83. package/fixtures/build-e2e/aidc/paperlint.json +1 -1
  84. package/fixtures/build-e2e/anon-ack/PIPELINE-STATUS.md +3 -0
  85. package/fixtures/build-e2e/anon-ack/expect.json +19 -0
  86. package/fixtures/build-e2e/anon-ack/paper.tex +31 -0
  87. package/fixtures/build-e2e/anon-ack/paperlint.json +1 -0
  88. package/fixtures/build-e2e/anon-author/PIPELINE-STATUS.md +3 -0
  89. package/fixtures/build-e2e/anon-author/expect.json +19 -0
  90. package/fixtures/build-e2e/anon-author/paper.tex +29 -0
  91. package/fixtures/build-e2e/anon-author/paperlint.json +1 -0
  92. package/fixtures/build-e2e/anon-bib/PIPELINE-STATUS.md +3 -0
  93. package/fixtures/build-e2e/anon-bib/expect.json +20 -0
  94. package/fixtures/build-e2e/anon-bib/paper.tex +35 -0
  95. package/fixtures/build-e2e/anon-bib/paperlint.json +1 -0
  96. package/fixtures/build-e2e/anon-href/PIPELINE-STATUS.md +3 -0
  97. package/fixtures/build-e2e/anon-href/expect.json +19 -0
  98. package/fixtures/build-e2e/anon-href/paper.tex +30 -0
  99. package/fixtures/build-e2e/anon-href/paperlint.json +1 -0
  100. package/fixtures/build-e2e/anon-macro/PIPELINE-STATUS.md +3 -0
  101. package/fixtures/build-e2e/anon-macro/expect.json +19 -0
  102. package/fixtures/build-e2e/anon-macro/paper.tex +30 -0
  103. package/fixtures/build-e2e/anon-macro/paperlint.json +1 -0
  104. package/fixtures/build-e2e/anon-pdfauthor/PIPELINE-STATUS.md +3 -0
  105. package/fixtures/build-e2e/anon-pdfauthor/expect.json +19 -0
  106. package/fixtures/build-e2e/anon-pdfauthor/paper.tex +31 -0
  107. package/fixtures/build-e2e/anon-pdfauthor/paperlint.json +1 -0
  108. package/fixtures/build-e2e/unbalanced/expect.json +2 -2
  109. package/lib/paper-config.ts +3 -1
  110. package/package.json +1 -1
  111. package/presets/acm-sigconf.jsonc +3 -1
  112. package/presets/aidc.jsonc +16 -17
  113. package/presets/ieee-conference.jsonc +8 -0
  114. package/presets/venue-profile.schema.json +9 -0
  115. package/skills/render-paper/extract-pdf-facts.harness.ts +3 -3
  116. package/src/adapters/latex/index.ts +3 -0
  117. package/src/adapters/latex/layout.ts +106 -0
  118. package/src/adapters/latex/nodes.ts +11 -3
  119. package/src/adapters/latex/parse.ts +5 -1
  120. package/src/build.harness.mjs +2 -2
  121. package/src/build.test.ts +5 -0
  122. package/src/cli.test.ts +13 -0
  123. package/src/cli.ts +36 -4
  124. package/src/domain/anonymity.test.ts +163 -0
  125. package/src/domain/anonymity.ts +129 -0
  126. package/src/domain/body-pages.test.ts +300 -0
  127. package/src/domain/body-pages.ts +223 -0
  128. package/src/domain/tex-document.ts +10 -0
  129. package/src/facts-file.test.ts +100 -4
  130. package/src/facts-file.ts +91 -9
  131. package/src/new-paper.test.ts +7 -1
  132. package/src/paper-settings.test.ts +63 -6
  133. package/src/paper-settings.ts +53 -5
  134. package/src/pdf-content.test.ts +71 -0
  135. package/src/pdf-content.ts +125 -0
  136. package/src/pdf-facts.test.ts +110 -2
  137. package/src/pdf-facts.ts +106 -8
  138. package/src/ports/latex.ts +3 -0
  139. package/src/presets.ts +8 -8
  140. package/src/rule-cases.test.ts +29 -3
  141. package/src/rule-docs.test.ts +0 -2
  142. package/src/tex-requirements.ts +9 -0
  143. package/src/tex-venue-rules.test.ts +110 -5
  144. package/src/tex-venue-rules.ts +57 -2
  145. package/src/types.ts +2 -0
  146. package/src/venue-rules.test.ts +351 -39
  147. package/src/venue-rules.ts +247 -47
package/docs/rules.md CHANGED
@@ -3,34 +3,36 @@
3
3
  The README lists what each check catches in one line. This page says exactly which file each one
4
4
  reads and when it fails. Errors fail `paperlint lint`; warnings print and do not.
5
5
 
6
- | Rule | Level | Reads | Fails when |
7
- | ------------------------------------------------------- | ----- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
- | `paper/stages` | error | `PIPELINE-STATUS.md` | a declared stage's PDF is missing, or the `bytes:` it names does not match the file's real size, or a frozen PDF exists that no stage declares |
9
- | `paper/source` | error | `PIPELINE-STATUS.md` | a declared stage has no frozen `.tex` beside its PDF (a commit hash does not count — squash and gc destroy it) |
10
- | `paper/author-list` | error | `paper.tex` → `_build/references.json` | an entry's authors are not those of the version it cites — typically the arXiv preprint's list under a published venue. Checked online by `paperlint build` (DBLP), reported on the entry's own line |
11
- | `paper/section-word` | warn | `paper.tex` and its body files, `paper.md` | `§` or `\S\ref` instead of the word Section. **Fixable:** `--fix` writes `Section~\ref{…}` / `Section 5` |
12
- | `paper/leading-zero` | warn | `paper.tex` and its body files, `paper.md` | a decimal below 1 without its leading zero (`.05` instead of `0.05`, IEEE / ISO 80000-1 style), counted only where the reader sees it — prose, math and table cells, not macro options, column specs, comments, code or tikz. A number right after `¶` or `§` (`¶¶.42`) is a paragraph designator and is not reported; in a paragraph that cites numbers that way, another bare decimal is reported without a fix, with the zero as a suggestion. **Fixable** |
13
- | `paper/figure-ref-style` | warn | `paper.tex` and its body files | `Fig.~\ref` and `Figure~\ref` mixed in one document; each minority occurrence is reported. **Fixable:** `--fix` writes the majority form |
14
- | `bib/reachable-entry` | warn | `paper.tex` (its `filecontents` bibliography) | an entry has no doi, url or arXiv id — a reader has nothing to follow. Reported on the entry; no fix, the link has to be looked up |
15
- | `paper/cite-exists` | error | `paper.tex` → `_build/references.json` | an entry's doi or arXiv id resolves to nothing, or to a different work. Checked online by `paperlint build`; a work that was merely not found is not a finding |
16
- | `paper/refs-fresh` | error | `paper.tex` → `_build/references.json` | the bibliography changed since the build checked it (its SHA-256 differs) — run `npx paperlint build` |
17
- | `paper/refs-checked` | warn | `paper.tex` → `_build/references.json` | the paper has a bibliography and no build has checked it, or the last build could not (no network) — so the two rules above did not run |
18
- | `tex/future-promise` | warn | `paper.tex` and its body files | a camera-ready build still says "will be released" about something already handed over |
19
- | `tex/acm-frontmatter-override` | error | `paper.tex` | an `acmart` build overrides ACM's front-matter commands and drops template elements from page 1 |
20
- | [`tex/template`](rules/tex/template.md) | error | `paper.tex` → `paperlint.json` | the `\documentclass` is not the preset's `template` class, or lacks an option it names — [page](rules/tex/template.md) |
21
- | [`tex/required-section`](rules/tex/required-section.md) | error | `paper.tex` → `paperlint.json` | a section the preset requires (AIDC: «LLM Usage Statement», last) is missing or not where it must be — [page](rules/tex/required-section.md) |
22
- | [`tex/venue-leftover`](rules/tex/venue-leftover.md) | warn | `paper.tex` → `paperlint.json` | the text names another shipped venue than the one the paper extends («Submission to VenueA 2026» in a paper now set for VenueB) — [page](rules/tex/venue-leftover.md) |
23
- | [`tex/claim-provenance`](rules/tex/claim-provenance.md) | warn | `paper.tex` | a sentence of the body states a number and does not say whose it is — no citation or link, no _we_/_our_, no `\ref` or "Table 2", no sample ("n = 134", "48 runs") — [page](rules/tex/claim-provenance.md) |
24
- | [`tex/register`](rules/tex/register.md) | warn | `paper.tex` and the files it includes | the body runs to a post's register: more than 0.8 sentences per 1000 words open with _And_, _So_, _But_, _Nor_, _Or_ or _Yet_ — the limit is an option — [page](rules/tex/register.md) |
25
- | `review/frontmatter` | error | `reviews/*.md` | the review's frontmatter fails paperlint's JSON Schema — a `findings` record without `id`/`status`, an unknown field, or an **open** finding with no `cause` (`skill-defect` · `missing-skill` · `hook` · `rule`). A review with no `findings` key is not checked for findings |
26
- | `sibling/frontmatter` | warn | `siblings/*.md` (not `README.md`) | a sibling card's frontmatter has no `read:` saying how much of the competing paper was read (`full` · `abstract` · `none`) |
27
- | `pdf/fresh` | error | `paper.tex` → `_build/paper.facts.json` | the paper names a venue and the facts cannot be judged: not JSON, a schema other than 2, or they describe a PDF that is gone or differs from the one on disk (its SHA-256) |
28
- | `pdf/profile` | error | `paper.tex` → `paperlint.json` | `paperlint.json` is not JSON or has an unknown key, its `extends` does not resolve (not found, a cycle, a chain longer than four, a preset that fails the schema, an npm name), it names no `kind` while the preset has kinds, or names a kind the preset does not have |
29
- | `pdf/fonts` | error | `paper.tex` → `_build/paper.facts.json` | a font the pages draw is Type 3 or not embedded, or no font starts with the family the venue preset names for body text (`fonts_text`) or headings (`fonts_title`) |
30
- | `pdf/geometry` | error | `paper.tex` → `_build/paper.facts.json` | the page width or height is more than `dimTol` (default 0.05 in) off the preset's, or the column count differs |
31
- | `pdf/limits` | error | `paper.tex` → `_build/paper.facts.json` | body or reference pages exceed the limit of the paper's kind, or the reference font size is outside the preset's range widened by `body_pt_tol` |
32
- | `pdf/body-size` | warn | `paper.tex` → `_build/paper.facts.json` | the body font size is more than `body_pt_tol` off the preset's. A warning: banal measures the mode of the rendered text, not the declared size (9.30 pt measured at a declared 9) |
33
- | `pdf/measured` | warn | `paper.tex` → `_build/paper.facts.json` | the paper's `paperlint.json` names no venue preset yet; or it names one and there are no facts (it was not built), or the facts carry no page geometry (banal was not found) — so the checks above did not run |
6
+ | Rule | Level | Reads | Fails when |
7
+ | ----------------------------------------------------------- | ----- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
8
+ | `paper/stages` | error | `PIPELINE-STATUS.md` | a declared stage's PDF is missing, or the `bytes:` it names does not match the file's real size, or a frozen PDF exists that no stage declares |
9
+ | `paper/source` | error | `PIPELINE-STATUS.md` | a declared stage has no frozen `.tex` beside its PDF (a commit hash does not count — squash and gc destroy it) |
10
+ | `paper/author-list` | error | `paper.tex` → `_build/references.json` | an entry's authors are not those of the version it cites — typically the arXiv preprint's list under a published venue. Checked online by `paperlint build` (DBLP), reported on the entry's own line |
11
+ | `paper/section-word` | warn | `paper.tex` and its body files, `paper.md` | `§` or `\S\ref` instead of the word Section. **Fixable:** `--fix` writes `Section~\ref{…}` / `Section 5` |
12
+ | `paper/leading-zero` | warn | `paper.tex` and its body files, `paper.md` | a decimal below 1 without its leading zero (`.05` instead of `0.05`, IEEE / ISO 80000-1 style), counted only where the reader sees it — prose, math and table cells, not macro options, column specs, comments, code or tikz. A number right after `¶` or `§` (`¶¶.42`) is a paragraph designator and is not reported; in a paragraph that cites numbers that way, another bare decimal is reported without a fix, with the zero as a suggestion. **Fixable** |
13
+ | `paper/figure-ref-style` | warn | `paper.tex` and its body files | `Fig.~\ref` and `Figure~\ref` mixed in one document; each minority occurrence is reported. **Fixable:** `--fix` writes the majority form |
14
+ | `bib/reachable-entry` | warn | `paper.tex` (its `filecontents` bibliography) | an entry has no doi, url or arXiv id — a reader has nothing to follow. Reported on the entry; no fix, the link has to be looked up |
15
+ | `paper/cite-exists` | error | `paper.tex` → `_build/references.json` | an entry's doi or arXiv id resolves to nothing, or to a different work. Checked online by `paperlint build`; a work that was merely not found is not a finding |
16
+ | `paper/refs-fresh` | error | `paper.tex` → `_build/references.json` | the bibliography changed since the build checked it (its SHA-256 differs) — run `npx paperlint build` |
17
+ | `paper/refs-checked` | warn | `paper.tex` → `_build/references.json` | the paper has a bibliography and no build has checked it, or the last build could not (no network) — so the two rules above did not run |
18
+ | `tex/future-promise` | warn | `paper.tex` and its body files | a camera-ready build still says "will be released" about something already handed over |
19
+ | `tex/acm-frontmatter-override` | error | `paper.tex` | an `acmart` build overrides ACM's front-matter commands and drops template elements from page 1 |
20
+ | [`tex/template`](rules/tex/template.md) | error | `paper.tex` → `paperlint.json` | the `\documentclass` is not the preset's `template` class, or lacks an option it names — [page](rules/tex/template.md) |
21
+ | [`tex/required-section`](rules/tex/required-section.md) | error | `paper.tex` → `paperlint.json` | a section the preset requires (AIDC: «LLM Usage Statement», last) is missing or not where it must be — [page](rules/tex/required-section.md) |
22
+ | [`format/layout-override`](rules/format/layout-override.md) | error | `paper.tex` → `paperlint.json` | the source changes the page layout the venue's template sets for the whole document — `geometry`, a layout `\setlength`, `\linespread`, `\baselinestretch` — [page](rules/format/layout-override.md) |
23
+ | [`anonymity/identity`](rules/anonymity/identity.md) | error | `paper.tex` → `_build/paper.facts.json` | a double-blind venue (`"blind": true`) and no `identity` declared, or a declared name, handle, email or project in the PDF's text, metadata or link targets — [page](rules/anonymity/identity.md) |
24
+ | [`tex/venue-leftover`](rules/tex/venue-leftover.md) | warn | `paper.tex` → `paperlint.json` | the text names another shipped venue than the one the paper extends («Submission to VenueA 2026» in a paper now set for VenueB) — [page](rules/tex/venue-leftover.md) |
25
+ | [`tex/claim-provenance`](rules/tex/claim-provenance.md) | warn | `paper.tex` | a sentence of the body states a number and does not say whose it is — no citation or link, no _we_/_our_, no `\ref` or "Table 2", no sample ("n = 134", "48 runs") — [page](rules/tex/claim-provenance.md) |
26
+ | [`tex/register`](rules/tex/register.md) | warn | `paper.tex` and the files it includes | the body runs to a post's register: more than 0.8 sentences per 1000 words open with _And_, _So_, _But_, _Nor_, _Or_ or _Yet_ — the limit is an option — [page](rules/tex/register.md) |
27
+ | `review/frontmatter` | error | `reviews/*.md` | the review's frontmatter fails paperlint's JSON Schema — a `findings` record without `id`/`status`, an unknown field, or an **open** finding with no `cause` (`skill-defect` · `missing-skill` · `hook` · `rule`). A review with no `findings` key is not checked for findings |
28
+ | `sibling/frontmatter` | warn | `siblings/*.md` (not `README.md`) | a sibling card's frontmatter has no `read:` saying how much of the competing paper was read (`full` · `abstract` · `none`) |
29
+ | `pdf/fresh` | error | `paper.tex` → `_build/paper.facts.json` | the paper names a venue and the facts cannot be judged: not JSON, a schema other than 3, or they describe a PDF that is gone or differs from the one on disk (its SHA-256) |
30
+ | `pdf/profile` | error | `paper.tex` → `paperlint.json` | `paperlint.json` is not JSON or has an unknown key, its `extends` does not resolve (not found, a cycle, a chain longer than four, a preset that fails the schema, an npm name), it names no `kind` while the preset has kinds, or names a kind the preset does not have |
31
+ | `pdf/fonts` | error | `paper.tex` → `_build/paper.facts.json` | a font the pages draw is Type 3 or not embedded, or no font starts with the family the venue preset names for body text (`fonts_text`) or headings (`fonts_title`) |
32
+ | `pdf/geometry` | error | `paper.tex` → `_build/paper.facts.json` | the page width or height is more than `dimTol` (default 0.05 in) off the preset's, or the column count differs |
33
+ | [`format/page-limit`](rules/format/page-limit.md) | error | `paper.tex` → `_build/paper.facts.json` | body or reference pages exceed the limits of the paper's kind. With `body_ends_at: "references"` (AIDC) the body ends at the references or the appendix, whichever comes first — found by hyperref's anchors, then the heading line — and the page it ends on counts when body text stands above the heading; an end it cannot find, or signals that disagree, are reported — [page](rules/format/page-limit.md) |
34
+ | [`pdf/body-size`](rules/pdf/body-size.md) | error | `paper.tex` → `_build/paper.facts.json` | the body font size is more than `body_pt_tol` off the preset's, or the reference font size is outside the preset's range widened by `body_pt_tol`. banal reads 0.3 pt above the size the glyphs are set in; checked on five built accepted papers (none reported) and three variants one size off (each reported) — [page](rules/pdf/body-size.md) |
35
+ | `pdf/measured` | warn | `paper.tex` → `_build/paper.facts.json` | the paper's `paperlint.json` names no venue preset yet; or it names one and there are no facts (it was not built), or the facts carry no page geometry (banal was not found) — so the checks above did not run |
34
36
 
35
37
  **Body files** are the files `paper.tex` includes from its document body (`\input`, `\include`,
36
38
  `\subfile`, nested ones too), found in the paper's directory — not a preamble include, not a file
@@ -94,14 +96,14 @@ for papers, each with the quote it came from, the TeX packages its template need
94
96
  the venue implies. A preset may itself extend another: the ACM venues extend the `acm-sigconf`
95
97
  family, which holds everything the ACM template decides.
96
98
 
97
- | preset | extends | template | kinds | page limit checked | rules it turns on |
98
- | --------------------------- | --------------------------- | ------------------------------------- | -------------------------------------------------------- | ------------------ | ----------------------- |
99
- | `paperlint:acm-sigconf` | — | ACM `acmart` sigconf | none | no (no kinds) | — |
100
- | `paperlint:agenticdev` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `short` (5 + 2 refs), `full` (10 + 2), `demo` (5 + 2) | yes | `pdf/last-page-balance` |
101
- | `paperlint:aisec` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `research`, `benchmark`, `position`, `sok` (10 + 2 each) | yes | — |
102
- | `paperlint:realm` | — | ACL | `long`, `short` | no — see below | — |
103
- | `paperlint:ieee-conference` | — | IEEE `IEEEtran` conference | none | no (no kinds) | — |
104
- | `paperlint:aidc` | `paperlint:ieee-conference` | IEEE `IEEEtran` conference, `compsoc` | `regular` (12), `short` (6) | no — see below | — |
99
+ | preset | extends | template | kinds | page limit checked | rules it turns on |
100
+ | --------------------------- | --------------------------- | ------------------------------------- | -------------------------------------------------------- | -------------------------------------- | ----------------------- |
101
+ | `paperlint:acm-sigconf` | — | ACM `acmart` sigconf | none | no (no kinds) | — |
102
+ | `paperlint:agenticdev` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `short` (5 + 2 refs), `full` (10 + 2), `demo` (5 + 2) | yes | `pdf/last-page-balance` |
103
+ | `paperlint:aisec` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `research`, `benchmark`, `position`, `sok` (10 + 2 each) | yes | — |
104
+ | `paperlint:realm` | — | ACL | `long`, `short` | no — see below | — |
105
+ | `paperlint:ieee-conference` | — | IEEE `IEEEtran` conference | none | no (no kinds) | — |
106
+ | `paperlint:aidc` | `paperlint:ieee-conference` | IEEE `IEEEtran` conference, `compsoc` | `regular` (12), `short` (6) | yes, before the references — see below | — (`blind`) |
105
107
 
106
108
  That is all that ships today. There is no NeurIPS, USENIX or Springer preset. A paper for an ACM or
107
109
  IEEE conference venue nobody has profiled can extend `paperlint:acm-sigconf` or
@@ -109,9 +111,11 @@ IEEE conference venue nobody has profiled can extend `paperlint:acm-sigconf` or
109
111
  says the page limit is not. For anything else, write your own preset
110
112
  ([below](#writing-your-own-venue-preset)). REALM's preset sets no page limit on purpose: banal
111
113
  counts the Limitations and Ethics sections as body, ACL does not, and a limit on banal's number
112
- would fail a correct paper. AIDC's sets none for the same reason, measured: banal counts a page as
113
- body when an appendix or the LLM Usage Statement sits on it before the bibliography, and AIDC counts
114
- neither, so a correct 12-page paper measured 13. AgenticDev's turns on `pdf/last-page-balance`
114
+ would fail a correct paper. AIDC's limit is checked by another count, for the same reason: banal counts
115
+ a page as body when an appendix or the LLM Usage Statement sits on it, and AIDC counts neither, so a
116
+ correct 12-page paper measured 13. Its preset sets `"body_ends_at": "references"`: the body is the
117
+ pages before the one where the references heading first appears. It is also `"blind": true`, which
118
+ turns on [`anonymity/identity`](rules/anonymity/identity.md). AgenticDev's turns on `pdf/last-page-balance`
115
119
  because its proceedings are produced by Conference Publishing Consulting, which sends back an
116
120
  unbalanced last page; AISec's does not, because nothing in hand says who produces the AISec
117
121
  proceedings.
@@ -204,6 +208,7 @@ The numbers and packages above illustrate the shape; take yours from the venue's
204
208
  | `name` | how messages name the venue; the file name otherwise |
205
209
  | `template` | the `\documentclass` the venue's template uses — a whole line (`\documentclass[conference,compsoc]{IEEEtran}`) or a bare class name; `tex/template` requires the paper's class and every option named here |
206
210
  | `aliases` | other names the venue goes by in a paper's text — its acronym, its parent conference: `["AISec", "ACM CCS"]`. Collected along `extends`, with `name`. Read by `tex/venue-leftover` |
211
+ | `blind` | the venue reviews double-blind — set only where its call says so, with the quote. Turns on `anonymity/identity`; a child's value replaces its parent's |
207
212
  | `required_sections` | sections the venue requires, `[{ "title": "LLM Usage Statement", "position": "last" }]`: the exact title, and `last` when it must close the paper. Read by `tex/required-section`; a child's list replaces its parent's |
208
213
  | `format` | page size, columns, fonts, font sizes, and `kinds` (page limits per kind of paper) |
209
214
  | `tex` | TeX Live packages, each with the files that prove it is installed. Required unless `extends` is set |
@@ -39,7 +39,12 @@ const TEX =
39
39
  const PDF = "%PDF-1.5 pretend";
40
40
  const sha = (s) => createHash("sha256").update(s).digest("hex");
41
41
  const facts = (lastPage, over = {}) => ({
42
- schema: 2,
42
+ schema: 3,
43
+ pages_text: [],
44
+ metadata: {},
45
+ links: [],
46
+ bib_anchor_page: null,
47
+ appendix_anchor_page: null,
43
48
  pdf: "paper.pdf",
44
49
  pdf_sha256: sha(PDF),
45
50
  last_page: lastPage,
@@ -91,7 +91,7 @@ const RuleOptions = z
91
91
  /** The difference, in points, that two columns may end apart. See the harness for why 120. */
92
92
  export const DEFAULT_TOLERANCE_PT = 120;
93
93
  /** The schema of `paper.facts.json` this rule reads (`src/facts-file.ts`, FACTS_SCHEMA). */
94
- export const FACTS_SCHEMA = 2;
94
+ export const FACTS_SCHEMA = 3;
95
95
  export const FACTS_REL = join("_build", "paper.facts.json");
96
96
 
97
97
  /** The `last_page` field, parsed. */
@@ -249,7 +249,7 @@ const rule = {
249
249
  factsBroken:
250
250
  "{{why}} in _build/paper.facts.json — rebuild the paper (`paperlint build`) to rewrite it",
251
251
  schema:
252
- "_build/paper.facts.json has schema {{got}}; this rule reads schema 2 — rebuild the paper " +
252
+ "_build/paper.facts.json has schema {{got}}; this rule reads schema 3 — rebuild the paper " +
253
253
  "(`paperlint build`) to rewrite it",
254
254
  pdfMissing:
255
255
  "_build/paper.facts.json describes {{pdf}}, which is not on disk (a failed build removes " +
@@ -1,5 +1,5 @@
1
1
  {
2
- "$comment": "A real IEEEtran [conference,compsoc] paper for AIDC, built on paperlint's TeX Live: IEEE's Times, and not one finding from any rule — which is what judges pdf/limits, pdf/body-size and the rest against a real PDF of the class.",
2
+ "$comment": "A real IEEEtran [conference,compsoc] paper for AIDC, built on paperlint's TeX Live: IEEE's Times, and not one finding from any rule — which is what judges format/page-limit, pdf/body-size and the rest against a real PDF of the class.",
3
3
  "build": {
4
4
  "outcome": "pdf"
5
5
  },
@@ -1 +1 @@
1
- { "extends": "paperlint:aidc", "kind": "short" }
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,19 @@
1
+ {
2
+ "$comment": "anonymity/identity on a real IEEEtran build: B: the name in an acknowledgments paragraph. Exactly one finding, naming where.",
3
+ "build": {
4
+ "outcome": "pdf"
5
+ },
6
+ "lint": {
7
+ "rules": {
8
+ "anonymity/identity": [
9
+ {
10
+ "severity": 2,
11
+ "says": [
12
+ "«Ada Example»",
13
+ "PDF, page"
14
+ ]
15
+ }
16
+ ]
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,31 @@
1
+ % B: the name in an acknowledgments paragraph.
2
+ % The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
3
+ \documentclass[conference,compsoc]{IEEEtran}
4
+ \begin{filecontents*}{refs.bib}
5
+ @article{knuth84,
6
+ title = {Literate Programming},
7
+ author = {Knuth, Donald E.},
8
+ journal = {The Computer Journal},
9
+ volume = {27},
10
+ number = {2},
11
+ pages = {97--111},
12
+ year = {1984},
13
+ doi = {10.1093/comjnl/27.2.97}
14
+ }
15
+ \end{filecontents*}
16
+ \begin{document}
17
+ \title{A Fixture for Double-Blind Review}
18
+ \author{\IEEEauthorblockN{Anonymous Authors}}
19
+ \maketitle
20
+ \section{Introduction}
21
+ This paper builds on earlier work~\cite{knuth84}.
22
+
23
+ \section{Conclusion}
24
+ The conclusion restates that the fixture builds.
25
+ \section*{Acknowledgments}
26
+ We thank Ada Example for comments on a draft.
27
+ \bibliographystyle{IEEEtran}
28
+ \bibliography{refs}
29
+ \section*{LLM Usage Statement}
30
+ No LLMs were used in writing this fixture.
31
+ \end{document}
@@ -0,0 +1 @@
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,19 @@
1
+ {
2
+ "$comment": "anonymity/identity on a real IEEEtran build: A: the name in the author block. Exactly one finding, naming where.",
3
+ "build": {
4
+ "outcome": "pdf"
5
+ },
6
+ "lint": {
7
+ "rules": {
8
+ "anonymity/identity": [
9
+ {
10
+ "severity": 2,
11
+ "says": [
12
+ "«Ada Example»",
13
+ "PDF, page 1"
14
+ ]
15
+ }
16
+ ]
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,29 @@
1
+ % A: the name in the author block.
2
+ % The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
3
+ \documentclass[conference,compsoc]{IEEEtran}
4
+ \begin{filecontents*}{refs.bib}
5
+ @article{knuth84,
6
+ title = {Literate Programming},
7
+ author = {Knuth, Donald E.},
8
+ journal = {The Computer Journal},
9
+ volume = {27},
10
+ number = {2},
11
+ pages = {97--111},
12
+ year = {1984},
13
+ doi = {10.1093/comjnl/27.2.97}
14
+ }
15
+ \end{filecontents*}
16
+ \begin{document}
17
+ \title{A Fixture for Double-Blind Review}
18
+ \author{\IEEEauthorblockN{Ada Example}\IEEEauthorblockA{Anonymous Institution}}
19
+ \maketitle
20
+ \section{Introduction}
21
+ This paper builds on earlier work~\cite{knuth84}.
22
+
23
+ \section{Conclusion}
24
+ The conclusion restates that the fixture builds.
25
+ \bibliographystyle{IEEEtran}
26
+ \bibliography{refs}
27
+ \section*{LLM Usage Statement}
28
+ No LLMs were used in writing this fixture.
29
+ \end{document}
@@ -0,0 +1 @@
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,20 @@
1
+ {
2
+ "$comment": "anonymity/identity on a real IEEEtran build: C: a self-citation: the name only in a .bib author field, printed by IEEEtran.bst as \"A. Example\". Exactly one finding, naming where.",
3
+ "build": {
4
+ "outcome": "pdf"
5
+ },
6
+ "lint": {
7
+ "rules": {
8
+ "anonymity/identity": [
9
+ {
10
+ "severity": 2,
11
+ "says": [
12
+ "«A. Example»",
13
+ "matches «Ada Example»",
14
+ "PDF, page"
15
+ ]
16
+ }
17
+ ]
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,35 @@
1
+ % C: a self-citation: the name only in a .bib author field, printed by IEEEtran.bst as "A. Example".
2
+ % The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
3
+ \documentclass[conference,compsoc]{IEEEtran}
4
+ \begin{filecontents*}{refs.bib}
5
+ @article{knuth84,
6
+ title = {Literate Programming},
7
+ author = {Knuth, Donald E.},
8
+ journal = {The Computer Journal},
9
+ volume = {27},
10
+ number = {2},
11
+ pages = {97--111},
12
+ year = {1984},
13
+ doi = {10.1093/comjnl/27.2.97}
14
+ }
15
+ @misc{example25,
16
+ title = {A Tool for Measuring Things},
17
+ author = {Example, Ada and Other, Bob},
18
+ year = {2025},
19
+ note = {Technical report}
20
+ }
21
+ \end{filecontents*}
22
+ \begin{document}
23
+ \title{A Fixture for Double-Blind Review}
24
+ \author{\IEEEauthorblockN{Anonymous Authors}}
25
+ \maketitle
26
+ \section{Introduction}
27
+ This paper builds on earlier work~\cite{knuth84,example25}.
28
+
29
+ \section{Conclusion}
30
+ The conclusion restates that the fixture builds.
31
+ \bibliographystyle{IEEEtran}
32
+ \bibliography{refs}
33
+ \section*{LLM Usage Statement}
34
+ No LLMs were used in writing this fixture.
35
+ \end{document}
@@ -0,0 +1 @@
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,19 @@
1
+ {
2
+ "$comment": "anonymity/identity on a real IEEEtran build: E: a link whose visible text names nobody and whose target is the author's account. The anonymous mirror beside it is not reported. Exactly one finding, naming where.",
3
+ "build": {
4
+ "outcome": "pdf"
5
+ },
6
+ "lint": {
7
+ "rules": {
8
+ "anonymity/identity": [
9
+ {
10
+ "severity": 2,
11
+ "says": [
12
+ "link target on page 1 (https://github.com/adaexample/tool)",
13
+ "«adaexample»"
14
+ ]
15
+ }
16
+ ]
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,30 @@
1
+ % E: a link whose visible text names nobody and whose target is the author's account. The anonymous mirror beside it is not reported.
2
+ % The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
3
+ \documentclass[conference,compsoc]{IEEEtran}
4
+ \usepackage{hyperref}
5
+ \begin{filecontents*}{refs.bib}
6
+ @article{knuth84,
7
+ title = {Literate Programming},
8
+ author = {Knuth, Donald E.},
9
+ journal = {The Computer Journal},
10
+ volume = {27},
11
+ number = {2},
12
+ pages = {97--111},
13
+ year = {1984},
14
+ doi = {10.1093/comjnl/27.2.97}
15
+ }
16
+ \end{filecontents*}
17
+ \begin{document}
18
+ \title{A Fixture for Double-Blind Review}
19
+ \author{\IEEEauthorblockN{Anonymous Authors}}
20
+ \maketitle
21
+ \section{Introduction}
22
+ This paper builds on earlier work~\cite{knuth84}.
23
+ The code is at \href{https://github.com/adaexample/tool}{the tool's repository}, mirrored anonymously at \href{https://anonymous.4open.science/r/tool-1A2B}{an anonymous mirror}.
24
+ \section{Conclusion}
25
+ The conclusion restates that the fixture builds.
26
+ \bibliographystyle{IEEEtran}
27
+ \bibliography{refs}
28
+ \section*{LLM Usage Statement}
29
+ No LLMs were used in writing this fixture.
30
+ \end{document}
@@ -0,0 +1 @@
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,19 @@
1
+ {
2
+ "$comment": "anonymity/identity on a real IEEEtran build: F: the name hidden behind a macro; only the typeset text shows it. Exactly one finding, naming where.",
3
+ "build": {
4
+ "outcome": "pdf"
5
+ },
6
+ "lint": {
7
+ "rules": {
8
+ "anonymity/identity": [
9
+ {
10
+ "severity": 2,
11
+ "says": [
12
+ "«Ada Example»",
13
+ "PDF, page 1"
14
+ ]
15
+ }
16
+ ]
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,30 @@
1
+ % F: the name hidden behind a macro; only the typeset text shows it.
2
+ % The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
3
+ \documentclass[conference,compsoc]{IEEEtran}
4
+ \newcommand{\me}{Ada Example}
5
+ \begin{filecontents*}{refs.bib}
6
+ @article{knuth84,
7
+ title = {Literate Programming},
8
+ author = {Knuth, Donald E.},
9
+ journal = {The Computer Journal},
10
+ volume = {27},
11
+ number = {2},
12
+ pages = {97--111},
13
+ year = {1984},
14
+ doi = {10.1093/comjnl/27.2.97}
15
+ }
16
+ \end{filecontents*}
17
+ \begin{document}
18
+ \title{A Fixture for Double-Blind Review}
19
+ \author{\IEEEauthorblockN{Anonymous Authors}}
20
+ \maketitle
21
+ \section{Introduction}
22
+ This paper builds on earlier work~\cite{knuth84}.
23
+ This extends a tool first described by \me.
24
+ \section{Conclusion}
25
+ The conclusion restates that the fixture builds.
26
+ \bibliographystyle{IEEEtran}
27
+ \bibliography{refs}
28
+ \section*{LLM Usage Statement}
29
+ No LLMs were used in writing this fixture.
30
+ \end{document}
@@ -0,0 +1 @@
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,19 @@
1
+ {
2
+ "$comment": "anonymity/identity on a real IEEEtran build: D: the name only in the PDF metadata, set by hyperref; no page shows it. Exactly one finding, naming where.",
3
+ "build": {
4
+ "outcome": "pdf"
5
+ },
6
+ "lint": {
7
+ "rules": {
8
+ "anonymity/identity": [
9
+ {
10
+ "severity": 2,
11
+ "says": [
12
+ "PDF metadata: Author",
13
+ "«Ada Example»"
14
+ ]
15
+ }
16
+ ]
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,31 @@
1
+ % D: the name only in the PDF metadata, set by hyperref; no page shows it.
2
+ % The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
3
+ \documentclass[conference,compsoc]{IEEEtran}
4
+ \usepackage{hyperref}
5
+ \hypersetup{pdfauthor={Ada Example}}
6
+ \begin{filecontents*}{refs.bib}
7
+ @article{knuth84,
8
+ title = {Literate Programming},
9
+ author = {Knuth, Donald E.},
10
+ journal = {The Computer Journal},
11
+ volume = {27},
12
+ number = {2},
13
+ pages = {97--111},
14
+ year = {1984},
15
+ doi = {10.1093/comjnl/27.2.97}
16
+ }
17
+ \end{filecontents*}
18
+ \begin{document}
19
+ \title{A Fixture for Double-Blind Review}
20
+ \author{\IEEEauthorblockN{Anonymous Authors}}
21
+ \maketitle
22
+ \section{Introduction}
23
+ This paper builds on earlier work~\cite{knuth84}.
24
+
25
+ \section{Conclusion}
26
+ The conclusion restates that the fixture builds.
27
+ \bibliographystyle{IEEEtran}
28
+ \bibliography{refs}
29
+ \section*{LLM Usage Statement}
30
+ No LLMs were used in writing this fixture.
31
+ \end{document}
@@ -0,0 +1 @@
1
+ {"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
@@ -18,7 +18,7 @@
18
18
  }
19
19
  },
20
20
  "facts": {
21
- "schema": 2,
21
+ "schema": 3,
22
22
  "lastPageColumnsPt": [
23
23
  621.5,
24
24
  264.8
@@ -45,7 +45,7 @@
45
45
  "pdf/profile": [],
46
46
  "pdf/fonts": [],
47
47
  "pdf/geometry": [],
48
- "pdf/limits": [],
48
+ "format/page-limit": [],
49
49
  "pdf/body-size": [],
50
50
  "pdf/measured": [
51
51
  {