paperlint 6.2.3 → 6.3.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/README.md +8 -1
- package/dist/adapters/hotcrp/index.d.ts +7 -0
- package/dist/adapters/hotcrp/index.d.ts.map +1 -0
- package/dist/adapters/hotcrp/index.js +7 -0
- package/dist/adapters/hotcrp/index.js.map +1 -0
- package/dist/adapters/hotcrp/portal.io.d.ts +20 -0
- package/dist/adapters/hotcrp/portal.io.d.ts.map +1 -0
- package/dist/adapters/hotcrp/portal.io.js +90 -0
- package/dist/adapters/hotcrp/portal.io.js.map +1 -0
- package/dist/adapters/hotcrp/response.d.ts +13 -0
- package/dist/adapters/hotcrp/response.d.ts.map +1 -0
- package/dist/adapters/hotcrp/response.js +138 -0
- package/dist/adapters/hotcrp/response.js.map +1 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +109 -34
- package/dist/cli.js.map +1 -1
- package/dist/domain/result.d.ts +4 -0
- package/dist/domain/result.d.ts.map +1 -1
- package/dist/domain/result.js +2 -0
- package/dist/domain/result.js.map +1 -1
- package/dist/domain/submission.d.ts +106 -0
- package/dist/domain/submission.d.ts.map +1 -0
- package/dist/domain/submission.js +39 -0
- package/dist/domain/submission.js.map +1 -0
- package/dist/domain/venue-name.d.ts +38 -0
- package/dist/domain/venue-name.d.ts.map +1 -0
- package/dist/domain/venue-name.js +71 -0
- package/dist/domain/venue-name.js.map +1 -0
- package/dist/folder-venue-rule.d.ts +51 -0
- package/dist/folder-venue-rule.d.ts.map +1 -0
- package/dist/folder-venue-rule.js +96 -0
- package/dist/folder-venue-rule.js.map +1 -0
- package/dist/init.d.ts +6 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +3 -3
- package/dist/init.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +5 -1
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/new-paper.d.ts +19 -5
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +23 -4
- package/dist/new-paper.js.map +1 -1
- package/dist/paper-settings.d.ts +3 -0
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +20 -4
- package/dist/paper-settings.js.map +1 -1
- package/dist/ports/submission-portal.d.ts +19 -0
- package/dist/ports/submission-portal.d.ts.map +1 -0
- package/dist/ports/submission-portal.js +2 -0
- package/dist/ports/submission-portal.js.map +1 -0
- package/dist/presets.d.ts +24 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +35 -3
- package/dist/presets.js.map +1 -1
- package/dist/rules-config.js +1 -1
- package/dist/submission.d.ts +61 -0
- package/dist/submission.d.ts.map +1 -0
- package/dist/submission.js +211 -0
- package/dist/submission.js.map +1 -0
- package/dist/tex-requirements.d.ts +3 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +3 -0
- package/dist/tex-requirements.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +6 -7
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js +10 -14
- package/dist/tex-venue-rules.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/configuration.md +17 -10
- package/docs/rules/paper/folder-venue-leftover.md +104 -0
- package/docs/rules/talk/captions-cover.md +1 -1
- package/docs/rules/talk/duration-floor.md +1 -1
- package/docs/rules.md +44 -42
- package/docs/skills.md +5 -4
- package/docs/submission.md +64 -0
- package/docs/talk.md +1 -1
- package/lib/paper-config.ts +6 -1
- package/lib/skill-checks.d.mts +7 -0
- package/lib/skill-trigger-cases.mjs +11 -0
- package/package.json +2 -2
- package/presets/aidc.jsonc +6 -0
- package/presets/venue-profile.schema.json +17 -1
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +4 -0
- package/skills/submission-portal/SKILL.md +69 -0
- package/skills/submission-portal/SKILL.md.spec.ts +71 -0
- package/skills/submission-portal/submission-portal.eval.mjs +15 -0
- package/skills/submission-portal/submission-portal.test.ts +81 -0
- package/skills/submit-paper/SKILL.md +2 -1
- package/skills/submit-paper/SKILL.md.spec.ts +1 -0
- package/src/adapters/hotcrp/cassette/README.md +24 -0
- package/src/adapters/hotcrp/cassette/get-noauth.json +10 -0
- package/src/adapters/hotcrp/cassette/get-paper.json +39 -0
- package/src/adapters/hotcrp/cassette/post-dot.json +21 -0
- package/src/adapters/hotcrp/cassette/post-ok.json +12 -0
- package/src/adapters/hotcrp/index.ts +11 -0
- package/src/adapters/hotcrp/portal.io.ts +130 -0
- package/src/adapters/hotcrp/portal.test.ts +503 -0
- package/src/adapters/hotcrp/response.ts +181 -0
- package/src/cli.test.ts +109 -0
- package/src/cli.ts +140 -21
- package/src/domain/result.test.ts +9 -1
- package/src/domain/result.ts +5 -0
- package/src/domain/submission.test.ts +45 -0
- package/src/domain/submission.ts +141 -0
- package/src/domain/venue-name.test.ts +115 -0
- package/src/domain/venue-name.ts +129 -0
- package/src/folder-venue-rule.test.ts +182 -0
- package/src/folder-venue-rule.ts +141 -0
- package/src/init.test.ts +22 -0
- package/src/init.ts +9 -2
- package/src/new-paper.harness.mjs +11 -9
- package/src/new-paper.test.ts +129 -8
- package/src/new-paper.ts +38 -7
- package/src/paper-settings.test.ts +12 -1
- package/src/paper-settings.ts +25 -5
- package/src/parse-args.test.ts +19 -0
- package/src/ports/submission-portal.ts +26 -0
- package/src/presets.test.ts +22 -0
- package/src/presets.ts +46 -3
- package/src/rule-cases.test.ts +19 -0
- package/src/rules-config.ts +1 -1
- package/src/submission.test.ts +496 -0
- package/src/submission.ts +311 -0
- package/src/tex-requirements.ts +8 -0
- package/src/tex-venue-rules.test.ts +1 -1
- package/src/tex-venue-rules.ts +12 -25
- package/src/types.ts +13 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# paper/folder-venue-leftover
|
|
2
|
+
|
|
3
|
+
**Level:** warn · **Reads:** the paper folder's name, its `paperlint.json`, and the shipped venue
|
|
4
|
+
presets · **Reported on:** the first line of the paper's `PIPELINE-STATUS.md`
|
|
5
|
+
|
|
6
|
+
## What it catches
|
|
7
|
+
|
|
8
|
+
The paper's folder is named after a venue other than the one its `paperlint.json` extends. Usually
|
|
9
|
+
the folder was named for the first venue the paper went to, and the paper has since been retargeted:
|
|
10
|
+
`papers/aisec-2026/` holding a paper that now extends `paperlint:aidc`.
|
|
11
|
+
|
|
12
|
+
The folder name is read as words: runs of letters and runs of digits, split on everything else, case
|
|
13
|
+
ignored. `aisec-2026`, `aisec_2026` and `aisec2026` all name AISec; `overrealm` and `realms` do not
|
|
14
|
+
name REALM. A venue name of several words (`ACM CCS`) counts only when its words stand in a row.
|
|
15
|
+
|
|
16
|
+
The venue names come from the preset registry: every shipped preset's label (`aisec`) and its `name`
|
|
17
|
+
and `aliases` (`AISec`, `ACM CCS`), collected along `extends` — the same names `tex/venue-leftover`
|
|
18
|
+
looks for in the text. A venue with no shipped preset is not recognized.
|
|
19
|
+
|
|
20
|
+
## Why
|
|
21
|
+
|
|
22
|
+
Venues change on resubmission: a workshop paper that is rejected goes to the next workshop, and a
|
|
23
|
+
venue can be cancelled. The folder name does not change with it, and a folder named after the old
|
|
24
|
+
venue tells everyone who opens the repository — a co-author, a script, an agent — which venue the
|
|
25
|
+
paper is for, wrongly. The venue is already declared once, in `paperlint.json`; a second, stale
|
|
26
|
+
copy of it in the path is the one that misleads.
|
|
27
|
+
|
|
28
|
+
A name that describes the work (`agent-rule-drift`, `harness-misconfig`) stays right whichever venue
|
|
29
|
+
the paper goes to.
|
|
30
|
+
|
|
31
|
+
## Examples
|
|
32
|
+
|
|
33
|
+
Failing — a paper whose `paperlint.json` is `{ "extends": "paperlint:aidc", "kind": "regular" }`,
|
|
34
|
+
in `papers/aisec-2026/`:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
papers/aisec-2026/PIPELINE-STATUS.md
|
|
38
|
+
1:1 warning the folder name «aisec-2026» names the venue aisec, and this paper extends aidc — the
|
|
39
|
+
name went stale when the venue changed, and venues change on every resubmission. Name
|
|
40
|
+
the folder after the work (what the paper shows), not the venue
|
|
41
|
+
paper/folder-venue-leftover
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Named by an alias, the message says which: `papers/acm-ccs-agents/` under `paperlint:aidc` names
|
|
45
|
+
`aisec («ACM CCS»)`.
|
|
46
|
+
|
|
47
|
+
Passing:
|
|
48
|
+
|
|
49
|
+
- `papers/agent-rule-drift/` — names no venue;
|
|
50
|
+
- `papers/aidc-2026/` or `papers/acsac-2026/` under `paperlint:aidc` — the paper's own venue, by its
|
|
51
|
+
label or its alias;
|
|
52
|
+
- `papers/overrealm-study/` — `realm` inside another word is that other word;
|
|
53
|
+
- any folder whose `paperlint.json` has no `extends` yet, or none at all;
|
|
54
|
+
- `papers/secure-acsac24/` under `paperlint:ieee-conference` — a bare template family names no venue.
|
|
55
|
+
|
|
56
|
+
## Options / preset fields
|
|
57
|
+
|
|
58
|
+
No rule options. It reads each shipped preset's `name` and `aliases`, the fields
|
|
59
|
+
`tex/venue-leftover` reads too:
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
"aliases": ["AISec", "ACM CCS"]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
A name the paper's own chain also declares (two workshops of one parent conference) is never
|
|
66
|
+
reported.
|
|
67
|
+
|
|
68
|
+
## What it does not check
|
|
69
|
+
|
|
70
|
+
- A venue no shipped preset describes — including one that was cancelled and has no preset.
|
|
71
|
+
- A folder named after the paper's own venue. It is right today and goes stale on the next
|
|
72
|
+
resubmission, so `paperlint new` refuses to create such a folder at all (unless given
|
|
73
|
+
`--allow-venue-name`); this rule is the backstop for folders made by hand, with that flag, or
|
|
74
|
+
before the refusal, and reports only the name that is already wrong.
|
|
75
|
+
- A paper whose `extends` is unset or does not resolve: with no venue there is nothing to compare,
|
|
76
|
+
and `pdf/measured` or `pdf/profile` already speaks.
|
|
77
|
+
- A paper whose `extends` names only a template family (`paperlint:acm-sigconf`,
|
|
78
|
+
`paperlint:ieee-conference` — a preset with no kinds). It declares a format, not a venue, so a venue
|
|
79
|
+
in its folder name may well be its own: the accepted ACSAC papers this rule is checked on live in
|
|
80
|
+
`…-acsac24` folders and extend `ieee-conference`, while ACSAC is an alias of `aidc`.
|
|
81
|
+
|
|
82
|
+
## How to fix
|
|
83
|
+
|
|
84
|
+
Rename the folder after the work, and update whatever names the path (a CI matrix, a link in a
|
|
85
|
+
README):
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
git mv papers/aisec-2026 papers/agent-rule-drift
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A folder that should keep its name — a team convention, links you cannot change — turns the rule off
|
|
92
|
+
in that paper's `paperlint.json`, beside the `extends` it compares with:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"extends": "paperlint:aidc",
|
|
97
|
+
"kind": "regular",
|
|
98
|
+
"rules": { "paper/folder-venue-leftover": "off" }
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
A disable comment in `PIPELINE-STATUS.md` does not work here: the finding is on the file's first
|
|
103
|
+
line, the frontmatter's `---`, and a directive below the frontmatter comes after it, so ESLint
|
|
104
|
+
reports the directive as unused and the finding stays.
|
|
@@ -24,7 +24,7 @@ can see.
|
|
|
24
24
|
|
|
25
25
|
Warning — the AgenticDev talk's last cue ends 4.2 s before the video:
|
|
26
26
|
|
|
27
|
-
> papers/
|
|
27
|
+
> papers/rule-drift/talk/rule-drift-talk.srt: the last caption ends at 5:16.6 (316.6 s),
|
|
28
28
|
> and the video runs 5:20.8 (320.84 s) — more than 2 s uncaptioned at the end
|
|
29
29
|
|
|
30
30
|
Passing: cues from 0 s to within 2 s of the end, no silence between cues over 5 s.
|
|
@@ -18,7 +18,7 @@ an error, without touching the ceiling.
|
|
|
18
18
|
|
|
19
19
|
Warning — the AgenticDev talk measured 320.84 s against the organizers' 6–7 minutes:
|
|
20
20
|
|
|
21
|
-
> papers/
|
|
21
|
+
> papers/rule-drift/talk/rule-drift-talk.mp4 runs 5:20.8 (320.84 s), under the 6:00.0
|
|
22
22
|
> (360 s) talk agenticdev asks for a short paper — decide whether that is fine, or set this rule to
|
|
23
23
|
> off for the paper
|
|
24
24
|
|
package/docs/rules.md
CHANGED
|
@@ -3,47 +3,48 @@
|
|
|
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
|
|
7
|
-
|
|
|
8
|
-
| `paper/stages`
|
|
9
|
-
| `paper/source`
|
|
10
|
-
| `paper/
|
|
11
|
-
| `paper/
|
|
12
|
-
| `paper/
|
|
13
|
-
| `paper/
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `paper/
|
|
17
|
-
| `paper/refs-
|
|
18
|
-
| `
|
|
19
|
-
| `tex/
|
|
20
|
-
|
|
|
21
|
-
| [`tex/
|
|
22
|
-
| [`
|
|
23
|
-
| [`
|
|
24
|
-
| [`
|
|
25
|
-
| [`tex/
|
|
26
|
-
| [`tex/
|
|
27
|
-
| [`tex/
|
|
28
|
-
| [`tex/
|
|
29
|
-
| [`tex/
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
33
|
-
| `pdf/
|
|
34
|
-
| `pdf/
|
|
35
|
-
| `pdf/
|
|
36
|
-
|
|
|
37
|
-
| [`
|
|
38
|
-
| `pdf/
|
|
39
|
-
|
|
|
40
|
-
| [`talk/
|
|
41
|
-
| [`talk/
|
|
42
|
-
| [`talk/
|
|
43
|
-
| [`talk/duration
|
|
44
|
-
| [`talk/
|
|
45
|
-
| [`talk/
|
|
46
|
-
| [`talk/
|
|
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/folder-venue-leftover`](rules/paper/folder-venue-leftover.md) | warn | the folder name → `paperlint.json` | the paper's folder is named after another shipped venue than the one it extends (`papers/aisec-2026/` for a paper now set for AIDC); reported on `PIPELINE-STATUS.md` — [page](rules/paper/folder-venue-leftover.md) |
|
|
11
|
+
| `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 |
|
|
12
|
+
| `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` |
|
|
13
|
+
| `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** |
|
|
14
|
+
| `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 |
|
|
15
|
+
| `bib/reachable-entry` | warn | `paper.tex` (its `filecontents` bibliography) | an entry has no doi, url or arXiv id — a reader has nothing to follow. Reported on the entry; no fix, the link has to be looked up |
|
|
16
|
+
| `paper/cite-exists` | error | `paper.tex` → `_build/references.json` | an entry's doi or arXiv id resolves to nothing, or to a different work. Checked online by `paperlint build`; a work that was merely not found is not a finding |
|
|
17
|
+
| `paper/refs-fresh` | error | `paper.tex` → `_build/references.json` | the bibliography changed since the build checked it (its SHA-256 differs) — run `npx paperlint build` |
|
|
18
|
+
| `paper/refs-checked` | warn | `paper.tex` → `_build/references.json` | the paper has a bibliography and no build has checked it, or the last build could not (no network) — so the two rules above did not run |
|
|
19
|
+
| `tex/future-promise` | warn | `paper.tex` and its body files | a camera-ready build still says "will be released" about something already handed over |
|
|
20
|
+
| `tex/acm-frontmatter-override` | error | `paper.tex` | an `acmart` build overrides ACM's front-matter commands and drops template elements from page 1 |
|
|
21
|
+
| [`tex/template`](rules/tex/template.md) | error | `paper.tex` → `paperlint.json` | the `\documentclass` is not the preset's `template` class, or lacks an option it names — [page](rules/tex/template.md) |
|
|
22
|
+
| [`tex/required-section`](rules/tex/required-section.md) | error | `paper.tex` → `paperlint.json` | a section the preset requires (AIDC: «LLM Usage Statement», last) is missing or not where it must be — [page](rules/tex/required-section.md) |
|
|
23
|
+
| [`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) |
|
|
24
|
+
| [`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) |
|
|
25
|
+
| [`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) |
|
|
26
|
+
| [`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) |
|
|
27
|
+
| [`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) |
|
|
28
|
+
| [`tex/contrast-frames`](rules/tex/contrast-frames.md) | warn | `paper.tex` and the files it includes → `paperlint.json` | contrast frames (_X, not Y_, _not X but Y_, _rather than_, _instead of_, _as opposed to_) per 10,000 words fall outside the band the venue preset's anchors set (AIDC: 0–10.4, from five accepted ACSAC papers); above it, each frame is reported too — [page](rules/tex/contrast-frames.md) |
|
|
29
|
+
| [`tex/claim-emphasis`](rules/tex/claim-emphasis.md) | warn | `paper.tex` and the files it includes → `paperlint.json` | claims set in bold inside a sentence (six words or more, or holding a number; not a term, not a label opening a paragraph) per 10,000 words fall outside the preset's band (AIDC: 0–17.8); above it, each is reported too — [page](rules/tex/claim-emphasis.md) |
|
|
30
|
+
| [`tex/relation-markers`](rules/tex/relation-markers.md) | warn | `paper.tex` and the files it includes → `paperlint.json` | words that name how a sentence relates to the one before (_because_, _therefore_, _however_, _for example_ …) per 10,000 words fall outside the preset's band (AIDC: 25.4–135.0) — the floor that catches relations left to infer — [page](rules/tex/relation-markers.md) |
|
|
31
|
+
| `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 |
|
|
32
|
+
| `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`) |
|
|
33
|
+
| `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) |
|
|
34
|
+
| `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 |
|
|
35
|
+
| `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`) |
|
|
36
|
+
| `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 |
|
|
37
|
+
| [`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) |
|
|
38
|
+
| [`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) |
|
|
39
|
+
| `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 |
|
|
40
|
+
| [`talk/profile`](rules/talk/profile.md) | error | `paper.tex` → `paperlint.json` | the paper declares `talk` and names no preset, the preset has no `talk` block, the mode is not one the venue allows, or the venue sets no talk slot for the paper's kind — [page](rules/talk/profile.md) |
|
|
41
|
+
| [`talk/required-files`](rules/talk/required-files.md) | error | `paper.tex` → `paperlint.json`, the talk folder | a file the venue requires for the paper's talk mode (video, one-slide, captions…) is not in the talk folder — [page](rules/talk/required-files.md) |
|
|
42
|
+
| [`talk/undeclared`](rules/talk/undeclared.md) | warn | `paper.tex` → the paper's `talk/` folder | an `.mp4` sits in `talk/` and the paper declares no `talk`, so nothing checks it — [page](rules/talk/undeclared.md) |
|
|
43
|
+
| [`talk/duration`](rules/talk/duration.md) | error | `paper.tex` → the talk video | the video runs longer than the slot's `talk_s_max`, or its audio track is more than 1 s off the video's length — [page](rules/talk/duration.md) |
|
|
44
|
+
| [`talk/duration-floor`](rules/talk/duration-floor.md) | warn | `paper.tex` → the talk video | the video runs shorter than the slot's `talk_s_min` — [page](rules/talk/duration-floor.md) |
|
|
45
|
+
| [`talk/video-format`](rules/talk/video-format.md) | error | `paper.tex` → the talk video | the video is not ISO media, is QuickTime where the venue asks for MP4, is under `min_height_px`, or over `max_bytes` — [page](rules/talk/video-format.md) |
|
|
46
|
+
| [`talk/one-slide-size`](rules/talk/one-slide-size.md) | error | `paper.tex` → the one-slide PNG | the one-slide image is not the size the paper or the preset states, or not a PNG — [page](rules/talk/one-slide-size.md) |
|
|
47
|
+
| [`talk/captions-cover`](rules/talk/captions-cover.md) | warn | `paper.tex` → the captions and the video | the captions start late, end early or leave a long gap (uncalibrated thresholds) — [page](rules/talk/captions-cover.md) |
|
|
47
48
|
|
|
48
49
|
**Body files** are the files `paper.tex` includes from its document body (`\input`, `\include`,
|
|
49
50
|
`\subfile`, nested ones too), found in the paper's directory — not a preamble include, not a file
|
|
@@ -221,7 +222,8 @@ The numbers and packages above illustrate the shape; take yours from the venue's
|
|
|
221
222
|
| `extends` | the preset this one builds on: `paperlint:<name>` or `./path` / `../path`, relative to this file |
|
|
222
223
|
| `name` | how messages name the venue; the file name otherwise |
|
|
223
224
|
| `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 |
|
|
224
|
-
| `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`
|
|
225
|
+
| `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` and `paper/folder-venue-leftover` |
|
|
226
|
+
| `portal` | where the venue takes submissions, `{ "kind": "hotcrp", "url": "https://…" }` — read by [`paperlint submission`](submission.md); a child's value replaces its parent's |
|
|
225
227
|
| `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 |
|
|
226
228
|
| `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 |
|
|
227
229
|
| `format` | page size, columns, fonts, font sizes, and `kinds` (page limits per kind of paper) |
|
package/docs/skills.md
CHANGED
|
@@ -62,10 +62,11 @@ the skill whose description matches starts. `paperlint init` installs them into
|
|
|
62
62
|
|
|
63
63
|
## 6 · Submit
|
|
64
64
|
|
|
65
|
-
| you get
|
|
66
|
-
|
|
|
67
|
-
| the submission, step by step: anonymization, the form, the artifact
|
|
68
|
-
| the reproduction artifact uploaded to OSF for anonymous review
|
|
65
|
+
| you get | skill |
|
|
66
|
+
| ------------------------------------------------------------------------------ | --------------------- |
|
|
67
|
+
| the submission, step by step: anonymization, the form, the artifact | `submit-paper` |
|
|
68
|
+
| the reproduction artifact uploaded to OSF for anonymous review | `osf-artifact-upload` |
|
|
69
|
+
| the PDF and abstract replaced on HotCRP, and proof the portal holds your build | `submission-portal` |
|
|
69
70
|
|
|
70
71
|
## 7 · Camera-ready
|
|
71
72
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# The submission on the venue's portal
|
|
2
|
+
|
|
3
|
+
`paperlint submission` reads and updates a paper's submission on the venue's submission portal,
|
|
4
|
+
through the portal's API. Only [HotCRP](https://github.com/kohler/hotcrp) is supported.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npx paperlint submission show papers/my-paper
|
|
8
|
+
npx paperlint submission update papers/my-paper # a dry run: nothing is saved
|
|
9
|
+
npx paperlint submission update papers/my-paper --save # changes the real submission
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## What it needs
|
|
13
|
+
|
|
14
|
+
Two keys, each in the file that owns the fact, and a token:
|
|
15
|
+
|
|
16
|
+
| where | key | what it says |
|
|
17
|
+
| ---------------------------- | ---------------------------------------------------- | ----------------------------------------------- |
|
|
18
|
+
| the venue preset | `"portal": { "kind": "hotcrp", "url": "https://…" }` | where the venue takes submissions |
|
|
19
|
+
| the paper's `paperlint.json` | `"submission": { "id": 7 }` | which submission on that portal is this paper's |
|
|
20
|
+
| the environment | `HOTCRP_TOKEN` | an API token for your HotCRP account |
|
|
21
|
+
|
|
22
|
+
`paperlint:aidc` declares its portal. For another venue, add `portal` to your own preset (see
|
|
23
|
+
[`rules.md`](rules.md)) — or upload by hand: a kind paperlint has no adapter for is refused with
|
|
24
|
+
`portal kind "<kind>" is not supported; upload by hand`.
|
|
25
|
+
|
|
26
|
+
```jsonc
|
|
27
|
+
// papers/my-paper/paperlint.json
|
|
28
|
+
{ "extends": "paperlint:aidc", "kind": "regular", "submission": { "id": 7 } }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**The token** is read only from `HOTCRP_TOKEN`. Create it on the HotCRP site under **Account
|
|
32
|
+
settings → Developer**; `show` needs the scopes `submeta:read` and `document:read`, `update` also
|
|
33
|
+
`submeta:write` and `document:write`. paperlint sends it as `Authorization: bearer <token>` and
|
|
34
|
+
never prints it or writes it anywhere.
|
|
35
|
+
|
|
36
|
+
A missing key or token stops the command with exit 2 and a line naming the file and key, or the
|
|
37
|
+
variable, to set.
|
|
38
|
+
|
|
39
|
+
## `show`
|
|
40
|
+
|
|
41
|
+
Prints the submission's status (and when it was submitted), its id, title, paper type, topics, the
|
|
42
|
+
abstract's length in words, and the PDF the portal holds — its hash, size and upload time — then
|
|
43
|
+
whether that PDF is the local one: HotCRP stores a PDF's sha256 as `sha2-<hex>`, and paperlint
|
|
44
|
+
compares it with the sha256 of the paper's `paper.pdf` (or its `pdf` setting, or `--pdf <file>`).
|
|
45
|
+
`match yes` means the portal holds exactly the file you built. Exit 0 whenever the portal answered.
|
|
46
|
+
|
|
47
|
+
## `update`
|
|
48
|
+
|
|
49
|
+
Sends the PDF — the paper's own unless `--pdf <file>` names another — and, when asked, a new
|
|
50
|
+
abstract (`--abstract <file>`, plain text) and the status "submitted" (`--submit`).
|
|
51
|
+
|
|
52
|
+
**Without `--save` it is a dry run**: HotCRP's `dry_run=1` checks the change and keeps nothing. With
|
|
53
|
+
`--save` the real submission changes. Either way it prints HotCRP's verdict — `valid`, the fields the
|
|
54
|
+
change touched (`change_list`), HotCRP's messages — and the local file's sha256. Exit 1 when the
|
|
55
|
+
change is not valid or the HTTP status is not 2xx.
|
|
56
|
+
|
|
57
|
+
The safe order: `show`, `update` (dry run), read what it says, `update --save`, then `show` again and
|
|
58
|
+
check `match yes`.
|
|
59
|
+
|
|
60
|
+
## What it does not do
|
|
61
|
+
|
|
62
|
+
- It does not create a submission, edit authors, topics or other form fields, or upload
|
|
63
|
+
supplementary files.
|
|
64
|
+
- It does not check the PDF against the venue; that is `paperlint lint`.
|
package/docs/talk.md
CHANGED
|
@@ -41,7 +41,7 @@ A video named after the paper is declared once:
|
|
|
41
41
|
```json
|
|
42
42
|
"talk": {
|
|
43
43
|
"mode": "remote-video",
|
|
44
|
-
"files": { "video": "
|
|
44
|
+
"files": { "video": "rule-drift-talk.mp4", "captions": "rule-drift-talk.srt" }
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
package/lib/paper-config.ts
CHANGED
|
@@ -141,6 +141,8 @@ export const SETTINGS_KEYS: Readonly<Record<string, string>> = Object.freeze({
|
|
|
141
141
|
identity:
|
|
142
142
|
"what identifies the authors — names, handles, emails, affiliations, own project names; a blind venue's PDF must not say any of them — anonymity/identity. The root's list and a paper's are joined",
|
|
143
143
|
talk: 'how this paper is presented: { "mode": "remote-video", "dir"?, "files"?, "one_slide"? } — the talk/ rules. A paper\'s own; refused in the root file',
|
|
144
|
+
submission:
|
|
145
|
+
"which submission on the venue's portal is this paper's: { \"id\": <number> } — paperlint submission, with the preset's \"portal\". A paper's own; refused in the root file",
|
|
144
146
|
scripts: "how skill prose names the scripts — consumer.mjs",
|
|
145
147
|
timezone: "the zone deadline anchors are written in — consumer.mjs",
|
|
146
148
|
contactEmail: "the polite-pool address for citation lookups — consumer.mjs",
|
|
@@ -150,7 +152,10 @@ export const SETTINGS_KEYS: Readonly<Record<string, string>> = Object.freeze({
|
|
|
150
152
|
});
|
|
151
153
|
|
|
152
154
|
/** The keys that only mean something for one paper: refused in the root `paperlint.json`. */
|
|
153
|
-
export const PAPER_ONLY_KEYS: readonly string[] = Object.freeze([
|
|
155
|
+
export const PAPER_ONLY_KEYS: readonly string[] = Object.freeze([
|
|
156
|
+
"talk",
|
|
157
|
+
"submission",
|
|
158
|
+
]);
|
|
154
159
|
|
|
155
160
|
/** The keys that only mean something for the whole project: refused in a paper's `paperlint.json`. */
|
|
156
161
|
export const ROOT_ONLY_KEYS: readonly string[] = Object.freeze([
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for `skill-checks.mjs`, for the TypeScript tests that call it. Only what they call is
|
|
3
|
+
* declared; the module stays JavaScript.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** The shared per-skill checks for `skills/<name>/SKILL.md`; rejects naming every failure. */
|
|
7
|
+
export function checkSkill(name: string): Promise<void>;
|
|
@@ -304,6 +304,17 @@ const PACKAGE_CASES = [
|
|
|
304
304
|
],
|
|
305
305
|
collides: ["submit-paper"],
|
|
306
306
|
},
|
|
307
|
+
{
|
|
308
|
+
skill: "submission-portal",
|
|
309
|
+
why: "READ or CHANGE the submission on the HotCRP portal over its API, and prove the portal holds the latest build",
|
|
310
|
+
prompts: [
|
|
311
|
+
"replace the PDF on hotcrp with the new build",
|
|
312
|
+
"проверь, что статья на hotcrp правда в статусе Submitted",
|
|
313
|
+
"залей новый абстракт и пдф в hotcrp, дедлайн через час",
|
|
314
|
+
"какую версию pdf увидят рецензенты — ту, что я собрал сейчас?",
|
|
315
|
+
],
|
|
316
|
+
collides: ["submit-paper", "osf-artifact-upload"],
|
|
317
|
+
},
|
|
307
318
|
{
|
|
308
319
|
skill: "paper-pipeline",
|
|
309
320
|
why: "DRIVE the whole lifecycle — the conductor, when the ask is the whole arc not one step",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paperlint",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "A linter for scientific papers written in LaTeX: catches mistakes before you submit to a conference or journal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"ts-essentials": "^10.2.1",
|
|
34
34
|
"typescript": "^6.0.3",
|
|
35
35
|
"unpdf": "^1.8.1",
|
|
36
|
-
"vigiles": "^
|
|
36
|
+
"vigiles": "^32.1.0",
|
|
37
37
|
"zod": "^4.6.5"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
package/presets/aidc.jsonc
CHANGED
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
// `"blind":true` in the portal's data. anonymity/identity then requires the paper's `identity`.
|
|
27
27
|
"blind": true,
|
|
28
28
|
|
|
29
|
+
// Where submissions go: the HotCRP site named in the deadline note above. `paperlint submission`
|
|
30
|
+
// reads and updates a paper's submission there through HotCRP's API (`/api/paper`). Recorded
|
|
31
|
+
// 2026-10-03: `/api/whoami` on this site answers 401 "Missing credentials" without a token —
|
|
32
|
+
// the HotCRP API, there.
|
|
33
|
+
"portal": { "kind": "hotcrp", "url": "https://aidc.submit.acsac.org" },
|
|
34
|
+
|
|
29
35
|
// What the venue is called in a paper's text (tex/venue-leftover): the workshop, and the
|
|
30
36
|
// conference it is held at.
|
|
31
37
|
"aliases": ["AIDC", "ACSAC"],
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"type": "boolean"
|
|
30
30
|
},
|
|
31
31
|
"aliases": {
|
|
32
|
-
"description": "Other names the venue goes by in a paper's text — its acronym, its parent conference (`[\"AISec\", \"ACM CCS\"]`). Read by `tex/venue-leftover`: a paper that extends another venue and says one of these is flagged. Matched as whole words, case-sensitive. Collected along the `extends` chain, with `name`.",
|
|
32
|
+
"description": "Other names the venue goes by in a paper's text — its acronym, its parent conference (`[\"AISec\", \"ACM CCS\"]`). Read by `tex/venue-leftover`: a paper that extends another venue and says one of these is flagged. Matched as whole words, case-sensitive. Also read by `paper/folder-venue-leftover`, against the words of the paper's folder name, case ignored. Collected along the `extends` chain, with `name`.",
|
|
33
33
|
"type": "array",
|
|
34
34
|
"uniqueItems": true,
|
|
35
35
|
"items": {
|
|
@@ -37,6 +37,22 @@
|
|
|
37
37
|
"minLength": 1
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
"portal": {
|
|
41
|
+
"description": "Where the venue takes submissions, read by `paperlint submission`: the portal's kind (an adapter exists for `hotcrp`) and the site's base URL, the one its pages and `/api/` hang off. A paper says which submission is its own with `submission: { id }` in its paperlint.json. A child's value replaces its parent's.",
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": ["kind", "url"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"kind": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"minLength": 1
|
|
49
|
+
},
|
|
50
|
+
"url": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"pattern": "^https?://[^\\s/]+[^\\s]*$"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
40
56
|
"required_sections": {
|
|
41
57
|
"description": "Sections the venue requires, read by `tex/required-section`. Each is a `\\section` or `\\section*` whose title equals `title` once whitespace is collapsed. `position: \"last\"`: after every section of the body (the ones before the appendix and the bibliography); it may stand after the bibliography. A child preset's list replaces its parent's.",
|
|
42
58
|
"type": "array",
|
|
@@ -94,6 +94,10 @@ const NOT_IN_MAP = new Map([
|
|
|
94
94
|
"osf-artifact-upload",
|
|
95
95
|
"a helper that uploads an artifact file, not a stage of writing a paper",
|
|
96
96
|
],
|
|
97
|
+
[
|
|
98
|
+
"submission-portal",
|
|
99
|
+
"a helper that reads and updates the submission on the portal, reached through `submit-paper`",
|
|
100
|
+
],
|
|
97
101
|
]);
|
|
98
102
|
|
|
99
103
|
for (const name of dirs) {
|