paperlint 11.1.3 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CONTRIBUTING.md +2 -1
  2. package/dist/build.d.ts.map +1 -1
  3. package/dist/build.js +18 -8
  4. package/dist/build.js.map +1 -1
  5. package/dist/latex-log.d.ts +61 -26
  6. package/dist/latex-log.d.ts.map +1 -1
  7. package/dist/latex-log.js +59 -6
  8. package/dist/latex-log.js.map +1 -1
  9. package/dist/latex-loop.d.ts +21 -6
  10. package/dist/latex-loop.d.ts.map +1 -1
  11. package/dist/latex-loop.js +32 -12
  12. package/dist/latex-loop.js.map +1 -1
  13. package/docs/configuration.md +30 -1
  14. package/docs/e2e.md +1 -0
  15. package/fixtures/build-e2e/lost-character/PIPELINE-STATUS.md +3 -0
  16. package/fixtures/build-e2e/lost-character/expect.json +15 -0
  17. package/fixtures/build-e2e/lost-character/paper.tex +8 -0
  18. package/package.json +1 -1
  19. package/presets/agent.jsonc +75 -0
  20. package/presets/agent.md +70 -0
  21. package/presets/agentverify.jsonc +72 -0
  22. package/presets/agentverify.md +85 -0
  23. package/presets/ieee-conference.md +1 -1
  24. package/presets/nlbse.jsonc +76 -0
  25. package/presets/nlbse.md +85 -0
  26. package/scripts/coverage-config.test.ts +3 -0
  27. package/skills/CLAUDE.md +2 -2
  28. package/skills/CLAUDE.md.spec.ts +1 -1
  29. package/src/build.test.ts +46 -3
  30. package/src/build.ts +20 -8
  31. package/src/latex-log.harness.ts +145 -14
  32. package/src/latex-log.ts +105 -16
  33. package/src/latex-loop.harness.ts +70 -34
  34. package/src/latex-loop.ts +51 -30
  35. package/src/paper-settings-commands.test.ts +1 -1
  36. package/src/preset-card-rule.test.ts +3 -0
  37. package/src/presets.test.ts +55 -31
  38. package/src/tex-venue-rules.test.ts +3 -0
  39. package/src/venue-rules.test.ts +2 -2
@@ -399,7 +399,8 @@ papers/my-paper
399
399
  keys or a `.bib` file changed. After that, one **final** pass defines `\finalpass`, which arms
400
400
  the reference guards in `paper-guards.tex`: an undefined `\ref` or `\cite` fails the build
401
401
  there instead of printing `??`. A document that still changes after five passes fails, naming
402
- the file that kept changing. After a green compile the step also writes
402
+ the file that kept changing. The final pass's log is then read for the warnings that fail the
403
+ build (below). After a green compile the step also writes
403
404
  `_build/sources.json`, the record of what TeX read: every file of the paper directory its passes
404
405
  opened (from the `.fls` that `-recorder` makes), whether each came before or after
405
406
  `\begin{document}`, the `.bib` files TeX itself wrote, the databases and keys bibtex read, and a
@@ -452,6 +453,34 @@ without a new one:
452
453
  paper.pdf removed — a stale PDF must not pass for this build
453
454
  ```
454
455
 
456
+ **Some warnings fail the build although pdflatex exits 0**, because the PDF it wrote is wrong. They
457
+ are one list, `FAILING_WARNINGS` in [`src/latex-log.ts`](../src/latex-log.ts), and only the log of
458
+ the **final** pass is read — before the rerun every reference is undefined by construction:
459
+
460
+ | id | the log line | why it fails |
461
+ | ------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------- |
462
+ | `lost-character` | `Missing character: There is no <char> in font <font>!` | the font has no glyph for the character, so the PDF lacks it (`10^-13` → `10^13`) |
463
+ | `undefined-references` | `LaTeX Warning: There were undefined references.` | the PDF prints `??` for a `\ref`, or `[?]` for a `\cite` without natbib |
464
+ | `undefined-citations` | `Package natbib Warning: There were undefined citations.` | the PDF prints `[?]` for a `\cite` (natbib) |
465
+ | `multiply-defined-labels` | `LaTeX Warning: There were multiply-defined labels.` | a `\ref` may point at the wrong one of two labels |
466
+
467
+ Every other warning — overfull and underfull boxes, font substitutions, "Rerun to get …" — leaves
468
+ the build as it was. The failure quotes each distinct line once, with how many times the log has it
469
+ (here `\char"FF` in `cmr10`, measured on TeX Live 2026; TeX writes the character as one raw byte,
470
+ which is no UTF-8 character, so it shows as `�`):
471
+
472
+ ```
473
+ ✗ compile: pdflatex exited 0, but its final log carries a warning that fails the build
474
+ lost-character — the font has no glyph for this character, so pdflatex left it out of the PDF:
475
+ Missing character: There is no � in font cmr10! (2 times)
476
+ full log: papers/my-paper/paper.log
477
+ paper.pdf removed — a stale PDF must not pass for this build
478
+ ```
479
+
480
+ ⚠️ TeX writes the `Missing character` line only while `\tracinglostchars` is above 0. LaTeX sets it
481
+ to 2 (TeX Live 2026); a paper that sets it to 0 hides the line, and this check sees nothing. At 3
482
+ and above TeX makes it an error, and the build fails on pdflatex's exit code instead.
483
+
455
484
  **A paper with no `paper.tex` is a FAILURE, not a skip.** "Nothing to build" and "built" must never
456
485
  look alike: the corpus this came from once let a paper reach its venue without a single paper job
457
486
  having run on it, because a missing build read as nothing to do.
package/docs/e2e.md CHANGED
@@ -98,6 +98,7 @@ A new venue fixture is a new folder: its paper, its `paperlint.json`, its `expec
98
98
  | `broken` | a failing build names pdflatex and its exit code, quotes the error line and its `l.NNN` context, and deletes the stale `paper.pdf` planted before the run |
99
99
  | `no-source` | a paper with no `paper.tex` is named separately, and the run as a whole is a failure |
100
100
  | `empty` | a document with no pages: pdflatex exits 0 and writes no PDF, and that is a failure, not a green `paper.pdf` |
101
+ | `lost-character` | pdflatex exits 0 and writes a PDF without a character its font cannot draw (`\char"FF` in cmr10); the build fails, quotes the `Missing character` line from the log and leaves no `paper.pdf` |
101
102
  | `aidc` | a real `[conference,compsoc]{IEEEtran}` paper builds on paperlint's TeX Live in NimbusRomNo9L, `tex/template`, `tex/required-section` and the `pdf/*` rules find nothing, and `tex/venue-leftover` warns once, on its planted line. It declares `identity` and names nobody, so `anonymity/identity` is silent on a real build, and `format/page-limit` finds the IEEEtran «References» heading |
102
103
  | `anon-*` | six AIDC papers, each planting the declared (invented) name on ONE path, and `anonymity/identity` reports exactly one finding naming where: `author` the author block · `ack` an acknowledgments paragraph · `bib` a self-citation, printed by `IEEEtran.bst` as «A. Example» · `pdfauthor` `\hypersetup{pdfauthor=…}`, on no page · `href` a link whose target is the author's account while its text is not (the anonymous mirror beside it is not reported) · `macro` the name behind `\newcommand` |
103
104
  | `msr` | a real `[10pt,conference]{IEEEtran}` paper whose ten pages of main text include an appendix before the references, then two pages of only references: `format/page-limit`, `tex/template` and `anonymity/identity` find nothing. banal's count of the same PDF (body 9, references 3) would have failed it |
@@ -0,0 +1,3 @@
1
+ # Fixture
2
+
3
+ Stage: draft
@@ -0,0 +1,15 @@
1
+ {
2
+ "$comment": "pdflatex exits 0 and writes a PDF without a character the font has no glyph for; the build fails on the log line (FAILING_WARNINGS in src/latex-log.ts).",
3
+ "build": {
4
+ "outcome": "failed"
5
+ },
6
+ "says": [
7
+ "✗ compile: pdflatex exited 0, but its final log carries a warning that fails the build",
8
+ "lost-character — the font has no glyph for this character, so pdflatex left it out of the PDF:",
9
+ "Missing character: There is no",
10
+ "in font cmr10!"
11
+ ],
12
+ "saysNot": [
13
+ "✓"
14
+ ]
15
+ }
@@ -0,0 +1,8 @@
1
+ % A paper whose font has no glyph for one character. pdflatex prints "Missing character: There is no
2
+ % ... in font cmr10!" to the log (LaTeX sets \tracinglostchars=2), exits 0 and writes a PDF without
3
+ % it -- the way an abstract once printed 7 x 10^13 for 7 x 10^-13. `paperlint build` must fail, quote
4
+ % the log line, and leave no paper.pdf.
5
+ \documentclass{article}
6
+ \begin{document}
7
+ A rate of $7\times 10^{13}$ and a character cmr10 cannot draw: \char"FF.
8
+ \end{document}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperlint",
3
- "version": "11.1.3",
3
+ "version": "12.1.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",
@@ -0,0 +1,75 @@
1
+ // AGENT'27 (the Second International Workshop on Agentic Engineering, an ICSE 2027 workshop) — a
2
+ // VENUE preset over the IEEE conference family. Everything the IEEEtran template decides (page
3
+ // size, columns, fonts, body size, TeX packages) comes from ieee-conference.jsonc; this file adds
4
+ // what AGENT's call for papers sets. Its card, in prose: `agent.md` beside this file.
5
+ //
6
+ // Verbatim from https://conf.researchr.org/home/icse-2027/agent-2027 (fetched 2026-10-26):
7
+ // «Full papers (research or experience): up to 8 pages, including references.»
8
+ // «Short papers (position, emerging research, tool, benchmark, or experience): up to 5 pages,
9
+ // including references.»
10
+ // «All submissions must be original, written in English, and formatted according to the IEEE
11
+ // conference proceedings template. Submissions will be reviewed single-anonymously. Accepted
12
+ // workshop papers will be published by IEEE. It is not possible to pay for extra pages.»
13
+ // «Workshop paper submission deadline: November 13, 2026 / Notification of acceptance: December
14
+ // 11, 2026 / Camera-ready deadline: January 29, 2027 / All dates are Anywhere on Earth (AoE).»
15
+ {
16
+ "type": "venue",
17
+ "name": "AGENT 2027",
18
+ // The call quoted above.
19
+ "url": "https://conf.researchr.org/home/icse-2027/agent-2027",
20
+ "extends": "paperlint:ieee-conference",
21
+
22
+ // «AGENT» alone is an ordinary word: as a name it would flag every paper folder called
23
+ // `agent-…` (paper/folder-venue-leftover compares folder names by words, and `mentions` reaches
24
+ // only the text rules). So the venue is «AGENT 2027» and «AGENT'27» (the call's own spelling,
25
+ // with either apostrophe). ICSE is left out: papers cite ICSE papers by name.
26
+ "aliases": ["AGENT'27", "AGENT\u201927"],
27
+
28
+ // No `template` and no `blind`, on purpose. The call names «the IEEE conference proceedings
29
+ // template» and no class line, so the family's `[conference]` stands (the ICSE workshops page
30
+ // gives `[10pt,conference]{IEEEtran}` for workshop PROPOSALS only). The review is
31
+ // single-anonymous (above), so `blind` — which turns on anonymity/identity — stays unset; the
32
+ // portal agrees: its status data carries no `"blind":true` (read 2026-10-26).
33
+
34
+ // «Submission link» on the call's page: HotCRP.
35
+ "portal": { "kind": "hotcrp", "url": "https://icse2027-agent.hotcrp.com" },
36
+
37
+ // The portal's reading: `"sub":1794657599` on https://icse2027-agent.hotcrp.com/deadlines, shown
38
+ // as «Saturday Nov 14, 2026, 6:59:59 AM EST» = 2026-11-14T11:59:59Z = the end of 13 Nov AoE. The
39
+ // scheduled refresh rewrites it. The call's two other dates are not on the portal; they are the
40
+ // call's, in UTC at the end of the AoE day.
41
+ "deadlines": [
42
+ {
43
+ "what": "submission",
44
+ "at": "2026-11-14T11:59:59Z",
45
+ "source": "portal",
46
+ "url": "https://icse2027-agent.hotcrp.com/deadlines",
47
+ "read": "2026-10-26",
48
+ },
49
+ {
50
+ "what": "notification",
51
+ "at": "2026-12-12T11:59:59Z",
52
+ "source": "call",
53
+ "url": "https://conf.researchr.org/home/icse-2027/agent-2027",
54
+ "read": "2026-10-26",
55
+ },
56
+ {
57
+ "what": "camera-ready",
58
+ "at": "2027-01-30T11:59:59Z",
59
+ "source": "call",
60
+ "url": "https://conf.researchr.org/home/icse-2027/agent-2027",
61
+ "read": "2026-10-26",
62
+ },
63
+ ],
64
+
65
+ "format": {
66
+ // 🔴 THE LIMITS INCLUDE THE REFERENCES («up to 8 pages, including references»), and no key
67
+ // gates a total. `body_pages_max` is banal's body count, which is never more than the total, so
68
+ // a paper over it is over the limit; a paper whose references sit alone on a page after a full
69
+ // body passes this gate and is still over. The card says so.
70
+ "kinds": {
71
+ "full": { "body_pages_max": 8 },
72
+ "short": { "body_pages_max": 5 },
73
+ },
74
+ },
75
+ }
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: "AGENT @ ICSE — venue card"
3
+ ---
4
+
5
+ # AGENT @ ICSE
6
+
7
+ The card of the venue preset `paperlint:agent` ([`agent.jsonc`](agent.jsonc)): what the venue asks
8
+ for, in prose. The numbers a machine checks live in the preset; the section at the end is generated
9
+ from it. The `submit-paper` skill reads this card for the venue's specifics.
10
+
11
+ **Re-verify the call for papers every year**
12
+ ([conf.researchr.org/home/icse-2027/agent-2027](https://conf.researchr.org/home/icse-2027/agent-2027)).
13
+ Sources read 2026-10-26: that page, the portal's
14
+ [deadlines page](https://icse2027-agent.hotcrp.com/deadlines), and the
15
+ [ICSE 2027 workshops page](https://conf.researchr.org/track/icse-2027/icse-2027-workshops).
16
+
17
+ ## The venue (2027 edition)
18
+
19
+ - **Venue**: The Second International Workshop on Agentic Engineering, an ICSE 2027 workshop,
20
+ Mon 26 April 2027, Dublin.
21
+ - **Portal**: HotCRP, `https://icse2027-agent.hotcrp.com/` (the page's «Submission link»).
22
+ - **Format**: «formatted according to the IEEE conference proceedings template». No class line is
23
+ given for papers, so the preset keeps the family's `\documentclass[conference]{IEEEtran}`.
24
+ - **Review**: «Submissions will be reviewed single-anonymously.» The authors' names stay on the
25
+ paper; the portal's status data carries no `"blind":true`, which agrees.
26
+ - **Publisher**: «Accepted workshop papers will be published by IEEE.» The page does not say
27
+ «archival» or offer a non-archival choice.
28
+ - **Deadlines (AoE)**: submission 13 Nov 2026, notification 11 Dec 2026, camera-ready 29 Jan 2027.
29
+ The portal reads `"sub":1794657599`, 2026-11-14T11:59:59Z, the end of 13 Nov AoE: the two agree.
30
+
31
+ ## Paper kinds and limits
32
+
33
+ | kind | pages | what it is (the call's words) |
34
+ | ------- | ----: | ------------------------------------------------------------------------------------------------------------------ |
35
+ | `full` | 8 | «Full papers (research or experience): up to 8 pages, including references.» |
36
+ | `short` | 5 | «Short papers (position, emerging research, tool, benchmark, or experience): up to 5 pages, including references.» |
37
+
38
+ 🔴 **The limit is a total, references included**, and «It is not possible to pay for extra pages.»
39
+ `format/page-limit` can only compare banal's body count with the number, so a paper whose body
40
+ fills the pages and whose references stand alone on one more page passes the rule and is over the
41
+ limit. Count the PDF's pages yourself before submitting.
42
+
43
+ ## What else the preset encodes
44
+
45
+ - **The IEEE template**, through `extends: paperlint:ieee-conference` ([`ieee-conference.md`](ieee-conference.md)).
46
+ - **The venue's name** is `AGENT 2027`, with the aliases `AGENT'27` and `AGENT’27` (what
47
+ `tex/venue-leftover` looks for in another venue's paper). «AGENT» alone is an ordinary word, and
48
+ as a name it would flag every paper folder called `agent-…` (`paper/folder-venue-leftover`).
49
+ - **Portal and deadlines** (`portal`, `deadlines`): the submission reading is the portal's and is
50
+ refreshed by paperlint's scheduled workflow; notification and camera-ready are the call's.
51
+
52
+ ## Not verified
53
+
54
+ - **Remote presentation**: neither the workshop page, the ICSE workshops page nor the ICSE 2027
55
+ site's «Attending» menu states a policy. Ask the chairs before relying on one.
56
+ - **AI / LLM usage policy and required sections**: none stated on the workshop page.
57
+ - **The proceedings' class line**: see Format above; the page links the IEEE templates page only.
58
+
59
+ ## What the preset resolves to
60
+
61
+ <!-- paperlint:preset-rules -->
62
+ <!-- prettier-ignore-start -->
63
+ <!-- Generated from agent.jsonc by `npx eslint --fix` (rule preset/card-rules). Edit the preset, not this section. -->
64
+
65
+ **`paperlint:agent`** — venue preset for AGENT 2027 · call for papers: <https://conf.researchr.org/home/icse-2027/agent-2027> · extends `paperlint:ieee-conference`
66
+
67
+ No preset of this chain sets a rule: under it, every rule keeps paperlint's default.
68
+
69
+ <!-- prettier-ignore-end -->
70
+ <!-- /paperlint:preset-rules -->
@@ -0,0 +1,72 @@
1
+ // AGENTVERIFY 2027 (the International Workshop on Infrastructure for Trustworthy Software Agents, an
2
+ // ICSE 2027 workshop) — a VENUE preset over the IEEE conference family. Everything the IEEEtran
3
+ // template decides comes from ieee-conference.jsonc; this file adds what AGENTVERIFY's call sets.
4
+ // Its card, in prose: `agentverify.md` beside this file.
5
+ //
6
+ // Verbatim from https://agentverify2027.github.io/cfp.html (fetched 2026-10-26):
7
+ // «Full Papers: Maximum of 8 pages, including references.»
8
+ // «Short & Demonstration Papers: Maximum of 4 pages, including references.»
9
+ // «Extended Abstracts: Maximum of 2 pages, including references.»
10
+ // «Papers will be submitted via HotCRP and reviewed double-blind. Submissions should follow the
11
+ // IEEE format in line with ICSE 2027 and present an original contribution.»
12
+ // «Papers are due November 13th, 2026 (AoE).»
13
+ // and from https://agentverify2027.github.io/ (same day): «Paper submission deadline November 13,
14
+ // 2026 / Final notification December 11, 2026 / Camera-ready deadline January 29, 2027 / All
15
+ // deadlines are Anywhere on Earth (AoE).»
16
+ {
17
+ "type": "venue",
18
+ "name": "AGENTVERIFY",
19
+ // The call quoted above.
20
+ "url": "https://agentverify2027.github.io/cfp.html",
21
+ "extends": "paperlint:ieee-conference",
22
+
23
+ // «reviewed double-blind» (the call above), and `"blind":true` in the portal's status data
24
+ // (https://icse2027-agentverify.hotcrp.com/deadlines, read 2026-10-26). anonymity/identity then
25
+ // requires the paper's `identity`.
26
+ "blind": true,
27
+
28
+ // «Submit Your Paper →» on the workshop's site: HotCRP.
29
+ "portal": {
30
+ "kind": "hotcrp",
31
+ "url": "https://icse2027-agentverify.hotcrp.com",
32
+ },
33
+
34
+ // The portal's reading: `"sub":1794657599` = 2026-11-14T11:59:59Z = the end of 13 Nov AoE. It
35
+ // agrees with the call and with the ICSE workshops page; the organizers' email of 2026-10-23
36
+ // (agentverify.md) says the same and that there is no separate abstract deadline, so there is no
37
+ // `registration`. Notification and camera-ready are the site's, at the end of the AoE day.
38
+ "deadlines": [
39
+ {
40
+ "what": "submission",
41
+ "at": "2026-11-14T11:59:59Z",
42
+ "source": "portal",
43
+ "url": "https://icse2027-agentverify.hotcrp.com/deadlines",
44
+ "read": "2026-10-26",
45
+ },
46
+ {
47
+ "what": "notification",
48
+ "at": "2026-12-12T11:59:59Z",
49
+ "source": "call",
50
+ "url": "https://agentverify2027.github.io/",
51
+ "read": "2026-10-26",
52
+ },
53
+ {
54
+ "what": "camera-ready",
55
+ "at": "2027-01-30T11:59:59Z",
56
+ "source": "call",
57
+ "url": "https://agentverify2027.github.io/",
58
+ "read": "2026-10-26",
59
+ },
60
+ ],
61
+
62
+ "format": {
63
+ // 🔴 THE LIMITS INCLUDE THE REFERENCES, and no key gates a total: `body_pages_max` is banal's
64
+ // body count, never more than the total, so a paper over it is over the limit; references alone
65
+ // on a page after a full body pass this gate and are still over (agentverify.md).
66
+ "kinds": {
67
+ "full": { "body_pages_max": 8 },
68
+ "short": { "body_pages_max": 4 },
69
+ "abstract": { "body_pages_max": 2 },
70
+ },
71
+ },
72
+ }
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: "AGENTVERIFY @ ICSE — venue card"
3
+ ---
4
+
5
+ # AGENTVERIFY @ ICSE
6
+
7
+ The card of the venue preset `paperlint:agentverify` ([`agentverify.jsonc`](agentverify.jsonc)):
8
+ what the venue asks for, in prose. The numbers a machine checks live in the preset; the section at
9
+ the end is generated from it. The `submit-paper` skill reads this card for the venue's specifics.
10
+
11
+ **Re-verify the call for papers every year**
12
+ ([agentverify2027.github.io/cfp.html](https://agentverify2027.github.io/cfp.html)). Sources read
13
+ 2026-10-26: that page, [the home page](https://agentverify2027.github.io/), the portal's
14
+ [deadlines page](https://icse2027-agentverify.hotcrp.com/deadlines), and the
15
+ [ICSE 2027 workshops page](https://conf.researchr.org/track/icse-2027/icse-2027-workshops). The
16
+ researchr page `conf.researchr.org/home/agentverify-2027` only redirects to the workshop's site.
17
+
18
+ ## The venue (2027 edition)
19
+
20
+ - **Venue**: Workshop on Infrastructure for Trustworthy Software Agents, an ICSE 2027 workshop,
21
+ Sun 25 April 2027, Dublin.
22
+ - **Portal**: HotCRP, `https://icse2027-agentverify.hotcrp.com/` («Submit Your Paper →»).
23
+ - **Format and review**: «Papers will be submitted via HotCRP and reviewed double-blind.
24
+ Submissions should follow the IEEE format in line with ICSE 2027 and present an original
25
+ contribution.» The portal's status data carries `"blind":true`. No class line is given, so the
26
+ preset keeps the family's `\documentclass[conference]{IEEEtran}`.
27
+ - **Publisher**: «Accepted papers will appear in the ICSE 2027 workshop proceedings by default.»
28
+ The ICSE workshops page: «The workshop papers will be published by the IEEE.» The CFP does not
29
+ say what a non-default route would be, or whether it is archival.
30
+ - **Presenting**: «At least one author of each accepted paper must register and present.»
31
+ - **Deadlines (AoE)**: submission 13 Nov 2026, reviews due 5 Dec, final notification 11 Dec 2026,
32
+ camera-ready 29 Jan 2027.
33
+
34
+ ## 🔴 The submission deadline moved
35
+
36
+ The organizers' email of 2026-10-23 (as received by an author; the email itself is not public):
37
+
38
+ > The submission deadline for AGENTVERIFY 2027 has been updated to November 13, 2026. We do not
39
+ > have a separate abstract submission deadline.
40
+
41
+ Source: **organizers' email, 2026-10-23**. On 2026-10-26 every public source agreed with it: the
42
+ CFP, the home page («Papers are due November 13th, 2026 (AoE)»), the ICSE workshops page («Workshop
43
+ Papers Submission Deadline for all Workshops: 13 November 2026») and the portal (`"sub":1794657599`,
44
+ 2026-11-14T11:59:59Z). None of the pages read showed 6 November. If a cached copy of any of them
45
+ does, the email and the live pages win.
46
+
47
+ ## Paper kinds and limits
48
+
49
+ | kind | pages | the call's words |
50
+ | ---------- | ----: | --------------------------------------------------------------------------------------------------------------------------------------- |
51
+ | `full` | 8 | «Full Papers: Maximum of 8 pages, including references.» |
52
+ | `short` | 4 | «Short & Demonstration Papers: Maximum of 4 pages, including references.» |
53
+ | `abstract` | 2 | «Extended Abstracts: Maximum of 2 pages, including references.» They «are free of APC charges and will be included in the proceedings.» |
54
+
55
+ 🔴 **Every limit is a total, references included.** `format/page-limit` can only compare banal's
56
+ body count with the number, so references standing alone on a page after a full body pass the rule
57
+ and are over the limit. Count the PDF's pages yourself before submitting.
58
+
59
+ ## What else the preset encodes
60
+
61
+ - **The IEEE template**, through `extends: paperlint:ieee-conference` ([`ieee-conference.md`](ieee-conference.md)).
62
+ - **Double-blind review** (`blind`), so `anonymity/identity` checks the PDF against the paper's
63
+ declared `identity`.
64
+ - **Portal and deadlines**: the submission reading is the portal's, refreshed by paperlint's
65
+ scheduled workflow; notification and camera-ready are the site's. No `registration`: there is no
66
+ abstract deadline.
67
+
68
+ ## Not verified
69
+
70
+ - **Remote presentation**: not stated (only «must register and present»).
71
+ - **Archival / non-archival choice**: «by default» suggests an alternative; none is described.
72
+ - **AI / LLM usage policy and required sections**: none stated.
73
+
74
+ ## What the preset resolves to
75
+
76
+ <!-- paperlint:preset-rules -->
77
+ <!-- prettier-ignore-start -->
78
+ <!-- Generated from agentverify.jsonc by `npx eslint --fix` (rule preset/card-rules). Edit the preset, not this section. -->
79
+
80
+ **`paperlint:agentverify`** — venue preset for AGENTVERIFY · call for papers: <https://agentverify2027.github.io/cfp.html> · extends `paperlint:ieee-conference`
81
+
82
+ No preset of this chain sets a rule: under it, every rule keeps paperlint's default.
83
+
84
+ <!-- prettier-ignore-end -->
85
+ <!-- /paperlint:preset-rules -->
@@ -30,7 +30,7 @@ versions. `compsoc` changes the text block and the headings, and nothing the `pd
30
30
  <!-- prettier-ignore-start -->
31
31
  <!-- Generated from ieee-conference.jsonc by `npx eslint --fix` (rule preset/card-rules). Edit the preset, not this section. -->
32
32
 
33
- **`paperlint:ieee-conference`** — template family, no venue of its own · extended by `paperlint:aidc`, `paperlint:msr`
33
+ **`paperlint:ieee-conference`** — template family, no venue of its own · extended by `paperlint:agent`, `paperlint:agentverify`, `paperlint:aidc`, `paperlint:msr`, `paperlint:nlbse`
34
34
 
35
35
  No preset of this chain sets a rule: under it, every rule keeps paperlint's default.
36
36
 
@@ -0,0 +1,76 @@
1
+ // NLBSE 2027 (the 6th Natural Language-based Software Engineering Workshop, an ICSE 2027 workshop)
2
+ // — a VENUE preset over the IEEE conference family. Everything the IEEEtran template decides comes
3
+ // from ieee-conference.jsonc; this file adds what NLBSE's call sets. Its card, in prose:
4
+ // `nlbse.md` beside this file.
5
+ //
6
+ // Verbatim from https://conf.researchr.org/home/icse-2027/nlbse-2027 (fetched 2026-10-26):
7
+ // «Full papers (maximum of 8 pages, including references).» · «Education tools and materials
8
+ // (maximum of 8 pages, including references).» · «Replication Studies and Negative results
9
+ // (maximum of 8 pages, including references).» · «Short and demonstration papers (maximum of 4
10
+ // pages, including references).» · «Position papers (maximum of 2 pages, including
11
+ // references).» · «Tool Competition entries (maximum of 4 pages, including references).»
12
+ // «All submissions must conform to the ICSE’27 formatting and submission instructions. All
13
+ // submissions must be anonymized, in PDF format and should be performed electronically through
14
+ // HotCRP: https://icse2027-nlbse.hotcrp.com/.»
15
+ // Dates: «Fri 13 Nov 2026 (updated) Paper submission / Fri 27 Nov 2026 (new) Tool
16
+ // competition/Research challenge paper submission / Fri 11 Dec 2026 Author notification / Fri
17
+ // 29 Jan 2027 Camera ready», «All dates are Anywhere on Earth (AoE).»
18
+ {
19
+ "type": "venue",
20
+ "name": "NLBSE",
21
+ // The call quoted above.
22
+ "url": "https://conf.researchr.org/home/icse-2027/nlbse-2027",
23
+ "extends": "paperlint:ieee-conference",
24
+
25
+ // «All submissions must be anonymized» (the call above), and `"blind":true` in the portal's
26
+ // status data (https://icse2027-nlbse.hotcrp.com/deadlines, read 2026-10-26). The call never
27
+ // says «double-blind»; anonymity/identity then requires the paper's `identity`.
28
+ "blind": true,
29
+
30
+ // «should be performed electronically through HotCRP» (the call above).
31
+ "portal": { "kind": "hotcrp", "url": "https://icse2027-nlbse.hotcrp.com" },
32
+
33
+ // 🔴 THE PORTAL HOLDS NO DEADLINE YET: on 2026-10-26 its status data read `"sub":{"open":false}`
34
+ // with no date, while the call lists 13 Nov. So these are the call's readings, in UTC at the end
35
+ // of the AoE day; the refresh adds the portal's the day it publishes one (the earlier binds).
36
+ // The competition papers' 27 Nov is in the card only: one reading per kind and source.
37
+ "deadlines": [
38
+ {
39
+ "what": "submission",
40
+ "at": "2026-11-14T11:59:59Z",
41
+ "source": "call",
42
+ "url": "https://conf.researchr.org/home/icse-2027/nlbse-2027",
43
+ "read": "2026-10-26",
44
+ },
45
+ {
46
+ "what": "notification",
47
+ "at": "2026-12-12T11:59:59Z",
48
+ "source": "call",
49
+ "url": "https://conf.researchr.org/home/icse-2027/nlbse-2027",
50
+ "read": "2026-10-26",
51
+ },
52
+ {
53
+ "what": "camera-ready",
54
+ "at": "2027-01-30T11:59:59Z",
55
+ "source": "call",
56
+ "url": "https://conf.researchr.org/home/icse-2027/nlbse-2027",
57
+ "read": "2026-10-26",
58
+ },
59
+ ],
60
+
61
+ "format": {
62
+ // 🔴 EVERY LIMIT INCLUDES THE REFERENCES, and no key gates a total: `body_pages_max` is banal's
63
+ // body count, never more than the total, so a paper over it is over the limit; references alone
64
+ // on a page after a full body pass this gate and are still over (nlbse.md). The competition
65
+ // papers' «2-4 pages» (Multitask Code Classification) does not say whether references count, so
66
+ // only the call's «Tool Competition entries» line is a kind; the research challenge has no limit.
67
+ "kinds": {
68
+ "full": { "body_pages_max": 8 },
69
+ "education": { "body_pages_max": 8 },
70
+ "replication": { "body_pages_max": 8 },
71
+ "short": { "body_pages_max": 4 },
72
+ "position": { "body_pages_max": 2 },
73
+ "tool-competition": { "body_pages_max": 4 },
74
+ },
75
+ },
76
+ }
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: "NLBSE @ ICSE — venue card"
3
+ ---
4
+
5
+ # NLBSE @ ICSE
6
+
7
+ The card of the venue preset `paperlint:nlbse` ([`nlbse.jsonc`](nlbse.jsonc)): what the venue asks
8
+ for, in prose. The numbers a machine checks live in the preset; the section at the end is generated
9
+ from it. The `submit-paper` skill reads this card for the venue's specifics.
10
+
11
+ **Re-verify the call for papers every year**
12
+ ([conf.researchr.org/home/icse-2027/nlbse-2027](https://conf.researchr.org/home/icse-2027/nlbse-2027)).
13
+ Sources read 2026-10-26: that page, the portal's
14
+ [deadlines page](https://icse2027-nlbse.hotcrp.com/deadlines), and the
15
+ [ICSE 2027 workshops page](https://conf.researchr.org/track/icse-2027/icse-2027-workshops).
16
+
17
+ ## The venue (2027 edition)
18
+
19
+ - **Venue**: The 6th Natural Language-based Software Engineering Workshop, an ICSE 2027 workshop,
20
+ Sun 25 April 2027, Dublin. «NLBSE 2027 is sponsored by ACM SIGSOFT and IEEE-CS TCSE.»
21
+ - **Portal**: HotCRP, `https://icse2027-nlbse.hotcrp.com/`.
22
+ - **Format**: «All submissions must conform to the ICSE’27 formatting and submission instructions.»
23
+ No template or class line is named on the page; the ICSE 2027 workshops page says «The workshop
24
+ papers will be published by the IEEE.» and links the IEEE templates only for workshop proposals.
25
+ The preset keeps the family's `\documentclass[conference]{IEEEtran}`, an inference, not a quote.
26
+ - **Review**: «All submissions must be anonymized, in PDF format». The call never says single- or
27
+ double-blind; the portal's status data carries `"blind":true`, which the preset follows.
28
+ - **Publisher**: the call says only «The accepted submissions will be published in the workshop
29
+ proceedings.» (tool competitions) and «Accepted papers will appear in the NLBSE ’27 proceedings.»
30
+ (research challenge, skill classification). IEEE comes from the ICSE page above. No archival /
31
+ non-archival choice is mentioned.
32
+ - **Deadlines (AoE)**: paper submission 13 Nov 2026 (marked «updated»), tool competition and
33
+ research challenge papers **27 Nov 2026** (marked «new»), notification 11 Dec 2026, camera-ready
34
+ 29 Jan 2027. Only the 13 Nov line is in the preset.
35
+ - 🔴 **Disagreement**: the call lists 13 Nov, but the portal's status data on 2026-10-26 reads
36
+ `"sub":{"open":false}` with no date, i.e. it was closed and showed none. The preset therefore
37
+ carries the call's reading until the portal publishes one.
38
+
39
+ ## Paper kinds and limits
40
+
41
+ Every limit says «including references».
42
+
43
+ | kind | pages | the call's words |
44
+ | ------------------ | ----: | -------------------------------------------------------------------------------------- |
45
+ | `full` | 8 | «Full papers (maximum of 8 pages, including references).» |
46
+ | `education` | 8 | «Education tools and materials (maximum of 8 pages, including references).» |
47
+ | `replication` | 8 | «Replication Studies and Negative results (maximum of 8 pages, including references).» |
48
+ | `short` | 4 | «Short and demonstration papers (maximum of 4 pages, including references).» |
49
+ | `position` | 2 | «Position papers (maximum of 2 pages, including references).» |
50
+ | `tool-competition` | 4 | «Tool Competition entries (maximum of 4 pages, including references).» |
51
+
52
+ Two competition papers have no kind. Multitask Code Classification: «you must write a paper (2-4
53
+ pages)», references not mentioned. The research challenge states no limit.
54
+
55
+ 🔴 **The limits are totals.** `format/page-limit` can only compare banal's body count with the
56
+ number, so references standing alone on a page after a full body pass the rule and are over the
57
+ limit. Count the PDF's pages yourself before submitting.
58
+
59
+ ## What else the preset encodes
60
+
61
+ - **The IEEE template**, through `extends: paperlint:ieee-conference` ([`ieee-conference.md`](ieee-conference.md)).
62
+ - **Anonymous review** (`blind`), so `anonymity/identity` checks the PDF against the paper's
63
+ declared `identity`.
64
+ - **Portal and deadlines**: all three readings are the call's for now (see Disagreement above).
65
+
66
+ ## Not verified
67
+
68
+ - **Remote presentation**: not stated on the page.
69
+ - **AI / LLM usage policy**: not stated. Required content exists only for the competition papers
70
+ (model, pre-processing, tuning, validation results, code link; the challenge: research problem,
71
+ role of natural language, dataset version, methods, findings, reproducibility link).
72
+ - **The template's class line** and **whether a non-archival route exists**: not stated.
73
+
74
+ ## What the preset resolves to
75
+
76
+ <!-- paperlint:preset-rules -->
77
+ <!-- prettier-ignore-start -->
78
+ <!-- Generated from nlbse.jsonc by `npx eslint --fix` (rule preset/card-rules). Edit the preset, not this section. -->
79
+
80
+ **`paperlint:nlbse`** — venue preset for NLBSE · call for papers: <https://conf.researchr.org/home/icse-2027/nlbse-2027> · extends `paperlint:ieee-conference`
81
+
82
+ No preset of this chain sets a rule: under it, every rule keeps paperlint's default.
83
+
84
+ <!-- prettier-ignore-end -->
85
+ <!-- /paperlint:preset-rules -->
@@ -403,6 +403,9 @@ test("the exclude list is exactly the justified set", () => {
403
403
  // skill and CLAUDE.md sources vigiles compiles; a glob's `**` skips a dot directory
404
404
  "**/*.spec.ts",
405
405
  ".github/*.spec.ts",
406
+ // the same two kinds in a maintainer skill, which does not ship (`.claude/skills/<name>/`)
407
+ ".claude/skills/*/*.spec.ts",
408
+ ".claude/skills/*/*.eval.*",
406
409
  // type declarations
407
410
  "**/*.d.ts",
408
411
  "**/*.d.mts",
package/skills/CLAUDE.md CHANGED
@@ -1,4 +1,4 @@
1
- <!-- vigiles:sha256:e0aa2cec8926b04f compiled from skills/CLAUDE.md.spec.ts -->
1
+ <!-- vigiles:sha256:b9427668f4875ea5 compiled from skills/CLAUDE.md.spec.ts -->
2
2
 
3
3
  # CLAUDE.md
4
4
 
@@ -12,7 +12,7 @@ package's location come from `skills/paper-pipeline/scripts/consumer.mjs`; the l
12
12
 
13
13
  ### Skills Ship In Skills
14
14
 
15
- **Guidance only** — Skills ship in `skills/`, never `.claude/skills/`. `paperlint init` symlinks each one into the consumer's `.claude/skills/<name>`; the link's directory name is the skill's name. `skills/` is the npm layout: of 855 packages scanned, 336 shipped `skills/` against 15 `.claude/skills/`. Rejected: leaving the skills for Claude Code to find inside `node_modules` (`docs/install.md`); a symlink loads at startup, deterministically.
15
+ **Guidance only** — Skills ship in `skills/`, never `.claude/skills/`. `paperlint init` symlinks each one into the consumer's `.claude/skills/<name>`; the link's directory name is the skill's name. `skills/` is the npm layout: of 855 packages scanned, 336 shipped `skills/` against 15 `.claude/skills/`. Rejected: leaving the skills for Claude Code to find inside `node_modules` (`docs/install.md`); a symlink loads at startup, deterministically. A skill for working on paperlint itself (it edits this repository's presets, tests or source) does not ship: it lives in `.claude/skills/<name>/` as a real directory, outside `files`, and no shipped skill or user doc names it (`add-venue`).
16
16
 
17
17
  ### A Criterion That Judges Prose
18
18
 
@@ -9,7 +9,7 @@ ${file("src/link-skills.ts")}; install-specific paths are flagged by ${file("esl
9
9
  },
10
10
  rules: {
11
11
  "skills-ship-in-skills": guidance(
12
- "Skills ship in `skills/`, never `.claude/skills/`. `paperlint init` symlinks each one into the consumer's `.claude/skills/<name>`; the link's directory name is the skill's name. `skills/` is the npm layout: of 855 packages scanned, 336 shipped `skills/` against 15 `.claude/skills/`. Rejected: leaving the skills for Claude Code to find inside `node_modules` (`docs/install.md`); a symlink loads at startup, deterministically.",
12
+ "Skills ship in `skills/`, never `.claude/skills/`. `paperlint init` symlinks each one into the consumer's `.claude/skills/<name>`; the link's directory name is the skill's name. `skills/` is the npm layout: of 855 packages scanned, 336 shipped `skills/` against 15 `.claude/skills/`. Rejected: leaving the skills for Claude Code to find inside `node_modules` (`docs/install.md`); a symlink loads at startup, deterministically. A skill for working on paperlint itself (it edits this repository's presets, tests or source) does not ship: it lives in `.claude/skills/<name>/` as a real directory, outside `files`, and no shipped skill or user doc names it (`add-venue`).",
13
13
  ),
14
14
  "a-criterion-that-judges-prose": guidance(
15
15
  'It follows the five principles in `eslint-rules/CLAUDE.md` ("A rule that judges prose"). A skill does not grep prose for what a rule can count.',