paperlint 5.0.0 → 6.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/CLAUDE.md +13 -0
- package/CONTRIBUTING.md +3 -0
- package/README.md +8 -8
- package/bin/paperlint.mjs +5 -1
- package/dist/adapters/latex/index.d.ts +2 -1
- package/dist/adapters/latex/index.d.ts.map +1 -1
- package/dist/adapters/latex/index.js +6 -2
- package/dist/adapters/latex/index.js.map +1 -1
- package/dist/adapters/latex/layout.d.ts +27 -0
- package/dist/adapters/latex/layout.d.ts.map +1 -0
- package/dist/adapters/latex/layout.js +62 -0
- package/dist/adapters/latex/layout.js.map +1 -0
- package/dist/adapters/latex/nodes.d.ts.map +1 -1
- package/dist/adapters/latex/nodes.js +11 -1
- package/dist/adapters/latex/nodes.js.map +1 -1
- package/dist/adapters/latex/parse.d.ts.map +1 -1
- package/dist/adapters/latex/parse.js +5 -1
- package/dist/adapters/latex/parse.js.map +1 -1
- package/dist/adapters/latex/prose.d.ts +6 -1
- package/dist/adapters/latex/prose.d.ts.map +1 -1
- package/dist/adapters/latex/prose.js +142 -31
- package/dist/adapters/latex/prose.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +35 -18
- package/dist/cli.js.map +1 -1
- package/dist/domain/anonymity.d.ts +68 -0
- package/dist/domain/anonymity.d.ts.map +1 -0
- package/dist/domain/anonymity.js +94 -0
- package/dist/domain/anonymity.js.map +1 -0
- package/dist/domain/body-pages.d.ts +69 -0
- package/dist/domain/body-pages.d.ts.map +1 -0
- package/dist/domain/body-pages.js +141 -0
- package/dist/domain/body-pages.js.map +1 -0
- package/dist/domain/register.d.ts +96 -0
- package/dist/domain/register.d.ts.map +1 -0
- package/dist/domain/register.js +136 -0
- package/dist/domain/register.js.map +1 -0
- package/dist/domain/tex-document.d.ts +28 -0
- package/dist/domain/tex-document.d.ts.map +1 -1
- package/dist/domain/tex-document.js +8 -3
- package/dist/domain/tex-document.js.map +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.js +2 -2
- package/dist/facts-file.d.ts +28 -2
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +54 -9
- package/dist/facts-file.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +2 -1
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/paper-settings.d.ts +11 -0
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +38 -4
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-content.d.ts +40 -0
- package/dist/pdf-content.d.ts.map +1 -0
- package/dist/pdf-content.js +97 -0
- package/dist/pdf-content.js.map +1 -0
- package/dist/pdf-facts.d.ts +30 -0
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +37 -1
- package/dist/pdf-facts.js.map +1 -1
- package/dist/ports/latex.d.ts +8 -1
- package/dist/ports/latex.d.ts.map +1 -1
- package/dist/presets.d.ts +5 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +8 -1
- package/dist/presets.js.map +1 -1
- package/dist/register-bands.d.ts +37 -0
- package/dist/register-bands.d.ts.map +1 -0
- package/dist/register-bands.js +196 -0
- package/dist/register-bands.js.map +1 -0
- package/dist/register.d.ts +4 -2
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +6 -45
- package/dist/register.js.map +1 -1
- package/dist/tex-requirements.d.ts +10 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +29 -6
- package/dist/tex-requirements.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +8 -2
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js +40 -0
- package/dist/tex-venue-rules.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts +38 -8
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +179 -41
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +18 -16
- package/docs/e2e.md +32 -11
- package/docs/rules/anonymity/identity.md +111 -0
- package/docs/rules/format/layout-override.md +61 -0
- package/docs/rules/format/page-limit.md +108 -0
- package/docs/rules/pdf/body-size.md +87 -0
- package/docs/rules/tex/claim-emphasis.md +71 -0
- package/docs/rules/tex/contrast-frames.md +100 -0
- package/docs/rules/tex/relation-markers.md +72 -0
- package/docs/rules.md +59 -50
- package/eslint-rules/pdf-last-page-balance.harness.mjs +6 -1
- package/eslint-rules/pdf-last-page-balance.ts +2 -2
- package/fixtures/build-e2e/aidc/expect.json +1 -1
- package/fixtures/build-e2e/aidc/paperlint.json +1 -1
- package/fixtures/build-e2e/anon-ack/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-ack/expect.json +19 -0
- package/fixtures/build-e2e/anon-ack/paper.tex +31 -0
- package/fixtures/build-e2e/anon-ack/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-author/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-author/expect.json +19 -0
- package/fixtures/build-e2e/anon-author/paper.tex +29 -0
- package/fixtures/build-e2e/anon-author/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-bib/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-bib/expect.json +20 -0
- package/fixtures/build-e2e/anon-bib/paper.tex +35 -0
- package/fixtures/build-e2e/anon-bib/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-href/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-href/expect.json +19 -0
- package/fixtures/build-e2e/anon-href/paper.tex +30 -0
- package/fixtures/build-e2e/anon-href/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-macro/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-macro/expect.json +19 -0
- package/fixtures/build-e2e/anon-macro/paper.tex +30 -0
- package/fixtures/build-e2e/anon-macro/paperlint.json +1 -0
- package/fixtures/build-e2e/anon-pdfauthor/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/anon-pdfauthor/expect.json +19 -0
- package/fixtures/build-e2e/anon-pdfauthor/paper.tex +31 -0
- package/fixtures/build-e2e/anon-pdfauthor/paperlint.json +1 -0
- package/fixtures/build-e2e/unbalanced/expect.json +2 -2
- package/lib/paper-config.ts +3 -1
- package/package.json +1 -1
- package/presets/acm-sigconf.jsonc +3 -1
- package/presets/aidc.jsonc +66 -17
- package/presets/ieee-conference.jsonc +8 -0
- package/presets/venue-profile.schema.json +57 -1
- package/skills/grade-paper-writing/SKILL.md +59 -27
- package/skills/grade-paper-writing/SKILL.md.spec.ts +58 -26
- package/skills/render-paper/extract-pdf-facts.harness.ts +3 -3
- package/src/adapters/latex/index.test.ts +91 -0
- package/src/adapters/latex/index.ts +6 -2
- package/src/adapters/latex/layout.ts +106 -0
- package/src/adapters/latex/nodes.ts +11 -3
- package/src/adapters/latex/parse.ts +5 -1
- package/src/adapters/latex/prose.ts +188 -58
- package/src/build.harness.mjs +2 -2
- package/src/build.test.ts +5 -0
- package/src/cli.test.ts +13 -0
- package/src/cli.ts +50 -17
- package/src/domain/anonymity.test.ts +163 -0
- package/src/domain/anonymity.ts +129 -0
- package/src/domain/body-pages.test.ts +300 -0
- package/src/domain/body-pages.ts +223 -0
- package/src/domain/register.test.ts +153 -0
- package/src/domain/register.ts +261 -0
- package/src/domain/tex-document.ts +47 -3
- package/src/facts-file.test.ts +100 -4
- package/src/facts-file.ts +91 -9
- package/src/new-paper.test.ts +7 -1
- package/src/paper-settings.test.ts +63 -6
- package/src/paper-settings.ts +53 -5
- package/src/pdf-content.test.ts +71 -0
- package/src/pdf-content.ts +125 -0
- package/src/pdf-facts.test.ts +110 -2
- package/src/pdf-facts.ts +106 -8
- package/src/ports/latex.ts +9 -0
- package/src/presets.ts +15 -9
- package/src/register-bands.test.ts +327 -0
- package/src/register-bands.ts +291 -0
- package/src/register.ts +7 -37
- package/src/rule-cases.test.ts +96 -20
- package/src/rule-docs.test.ts +0 -2
- package/src/tex-requirements.ts +56 -8
- package/src/tex-venue-rules.test.ts +110 -5
- package/src/tex-venue-rules.ts +64 -3
- package/src/types.ts +2 -0
- package/src/venue-rules.test.ts +351 -39
- package/src/venue-rules.ts +247 -47
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "anonymity/identity on a real IEEEtran build: D: the name only in the PDF metadata, set by hyperref; no page shows it. Exactly one finding, naming where.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf"
|
|
5
|
+
},
|
|
6
|
+
"lint": {
|
|
7
|
+
"rules": {
|
|
8
|
+
"anonymity/identity": [
|
|
9
|
+
{
|
|
10
|
+
"severity": 2,
|
|
11
|
+
"says": [
|
|
12
|
+
"PDF metadata: Author",
|
|
13
|
+
"«Ada Example»"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
% D: the name only in the PDF metadata, set by hyperref; no page shows it.
|
|
2
|
+
% The declared identity is invented: "Ada Example", handle "adaexample" (paperlint.json).
|
|
3
|
+
\documentclass[conference,compsoc]{IEEEtran}
|
|
4
|
+
\usepackage{hyperref}
|
|
5
|
+
\hypersetup{pdfauthor={Ada Example}}
|
|
6
|
+
\begin{filecontents*}{refs.bib}
|
|
7
|
+
@article{knuth84,
|
|
8
|
+
title = {Literate Programming},
|
|
9
|
+
author = {Knuth, Donald E.},
|
|
10
|
+
journal = {The Computer Journal},
|
|
11
|
+
volume = {27},
|
|
12
|
+
number = {2},
|
|
13
|
+
pages = {97--111},
|
|
14
|
+
year = {1984},
|
|
15
|
+
doi = {10.1093/comjnl/27.2.97}
|
|
16
|
+
}
|
|
17
|
+
\end{filecontents*}
|
|
18
|
+
\begin{document}
|
|
19
|
+
\title{A Fixture for Double-Blind Review}
|
|
20
|
+
\author{\IEEEauthorblockN{Anonymous Authors}}
|
|
21
|
+
\maketitle
|
|
22
|
+
\section{Introduction}
|
|
23
|
+
This paper builds on earlier work~\cite{knuth84}.
|
|
24
|
+
|
|
25
|
+
\section{Conclusion}
|
|
26
|
+
The conclusion restates that the fixture builds.
|
|
27
|
+
\bibliographystyle{IEEEtran}
|
|
28
|
+
\bibliography{refs}
|
|
29
|
+
\section*{LLM Usage Statement}
|
|
30
|
+
No LLMs were used in writing this fixture.
|
|
31
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:aidc", "kind": "short", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"facts": {
|
|
21
|
-
"schema":
|
|
21
|
+
"schema": 3,
|
|
22
22
|
"lastPageColumnsPt": [
|
|
23
23
|
621.5,
|
|
24
24
|
264.8
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"pdf/profile": [],
|
|
46
46
|
"pdf/fonts": [],
|
|
47
47
|
"pdf/geometry": [],
|
|
48
|
-
"
|
|
48
|
+
"format/page-limit": [],
|
|
49
49
|
"pdf/body-size": [],
|
|
50
50
|
"pdf/measured": [
|
|
51
51
|
{
|
package/lib/paper-config.ts
CHANGED
|
@@ -136,8 +136,10 @@ export const SETTINGS_KEYS: Readonly<Record<string, string>> = Object.freeze({
|
|
|
136
136
|
"rule overrides: { id: severity } for every paper in scope, or ESLint blocks (files, ignores, rules) — paperlint lint",
|
|
137
137
|
extends:
|
|
138
138
|
"the venue preset: paperlint:<name> or ./path.jsonc — the pdf/ venue rules, paperlint build",
|
|
139
|
-
kind: "the kind of paper, whose page limit applies —
|
|
139
|
+
kind: "the kind of paper, whose page limit applies — format/page-limit",
|
|
140
140
|
pdf: "where the built PDF is, relative to the paper, when it is not paper.pdf — the facts",
|
|
141
|
+
identity:
|
|
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",
|
|
141
143
|
scripts: "how skill prose names the scripts — consumer.mjs",
|
|
142
144
|
timezone: "the zone deadline anchors are written in — consumer.mjs",
|
|
143
145
|
contactEmail: "the polite-pool address for citation lookups — consumer.mjs",
|
package/package.json
CHANGED
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
// «font size is 9 pt for all body text»
|
|
75
75
|
"body_pt": 9,
|
|
76
76
|
// banal measures the MODE of the rendered text, not the declared size (measured 08-26: 9.30 at
|
|
77
|
-
// acmart's declared 9). Hence the tolerance
|
|
77
|
+
// acmart's declared 9). Hence the tolerance: banal reads 0.3 pt high on every template measured
|
|
78
|
+
// (fixtures/accepted-papers/body-size.json), and 0.5 absorbs that while a paper one size off is
|
|
79
|
+
// still reported.
|
|
78
80
|
"body_pt_tol": 0.5,
|
|
79
81
|
|
|
80
82
|
// «font size of the references can be from 7 pt to 9 pt»
|
package/presets/aidc.jsonc
CHANGED
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
{
|
|
23
23
|
"extends": "paperlint:ieee-conference",
|
|
24
24
|
|
|
25
|
+
// «Submissions must be properly anonymized for double-blind review.» (the call above), and
|
|
26
|
+
// `"blind":true` in the portal's data. anonymity/identity then requires the paper's `identity`.
|
|
27
|
+
"blind": true,
|
|
28
|
+
|
|
25
29
|
// What the venue is called in a paper's text (tex/venue-leftover): the workshop, and the
|
|
26
30
|
// conference it is held at.
|
|
27
31
|
"aliases": ["AIDC", "ACSAC"],
|
|
@@ -39,35 +43,80 @@
|
|
|
39
43
|
// for) is not a section with this title and does not count.
|
|
40
44
|
"required_sections": [{ "title": "LLM Usage Statement", "position": "last" }],
|
|
41
45
|
|
|
46
|
+
// THE REGISTER OF THE BODY IS JUDGED AGAINST ACSAC, AIDC'S PARENT CONFERENCE: AIDC 2026 is the
|
|
47
|
+
// workshop's first edition, so it has no accepted papers yet, and it uses ACSAC's template. The
|
|
48
|
+
// anchors are the five accepted ACSAC papers in fixtures/accepted-papers/, measured by paperlint's
|
|
49
|
+
// own counters on their LaTeX source (tex/contrast-frames, tex/claim-emphasis, tex/relation-markers).
|
|
50
|
+
// src/register-bands.test.ts re-measures every anchor that has a fixture and requires these exact
|
|
51
|
+
// numbers, so a change to a counter changes this list in the same commit. The bands they set, per
|
|
52
|
+
// 10,000 words (the anchors' range, widened by two Poisson standard deviations at each end):
|
|
53
|
+
// contrast frames anchors 1.3–5.5 band 0–10.4
|
|
54
|
+
// claims in bold anchors 0.0–10.4 band 0–17.8
|
|
55
|
+
// relation markers anchors 39.4–112.8 band 25.4–135.0
|
|
56
|
+
"register": {
|
|
57
|
+
"anchors": [
|
|
58
|
+
{
|
|
59
|
+
"paper": "barovox-acsac24",
|
|
60
|
+
"words": 7670,
|
|
61
|
+
"contrast_frames": 1,
|
|
62
|
+
"claim_emphasis": 8,
|
|
63
|
+
"relation_markers": 31,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"paper": "leaking-queries-acsac25",
|
|
67
|
+
"words": 9133,
|
|
68
|
+
"contrast_frames": 5,
|
|
69
|
+
"claim_emphasis": 0,
|
|
70
|
+
"relation_markers": 103,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"paper": "llm-splained-acsac25",
|
|
74
|
+
"words": 9529,
|
|
75
|
+
"contrast_frames": 4,
|
|
76
|
+
"claim_emphasis": 1,
|
|
77
|
+
"relation_markers": 84,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"paper": "rr-dataset-quality-acsac24",
|
|
81
|
+
"words": 8130,
|
|
82
|
+
"contrast_frames": 3,
|
|
83
|
+
"claim_emphasis": 0,
|
|
84
|
+
"relation_markers": 32,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"paper": "secure-acsac24",
|
|
88
|
+
"words": 7519,
|
|
89
|
+
"contrast_frames": 3,
|
|
90
|
+
"claim_emphasis": 0,
|
|
91
|
+
"relation_markers": 38,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
|
|
42
96
|
"format": {
|
|
43
97
|
// \textwidth and \textheight of [conference,compsoc], measured (ieee-conference.jsonc).
|
|
44
98
|
"textblock_w_in": 7.0,
|
|
45
99
|
"textblock_h_in": 9.02,
|
|
46
100
|
|
|
47
|
-
// 🔴 PAGE
|
|
48
|
-
// and references by what is on them, and a page that holds ANY non-bibliography text
|
|
49
|
-
// body. Measured 2026-09-27 on a [conference,compsoc] paper whose body ends at the
|
|
50
|
-
// page 12:
|
|
101
|
+
// 🔴 THE PAGE LIMIT IS COUNTED BEFORE THE REFERENCES, NOT BY banal. banal splits pages into
|
|
102
|
+
// body and references by what is on them, and a page that holds ANY non-bibliography text
|
|
103
|
+
// counts as body. Measured 2026-09-27 on a [conference,compsoc] paper whose body ends at the
|
|
104
|
+
// foot of page 12:
|
|
51
105
|
// LLM Usage Statement before the references → body 13, references 0
|
|
52
106
|
// an appendix before the references → body 13, references 2
|
|
53
107
|
// both placed after the references → body right, the tail counted as references
|
|
54
108
|
// AIDC counts neither in the limit («excluding references and appendices»; the ACSAC AI policy:
|
|
55
|
-
// the LLM Usage Statement «does not count towards the page limit»)
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
"
|
|
60
|
-
"_": "Body pages, excluding references, appendices and the LLM Usage Statement. banal counts a page holding an appendix or the statement before the bibliography as body, so its body count is not this number.",
|
|
61
|
-
"regular": 12,
|
|
62
|
-
"short": 6,
|
|
63
|
-
"references_and_appendices": "unlimited",
|
|
64
|
-
"llm_usage_statement": "not counted (ACSAC AI policy)",
|
|
65
|
-
},
|
|
109
|
+
// the LLM Usage Statement «does not count towards the page limit»). So format/page-limit counts
|
|
110
|
+
// the body up to where the references start (`body_ends_at`): the page they start on counts
|
|
111
|
+
// when body text stands above the heading there, and the limit below is gated. An appendix
|
|
112
|
+
// ends the body too, wherever it sits, when hyperref anchors it (docs/rules/format/page-limit.md).
|
|
113
|
+
"body_ends_at": "references",
|
|
66
114
|
|
|
67
115
|
// «Short position papers or work-in-progress (WIP) papers» share one limit, so one kind.
|
|
116
|
+
// References, appendices and the LLM Usage Statement: unlimited.
|
|
68
117
|
"kinds": {
|
|
69
|
-
"regular": {},
|
|
70
|
-
"short": {},
|
|
118
|
+
"regular": { "body_pages_max": 12 },
|
|
119
|
+
"short": { "body_pages_max": 6 },
|
|
71
120
|
},
|
|
72
121
|
},
|
|
73
122
|
}
|
|
@@ -59,6 +59,14 @@
|
|
|
59
59
|
"body_pt": 10,
|
|
60
60
|
"body_pt_tol": 0.5,
|
|
61
61
|
|
|
62
|
+
// The class sets the bibliography in \footnotesize, 8 pt at 10pt and at 9pt (IEEEtran.cls,
|
|
63
|
+
// \thebibliography). Measured 2026-09-29 on the four built ACSAC papers in
|
|
64
|
+
// fixtures/accepted-papers (body-size.json): pdf.js reads the reference glyphs at 8.00 pt
|
|
65
|
+
// (7.97 without compsoc), banal gives 8.3 on all four. body_pt_tol widens it to 7.5-8.5, so a
|
|
66
|
+
// bibliography shrunk to \scriptsize (7.3) or grown to \small (9.3) is reported.
|
|
67
|
+
"ref_pt_min": 8,
|
|
68
|
+
"ref_pt_max": 8,
|
|
69
|
+
|
|
62
70
|
// The Times clone. Headings and the title are set in the same family, so a `fonts_title` would
|
|
63
71
|
// repeat this check and report a Computer Modern build twice.
|
|
64
72
|
"fonts_text": "NimbusRomNo9L",
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"type": "string",
|
|
25
25
|
"minLength": 1
|
|
26
26
|
},
|
|
27
|
+
"blind": {
|
|
28
|
+
"description": "The venue reviews double-blind: its call says submissions must be anonymized. Read by `anonymity/identity`, which then requires the paper's `identity` and finds none of it in the PDF. Set only where the venue says so, with the quote. A child's value replaces its parent's.",
|
|
29
|
+
"type": "boolean"
|
|
30
|
+
},
|
|
27
31
|
"aliases": {
|
|
28
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`.",
|
|
29
33
|
"type": "array",
|
|
@@ -105,6 +109,11 @@
|
|
|
105
109
|
"type": "string",
|
|
106
110
|
"minLength": 1
|
|
107
111
|
},
|
|
112
|
+
"body_ends_at": {
|
|
113
|
+
"description": "How `format/page-limit` counts body pages. Absent: banal's body count (every page holding non-bibliography text). `references`: the pages up to where the body ends — at the references or the appendix, whichever comes first, found by hyperref's anchors and then the heading line — with that page counted when body text stands above the heading on it; for a venue whose limit excludes references and appendices (and what follows them, such as statements).",
|
|
114
|
+
"type": "string",
|
|
115
|
+
"enum": ["references"]
|
|
116
|
+
},
|
|
108
117
|
"page_limits_not_gated": {
|
|
109
118
|
"type": "object"
|
|
110
119
|
},
|
|
@@ -128,8 +137,55 @@
|
|
|
128
137
|
}
|
|
129
138
|
},
|
|
130
139
|
"rules": {
|
|
131
|
-
"description": "Rules the venue implies, rule id
|
|
140
|
+
"description": "Rules the venue implies, rule id → ESLint entry (a severity, or [severity, options]). Applied to every paper that extends this preset, before the paper's own rules.",
|
|
132
141
|
"type": "object"
|
|
142
|
+
},
|
|
143
|
+
"register": {
|
|
144
|
+
"description": "The register rules' anchors (`tex/contrast-frames`, `tex/claim-emphasis`, `tex/relation-markers`): accepted papers of the venue, or of its parent conference, each with its body's word count and its count of each measure as paperlint's own counters give them. A measure's band is the anchors' range widened by two Poisson standard deviations at each end (docs/rules/tex/contrast-frames.md). A child preset's block replaces its parent's.",
|
|
145
|
+
"type": "object",
|
|
146
|
+
"additionalProperties": false,
|
|
147
|
+
"required": ["anchors"],
|
|
148
|
+
"properties": {
|
|
149
|
+
"anchors": {
|
|
150
|
+
"type": "array",
|
|
151
|
+
"minItems": 1,
|
|
152
|
+
"items": {
|
|
153
|
+
"type": "object",
|
|
154
|
+
"additionalProperties": false,
|
|
155
|
+
"required": [
|
|
156
|
+
"paper",
|
|
157
|
+
"words",
|
|
158
|
+
"contrast_frames",
|
|
159
|
+
"claim_emphasis",
|
|
160
|
+
"relation_markers"
|
|
161
|
+
],
|
|
162
|
+
"properties": {
|
|
163
|
+
"paper": {
|
|
164
|
+
"description": "The anchor: a directory under fixtures/accepted-papers/ when the paper is there, or how to find it.",
|
|
165
|
+
"type": "string",
|
|
166
|
+
"minLength": 1
|
|
167
|
+
},
|
|
168
|
+
"words": {
|
|
169
|
+
"description": "Words of the body, as the register rules count them.",
|
|
170
|
+
"type": "integer",
|
|
171
|
+
"minimum": 1
|
|
172
|
+
},
|
|
173
|
+
"contrast_frames": {
|
|
174
|
+
"type": "integer",
|
|
175
|
+
"minimum": 0
|
|
176
|
+
},
|
|
177
|
+
"claim_emphasis": {
|
|
178
|
+
"type": "integer",
|
|
179
|
+
"minimum": 0
|
|
180
|
+
},
|
|
181
|
+
"relation_markers": {
|
|
182
|
+
"type": "integer",
|
|
183
|
+
"minimum": 0
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
133
189
|
}
|
|
134
190
|
},
|
|
135
191
|
"allOf": [
|
|
@@ -4,7 +4,7 @@ description: Use when asking "does this paper read well?" / "is the writing any
|
|
|
4
4
|
allowed-tools: [Read, Write, Edit, Grep, Glob, Agent, Skill]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:03d0377baf71967f compiled from skills/grade-paper-writing/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# grade-paper-writing — grade how the paper READS, then fix it sentence by sentence
|
|
10
10
|
|
|
@@ -172,16 +172,41 @@ is what happened.
|
|
|
172
172
|
3. **For every dimension scoring ≤3, name the specific offending sentence or section** and write the fix —
|
|
173
173
|
not "tighten the prose" but the rewritten sentence, or "move the point from ¶3 to ¶1", or "gloss
|
|
174
174
|
`operation-normalized` in plain words at first use." Fixes must be applyable, not vibes.
|
|
175
|
-
3a. **Grade #10, register distance, against the venue's own papers — not against
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
175
|
+
3a. **Grade #10, register distance, against the venue's own papers, section by section — not against
|
|
176
|
+
the exemplars.** The rules count and this step judges; it starts from their numbers, not from a
|
|
177
|
+
count of its own.
|
|
178
|
+
- **Take the counts from the rules.** `npx paperlint lint <paper-dir>` reports
|
|
179
|
+
`tex/contrast-frames`, `tex/claim-emphasis` and `tex/relation-markers` when the venue preset
|
|
180
|
+
records anchors (AIDC does): each gives the body's rate per 10,000 words, the band, and the
|
|
181
|
+
anchors' range, and above the band it reports every frame and every claim in bold where it
|
|
182
|
+
stands. Those locations are the worklist. Do not recount them by grep — a narrower count is
|
|
183
|
+
gamed by rewording (*, not* → *rather than*), and the rules count every form.
|
|
184
|
+
- **Take the reference papers from the preset.** Its `register.anchors` names the accepted papers
|
|
185
|
+
the band comes from (AIDC: five ACSAC papers, all on arXiv under CC licences). Read two or three
|
|
186
|
+
of the same paper type as LaTeX source (`https://arxiv.org/e-print/<id>`) or as built PDFs. A
|
|
187
|
+
preset without anchors: fetch 2–3 accepted papers of the venue (or, for a first-edition workshop,
|
|
188
|
+
of its parent conference) from the proceedings or the program page, or use the ones the author
|
|
189
|
+
supplies.
|
|
190
|
+
- **Compare section by section, not the paper as a whole:** abstract, introduction, threat model or
|
|
191
|
+
background, method, results, limitations, conclusion. For each, put the draft's section beside the
|
|
192
|
+
same section of each reference paper and record, for both sides: how each result is owned (*we
|
|
193
|
+
measured* · a citation · a named population); how the relation between neighbouring sentences is
|
|
194
|
+
named (*because*, *therefore*, *however*, *for example*) or left to infer (a colon, a dash, a short
|
|
195
|
+
sentence); how often a point is made by what it is not; what is set in bold; and whether any
|
|
196
|
+
sentence is an aphorism, a fragment or a closing punchline. Quote the reference sentence beside
|
|
197
|
+
each draft sentence you flag.
|
|
198
|
+
- **Return concrete rewrites, and every one keeps every number and claim.** For each flagged sentence:
|
|
199
|
+
the draft sentence → the rewrite → the reference sentence it is modelled on → one line saying that
|
|
200
|
+
every number, citation and hedge is unchanged and the claim is neither softened nor strengthened.
|
|
201
|
+
A contrast frame is rewritten by saying what the thing is and naming the relation (*because*,
|
|
202
|
+
*as a result*), not by switching to another contrast form; a claim in bold loses the bold and
|
|
203
|
+
gains its owner (*we measured*, `\ref` to the table); a relation left to infer gets its word.
|
|
204
|
+
Where the frame IS the claim (the paper's thesis sets one mechanism against another), keep it
|
|
205
|
+
once, in the abstract and the introduction, and say so.
|
|
206
|
+
- **Score the distance:** 5 = a reviewer could not tell the draft from the reference papers by
|
|
207
|
+
register, section by section; 1 = it reads as a different genre. After the rewrites, run
|
|
208
|
+
`npx paperlint lint` again: every register rule inside its band is the floor for a 4, not the
|
|
209
|
+
score itself.
|
|
185
210
|
If no accepted paper can be fetched or supplied, write `#10: not graded — no reference papers` and
|
|
186
211
|
say which were tried; a register score from memory is the guess this dimension exists to replace.
|
|
187
212
|
4. **Find the paper's three-move opportunities:** what held assumption could open it? what is its single
|
|
@@ -353,10 +378,13 @@ changes neither meaning nor register — and never rewrite a cited work's title
|
|
|
353
378
|
**Signposting is the register, not a tic, and this skill never removes it on style grounds.** Frame
|
|
354
379
|
markers and relation words — *we show*, *this section*, *first … finally*, *in contrast*, *therefore*,
|
|
355
380
|
*however* — are how academic prose tells the reader what kind of claim comes next and how it relates to
|
|
356
|
-
the last one.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
381
|
+
the last one. Relation words are a floor: `tex/relation-markers` reports a body below the band its
|
|
382
|
+
venue's accepted papers set (AIDC: 25.4 per 10,000 words; the paper reviewers called a blog post stood
|
|
383
|
+
at 19.1, and never wrote *however* once, where every accepted ACSAC paper writes it 6–11 times). Frame
|
|
384
|
+
markers do not separate a draft from accepted papers in either direction (see "Contrast framing"
|
|
385
|
+
below). Flag a connective only when it asserts a relation the two sentences do not have (a *therefore*
|
|
386
|
+
that does not follow), or when it is empty filler (*it is worth noting that*). Never flag one for being
|
|
387
|
+
academic.
|
|
360
388
|
|
|
361
389
|
**Other markers worth a pass:** nominalisation density (*an honest accounting of what the construction
|
|
362
390
|
costs* — abstract nouns doing the work verbs should do) and statistics chained through a paragraph
|
|
@@ -382,14 +410,15 @@ Two separable failures:
|
|
|
382
410
|
|
|
383
411
|
### 1. Contrast framing, and a frame that carries nothing
|
|
384
412
|
|
|
385
|
-
**What separates this corpus from accepted papers is contrast, not signposting —
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
must reconstruct. **Rewrite heuristic:** state the
|
|
391
|
-
|
|
392
|
-
|
|
413
|
+
**What separates this corpus from accepted papers is contrast, not signposting — and a rule counts
|
|
414
|
+
it.** `tex/contrast-frames` counts every form (*X, not Y* · *not X but Y* · *rather than* ·
|
|
415
|
+
*instead of* · *as opposed to*) per 10,000 words against the band the venue preset's anchors set: the
|
|
416
|
+
five accepted ACSAC papers measure 1.3–5.5, AIDC's band is 0–10.4, and the paper reviewers called a blog
|
|
417
|
+
post measured 101 before its rewrite and 28 after it. Every sentence that defines its point by what
|
|
418
|
+
it is not is a sentence whose point the reader must reconstruct. **Rewrite heuristic:** state the
|
|
419
|
+
thing and name the relation; move the rejected alternative to its own sentence, or drop it if nobody
|
|
420
|
+
proposed it. Swapping one form for another (*, not* → *rather than*) moves nothing — the rule counts
|
|
421
|
+
both, and so does a reviewer.
|
|
393
422
|
|
|
394
423
|
**Frame markers do not separate us from accepted papers, and are not a target in either direction.**
|
|
395
424
|
Hyland's *frame markers* (*this paper · this section · we show · first … finally · in what follows*)
|
|
@@ -464,10 +493,13 @@ one did, and it was the worst section in the paper by measured density both time
|
|
|
464
493
|
|
|
465
494
|
### What is NOT mechanizable here
|
|
466
495
|
|
|
467
|
-
Whether a frame marker carries its claim (*"we claim nothing there"* genuinely scopes one)
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
496
|
+
Whether a frame marker carries its claim (*"we claim nothing there"* genuinely scopes one), whether a
|
|
497
|
+
hedge is honest or defensive, whether a given contrast frame is the one a reader needs, and whether a
|
|
498
|
+
rewrite kept every claim at its strength. The mechanical legs that do exist: `tex/claim-provenance`
|
|
499
|
+
reports every sentence of the body that holds a number and no owner, and `tex/contrast-frames`,
|
|
500
|
+
`tex/claim-emphasis` and `tex/relation-markers` report a body outside its venue's band. Count them,
|
|
501
|
+
surface them, and leave the verdict to a reader. The counter's job is that nobody can say afterwards
|
|
502
|
+
they did not know.
|
|
471
503
|
|
|
472
504
|
## Compose with
|
|
473
505
|
- `harden-paper` — the multi-axis pre-submit gate calls this as its *writing* axis (the one a defect-hunt
|
|
@@ -178,16 +178,41 @@ is what happened.
|
|
|
178
178
|
3. **For every dimension scoring ≤3, name the specific offending sentence or section** and write the fix —
|
|
179
179
|
not "tighten the prose" but the rewritten sentence, or "move the point from ¶3 to ¶1", or "gloss
|
|
180
180
|
\`operation-normalized\` in plain words at first use." Fixes must be applyable, not vibes.
|
|
181
|
-
3a. **Grade #10, register distance, against the venue's own papers — not against
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
181
|
+
3a. **Grade #10, register distance, against the venue's own papers, section by section — not against
|
|
182
|
+
the exemplars.** The rules count and this step judges; it starts from their numbers, not from a
|
|
183
|
+
count of its own.
|
|
184
|
+
- **Take the counts from the rules.** \`npx paperlint lint <paper-dir>\` reports
|
|
185
|
+
\`tex/contrast-frames\`, \`tex/claim-emphasis\` and \`tex/relation-markers\` when the venue preset
|
|
186
|
+
records anchors (AIDC does): each gives the body's rate per 10,000 words, the band, and the
|
|
187
|
+
anchors' range, and above the band it reports every frame and every claim in bold where it
|
|
188
|
+
stands. Those locations are the worklist. Do not recount them by grep — a narrower count is
|
|
189
|
+
gamed by rewording (*, not* → *rather than*), and the rules count every form.
|
|
190
|
+
- **Take the reference papers from the preset.** Its \`register.anchors\` names the accepted papers
|
|
191
|
+
the band comes from (AIDC: five ACSAC papers, all on arXiv under CC licences). Read two or three
|
|
192
|
+
of the same paper type as LaTeX source (\`https://arxiv.org/e-print/<id>\`) or as built PDFs. A
|
|
193
|
+
preset without anchors: fetch 2–3 accepted papers of the venue (or, for a first-edition workshop,
|
|
194
|
+
of its parent conference) from the proceedings or the program page, or use the ones the author
|
|
195
|
+
supplies.
|
|
196
|
+
- **Compare section by section, not the paper as a whole:** abstract, introduction, threat model or
|
|
197
|
+
background, method, results, limitations, conclusion. For each, put the draft's section beside the
|
|
198
|
+
same section of each reference paper and record, for both sides: how each result is owned (*we
|
|
199
|
+
measured* · a citation · a named population); how the relation between neighbouring sentences is
|
|
200
|
+
named (*because*, *therefore*, *however*, *for example*) or left to infer (a colon, a dash, a short
|
|
201
|
+
sentence); how often a point is made by what it is not; what is set in bold; and whether any
|
|
202
|
+
sentence is an aphorism, a fragment or a closing punchline. Quote the reference sentence beside
|
|
203
|
+
each draft sentence you flag.
|
|
204
|
+
- **Return concrete rewrites, and every one keeps every number and claim.** For each flagged sentence:
|
|
205
|
+
the draft sentence → the rewrite → the reference sentence it is modelled on → one line saying that
|
|
206
|
+
every number, citation and hedge is unchanged and the claim is neither softened nor strengthened.
|
|
207
|
+
A contrast frame is rewritten by saying what the thing is and naming the relation (*because*,
|
|
208
|
+
*as a result*), not by switching to another contrast form; a claim in bold loses the bold and
|
|
209
|
+
gains its owner (*we measured*, \`\\ref\` to the table); a relation left to infer gets its word.
|
|
210
|
+
Where the frame IS the claim (the paper's thesis sets one mechanism against another), keep it
|
|
211
|
+
once, in the abstract and the introduction, and say so.
|
|
212
|
+
- **Score the distance:** 5 = a reviewer could not tell the draft from the reference papers by
|
|
213
|
+
register, section by section; 1 = it reads as a different genre. After the rewrites, run
|
|
214
|
+
\`npx paperlint lint\` again: every register rule inside its band is the floor for a 4, not the
|
|
215
|
+
score itself.
|
|
191
216
|
If no accepted paper can be fetched or supplied, write \`#10: not graded — no reference papers\` and
|
|
192
217
|
say which were tried; a register score from memory is the guess this dimension exists to replace.
|
|
193
218
|
4. **Find the paper's three-move opportunities:** what held assumption could open it? what is its single
|
|
@@ -359,10 +384,13 @@ changes neither meaning nor register — and never rewrite a cited work's title
|
|
|
359
384
|
**Signposting is the register, not a tic, and this skill never removes it on style grounds.** Frame
|
|
360
385
|
markers and relation words — *we show*, *this section*, *first … finally*, *in contrast*, *therefore*,
|
|
361
386
|
*however* — are how academic prose tells the reader what kind of claim comes next and how it relates to
|
|
362
|
-
the last one.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
387
|
+
the last one. Relation words are a floor: \`tex/relation-markers\` reports a body below the band its
|
|
388
|
+
venue's accepted papers set (AIDC: 25.4 per 10,000 words; the paper reviewers called a blog post stood
|
|
389
|
+
at 19.1, and never wrote *however* once, where every accepted ACSAC paper writes it 6–11 times). Frame
|
|
390
|
+
markers do not separate a draft from accepted papers in either direction (see "Contrast framing"
|
|
391
|
+
below). Flag a connective only when it asserts a relation the two sentences do not have (a *therefore*
|
|
392
|
+
that does not follow), or when it is empty filler (*it is worth noting that*). Never flag one for being
|
|
393
|
+
academic.
|
|
366
394
|
|
|
367
395
|
**Other markers worth a pass:** nominalisation density (*an honest accounting of what the construction
|
|
368
396
|
costs* — abstract nouns doing the work verbs should do) and statistics chained through a paragraph
|
|
@@ -388,14 +416,15 @@ Two separable failures:
|
|
|
388
416
|
|
|
389
417
|
### 1. Contrast framing, and a frame that carries nothing
|
|
390
418
|
|
|
391
|
-
**What separates this corpus from accepted papers is contrast, not signposting —
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
must reconstruct. **Rewrite heuristic:** state the
|
|
397
|
-
|
|
398
|
-
|
|
419
|
+
**What separates this corpus from accepted papers is contrast, not signposting — and a rule counts
|
|
420
|
+
it.** \`tex/contrast-frames\` counts every form (*X, not Y* · *not X but Y* · *rather than* ·
|
|
421
|
+
*instead of* · *as opposed to*) per 10,000 words against the band the venue preset's anchors set: the
|
|
422
|
+
five accepted ACSAC papers measure 1.3–5.5, AIDC's band is 0–10.4, and the paper reviewers called a blog
|
|
423
|
+
post measured 101 before its rewrite and 28 after it. Every sentence that defines its point by what
|
|
424
|
+
it is not is a sentence whose point the reader must reconstruct. **Rewrite heuristic:** state the
|
|
425
|
+
thing and name the relation; move the rejected alternative to its own sentence, or drop it if nobody
|
|
426
|
+
proposed it. Swapping one form for another (*, not* → *rather than*) moves nothing — the rule counts
|
|
427
|
+
both, and so does a reviewer.
|
|
399
428
|
|
|
400
429
|
**Frame markers do not separate us from accepted papers, and are not a target in either direction.**
|
|
401
430
|
Hyland's *frame markers* (*this paper · this section · we show · first … finally · in what follows*)
|
|
@@ -470,10 +499,13 @@ one did, and it was the worst section in the paper by measured density both time
|
|
|
470
499
|
|
|
471
500
|
### What is NOT mechanizable here
|
|
472
501
|
|
|
473
|
-
Whether a frame marker carries its claim (*"we claim nothing there"* genuinely scopes one)
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
502
|
+
Whether a frame marker carries its claim (*"we claim nothing there"* genuinely scopes one), whether a
|
|
503
|
+
hedge is honest or defensive, whether a given contrast frame is the one a reader needs, and whether a
|
|
504
|
+
rewrite kept every claim at its strength. The mechanical legs that do exist: \`tex/claim-provenance\`
|
|
505
|
+
reports every sentence of the body that holds a number and no owner, and \`tex/contrast-frames\`,
|
|
506
|
+
\`tex/claim-emphasis\` and \`tex/relation-markers\` report a body outside its venue's band. Count them,
|
|
507
|
+
surface them, and leave the verdict to a reader. The counter's job is that nobody can say afterwards
|
|
508
|
+
they did not know.
|
|
477
509
|
|
|
478
510
|
## Compose with
|
|
479
511
|
- \`harden-paper\` — the multi-axis pre-submit gate calls this as its *writing* axis (the one a defect-hunt
|
|
@@ -119,8 +119,8 @@ try {
|
|
|
119
119
|
const fonts = Fonts.safeParse(facts.fonts);
|
|
120
120
|
const fontList = fonts.success ? fonts.data : [];
|
|
121
121
|
check(
|
|
122
|
-
"the facts are schema
|
|
123
|
-
facts.schema ===
|
|
122
|
+
"the facts are schema 3, about paper.pdf, for the venue paperlint.json declares",
|
|
123
|
+
facts.schema === 3 &&
|
|
124
124
|
facts.pdf === "paper.pdf" &&
|
|
125
125
|
facts.venue === "agenticdev" &&
|
|
126
126
|
facts.kind === "short",
|
|
@@ -236,5 +236,5 @@ try {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
console.log(
|
|
239
|
-
`✓ ${String(check.count)} assertions passed — extract-pdf-facts: the exit-code contract, schema
|
|
239
|
+
`✓ ${String(check.count)} assertions passed — extract-pdf-facts: the exit-code contract, schema 3, and the no-no-yes font`,
|
|
240
240
|
);
|