paperlint 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +21 -0
- package/README.md +56 -14
- package/dist/build-engine.d.ts.map +1 -1
- package/dist/build-engine.js +5 -2
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +4 -3
- package/dist/build.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +138 -24
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +21 -4
- package/dist/doctor.js.map +1 -1
- package/dist/facts-file.d.ts +33 -9
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +117 -17
- package/dist/facts-file.js.map +1 -1
- package/dist/init.d.ts +11 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +67 -3
- package/dist/init.js.map +1 -1
- package/dist/new-paper.d.ts +2 -2
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +17 -2
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-settings.d.ts +68 -0
- package/dist/paper-settings.d.ts.map +1 -0
- package/dist/paper-settings.js +144 -0
- package/dist/paper-settings.js.map +1 -0
- package/dist/presets.d.ts +84 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +186 -0
- package/dist/presets.js.map +1 -0
- package/dist/rules-config.d.ts +7 -0
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +11 -6
- package/dist/rules-config.js.map +1 -1
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +2 -1
- package/dist/structure.js.map +1 -1
- package/dist/tex-requirements.d.ts +63 -7
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +91 -24
- package/dist/tex-requirements.js.map +1 -1
- package/dist/venue-rules.d.ts +109 -0
- package/dist/venue-rules.d.ts.map +1 -0
- package/dist/venue-rules.js +387 -0
- package/dist/venue-rules.js.map +1 -0
- package/docs/configuration.md +67 -7
- package/docs/optional-rules.md +25 -24
- package/docs/rules.md +131 -2
- package/eslint-rules/papers.mjs +6 -2
- package/eslint-rules/pdf-last-page-balance.mjs +23 -2
- package/fixtures/build-e2e/acmart/paperlint.json +1 -0
- package/lib/paper-config.d.mts +7 -0
- package/lib/paper-config.mjs +31 -0
- package/package.json +1 -1
- package/skills/find-venue/SKILL.md +5 -1
- package/skills/find-venue/SKILL.md.spec.ts +4 -0
- package/skills/paper-pipeline/PIPELINE-MAP.md +14 -4
- package/skills/paper-pipeline/SKILL.md +4 -3
- package/skills/paper-pipeline/SKILL.md.spec.ts +3 -2
- package/skills/render-paper/extract-pdf-facts.harness.mjs +5 -5
- package/skills/render-paper/extract-pdf-facts.mjs +4 -4
- package/skills/study-accepted-papers/SKILL.md +2 -1
- package/skills/study-accepted-papers/SKILL.md.spec.ts +1 -0
- package/skills/submit-paper/SKILL.md +9 -1
- package/skills/submit-paper/SKILL.md.spec.ts +8 -0
- package/skills/submit-paper/references/venues/acm-sigconf.jsonc +86 -0
- package/skills/submit-paper/references/venues/agenticdev.jsonc +34 -102
- package/skills/submit-paper/references/venues/aisec.jsonc +21 -82
- package/skills/submit-paper/references/venues/realm.jsonc +45 -43
- package/skills/submit-paper/references/venues/tex-base.jsonc +1 -1
- package/skills/submit-paper/references/venues/venue-profile.schema.json +119 -29
- package/src/build-engine.ts +10 -2
- package/src/build.harness.mjs +23 -18
- package/src/build.ts +5 -4
- package/src/cli.harness.mjs +4 -2
- package/src/cli.ts +158 -29
- package/src/doctor.ts +28 -3
- package/src/facts-file.test.ts +54 -7
- package/src/facts-file.ts +145 -24
- package/src/init.ts +81 -3
- package/src/new-paper.harness.mjs +9 -6
- package/src/new-paper.test.ts +145 -0
- package/src/new-paper.ts +22 -2
- package/src/paper-settings-commands.test.ts +311 -0
- package/src/paper-settings.test.ts +220 -0
- package/src/paper-settings.ts +206 -0
- package/src/presets.test.ts +236 -0
- package/src/presets.ts +307 -0
- package/src/rules-config.ts +12 -7
- package/src/structure.harness.mjs +3 -3
- package/src/structure.ts +2 -1
- package/src/tex-requirements.harness.mjs +11 -17
- package/src/tex-requirements.ts +179 -29
- package/src/venue-rules.test.ts +545 -0
- package/src/venue-rules.ts +573 -0
- package/templates/paper/paperlint.json +4 -0
- package/fixtures/build-e2e/acmart/venue.json +0 -1
package/docs/rules.md
CHANGED
|
@@ -14,6 +14,13 @@ reads and when it fails. Errors fail `paperlint lint`; warnings print and do not
|
|
|
14
14
|
| `tex/acm-frontmatter-override` | error | `paper.tex` | an `acmart` build overrides ACM's front-matter commands and drops template elements from page 1 |
|
|
15
15
|
| `review/findings-cause` | error | `reviews/*.md` | a review lists at least `minFindings` (default 3) findings and no cell introduces a cause with the marker (default `Cause:`) |
|
|
16
16
|
| `doc/fields` | warn | `reviews/*.md` | a front-matter field is missing or holds a value outside the list you configured. Off entirely unless you configure `docFields` |
|
|
17
|
+
| `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) |
|
|
18
|
+
| `pdf/profile` | error | `paper.tex` → `paperlint.json` | `paperlint.json` is not JSON or has an unknown key, only a pre-2.1.0 `venue.json` is there (`npx paperlint init` moves it), 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 |
|
|
19
|
+
| `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`) |
|
|
20
|
+
| `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 |
|
|
21
|
+
| `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` |
|
|
22
|
+
| `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) |
|
|
23
|
+
| `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 |
|
|
17
24
|
|
|
18
25
|
Optional rules — off unless you turn them on in the `rules` setting, because only some venues need
|
|
19
26
|
them — are on their own page: [`optional-rules.md`](optional-rules.md). Today there is one,
|
|
@@ -23,10 +30,132 @@ Besides these rules, `paperlint lint` reports a paper directory that is missing
|
|
|
23
30
|
default `PIPELINE-STATUS.md`) as an error. Which files are required is configurable — see
|
|
24
31
|
[`configuration.md`](configuration.md#required-files).
|
|
25
32
|
|
|
33
|
+
## Checks against the venue
|
|
34
|
+
|
|
35
|
+
A paper says where it is submitted in a `paperlint.json` beside `paper.tex`
|
|
36
|
+
([`configuration.md`](configuration.md#three-levels-of-settings)):
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{ "extends": "paperlint:aisec", "kind": "research" }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`extends` names a **venue preset** — the way an ESLint config extends a shareable config. `kind`
|
|
43
|
+
names the kind of paper, whose page limit applies. A preset holds the numbers from the venue's call
|
|
44
|
+
for papers, each with the quote it came from, the TeX packages its template needs, and the rules
|
|
45
|
+
the venue implies. A preset may itself extend another: the ACM venues extend the `acm-sigconf`
|
|
46
|
+
family, which holds everything the ACM template decides.
|
|
47
|
+
|
|
48
|
+
| preset | extends | template | kinds | page limit checked | rules it turns on |
|
|
49
|
+
| ----------------------- | ----------------------- | -------------------- | -------------------------------------------------------- | ------------------ | ----------------------- |
|
|
50
|
+
| `paperlint:acm-sigconf` | — | ACM `acmart` sigconf | none | no (no kinds) | — |
|
|
51
|
+
| `paperlint:agenticdev` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `short` (5 + 2 refs), `full` (10 + 2), `demo` (5 + 2) | yes | `pdf/last-page-balance` |
|
|
52
|
+
| `paperlint:aisec` | `paperlint:acm-sigconf` | ACM `acmart` sigconf | `research`, `benchmark`, `position`, `sok` (10 + 2 each) | yes | — |
|
|
53
|
+
| `paperlint:realm` | — | ACL | `long`, `short` | no — see below | — |
|
|
54
|
+
|
|
55
|
+
That is all that ships today. There is no IEEE, NeurIPS, USENIX or Springer preset. A paper for an
|
|
56
|
+
ACM venue nobody has profiled can extend `paperlint:acm-sigconf` directly: page size, columns and
|
|
57
|
+
fonts are checked, and `pdf/profile` says the page limit is not. For anything else, write your own
|
|
58
|
+
preset ([below](#writing-your-own-venue-preset)). REALM's preset sets no page limit on purpose:
|
|
59
|
+
banal counts the Limitations and Ethics sections as body, ACL does not, and a limit on banal's
|
|
60
|
+
number would fail a correct paper. AgenticDev's turns on `pdf/last-page-balance` because its
|
|
61
|
+
proceedings are produced by Conference Publishing Consulting, which sends back an unbalanced last
|
|
62
|
+
page; AISec's does not, because nothing in hand says who produces the AISec proceedings.
|
|
63
|
+
|
|
64
|
+
**Build, then lint.** The rules judge what `paperlint build` measured and wrote to
|
|
65
|
+
`_build/paper.facts.json` — page count, fonts, and, through banal, page size, columns, font sizes
|
|
66
|
+
and the split into body and reference pages. They report on the paper's `paper.tex`, at the
|
|
67
|
+
`\documentclass` line. What they say when there is nothing to judge, one rule per reason:
|
|
68
|
+
|
|
69
|
+
| the paper | what you get |
|
|
70
|
+
| ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
71
|
+
| has a `paperlint.json` that extends no preset (`"extends": null` is what `paperlint new` writes) | `pdf/measured` warning naming the file to set — no venue chosen yet |
|
|
72
|
+
| has no `paperlint.json` at all (a paper made before 2.1.0) | nothing |
|
|
73
|
+
| extends a preset that does not resolve (a typo, a missing file) | `pdf/profile` error, listing the shipped presets |
|
|
74
|
+
| has not been built (no facts file) | `pdf/measured` warning — it does not fail the run, because lint often runs where nothing is built (the CI action only lints) |
|
|
75
|
+
| was built without banal | `pdf/measured` warning; fonts are still checked, the rest is not |
|
|
76
|
+
| has facts about another PDF than the one on disk | `pdf/fresh` error, and nothing else is judged |
|
|
77
|
+
| names no `kind`, or a kind the preset lacks | `pdf/profile` error; everything but the page limit is still checked |
|
|
78
|
+
|
|
79
|
+
The venue comes from `paperlint.json`, not from the facts, so changing it needs no rebuild: the
|
|
80
|
+
measurements do not depend on it. Messages name the venue by the preset's `name`, else by the file
|
|
81
|
+
name of what the paper extends (`paperlint:agenticdev` → `agenticdev`).
|
|
82
|
+
|
|
83
|
+
To skip a check for one paper — a finding you accept — set it to `"off"` in the paper's own
|
|
84
|
+
`paperlint.json`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"extends": "paperlint:aisec",
|
|
89
|
+
"kind": "research",
|
|
90
|
+
"rules": { "pdf/body-size": "off" }
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Writing your own venue preset
|
|
95
|
+
|
|
96
|
+
A preset is a JSONC file (JSON with comments — keep the call-for-papers quote beside each number)
|
|
97
|
+
of the same shape as the shipped ones, validated by
|
|
98
|
+
[`venue-profile.schema.json`](../skills/submit-paper/references/venues/venue-profile.schema.json).
|
|
99
|
+
Put it in your repository and extend it by a path relative to the file that names it:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
package.json
|
|
103
|
+
venues/
|
|
104
|
+
usenix-sec.jsonc
|
|
105
|
+
papers/
|
|
106
|
+
usenix-2027/
|
|
107
|
+
paper.tex
|
|
108
|
+
paperlint.json { "extends": "../../venues/usenix-sec.jsonc", "kind": "full" }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```jsonc
|
|
112
|
+
// venues/usenix-sec.jsonc
|
|
113
|
+
{
|
|
114
|
+
"name": "USENIX Security",
|
|
115
|
+
// a standalone preset needs its template's TeX packages; one that extends a family inherits them
|
|
116
|
+
"template": "article",
|
|
117
|
+
// TeX Live packages only, each with a file that proves it is installed. The USENIX style file
|
|
118
|
+
// itself is not in TeX Live: keep it beside paper.tex.
|
|
119
|
+
"tex": { "packages": { "psnfss": ["times.sty"] } },
|
|
120
|
+
"format": {
|
|
121
|
+
"page_size": "letter",
|
|
122
|
+
"page_w_in": 8.5,
|
|
123
|
+
"page_h_in": 11,
|
|
124
|
+
"columns": 2,
|
|
125
|
+
"body_pt": 10,
|
|
126
|
+
"body_pt_tol": 0.5,
|
|
127
|
+
// the page limit of each kind of paper, as the call for papers states it
|
|
128
|
+
"kinds": { "full": { "body_pages_max": 13 } },
|
|
129
|
+
},
|
|
130
|
+
// only if the proceedings' producer asks for a balanced last page
|
|
131
|
+
"rules": { "pdf/last-page-balance": "error" },
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The numbers and packages above illustrate the shape; take yours from the venue's own call for papers and template.
|
|
136
|
+
|
|
137
|
+
| key | what it is |
|
|
138
|
+
| ---------- | --------------------------------------------------------------------------------------------------- |
|
|
139
|
+
| `extends` | the preset this one builds on: `paperlint:<name>` or `./path` / `../path`, relative to this file |
|
|
140
|
+
| `name` | how messages name the venue; the file name otherwise |
|
|
141
|
+
| `template` | the `\documentclass` the venue's template uses |
|
|
142
|
+
| `format` | page size, columns, fonts, font sizes, and `kinds` (page limits per kind of paper) |
|
|
143
|
+
| `tex` | TeX Live packages, each with the files that prove it is installed. Required unless `extends` is set |
|
|
144
|
+
| `rules` | rules the venue implies, rule id → severity or `[severity, options]` |
|
|
145
|
+
|
|
146
|
+
How a chain merges, from the root preset to the paper: `tex` is the union — a child never removes a
|
|
147
|
+
package; `format` keys are replaced one by one, and a child's kind replaces that kind whole;
|
|
148
|
+
`rules` are replaced rule by rule, and the paper's own `rules` come last. A chain is at most four
|
|
149
|
+
presets long, and a cycle is refused by name. `paperlint toolchain` installs the packages of every
|
|
150
|
+
shipped preset and of every preset your papers extend.
|
|
151
|
+
|
|
152
|
+
Presets from npm packages are not supported yet.
|
|
153
|
+
|
|
26
154
|
## The paper is LaTeX
|
|
27
155
|
|
|
28
|
-
The paper body is `paper.tex`, and it gets four rules: `paper/research-question`,
|
|
29
|
-
`paper/typography`, `tex/future-promise` and `tex/acm-frontmatter-override
|
|
156
|
+
The paper body is `paper.tex`, and it gets four rules of its own: `paper/research-question`,
|
|
157
|
+
`paper/typography`, `tex/future-promise` and `tex/acm-frontmatter-override` — plus the `pdf/`
|
|
158
|
+
venue rules above, which run on it but judge the files beside it. The scorecard and
|
|
30
159
|
the review notes are Markdown files, and the other five rules read those.
|
|
31
160
|
|
|
32
161
|
A Markdown body (`paper.md`, or `draft.md`) is still read today and gets only the two `paper/`
|
package/eslint-rules/papers.mjs
CHANGED
|
@@ -85,6 +85,7 @@ import {
|
|
|
85
85
|
CONFIG_KEY,
|
|
86
86
|
DEFAULT_PAPERS_ROOT,
|
|
87
87
|
PAPERS_DIR_FIELD,
|
|
88
|
+
PAPER_SETTINGS_FILE,
|
|
88
89
|
declaredSettings,
|
|
89
90
|
renamedFieldMessage,
|
|
90
91
|
settingsOf,
|
|
@@ -154,8 +155,11 @@ export function paperFiles(root) {
|
|
|
154
155
|
tex: [`${root}/*/paper.tex`],
|
|
155
156
|
/** The per-paper stage ledger. */
|
|
156
157
|
status: [`${root}/*/PIPELINE-STATUS.md`],
|
|
157
|
-
/**
|
|
158
|
-
|
|
158
|
+
/**
|
|
159
|
+
* The per-paper settings file, `paperlint.json` (`venue.json` before 2.1.0). The key keeps its
|
|
160
|
+
* old name so a consumer's config that lints these files keeps matching them.
|
|
161
|
+
*/
|
|
162
|
+
venue: [`${root}/*/${PAPER_SETTINGS_FILE}`],
|
|
159
163
|
/** Facts extracted from the built PDF. */
|
|
160
164
|
pdfFacts: [`${root}/*/_build/paper.facts.json`],
|
|
161
165
|
/** Facts extracted from the bibliography. */
|
|
@@ -29,12 +29,14 @@
|
|
|
29
29
|
*
|
|
30
30
|
* Silent, by design, where there is nothing to judge: a stub last page (a few lines) and a review
|
|
31
31
|
* build (numbered lines in the margins make both columns measure full height). Loud where the input
|
|
32
|
-
* is missing: no facts file
|
|
32
|
+
* is missing: no facts file (unless the paper extends a venue preset — then `pdf/measured` says it),
|
|
33
|
+
* a foreign schema, facts about a PDF that is not on disk or changed
|
|
33
34
|
* since — a rule that is on and reads nothing must not look like a rule that passed.
|
|
34
35
|
*/
|
|
35
36
|
import { createHash } from "node:crypto";
|
|
36
37
|
import { existsSync, readFileSync } from "node:fs";
|
|
37
38
|
import { basename, dirname, isAbsolute, join } from "node:path";
|
|
39
|
+
import { PAPER_SETTINGS_FILE } from "../lib/paper-config.mjs";
|
|
38
40
|
|
|
39
41
|
/** The difference, in points, that two columns may end apart. See the harness for why 120. */
|
|
40
42
|
export const DEFAULT_TOLERANCE_PT = 120;
|
|
@@ -133,11 +135,30 @@ function reportLine(file) {
|
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Whether the paper extends a venue preset. Then the venue rules run on it too, and `pdf/measured`
|
|
140
|
+
* already says — once, as a warning — that a paper with no facts was not checked; this rule
|
|
141
|
+
* repeating it as an error would fail a lint-only CI for every paper of a venue whose preset turns
|
|
142
|
+
* this rule on.
|
|
143
|
+
*/
|
|
144
|
+
function extendsPreset(paperDir) {
|
|
145
|
+
try {
|
|
146
|
+
const s = JSON.parse(
|
|
147
|
+
readFileSync(join(paperDir, PAPER_SETTINGS_FILE), "utf8"),
|
|
148
|
+
);
|
|
149
|
+
return typeof s?.extends === "string" && s.extends !== "";
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
136
155
|
/** Everything the rule decides for one paper, as a finding or null. */
|
|
137
156
|
function verdict(paperDir, tolerancePt) {
|
|
138
157
|
const factsFile = join(paperDir, FACTS_REL);
|
|
139
158
|
if (!existsSync(factsFile))
|
|
140
|
-
return
|
|
159
|
+
return extendsPreset(paperDir)
|
|
160
|
+
? null
|
|
161
|
+
: { messageId: "noFacts", data: { file: FACTS_REL } };
|
|
141
162
|
const facts = parseFacts(readFileSync(factsFile, "utf8"));
|
|
142
163
|
if (!facts.ok) return { messageId: facts.messageId, data: facts.data };
|
|
143
164
|
return staleness(paperDir, facts) ?? judgeColumns(facts.last, tolerancePt);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "extends": "paperlint:agenticdev", "kind": "short" }
|
package/lib/paper-config.d.mts
CHANGED
|
@@ -32,3 +32,10 @@ export declare function renamedFieldMessage(
|
|
|
32
32
|
|
|
33
33
|
/** Every key the settings object may hold, mapped to who reads it. */
|
|
34
34
|
export declare const SETTINGS_KEYS: Readonly<Record<string, string>>;
|
|
35
|
+
|
|
36
|
+
/** The per-paper settings file, `paperlint.json`, and its name before 2.1.0. */
|
|
37
|
+
export declare const PAPER_SETTINGS_FILE: string;
|
|
38
|
+
export declare const LEGACY_PAPER_SETTINGS_FILE: string;
|
|
39
|
+
/** Every key `paperlint.json` may hold, mapped to who reads it. */
|
|
40
|
+
export declare const PAPER_SETTINGS_KEYS: Readonly<Record<string, string>>;
|
|
41
|
+
export declare const LEGACY_PAPER_SETTINGS_MESSAGE: string;
|
package/lib/paper-config.mjs
CHANGED
|
@@ -30,6 +30,37 @@ export const CONFIG_KEY = "paperlint";
|
|
|
30
30
|
*/
|
|
31
31
|
export const LEGACY_CONFIG_KEY = "research-paper-pipeline";
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* THE THREE LEVELS OF SETTINGS, each named after the tool:
|
|
35
|
+
*
|
|
36
|
+
* package.json → "paperlint" the project: where the papers are, what every paper gets
|
|
37
|
+
* <paper>/paperlint.json one paper: the venue preset it extends, its kind, its own rules
|
|
38
|
+
* a venue preset one venue: its format, TeX packages and rules — shipped with
|
|
39
|
+
* paperlint (`paperlint:<name>`) or the project's own (`./x.jsonc`)
|
|
40
|
+
*
|
|
41
|
+
* The per-paper file was `venue.json` before 2.1.0. It is NOT read any more — a fallback would keep
|
|
42
|
+
* it working forever — and `paperlint init` moves it.
|
|
43
|
+
*/
|
|
44
|
+
export const PAPER_SETTINGS_FILE = "paperlint.json";
|
|
45
|
+
export const LEGACY_PAPER_SETTINGS_FILE = "venue.json";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Every key `paperlint.json` may hold. Any other key is REFUSED with its name: a typo would
|
|
49
|
+
* otherwise read as "not set". `$comment` is JSON Schema's own keyword for a comment, the one way
|
|
50
|
+
* to leave a note in a JSON file; paperlint ignores its value.
|
|
51
|
+
*/
|
|
52
|
+
export const PAPER_SETTINGS_KEYS = Object.freeze({
|
|
53
|
+
extends:
|
|
54
|
+
"the venue preset: paperlint:<name> or ./path.jsonc — the pdf/ venue rules, paperlint build",
|
|
55
|
+
kind: "the kind of paper, whose page limit applies — pdf/limits",
|
|
56
|
+
pdf: "where the built PDF is, relative to the paper, when it is not paper.pdf — the facts",
|
|
57
|
+
rules: "rule overrides for this paper alone — paperlint lint",
|
|
58
|
+
$comment: "a note for humans; ignored",
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** What a leftover pre-2.1.0 file is told. */
|
|
62
|
+
export const LEGACY_PAPER_SETTINGS_MESSAGE = `${LEGACY_PAPER_SETTINGS_FILE} is no longer read: it was renamed ${PAPER_SETTINGS_FILE} in paperlint 2.1.0. \`npx paperlint init\` moves it.`;
|
|
63
|
+
|
|
33
64
|
/**
|
|
34
65
|
* Where a parsed `package.json` keeps this package's settings — the new key, else the old one.
|
|
35
66
|
*
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ description: "Discover and rank real venues for a given paper, scored by authors
|
|
|
4
4
|
allowed-tools: [Read, Write, Grep, Glob, WebSearch, WebFetch, Agent, Bash(node .claude/skills/paper-pipeline/scripts/announce.mjs:*), Bash(node .claude/skills/paper-pipeline/scripts/ledger.mjs:*)]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:5efdcc0e1b178c1a compiled from skills/find-venue/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# find-venue — rank real venues by what earns the credit, then keep or switch
|
|
10
10
|
|
|
@@ -113,6 +113,10 @@ dropped and why, and a verdict with no table behind it cannot be re-checked when
|
|
|
113
113
|
## Compose with
|
|
114
114
|
- `research-ideate` (upstream) — consumes its candidate venue *types* and sharpest framing.
|
|
115
115
|
- `plan-paper-timeline` — feed it the chosen deadline to back-plan the work.
|
|
116
|
+
- once a venue is chosen, the paper declares it in `<paper>/paperlint.json`:
|
|
117
|
+
`{ "extends": "paperlint:<venue>", "kind": "<kind>" }` — a shipped preset, else a family
|
|
118
|
+
(`paperlint:acm-sigconf`) or the project's own `./venues/<name>.jsonc`; the `pdf/*` rules then
|
|
119
|
+
check the built PDF against its page limit and format.
|
|
116
120
|
- `submit-paper` venue data cards (`submit-paper/references/venues/<venue>.md`, e.g. `agenticdev.md`,
|
|
117
121
|
`aisec.md`) — the winner gets a venue-specific data card with its HotCRP quirks; save a new one per
|
|
118
122
|
venue as plain data, not a new skill.
|
|
@@ -129,6 +129,10 @@ dropped and why, and a verdict with no table behind it cannot be re-checked when
|
|
|
129
129
|
## Compose with
|
|
130
130
|
- \`research-ideate\` (upstream) — consumes its candidate venue *types* and sharpest framing.
|
|
131
131
|
- \`plan-paper-timeline\` — feed it the chosen deadline to back-plan the work.
|
|
132
|
+
- once a venue is chosen, the paper declares it in \`<paper>/paperlint.json\`:
|
|
133
|
+
\`{ "extends": "paperlint:<venue>", "kind": "<kind>" }\` — a shipped preset, else a family
|
|
134
|
+
(\`paperlint:acm-sigconf\`) or the project's own \`./venues/<name>.jsonc\`; the \`pdf/*\` rules then
|
|
135
|
+
check the built PDF against its page limit and format.
|
|
132
136
|
- \`submit-paper\` venue data cards (\`submit-paper/references/venues/<venue>.md\`, e.g. \`agenticdev.md\`,
|
|
133
137
|
\`aisec.md\`) — the winner gets a venue-specific data card with its HotCRP quirks; save a new one per
|
|
134
138
|
venue as plain data, not a new skill.
|
|
@@ -199,6 +199,14 @@ format.
|
|
|
199
199
|
|
|
200
200
|
## 3. Venue constants belong in a card, not in code
|
|
201
201
|
|
|
202
|
+
> **Done (#79, 2.1.0), in a different shape than planned below.** The constants live in **venue
|
|
203
|
+
> presets**, JSONC files in `submit-paper/references/venues/`: `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
|
+
|
|
202
210
|
Right now `LinLibertine`, `LinBiolinum`, `acmart` are hardcoded into `check-render.sh`. This is
|
|
203
211
|
**venue data**, and it belongs in
|
|
204
212
|
`.claude/skills/submit-paper/references/venues/<venue>.md`:
|
|
@@ -292,7 +300,7 @@ imports, paths inside regexes).
|
|
|
292
300
|
## 2. One build entry point for all papers, not one per paper
|
|
293
301
|
|
|
294
302
|
> **Done (#59, 2026-09-24).** `paperlint build <paper>` is the entry point, and `paperlint toolchain` installs
|
|
295
|
-
> TeX Live with the packages the venue
|
|
303
|
+
> TeX Live with the packages the venue presets declare; `ensure-toolchain.sh` and
|
|
296
304
|
> `ci-install-texlive.sh` are deleted. What follows is the plan as it was written.
|
|
297
305
|
|
|
298
306
|
**The hole:** `compile-rules` has `repro/build-submission.sh`, which calls `ensure-toolchain.sh`.
|
|
@@ -324,9 +332,11 @@ point. Nothing to check.
|
|
|
324
332
|
| page limit | **4** | `venues/realm.md` 8 · `build-submission.sh` 8 · `PIPELINE-STATUS` "8/8" · the build prints **9** |
|
|
325
333
|
| the TeX package list | **5** | `ensure-toolchain.sh` (executable) · `SKILL.md` · `render-paper.harness.mjs` (pins it ✅) · `build-submission.sh` · `PIPELINE-STATUS` |
|
|
326
334
|
|
|
327
|
-
The canonical source is the venue
|
|
328
|
-
format
|
|
329
|
-
|
|
335
|
+
The canonical source is the venue preset (`venues/<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.
|
|
330
340
|
|
|
331
341
|
## 3-ter. Drop the font gate from `check-render.sh` once the rules run in CI
|
|
332
342
|
|
|
@@ -4,7 +4,7 @@ description: The orchestrator for writing a research paper end-to-end, from idea
|
|
|
4
4
|
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, WebSearch, WebFetch, Agent, Skill]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:291d2266e29874be compiled from skills/paper-pipeline/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# paper-pipeline — the conductor for the whole organism
|
|
10
10
|
|
|
@@ -28,8 +28,9 @@ of that — who is filing what, and when — stays in the author's own private n
|
|
|
28
28
|
- `references/acl-venue-rules.md` — what holds at **every** ACL-family venue and workshop: the
|
|
29
29
|
page-limit map, the appendix rule and the trap inside it, Limitations/Ethics as free-but-restricted
|
|
30
30
|
space, anonymity, OpenReview mechanics. Fetch once, not per paper. Venue-specific facts stay in
|
|
31
|
-
`submit-paper/references/venues/<venue>.md`. (No equivalent yet for ACM or IEEE — write one
|
|
32
|
-
the next paper goes there.
|
|
31
|
+
`submit-paper/references/venues/<venue>.md`. (No prose equivalent yet for ACM or IEEE — write one
|
|
32
|
+
when the next paper goes there. ACM's machine-checked format already exists: the
|
|
33
|
+
`paperlint:acm-sigconf` preset, `submit-paper/references/venues/acm-sigconf.jsonc`.)
|
|
33
34
|
|
|
34
35
|
## The readiness scorecard (which boxes are checked)
|
|
35
36
|
Stages run in subagents and report into chat, which evaporates — so "did everything run?" becomes
|
|
@@ -45,8 +45,9 @@ of that — who is filing what, and when — stays in the author's own private n
|
|
|
45
45
|
- \`references/acl-venue-rules.md\` — what holds at **every** ACL-family venue and workshop: the
|
|
46
46
|
page-limit map, the appendix rule and the trap inside it, Limitations/Ethics as free-but-restricted
|
|
47
47
|
space, anonymity, OpenReview mechanics. Fetch once, not per paper. Venue-specific facts stay in
|
|
48
|
-
\`submit-paper/references/venues/<venue>.md\`. (No equivalent yet for ACM or IEEE — write one
|
|
49
|
-
the next paper goes there.
|
|
48
|
+
\`submit-paper/references/venues/<venue>.md\`. (No prose equivalent yet for ACM or IEEE — write one
|
|
49
|
+
when the next paper goes there. ACM's machine-checked format already exists: the
|
|
50
|
+
\`paperlint:acm-sigconf\` preset, \`submit-paper/references/venues/acm-sigconf.jsonc\`.)
|
|
50
51
|
|
|
51
52
|
## The readiness scorecard (which boxes are checked)
|
|
52
53
|
Stages run in subagents and report into chat, which evaporates — so "did everything run?" becomes
|
|
@@ -59,8 +59,8 @@ try {
|
|
|
59
59
|
mkdirSync(paper, { recursive: true });
|
|
60
60
|
cpSync(join(FIX, "t3-mixed.pdf"), join(paper, "paper.pdf"));
|
|
61
61
|
writeFileSync(
|
|
62
|
-
join(paper, "
|
|
63
|
-
JSON.stringify({
|
|
62
|
+
join(paper, "paperlint.json"),
|
|
63
|
+
JSON.stringify({ extends: "paperlint:agenticdev", kind: "short" }),
|
|
64
64
|
);
|
|
65
65
|
const factsFile = join(paper, "_build", "paper.facts.json");
|
|
66
66
|
|
|
@@ -88,7 +88,7 @@ try {
|
|
|
88
88
|
);
|
|
89
89
|
const facts = JSON.parse(readFileSync(factsFile, "utf8"));
|
|
90
90
|
check(
|
|
91
|
-
"the facts are schema 2, about paper.pdf, for the venue
|
|
91
|
+
"the facts are schema 2, about paper.pdf, for the venue paperlint.json declares",
|
|
92
92
|
facts.schema === 2 &&
|
|
93
93
|
facts.pdf === "paper.pdf" &&
|
|
94
94
|
facts.venue === "agenticdev" &&
|
|
@@ -148,8 +148,8 @@ try {
|
|
|
148
148
|
);
|
|
149
149
|
|
|
150
150
|
writeFileSync(
|
|
151
|
-
join(paper, "
|
|
152
|
-
JSON.stringify({
|
|
151
|
+
join(paper, "paperlint.json"),
|
|
152
|
+
JSON.stringify({ pdf: "build/other.pdf" }),
|
|
153
153
|
);
|
|
154
154
|
const missing = shim([paper, "--strict"], { BANAL: fake });
|
|
155
155
|
check(
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* it compiles a paper. This file is a composition root: it reads the environment and builds the real
|
|
9
9
|
* adapters (`dist/adapters/node/`), and it owns the `--strict` policy. This
|
|
10
10
|
* script exists for two callers the build does not serve: a PDF paperlint did not build (a paper that
|
|
11
|
-
* declares its artifact elsewhere in `
|
|
11
|
+
* declares its artifact elsewhere in `paperlint.json`), and CI steps that name this script by path.
|
|
12
12
|
* It reaches the package's compiled code through `../../dist/`, resolved from this file's real
|
|
13
13
|
* location, so it works the same from a checkout, from `node_modules` and through a symlink.
|
|
14
14
|
*
|
|
@@ -48,14 +48,14 @@ import {
|
|
|
48
48
|
import { whyNoGeometry } from "../../dist/domain/geometry.js";
|
|
49
49
|
import { exitCodeFor } from "../../dist/exit-code.js";
|
|
50
50
|
|
|
51
|
-
/** The paper's `
|
|
51
|
+
/** The venue the paper's `paperlint.json` declares, read from disk. */
|
|
52
52
|
export const declaredVenue = (paperDir) => declaredIn(nodeFiles, paperDir);
|
|
53
53
|
|
|
54
54
|
const ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Accept either a path to a PDF or a PAPER DIRECTORY — and in the second case find the artifact on
|
|
58
|
-
* its own: the path the paper declares in the `pdf` field of `
|
|
58
|
+
* its own: the path the paper declares in the `pdf` field of `paperlint.json`, else `paper.pdf` beside
|
|
59
59
|
* it. A paper written in markdown and built by its own script into `build/acl_latex.pdf` would
|
|
60
60
|
* otherwise be skipped silently. The facts ALWAYS go into `<paper directory>/_build/`, not next to
|
|
61
61
|
* the PDF, where neither a rule's glob nor a human looks.
|
|
@@ -111,7 +111,7 @@ if (isMain(import.meta.url)) {
|
|
|
111
111
|
finish(
|
|
112
112
|
"no-artifact",
|
|
113
113
|
strict,
|
|
114
|
-
`🛑 no artifact ${pdf} — the paper declared it in
|
|
114
|
+
`🛑 no artifact ${pdf} — the paper declared it in paperlint.json, but it is not built`,
|
|
115
115
|
);
|
|
116
116
|
// The composition root: banal as the measurer, wired from this process's environment.
|
|
117
117
|
const settings = parseBanalSettings(process.env, hostDirs());
|
|
@@ -5,7 +5,7 @@ context: fork
|
|
|
5
5
|
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, WebSearch, WebFetch, Agent]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
<!-- vigiles:sha256:
|
|
8
|
+
<!-- vigiles:sha256:177ca8805990361e compiled from skills/study-accepted-papers/SKILL.md.spec.ts -->
|
|
9
9
|
|
|
10
10
|
# study-accepted-papers — learn the venue's bar from its own accepted corpus, then lever your draft up
|
|
11
11
|
|
|
@@ -196,6 +196,7 @@ label on it.
|
|
|
196
196
|
- `verify-citations` — consumes the Step-4 citation gaps.
|
|
197
197
|
- `extend-paper` — the natural home for every EXPENSIVE lever this skill surfaces.
|
|
198
198
|
- `submit-paper` venue data card (`submit-paper/references/venues/<venue>.md`) — save durable venue-bar findings there as data, not as a new skill per venue.
|
|
199
|
+
- the paper's `<paper>/paperlint.json` (`{ "extends": "paperlint:<venue>", "kind": "<kind>" }`) — which venue preset the `pdf/*` rules check the built PDF against; a venue with no shipped preset extends a family (`paperlint:acm-sigconf`) or the project's own `./venues/<name>.jsonc`. Findings about the venue's page limit or format belong in that preset, with their source quote.
|
|
199
200
|
|
|
200
201
|
## Provenance
|
|
201
202
|
Built from the **AISec 2026 @ ACM CCS** polish run (2026-07): the "Safety Theater in Agentic Coding /
|
|
@@ -212,6 +212,7 @@ label on it.
|
|
|
212
212
|
- \`verify-citations\` — consumes the Step-4 citation gaps.
|
|
213
213
|
- \`extend-paper\` — the natural home for every EXPENSIVE lever this skill surfaces.
|
|
214
214
|
- \`submit-paper\` venue data card (\`submit-paper/references/venues/<venue>.md\`) — save durable venue-bar findings there as data, not as a new skill per venue.
|
|
215
|
+
- the paper's \`<paper>/paperlint.json\` (\`{ "extends": "paperlint:<venue>", "kind": "<kind>" }\`) — which venue preset the \`pdf/*\` rules check the built PDF against; a venue with no shipped preset extends a family (\`paperlint:acm-sigconf\`) or the project's own \`./venues/<name>.jsonc\`. Findings about the venue's page limit or format belong in that preset, with their source quote.
|
|
215
216
|
|
|
216
217
|
## Provenance
|
|
217
218
|
Built from the **AISec 2026 @ ACM CCS** polish run (2026-07): the "Safety Theater in Agentic Coding /
|
|
@@ -4,7 +4,7 @@ description: End-to-end playbook for submitting a peer-reviewed paper to a doubl
|
|
|
4
4
|
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, WebSearch, WebFetch, Skill]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:4a42424fd18098e5 compiled from skills/submit-paper/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# submit-paper — get a reviewed paper from "done" to "ready for review"
|
|
10
10
|
|
|
@@ -36,6 +36,14 @@ skill with `name:`/`description:`). This preserves the "save the exact venue ins
|
|
|
36
36
|
keeping the skill namespace from proliferating one card per venue. The *mechanics* stay here; the venue
|
|
37
37
|
file is only the facts.
|
|
38
38
|
|
|
39
|
+
**The card is prose; the machine-checked format is a PRESET beside it.** A paper declares its venue
|
|
40
|
+
in `<paper>/paperlint.json`: `{ "extends": "paperlint:<venue>", "kind": "<kind>" }`, and the
|
|
41
|
+
`pdf/*` lint rules judge the built PDF against that preset (page limit per kind, fonts, page size,
|
|
42
|
+
columns, font sizes). A venue with no shipped preset extends a family — `paperlint:acm-sigconf`
|
|
43
|
+
for an ACM venue — or a preset of the project's own, `./venues/<name>.jsonc` (paperlint's
|
|
44
|
+
`docs/rules.md`, "Writing your own venue preset"). Put the page limits you fetched from the CFP in
|
|
45
|
+
the preset's `format.kinds`, each with its quote.
|
|
46
|
+
|
|
39
47
|
## Publisher specifics — one level ABOVE the venue
|
|
40
48
|
Camera-ready mechanics belong to the **publisher**, not the venue: ACM eRights, the submit-vs-final
|
|
41
49
|
preamble swap, the copyright block, CCS 2012 codes and the mandatory Source-files upload are identical
|
|
@@ -52,6 +52,14 @@ skill with \`name:\`/\`description:\`). This preserves the "save the exact venue
|
|
|
52
52
|
keeping the skill namespace from proliferating one card per venue. The *mechanics* stay here; the venue
|
|
53
53
|
file is only the facts.
|
|
54
54
|
|
|
55
|
+
**The card is prose; the machine-checked format is a PRESET beside it.** A paper declares its venue
|
|
56
|
+
in \`<paper>/paperlint.json\`: \`{ "extends": "paperlint:<venue>", "kind": "<kind>" }\`, and the
|
|
57
|
+
\`pdf/*\` lint rules judge the built PDF against that preset (page limit per kind, fonts, page size,
|
|
58
|
+
columns, font sizes). A venue with no shipped preset extends a family — \`paperlint:acm-sigconf\`
|
|
59
|
+
for an ACM venue — or a preset of the project's own, \`./venues/<name>.jsonc\` (paperlint's
|
|
60
|
+
\`docs/rules.md\`, "Writing your own venue preset"). Put the page limits you fetched from the CFP in
|
|
61
|
+
the preset's \`format.kinds\`, each with its quote.
|
|
62
|
+
|
|
55
63
|
## Publisher specifics — one level ABOVE the venue
|
|
56
64
|
Camera-ready mechanics belong to the **publisher**, not the venue: ACM eRights, the submit-vs-final
|
|
57
65
|
preamble swap, the copyright block, CCS 2012 codes and the mandatory Source-files upload are identical
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// ACM `acmart` sigconf — the TEMPLATE FAMILY: everything the ACM template decides, whatever the
|
|
2
|
+
// venue. A venue preset extends it ("extends": "paperlint:acm-sigconf") and adds what its call for
|
|
3
|
+
// papers sets: the page limit of each kind of paper, and the rules its producer implies.
|
|
4
|
+
//
|
|
5
|
+
// The numbers were measured on acmart sigconf builds (banal + pdf.js, 2026-08-26) and quoted from
|
|
6
|
+
// the Conference Publishing author instructions for ACM (2026-08-25), which state ACM's own
|
|
7
|
+
// requirements. A paper may extend this family directly for an ACM venue nobody has profiled:
|
|
8
|
+
// page size, columns and fonts are checked; with no kinds, the page limit is not.
|
|
9
|
+
{
|
|
10
|
+
"template": "acmart",
|
|
11
|
+
|
|
12
|
+
// TeX Live packages the acmart template needs ON TOP OF tex-base.jsonc, each with the files that
|
|
13
|
+
// prove it is present (checked with kpsewhich after every install). Read by `paperlint toolchain` and
|
|
14
|
+
// `paperlint build`; the shape is venue-profile.schema.json.
|
|
15
|
+
// libertine · inconsolata (zi4) · newtx — acmart.cls checks ALL THREE and, if ANY is missing,
|
|
16
|
+
// silently falls back to Computer Modern: the PDF compiles, looks normal, is set in the wrong
|
|
17
|
+
// font, and the other metric gives another pagination. A submitted paper went out that way.
|
|
18
|
+
// kastrup (binhex.tex) — pulled in by newtx. Missing it is a HARD stop, so adding the fonts
|
|
19
|
+
// without it breaks a build that worked.
|
|
20
|
+
// fancyhdr — required by acmart itself; present on most images by accident, absent on a
|
|
21
|
+
// minimal one ("File `fancyhdr.sty' not found", measured on TinyTeX, issue #37).
|
|
22
|
+
// the rest — pulled in by acmart ITSELF, not by the paper, so reading \usepackage never finds
|
|
23
|
+
// them. Found 2026-09-01 by the loop build → missing file → tlmgr search --file → install.
|
|
24
|
+
"tex": {
|
|
25
|
+
"packages": {
|
|
26
|
+
"acmart": ["acmart.cls"],
|
|
27
|
+
"amscls": ["amsart.cls"],
|
|
28
|
+
"libertine": ["libertine.sty"],
|
|
29
|
+
"inconsolata": ["zi4.sty"],
|
|
30
|
+
"newtx": ["newtxmath.sty"],
|
|
31
|
+
"kastrup": ["binhex.tex"],
|
|
32
|
+
"fancyhdr": ["fancyhdr.sty"],
|
|
33
|
+
"totpages": ["totpages.sty"],
|
|
34
|
+
"environ": ["environ.sty"],
|
|
35
|
+
"preprint": ["balance.sty"],
|
|
36
|
+
// acmart's `pbalance` option (the vendor's first fix for an unbalanced last page, which the
|
|
37
|
+
// optional rule `pdf/last-page-balance` recommends) loads pbalance, which needs filehook and
|
|
38
|
+
// zref. Measured 2026-09-25 on an acmart sigconf camera-ready: without them the option stops
|
|
39
|
+
// the build; with them the last page went from 639.6 / 224.1 to 424.4 / 439.2 pt, same page count.
|
|
40
|
+
"pbalance": ["pbalance.sty"],
|
|
41
|
+
"filehook": ["filehook.sty"],
|
|
42
|
+
"zref": ["zref-abspage.sty"],
|
|
43
|
+
"xstring": ["xstring.sty"],
|
|
44
|
+
"everyshi": ["everyshi.sty"],
|
|
45
|
+
"hyperxmp": ["hyperxmp.sty"],
|
|
46
|
+
"ncctools": ["manyfoot.sty"],
|
|
47
|
+
"cmap": ["cmap.sty"],
|
|
48
|
+
"float": ["float.sty"],
|
|
49
|
+
"comment": ["comment.sty"],
|
|
50
|
+
"upquote": ["upquote.sty"],
|
|
51
|
+
"doclicense": ["doclicense.sty"],
|
|
52
|
+
"textcase": ["textcase.sty"],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
"format": {
|
|
57
|
+
// 8.5 x 11 in
|
|
58
|
+
"page_size": "letter",
|
|
59
|
+
"page_w_in": 8.5,
|
|
60
|
+
"page_h_in": 11.0,
|
|
61
|
+
|
|
62
|
+
// «text width must not exceed 18 cm»
|
|
63
|
+
"textblock_w_in": 7.087,
|
|
64
|
+
// «text height must not exceed 23.5 cm»
|
|
65
|
+
"textblock_h_in": 9.252,
|
|
66
|
+
// Last-page balance is NOT a format field: it is the optional rule pdf/last-page-balance, which
|
|
67
|
+
// a VENUE preset turns on in its `rules` when its producer asks (see agenticdev.jsonc).
|
|
68
|
+
|
|
69
|
+
"columns": 2,
|
|
70
|
+
|
|
71
|
+
// «font size is 9 pt for all body text»
|
|
72
|
+
"body_pt": 9,
|
|
73
|
+
// banal measures the MODE of the rendered text, not the declared size (measured 08-26: 9.30 at
|
|
74
|
+
// acmart's declared 9). Hence the tolerance — and hence why body size stays a nudge, not a gate.
|
|
75
|
+
"body_pt_tol": 0.5,
|
|
76
|
+
|
|
77
|
+
// «font size of the references can be from 7 pt to 9 pt»
|
|
78
|
+
"ref_pt_min": 7,
|
|
79
|
+
"ref_pt_max": 9,
|
|
80
|
+
|
|
81
|
+
// «text must be in serif font (Libertine)»
|
|
82
|
+
"fonts_text": "LinLibertine",
|
|
83
|
+
// «The title must be in sans-serif font (Biolinum)»
|
|
84
|
+
"fonts_title": "LinBiolinum",
|
|
85
|
+
},
|
|
86
|
+
}
|