paperlint 7.0.0 → 7.2.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/.github/workflows/ci.yml +3 -0
- package/.github/workflows/deadlines.yml +100 -0
- package/README.md +24 -11
- package/dist/adapters/hotcrp/deadlines.d.ts +8 -0
- package/dist/adapters/hotcrp/deadlines.d.ts.map +1 -0
- package/dist/adapters/hotcrp/deadlines.io.d.ts +6 -0
- package/dist/adapters/hotcrp/deadlines.io.d.ts.map +1 -0
- package/dist/adapters/hotcrp/deadlines.io.js +26 -0
- package/dist/adapters/hotcrp/deadlines.io.js.map +1 -0
- package/dist/adapters/hotcrp/deadlines.js +134 -0
- package/dist/adapters/hotcrp/deadlines.js.map +1 -0
- package/dist/adapters/hotcrp/index.d.ts +2 -0
- package/dist/adapters/hotcrp/index.d.ts.map +1 -1
- package/dist/adapters/hotcrp/index.js +2 -0
- package/dist/adapters/hotcrp/index.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +42 -7
- package/dist/cli.js.map +1 -1
- package/dist/cycle-rules.d.ts +24 -0
- package/dist/cycle-rules.d.ts.map +1 -0
- package/dist/cycle-rules.js +212 -0
- package/dist/cycle-rules.js.map +1 -0
- package/dist/domain/body-pages.d.ts +29 -0
- package/dist/domain/body-pages.d.ts.map +1 -1
- package/dist/domain/body-pages.js +25 -0
- package/dist/domain/body-pages.js.map +1 -1
- package/dist/domain/cycle.d.ts +148 -0
- package/dist/domain/cycle.d.ts.map +1 -0
- package/dist/domain/cycle.js +281 -0
- package/dist/domain/cycle.js.map +1 -0
- package/dist/domain/deadline.d.ts +128 -0
- package/dist/domain/deadline.d.ts.map +1 -0
- package/dist/domain/deadline.js +281 -0
- package/dist/domain/deadline.js.map +1 -0
- package/dist/eslint-rules/cycle-stage.d.ts +39 -0
- package/dist/eslint-rules/cycle-stage.d.ts.map +1 -0
- package/dist/eslint-rules/cycle-stage.js +119 -0
- package/dist/eslint-rules/cycle-stage.js.map +1 -0
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +2 -0
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/paper-includes.d.ts +3 -0
- package/dist/paper-includes.d.ts.map +1 -1
- package/dist/paper-includes.js +17 -2
- package/dist/paper-includes.js.map +1 -1
- package/dist/paper-settings.d.ts +7 -0
- package/dist/paper-settings.d.ts.map +1 -1
- package/dist/paper-settings.js +61 -8
- package/dist/paper-settings.js.map +1 -1
- package/dist/ports/venue-deadlines.d.ts +14 -0
- package/dist/ports/venue-deadlines.d.ts.map +1 -0
- package/dist/ports/venue-deadlines.js +2 -0
- package/dist/ports/venue-deadlines.js.map +1 -0
- package/dist/presets.d.ts +22 -3
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +26 -17
- package/dist/presets.js.map +1 -1
- package/dist/submission.d.ts +16 -0
- package/dist/submission.d.ts.map +1 -1
- package/dist/submission.js +59 -16
- package/dist/submission.js.map +1 -1
- package/dist/tex-requirements.d.ts +12 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +26 -3
- package/dist/tex-requirements.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +24 -2
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js +98 -10
- package/dist/tex-venue-rules.js.map +1 -1
- package/dist/venue-rules.d.ts +12 -1
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +81 -17
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +140 -12
- package/docs/e2e.md +14 -12
- package/docs/rules/cycle/evidence.md +87 -0
- package/docs/rules/cycle/port-done.md +75 -0
- package/docs/rules/cycle/record.md +152 -0
- package/docs/rules/cycle/stage.md +85 -0
- package/docs/rules/format/page-limit.md +18 -1
- package/docs/rules/tex/template.md +25 -5
- package/docs/rules/tex/venue-leftover.md +13 -0
- package/docs/rules.md +68 -55
- package/docs/submission.md +10 -1
- package/eslint-rules/cycle-stage.test.mjs +131 -0
- package/eslint-rules/cycle-stage.ts +141 -0
- package/eslint.config.mjs +41 -1
- package/fixtures/build-e2e/msr/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/msr/expect.json +18 -0
- package/fixtures/build-e2e/msr/paper.tex +49 -0
- package/fixtures/build-e2e/msr/paperlint.json +1 -0
- package/fixtures/build-e2e/msr-appendix-after/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/msr-appendix-after/expect.json +20 -0
- package/fixtures/build-e2e/msr-appendix-after/paper.tex +48 -0
- package/fixtures/build-e2e/msr-appendix-after/paperlint.json +1 -0
- package/lib/paper-config.ts +3 -0
- package/package.json +1 -1
- package/presets/aidc.jsonc +24 -3
- package/presets/aidc.md +6 -3
- package/presets/ieee-conference.md +1 -1
- package/presets/msr.jsonc +95 -0
- package/presets/msr.md +98 -0
- package/presets/venue-profile.schema.json +64 -0
- package/scripts/check.ts +4 -0
- package/scripts/refresh-deadlines.test.ts +431 -0
- package/scripts/refresh-deadlines.ts +387 -0
- package/skills/camera-ready/SKILL.md +8 -1
- package/skills/camera-ready/SKILL.md.spec.ts +7 -0
- package/skills/submission-portal/SKILL.md +2 -2
- package/skills/submission-portal/SKILL.md.spec.ts +1 -1
- package/skills/submit-paper/SKILL.md +9 -1
- package/skills/submit-paper/SKILL.md.spec.ts +8 -0
- package/src/adapters/hotcrp/cassette/README.md +22 -0
- package/src/adapters/hotcrp/cassette/deadlines-aidc26.html +17 -0
- package/src/adapters/hotcrp/cassette/deadlines-fse2027.html +24 -0
- package/src/adapters/hotcrp/cassette/deadlines-icse2027.html +25 -0
- package/src/adapters/hotcrp/cassette/deadlines-msr2027.html +25 -0
- package/src/adapters/hotcrp/cassette/deadlines-nosuch.html +18 -0
- package/src/adapters/hotcrp/cassette/deadlines-sosp26.html +26 -0
- package/src/adapters/hotcrp/deadlines.io.test.ts +86 -0
- package/src/adapters/hotcrp/deadlines.io.ts +27 -0
- package/src/adapters/hotcrp/deadlines.test.ts +170 -0
- package/src/adapters/hotcrp/deadlines.ts +161 -0
- package/src/adapters/hotcrp/index.ts +2 -0
- package/src/cli.test.ts +9 -0
- package/src/cli.ts +50 -6
- package/src/cycle-rules.test.ts +278 -0
- package/src/cycle-rules.ts +273 -0
- package/src/domain/body-pages.test.ts +144 -0
- package/src/domain/body-pages.ts +61 -1
- package/src/domain/cycle.test.ts +456 -0
- package/src/domain/cycle.ts +432 -0
- package/src/domain/deadline.test.ts +386 -0
- package/src/domain/deadline.ts +472 -0
- package/src/new-paper.test.ts +28 -0
- package/src/paper-includes.test.ts +26 -0
- package/src/paper-includes.ts +20 -2
- package/src/paper-settings-commands.test.ts +1 -1
- package/src/paper-settings.test.ts +167 -0
- package/src/paper-settings.ts +85 -11
- package/src/ports/venue-deadlines.ts +14 -0
- package/src/preset-card-rule.test.ts +1 -0
- package/src/presets.test.ts +171 -1
- package/src/presets.ts +65 -15
- package/src/rule-cases.test.ts +144 -0
- package/src/submission.test.ts +147 -4
- package/src/submission.ts +100 -18
- package/src/tex-requirements.ts +52 -4
- package/src/tex-venue-rules.test.ts +237 -0
- package/src/tex-venue-rules.ts +130 -15
- package/src/venue-rules.test.ts +255 -2
- package/src/venue-rules.ts +115 -22
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cycle/stage` — a declared stage names the ATTEMPT it belongs to, and that attempt exists.
|
|
3
|
+
*
|
|
4
|
+
* With `cycles` in the paper's `paperlint.json`, a `stages` entry in the scorecard's frontmatter
|
|
5
|
+
* says `cycle: <id>` instead of a free `venue:` string: the venue's name is then the cycle's
|
|
6
|
+
* preset's, spelled once, and a consumer can tell which rows of the scorecard belong to which
|
|
7
|
+
* attempt. Three things can be wrong, each an error:
|
|
8
|
+
*
|
|
9
|
+
* noCycle `cycles` is declared and a stage names no `cycle`
|
|
10
|
+
* unknownCycle the stage's `cycle` is no declared cycle's id
|
|
11
|
+
* porting a `submitted` or `camera-ready` stage in a cycle whose phase is still `porting` —
|
|
12
|
+
* a PDF was sent while the record says the source is in the previous venue's template
|
|
13
|
+
*
|
|
14
|
+
* Without `cycles` (the flat form) the rule is silent: `venue:` stays what it was. The settings file
|
|
15
|
+
* is read here only for the cycles' ids and phases; `cycle/record` (src/cycle-rules.ts) judges the
|
|
16
|
+
* whole record.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
19
|
+
import { dirname, join } from "node:path";
|
|
20
|
+
import { load } from "js-yaml";
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import type { RuleContext } from "./rule-context.ts";
|
|
23
|
+
|
|
24
|
+
const SETTINGS_FILE = "paperlint.json";
|
|
25
|
+
|
|
26
|
+
/** What this rule reads of a cycle: its id and phase. `cycle/record` parses the rest. */
|
|
27
|
+
const CycleHead = z.looseObject({
|
|
28
|
+
id: z.string(),
|
|
29
|
+
phase: z.string().optional(),
|
|
30
|
+
});
|
|
31
|
+
const Settings = z.looseObject({
|
|
32
|
+
cycles: z.array(CycleHead.catch({ id: "" })).optional(),
|
|
33
|
+
});
|
|
34
|
+
const Frontmatter = z.looseObject({ stages: z.unknown().optional() }).catch({});
|
|
35
|
+
const Stage = z
|
|
36
|
+
.looseObject({
|
|
37
|
+
stage: z.unknown().optional(),
|
|
38
|
+
cycle: z.unknown().optional(),
|
|
39
|
+
date: z.unknown().optional(),
|
|
40
|
+
})
|
|
41
|
+
.catch({});
|
|
42
|
+
|
|
43
|
+
/** The stages that send a PDF to the venue: a cycle still porting cannot have one. */
|
|
44
|
+
const SENT: readonly string[] = ["submitted", "camera-ready"];
|
|
45
|
+
|
|
46
|
+
interface Head {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly phase: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The declared cycles' heads, or null when the paper has no `cycles` (or no readable settings). */
|
|
52
|
+
function cyclesOf(dir: string): readonly Head[] | null {
|
|
53
|
+
const file = join(dir, SETTINGS_FILE);
|
|
54
|
+
if (!existsSync(file)) return null;
|
|
55
|
+
try {
|
|
56
|
+
const s = Settings.safeParse(JSON.parse(readFileSync(file, "utf8")));
|
|
57
|
+
return s.success && s.data.cycles !== undefined
|
|
58
|
+
? s.data.cycles.map((c) => ({ id: c.id, phase: c.phase ?? "prepared" }))
|
|
59
|
+
: null;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const text = (v: unknown): string =>
|
|
66
|
+
typeof v === "string" ? v : v === undefined ? "" : JSON.stringify(v);
|
|
67
|
+
|
|
68
|
+
/** A YAML date without quotes is a `Date`; shown as the day it names, as `paper/stages` does. */
|
|
69
|
+
const dateText = (v: unknown): string =>
|
|
70
|
+
v instanceof Date ? v.toISOString().slice(0, 10) : text(v);
|
|
71
|
+
|
|
72
|
+
interface Finding {
|
|
73
|
+
readonly messageId: "noCycle" | "unknownCycle" | "porting";
|
|
74
|
+
readonly data: Readonly<Record<string, string>>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Each stage against the declared cycles. Pure. */
|
|
78
|
+
export function judgeStages(
|
|
79
|
+
stages: readonly unknown[],
|
|
80
|
+
cycles: readonly Head[],
|
|
81
|
+
): readonly Finding[] {
|
|
82
|
+
const known = cycles.map((c) => c.id).join(" · ") || "(none)";
|
|
83
|
+
return stages.flatMap((entry): readonly Finding[] => {
|
|
84
|
+
const s = Stage.parse(entry);
|
|
85
|
+
const stage = text(s.stage);
|
|
86
|
+
const date = dateText(s.date);
|
|
87
|
+
if (s.cycle === undefined)
|
|
88
|
+
return [{ messageId: "noCycle", data: { stage, date, known } }];
|
|
89
|
+
const id = text(s.cycle);
|
|
90
|
+
const cycle = cycles.find((c) => c.id === id);
|
|
91
|
+
if (cycle === undefined)
|
|
92
|
+
return [{ messageId: "unknownCycle", data: { stage, date, id, known } }];
|
|
93
|
+
return SENT.includes(stage) && cycle.phase === "porting"
|
|
94
|
+
? [{ messageId: "porting", data: { stage, date, id } }]
|
|
95
|
+
: [];
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default {
|
|
100
|
+
rules: {
|
|
101
|
+
stage: {
|
|
102
|
+
meta: {
|
|
103
|
+
type: "problem" as const,
|
|
104
|
+
docs: {
|
|
105
|
+
description:
|
|
106
|
+
"with `cycles` declared, every stage names the cycle it belongs to, and no PDF is sent from a cycle still porting",
|
|
107
|
+
url: "https://github.com/zernie/paperlint/blob/main/docs/rules/cycle/stage.md",
|
|
108
|
+
},
|
|
109
|
+
schema: [],
|
|
110
|
+
messages: {
|
|
111
|
+
noCycle:
|
|
112
|
+
"the «{{stage}}» stage ({{date}}) names no `cycle` — this paper declares `cycles` in paperlint.json, so each stage says which attempt it belongs to: `cycle: <id>`, one of {{known}}",
|
|
113
|
+
unknownCycle:
|
|
114
|
+
"the «{{stage}}» stage ({{date}}) names the cycle «{{id}}», which paperlint.json does not declare — the declared ids: {{known}}",
|
|
115
|
+
porting:
|
|
116
|
+
"the «{{stage}}» stage ({{date}}) belongs to the cycle «{{id}}», whose phase is still `porting`: a PDF was sent while the record says the source is in the previous venue's template. Finish the port and drop the phase, or the stage is wrong",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
create(context: RuleContext) {
|
|
120
|
+
const cycles = cyclesOf(dirname(context.filename));
|
|
121
|
+
if (cycles === null) return {};
|
|
122
|
+
return {
|
|
123
|
+
yaml(node: { readonly value: string }) {
|
|
124
|
+
const data = ((): unknown => {
|
|
125
|
+
try {
|
|
126
|
+
return load(node.value);
|
|
127
|
+
} catch {
|
|
128
|
+
return undefined; // `paper/stages` reports the unreadable YAML
|
|
129
|
+
}
|
|
130
|
+
})();
|
|
131
|
+
const stages = Frontmatter.parse(data).stages;
|
|
132
|
+
if (!Array.isArray(stages)) return;
|
|
133
|
+
judgeStages(stages, cycles).forEach((f) => {
|
|
134
|
+
context.report({ node, messageId: f.messageId, data: f.data });
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
};
|
package/eslint.config.mjs
CHANGED
|
@@ -413,6 +413,40 @@ export const IO_GLOBALS = {
|
|
|
413
413
|
},
|
|
414
414
|
};
|
|
415
415
|
|
|
416
|
+
/**
|
|
417
|
+
* `paperlint lint` NEVER READS THE CLOCK. Its findings are a function of the files and the installed
|
|
418
|
+
* package: the same checkout lints the same tomorrow, and a deadline's distance belongs to a status
|
|
419
|
+
* view or a calendar, not to a gate (a lint that turns red on an untouched tree gets muted). The
|
|
420
|
+
* clock is an effect like the disk, so it is read where effects are — an adapter's `*.io.ts` and the
|
|
421
|
+
* root, `src/cli.ts` — and passed in. Matched on the AST: `Date.now` (called or passed along),
|
|
422
|
+
* `new Date()` and `Date()` without an argument. `new Date(ms)` converts a given time and passes.
|
|
423
|
+
* `toolchain.ts` and `build-engine.ts` keep `Date.now` as a default for their own timing (build and
|
|
424
|
+
* install only, neither runs under `lint`); that legacy I/O moves behind a port in #76.
|
|
425
|
+
*/
|
|
426
|
+
const READS_THE_CLOCK = [
|
|
427
|
+
"MemberExpression[object.name='Date'][property.name='now']",
|
|
428
|
+
"NewExpression[callee.name='Date'][arguments.length=0]",
|
|
429
|
+
"CallExpression[callee.name='Date']",
|
|
430
|
+
].map((selector) => ({
|
|
431
|
+
selector,
|
|
432
|
+
message:
|
|
433
|
+
"Lint never reads the clock: its findings are a function of the files. Take the time as an argument; read it in an adapter's *.io.ts or src/cli.ts.",
|
|
434
|
+
}));
|
|
435
|
+
|
|
436
|
+
/** Every source file the checks are made of, but the places effects are allowed. Same scope as axis B. */
|
|
437
|
+
export const NO_CLOCK = {
|
|
438
|
+
files: ["src/**/*.ts"],
|
|
439
|
+
ignores: [
|
|
440
|
+
...IO_GLOBALS.ignores,
|
|
441
|
+
// Legacy I/O, moves behind a port in #76 (see READS_THE_CLOCK).
|
|
442
|
+
"src/toolchain.ts",
|
|
443
|
+
"src/build-engine.ts",
|
|
444
|
+
],
|
|
445
|
+
rules: {
|
|
446
|
+
"no-restricted-syntax": ["error", AS_UNKNOWN_AS, ...READS_THE_CLOCK],
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
|
|
416
450
|
/**
|
|
417
451
|
* EVERY PRESET HAS A CARD, AND EVERY CARD'S RULES TABLE IS THE PRESET'S. Two checks, one block each:
|
|
418
452
|
*
|
|
@@ -608,6 +642,7 @@ export default [
|
|
|
608
642
|
},
|
|
609
643
|
// Hexagonal layers, both axes (src/CLAUDE.md): knowledge by element, purity by file category.
|
|
610
644
|
IO_GLOBALS,
|
|
645
|
+
NO_CLOCK,
|
|
611
646
|
layerBoundaries(dirname(fileURLToPath(import.meta.url))),
|
|
612
647
|
// The ratchet: per-file ceilings for the files written before the limits existed. See RATCHET.
|
|
613
648
|
...Object.entries(RATCHET).map(([file, max]) => ({
|
|
@@ -805,7 +840,12 @@ export default [
|
|
|
805
840
|
files: ["eslint-rules/*.ts", "eslint-rules/*.mjs"],
|
|
806
841
|
ignores: ["eslint-rules/*.test.*", "eslint-rules/*.harness.*"],
|
|
807
842
|
rules: {
|
|
808
|
-
"no-restricted-syntax": [
|
|
843
|
+
"no-restricted-syntax": [
|
|
844
|
+
"error",
|
|
845
|
+
AS_UNKNOWN_AS,
|
|
846
|
+
...GIT_IN_A_RULE,
|
|
847
|
+
...READS_THE_CLOCK,
|
|
848
|
+
],
|
|
809
849
|
},
|
|
810
850
|
},
|
|
811
851
|
// LAST, so no block above can replace its `no-restricted-syntax` options for these files (none
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "A real IEEEtran [10pt,conference] paper for MSR whose ten pages of main text include an appendix before the references, with two pages of only references: format/page-limit, tex/template and anonymity/identity have nothing to say. banal's own count (body 9, references 3) would fail it.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf",
|
|
5
|
+
"pages": 12
|
|
6
|
+
},
|
|
7
|
+
"fonts": {
|
|
8
|
+
"some": "NimbusRomNo9L",
|
|
9
|
+
"none": "^(CMR|CMBX|CMTI|CMTT|CMSS|LMRoman)"
|
|
10
|
+
},
|
|
11
|
+
"lint": {
|
|
12
|
+
"rules": {
|
|
13
|
+
"format/page-limit": [],
|
|
14
|
+
"tex/template": [],
|
|
15
|
+
"anonymity/identity": []
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
% A paper in the class MSR's call names, built by the e2e on paperlint's own TeX Live, that MEETS
|
|
2
|
+
% MSR's limit: ten pages of main text, its appendix included, and two pages holding only references
|
|
3
|
+
% (rendered and looked at, 2026-10-05: the appendix heading stands mid-column on page 9, appendix
|
|
4
|
+
% text then «REFERENCES» on page 10, nothing but entries on pages 11 and 12). banal's count says body
|
|
5
|
+
% 9, references 3 — a page whose first heading reads «Appendix» is typed as bibliography — and would
|
|
6
|
+
% fail it; format/page-limit counts from the text and must not.
|
|
7
|
+
%
|
|
8
|
+
% The prose is one paragraph set many times; each copy carries its own number in words on every
|
|
9
|
+
% line, so no line repeats from page to page as a running header would.
|
|
10
|
+
\documentclass[10pt,conference]{IEEEtran}
|
|
11
|
+
\usepackage{hyperref}
|
|
12
|
+
\newcount\paracount
|
|
13
|
+
\newcommand{\n}{\romannumeral\paracount}
|
|
14
|
+
\newcommand{\para}{\global\advance\paracount by 1
|
|
15
|
+
Paragraph \n{} studies the history of a repository, and \n{} counts its commits by author \n{}
|
|
16
|
+
and by month \n{}, so that the measurement \n{} has a body of prose \n{} set in the two columns
|
|
17
|
+
\n{} of the conference format. Paragraph \n{} says nothing new, and \n{} does not need to: the
|
|
18
|
+
fixture \n{} is about the class, \n{} the fonts and \n{} the page count, and \n{} not about its
|
|
19
|
+
content. A reviewer of \n{} would find it dull, \n{} which is what a measurement \n{} should be.\par}
|
|
20
|
+
\newcount\loopcount
|
|
21
|
+
\newcommand{\paras}[1]{\loopcount=0 \loop\para\advance\loopcount by 1 \ifnum\loopcount<#1\repeat}
|
|
22
|
+
\newcount\bibcount
|
|
23
|
+
\newcommand{\entries}[1]{\bibcount=0 \loop\advance\bibcount by 1
|
|
24
|
+
\bibitem{r\the\bibcount} A. Author, ``Mining study \romannumeral\bibcount,'' in \emph{Proc.
|
|
25
|
+
Workshop}, 2024, pp. 1--10.\ifnum\bibcount<#1\repeat}
|
|
26
|
+
\begin{document}
|
|
27
|
+
\title{A Fixture Typeset in the Class the Venue Requires}
|
|
28
|
+
\author{\IEEEauthorblockN{Anonymous Author}\IEEEauthorblockA{Anonymous Institution}}
|
|
29
|
+
\maketitle
|
|
30
|
+
\begin{abstract}
|
|
31
|
+
The abstract exists so the build has the front matter an IEEE paper carries.
|
|
32
|
+
\end{abstract}
|
|
33
|
+
\section{Introduction}
|
|
34
|
+
\paras{24}
|
|
35
|
+
\section{Part Two}
|
|
36
|
+
\paras{24}
|
|
37
|
+
\section{Part Three}
|
|
38
|
+
\paras{24}
|
|
39
|
+
\section{Part Four}
|
|
40
|
+
\paras{24}
|
|
41
|
+
\section{Part Five}
|
|
42
|
+
\paras{12}
|
|
43
|
+
\appendix
|
|
44
|
+
\section{Detailed Results}
|
|
45
|
+
\paras{12}
|
|
46
|
+
\begin{thebibliography}{999}
|
|
47
|
+
\entries{290}
|
|
48
|
+
\end{thebibliography}
|
|
49
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:msr", "kind": "technical", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "MSR: an appendix after the references brings the main text to eleven pages. Exactly one format/page-limit finding, naming where the appendix starts. banal's own count (body 9, references 2) would pass it.",
|
|
3
|
+
"build": {
|
|
4
|
+
"outcome": "pdf",
|
|
5
|
+
"pages": 11
|
|
6
|
+
},
|
|
7
|
+
"lint": {
|
|
8
|
+
"rules": {
|
|
9
|
+
"format/page-limit": [
|
|
10
|
+
{
|
|
11
|
+
"severity": 2,
|
|
12
|
+
"says": [
|
|
13
|
+
"body pages (up to the references on page 10, and the appendix from page 10): 11, over the limit 10 for MSR/technical"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"tex/template": []
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
% A paper in the class MSR's call names, built by the e2e on paperlint's own TeX Live, that is ONE
|
|
2
|
+
% PAGE OVER MSR's limit through its appendix: the body ends on page 10, the references follow it
|
|
3
|
+
% there, and the appendix after them runs from the foot of page 10 through page 11 (rendered and
|
|
4
|
+
% looked at, 2026-10-05) — eleven pages holding main text. banal's count says body 9, references 2,
|
|
5
|
+
% and would pass it; format/page-limit counts the appendix as body and must not.
|
|
6
|
+
%
|
|
7
|
+
% The prose is one paragraph set many times; each copy carries its own number in words on every
|
|
8
|
+
% line, so no line repeats from page to page as a running header would.
|
|
9
|
+
\documentclass[10pt,conference]{IEEEtran}
|
|
10
|
+
\usepackage{hyperref}
|
|
11
|
+
\newcount\paracount
|
|
12
|
+
\newcommand{\n}{\romannumeral\paracount}
|
|
13
|
+
\newcommand{\para}{\global\advance\paracount by 1
|
|
14
|
+
Paragraph \n{} studies the history of a repository, and \n{} counts its commits by author \n{}
|
|
15
|
+
and by month \n{}, so that the measurement \n{} has a body of prose \n{} set in the two columns
|
|
16
|
+
\n{} of the conference format. Paragraph \n{} says nothing new, and \n{} does not need to: the
|
|
17
|
+
fixture \n{} is about the class, \n{} the fonts and \n{} the page count, and \n{} not about its
|
|
18
|
+
content. A reviewer of \n{} would find it dull, \n{} which is what a measurement \n{} should be.\par}
|
|
19
|
+
\newcount\loopcount
|
|
20
|
+
\newcommand{\paras}[1]{\loopcount=0 \loop\para\advance\loopcount by 1 \ifnum\loopcount<#1\repeat}
|
|
21
|
+
\newcount\bibcount
|
|
22
|
+
\newcommand{\entries}[1]{\bibcount=0 \loop\advance\bibcount by 1
|
|
23
|
+
\bibitem{r\the\bibcount} A. Author, ``Mining study \romannumeral\bibcount,'' in \emph{Proc.
|
|
24
|
+
Workshop}, 2024, pp. 1--10.\ifnum\bibcount<#1\repeat}
|
|
25
|
+
\begin{document}
|
|
26
|
+
\title{A Fixture Typeset in the Class the Venue Requires}
|
|
27
|
+
\author{\IEEEauthorblockN{Anonymous Author}\IEEEauthorblockA{Anonymous Institution}}
|
|
28
|
+
\maketitle
|
|
29
|
+
\begin{abstract}
|
|
30
|
+
The abstract exists so the build has the front matter an IEEE paper carries.
|
|
31
|
+
\end{abstract}
|
|
32
|
+
\section{Introduction}
|
|
33
|
+
\paras{24}
|
|
34
|
+
\section{Part Two}
|
|
35
|
+
\paras{24}
|
|
36
|
+
\section{Part Three}
|
|
37
|
+
\paras{24}
|
|
38
|
+
\section{Part Four}
|
|
39
|
+
\paras{24}
|
|
40
|
+
\section{Part Five}
|
|
41
|
+
\paras{24}
|
|
42
|
+
\begin{thebibliography}{999}
|
|
43
|
+
\entries{60}
|
|
44
|
+
\end{thebibliography}
|
|
45
|
+
\appendix
|
|
46
|
+
\section{Detailed Results}
|
|
47
|
+
\paras{12}
|
|
48
|
+
\end{document}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"extends": "paperlint:msr", "kind": "technical", "identity": ["Ada Example", "adaexample", "ada@example.org", "Example University", "exampletool"]}
|
package/lib/paper-config.ts
CHANGED
|
@@ -143,6 +143,8 @@ export const SETTINGS_KEYS: Readonly<Record<string, string>> = Object.freeze({
|
|
|
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
144
|
submission:
|
|
145
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",
|
|
146
|
+
cycles:
|
|
147
|
+
"the paper's attempts at venues, oldest first: [{ id, venue, kind, opened, phase?, deadlines, submission?, outcome }] — extends, kind and submission are then the current attempt's, and the cycle/ rules judge the record. A paper's own; refused in the root file",
|
|
146
148
|
scripts: "how skill prose names the scripts — consumer.mjs",
|
|
147
149
|
timezone: "the zone deadline anchors are written in — consumer.mjs",
|
|
148
150
|
contactEmail: "the polite-pool address for citation lookups — consumer.mjs",
|
|
@@ -155,6 +157,7 @@ export const SETTINGS_KEYS: Readonly<Record<string, string>> = Object.freeze({
|
|
|
155
157
|
export const PAPER_ONLY_KEYS: readonly string[] = Object.freeze([
|
|
156
158
|
"talk",
|
|
157
159
|
"submission",
|
|
160
|
+
"cycles",
|
|
158
161
|
]);
|
|
159
162
|
|
|
160
163
|
/** The keys that only mean something for the whole project: refused in a paper's `paperlint.json`. */
|
package/package.json
CHANGED
package/presets/aidc.jsonc
CHANGED
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
// and appendices.»
|
|
14
14
|
// «Submissions must be properly anonymized for double-blind review.»
|
|
15
15
|
//
|
|
16
|
-
// THE DEADLINE PEOPLE GET WRONG
|
|
16
|
+
// THE DEADLINE PEOPLE GET WRONG: the HotCRP portal closed 2026-10-02 11:59:59 UTC first
|
|
17
17
|
// (`"sub":1790942399` on https://aidc.submit.acsac.org/deadlines, recorded in paperlint#90), while
|
|
18
|
-
// the workshop page
|
|
19
|
-
// what refuses the upload
|
|
18
|
+
// the workshop page said «October 2, 2026 (Anywhere-on-Earth, AoE)» — a day later; by 2026-10-05
|
|
19
|
+
// the portal had moved it a day (`"sub":1791028799`). The portal is what refuses the upload, so its
|
|
20
|
+
// readings are `deadlines` below, rewritten by the scheduled refresh in paperlint's repository
|
|
21
|
+
// (.github/workflows/deadlines.yml) when the portal changes them.
|
|
20
22
|
//
|
|
21
23
|
// THE REVIEW IS DOUBLE-BLIND: `"blind":true` in the same portal data, and the call above.
|
|
22
24
|
//
|
|
@@ -38,6 +40,25 @@
|
|
|
38
40
|
// the HotCRP API, there.
|
|
39
41
|
"portal": { "kind": "hotcrp", "url": "https://aidc.submit.acsac.org" },
|
|
40
42
|
|
|
43
|
+
// Read from the portal's public deadlines page; the camera-ready only in its status object
|
|
44
|
+
// (`"final":{"done":1793447999}`).
|
|
45
|
+
"deadlines": [
|
|
46
|
+
{
|
|
47
|
+
"what": "submission",
|
|
48
|
+
"at": "2026-10-03T11:59:59Z",
|
|
49
|
+
"source": "portal",
|
|
50
|
+
"url": "https://aidc.submit.acsac.org/deadlines",
|
|
51
|
+
"read": "2026-10-05",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"what": "camera-ready",
|
|
55
|
+
"at": "2026-10-31T11:59:59Z",
|
|
56
|
+
"source": "portal",
|
|
57
|
+
"url": "https://aidc.submit.acsac.org/deadlines",
|
|
58
|
+
"read": "2026-10-05",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
|
|
41
62
|
// What the venue is called in a paper's text (tex/venue-leftover): the workshop, and the
|
|
42
63
|
// conference it is held at.
|
|
43
64
|
"aliases": ["AIDC", "ACSAC"],
|
package/presets/aidc.md
CHANGED
|
@@ -21,9 +21,12 @@ from it. The `submit-paper` skill reads this card for the venue's specifics.
|
|
|
21
21
|
- **Double-blind**: «Submissions must be properly anonymized for double-blind review.», and
|
|
22
22
|
`"blind":true` in the portal's data.
|
|
23
23
|
- **Portal**: HotCRP at `https://aidc.submit.acsac.org`.
|
|
24
|
-
- 🔴 **The deadline people get wrong**: the HotCRP portal
|
|
25
|
-
(`"sub":1790942399` on `https://aidc.submit.acsac.org/deadlines`), while the workshop page
|
|
26
|
-
«October 2, 2026 (Anywhere-on-Earth, AoE)» — a day later
|
|
24
|
+
- 🔴 **The deadline people get wrong**: the HotCRP portal closed 2026-10-02 11:59:59 UTC first
|
|
25
|
+
(`"sub":1790942399` on `https://aidc.submit.acsac.org/deadlines`), while the workshop page said
|
|
26
|
+
«October 2, 2026 (Anywhere-on-Earth, AoE)» — a day later; on 2026-10-05 the portal read
|
|
27
|
+
2026-10-03 11:59:59 UTC (`"sub":1791028799`). The portal is what refuses the upload. The preset
|
|
28
|
+
carries its readings as `deadlines`, refreshed by paperlint's scheduled workflow when the portal
|
|
29
|
+
changes them.
|
|
27
30
|
|
|
28
31
|
## Paper kinds and limits
|
|
29
32
|
|
|
@@ -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`
|
|
33
|
+
**`paperlint:ieee-conference`** — template family, no venue of its own · extended by `paperlint:aidc`, `paperlint:msr`
|
|
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,95 @@
|
|
|
1
|
+
// MSR 2027 Technical Papers (the 24th International Conference on Mining Software Repositories) — 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 MSR's call for papers sets.
|
|
5
|
+
//
|
|
6
|
+
// Verbatim from https://2027.msrconf.org/track/msr-2027-technical-papers (fetched 2026-10-05):
|
|
7
|
+
// «All submissions must conform to the IEEE conference proceedings template, specified in the
|
|
8
|
+
// IEEE Conference Proceedings Formatting Guidelines (title in 24pt font and full text in 10pt
|
|
9
|
+
// type, LaTeX users must use \documentclass[10pt,conference]{IEEEtran} without including the
|
|
10
|
+
// compsoc or compsocconf options).»
|
|
11
|
+
// «Note that IEEE format is being used this year, whereas last year it was ACM format.»
|
|
12
|
+
// «All submissions must not exceed 10 pages for the main text, inclusive of all figures, tables,
|
|
13
|
+
// appendices, etc. Two more pages containing only references are permitted. All submissions
|
|
14
|
+
// must be in PDF. Accepted papers will be allowed one extra page for the main text of the
|
|
15
|
+
// camera-ready version.»
|
|
16
|
+
// «The MSR 2027 Technical Track will employ a double-anonymous review process.»
|
|
17
|
+
//
|
|
18
|
+
// THE DEADLINES ARE THE PORTAL'S, as read: `deadlines` below is rewritten by the scheduled refresh
|
|
19
|
+
// in paperlint's repository (.github/workflows/deadlines.yml) when the portal changes them, and a
|
|
20
|
+
// paper reaches the new dates through its normal update of paperlint. The call's own wording
|
|
21
|
+
// (abstract and paper days, AoE) is in the card, msr.md beside this file.
|
|
22
|
+
{
|
|
23
|
+
"type": "venue",
|
|
24
|
+
"name": "MSR",
|
|
25
|
+
// The call quoted above.
|
|
26
|
+
"url": "https://2027.msrconf.org/track/msr-2027-technical-papers",
|
|
27
|
+
"extends": "paperlint:ieee-conference",
|
|
28
|
+
|
|
29
|
+
// «The MSR 2027 Technical Track will employ a double-anonymous review process. Thus, no
|
|
30
|
+
// submission may reveal its authors' identities.» (the call above), and `"blind":true` in the
|
|
31
|
+
// portal's data (https://msr2027.hotcrp.com/deadlines, 2026-10-05). anonymity/identity then
|
|
32
|
+
// requires the paper's `identity`.
|
|
33
|
+
"blind": true,
|
|
34
|
+
|
|
35
|
+
// «Papers must be submitted through HotCRP: https://msr2027.hotcrp.com/» (the call above).
|
|
36
|
+
// Recorded 2026-10-05: `/api/whoami` on this site answers 401 "Missing credentials" without a
|
|
37
|
+
// token — the HotCRP API, there.
|
|
38
|
+
"portal": { "kind": "hotcrp", "url": "https://msr2027.hotcrp.com" },
|
|
39
|
+
|
|
40
|
+
// Read from the portal's public deadlines page (no account) by the adapter in src/adapters/hotcrp/.
|
|
41
|
+
// «Submissions must be completed by this deadline» is the `submission`: on the CALL's abstract
|
|
42
|
+
// day, 04:00 UTC — four days before the call's paper day. «Completed submissions may be updated
|
|
43
|
+
// until this deadline» is the `resubmission`.
|
|
44
|
+
"deadlines": [
|
|
45
|
+
{
|
|
46
|
+
"what": "submission",
|
|
47
|
+
"at": "2026-10-20T04:00:00Z",
|
|
48
|
+
"source": "portal",
|
|
49
|
+
"url": "https://msr2027.hotcrp.com/deadlines",
|
|
50
|
+
"read": "2026-10-05",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"what": "resubmission",
|
|
54
|
+
"at": "2026-10-23T04:00:00Z",
|
|
55
|
+
"source": "portal",
|
|
56
|
+
"url": "https://msr2027.hotcrp.com/deadlines",
|
|
57
|
+
"read": "2026-10-05",
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
|
|
61
|
+
// What the venue is called in a paper's text (tex/venue-leftover) — and only beside a year
|
|
62
|
+
// («MSR 2027», «MSR'27»): «MSR» is also Microsoft Research, and an acronym papers define for
|
|
63
|
+
// themselves («Manual Speech Recognition (MSR)», in an accepted ACSAC paper of
|
|
64
|
+
// fixtures/accepted-papers/, warned six times when any whole word counted).
|
|
65
|
+
"aliases": ["MSR"],
|
|
66
|
+
"mentions": "with-year",
|
|
67
|
+
|
|
68
|
+
// The class line the call names, with the two options it forbids (tex/template). The family's
|
|
69
|
+
// `[conference]` text block (7.14 x 9.30 in) is the one this line builds, so no `format` override.
|
|
70
|
+
"template": "\\documentclass[10pt,conference]{IEEEtran}",
|
|
71
|
+
"template_forbids": ["compsoc", "compsocconf"],
|
|
72
|
+
|
|
73
|
+
"format": {
|
|
74
|
+
// 🔴 THE MAIN TEXT INCLUDES THE APPENDICES, AND THE REFERENCE PAGES ARE THE ONES WITH ONLY
|
|
75
|
+
// REFERENCES — not banal's count. Measured 2026-10-05 on IEEEtran [10pt,conference] builds:
|
|
76
|
+
// 10 pages of main text, its appendix before the references, 2 reference-only pages
|
|
77
|
+
// → banal: body 9, references 3 (a page whose first heading reads «Appendix» is typed as
|
|
78
|
+
// bibliography) — a correct paper fails
|
|
79
|
+
// 11 pages of main text, the appendix after the references
|
|
80
|
+
// → banal: body 10, references 2 (the appendix taken for more references) — an over-long
|
|
81
|
+
// paper passes
|
|
82
|
+
// So format/page-limit counts from the text (`appendix_in_body`): the body is every page up to
|
|
83
|
+
// the references, that page too when body text stands above the heading, plus every page from
|
|
84
|
+
// an appendix that follows the references; the pages between are the reference pages
|
|
85
|
+
// (docs/rules/format/page-limit.md). An appendix after the references is found by hyperref's
|
|
86
|
+
// anchor: load hyperref.
|
|
87
|
+
"body_ends_at": "references",
|
|
88
|
+
"appendix_in_body": true,
|
|
89
|
+
|
|
90
|
+
// One kind: the Technical Track's papers. The camera-ready's extra page is not this limit.
|
|
91
|
+
"kinds": {
|
|
92
|
+
"technical": { "body_pages_max": 10, "ref_pages_max": 2 },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
}
|
package/presets/msr.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "MSR — venue card"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# MSR (Technical Papers)
|
|
6
|
+
|
|
7
|
+
The card of the venue preset `paperlint:msr` ([`msr.jsonc`](msr.jsonc)): what the venue asks for,
|
|
8
|
+
in prose. The numbers a machine checks live in the preset; the section at the end is generated from
|
|
9
|
+
it. The `submit-paper` skill reads this card for the venue's specifics.
|
|
10
|
+
|
|
11
|
+
**Re-verify the call for papers every year**
|
|
12
|
+
([2027.msrconf.org/track/msr-2027-technical-papers](https://2027.msrconf.org/track/msr-2027-technical-papers)):
|
|
13
|
+
the template changed from ACM to IEEE in 2027 («Note that IEEE format is being used this year,
|
|
14
|
+
whereas last year it was ACM format.»), and limits and dates change between editions.
|
|
15
|
+
|
|
16
|
+
## The venue (2027 edition)
|
|
17
|
+
|
|
18
|
+
- **Venue**: the Technical Papers track of **MSR 2027**, the International Conference on Mining
|
|
19
|
+
Software Repositories.
|
|
20
|
+
- **Portal**: HotCRP, `https://msr2027.hotcrp.com/` («Papers must be submitted through HotCRP»).
|
|
21
|
+
- **Dates** (the call, «AoE (UTC-12h)»): abstract **2026-10-20**, paper **2026-10-23**; early
|
|
22
|
+
reject notification 2026-12-03; author response 2026-12-04 to 2026-12-08; notification
|
|
23
|
+
2027-01-08; camera-ready 2027-01-26. The call's prose names the weekdays «Mon, 20 Oct 2026» and
|
|
24
|
+
«Thurs, 23 Oct 2026», its date table «Tue 20 Oct 2026» and «Fri 23 Oct 2026»; the calendar sides
|
|
25
|
+
with the table (2026-10-20 is a Tuesday).
|
|
26
|
+
- 🔴 **The portal closes earlier than the call says.** Read 2026-10-05 on
|
|
27
|
+
`https://msr2027.hotcrp.com/deadlines`: «Submission deadline: Tuesday Oct 20, 2026, 12 AM EDT»
|
|
28
|
+
(`"sub":1792468800`, 2026-10-20 04:00 UTC) and «Resubmission deadline: Friday Oct 23, 2026, 12 AM
|
|
29
|
+
EDT» («Completed submissions may be updated until this deadline»). Midnight EDT at the start of
|
|
30
|
+
each day is about a day and a half before the end of that day AoE. The portal is what refuses the
|
|
31
|
+
upload: plan for its times. The preset carries them as `deadlines` (`source: "portal"`, with the
|
|
32
|
+
day read), refreshed by paperlint's scheduled workflow when the portal changes them; a paper whose
|
|
33
|
+
current cycle names `paperlint:msr` derives them. Recording the call's days in the paper's own
|
|
34
|
+
cycle maps «abstract» to `registration` and «paper» to `submission` — and the portal's earlier
|
|
35
|
+
`submission` is then the one in force.
|
|
36
|
+
- **Format**, verbatim from the call: «LaTeX users must use \documentclass[10pt,conference]{IEEEtran}
|
|
37
|
+
without including the compsoc or compsocconf options», «title in 24pt font and full text in 10pt
|
|
38
|
+
type», and «Alterations of spacing, font size, and other changes that deviate from the
|
|
39
|
+
instructions may result in desk rejection without further review.»
|
|
40
|
+
- **Double-anonymous**: «The MSR 2027 Technical Track will employ a double-anonymous review process.
|
|
41
|
+
Thus, no submission may reveal its authors' identities.» The call adds: names omitted, prior work
|
|
42
|
+
cited in the third person, and a preprint must not say it was submitted to MSR. The portal's data
|
|
43
|
+
says `"blind":true`.
|
|
44
|
+
- **Attendance**: «If a submission is accepted, at least one author of the paper is required to
|
|
45
|
+
register for MSR 2027 and present the paper.» The call does not say whether a remote presentation
|
|
46
|
+
is allowed.
|
|
47
|
+
- **New in 2027**, from the call: a submission may be desk rejected for fabricated references
|
|
48
|
+
(«citations to papers, authors, venues, datasets, tools, or other artifacts that do not exist»),
|
|
49
|
+
clear signs of unverified AI-generated text, or hidden instructions aimed at automated tools.
|
|
50
|
+
|
|
51
|
+
## Paper kinds and limits
|
|
52
|
+
|
|
53
|
+
| kind | main-text pages | pages of only references | what the call says |
|
|
54
|
+
| ----------- | --------------: | -----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `technical` | 10 | 2 | «All submissions must not exceed 10 pages for the main text, inclusive of all figures, tables, appendices, etc. Two more pages containing only references are permitted.» |
|
|
56
|
+
|
|
57
|
+
«Accepted papers will be allowed one extra page for the main text of the camera-ready version.» —
|
|
58
|
+
not the submission's limit, so not in the preset.
|
|
59
|
+
|
|
60
|
+
🔴 **Appendices count in the ten pages**, and a page that holds anything but references is a
|
|
61
|
+
main-text page. banal's count gets both wrong on an IEEEtran build (an appendix before the
|
|
62
|
+
references turns its pages into «bibliography»; one after them into «references»), so the preset
|
|
63
|
+
counts from the text (`format.appendix_in_body`): the main text is every page up to the references —
|
|
64
|
+
that page too when text stands above the heading — and every page from an appendix that follows the
|
|
65
|
+
references; the pages between hold only references. **Load hyperref**: an appendix after the
|
|
66
|
+
references is found by hyperref's anchor, and without it is counted as reference pages. See
|
|
67
|
+
`docs/rules/format/page-limit.md`.
|
|
68
|
+
|
|
69
|
+
## What else the preset encodes
|
|
70
|
+
|
|
71
|
+
- **The IEEE template**, through `extends: paperlint:ieee-conference` — letter paper, two columns,
|
|
72
|
+
Times at 10 pt, IEEEtran's TeX packages ([`ieee-conference.md`](ieee-conference.md)) — with
|
|
73
|
+
`10pt` and `conference` required in the class line and `compsoc` and `compsocconf` forbidden
|
|
74
|
+
(`tex/template`, `template_forbids`).
|
|
75
|
+
- **Double-blind review** (`blind`), so `anonymity/identity` checks the PDF against the paper's
|
|
76
|
+
declared `identity`.
|
|
77
|
+
- **Where submissions go** (`portal`): `paperlint submission` reads and updates a paper's
|
|
78
|
+
submission through HotCRP's API on that site.
|
|
79
|
+
- **Names**: `MSR`, what `tex/venue-leftover` looks for in another venue's paper — only with a year
|
|
80
|
+
beside it (`mentions: with-year`: «MSR 2027», «MSR'27»), since «MSR» is also Microsoft Research
|
|
81
|
+
and an acronym papers define for themselves.
|
|
82
|
+
- **Not encoded**: the capitalization of the title and headings (`tex/heading-case` stays off: the
|
|
83
|
+
IEEE guidelines' rule has not been read and quoted here), and the register of the body (no
|
|
84
|
+
accepted MSR paper in the IEEE template exists yet to anchor `tex/contrast-frames` and its
|
|
85
|
+
siblings).
|
|
86
|
+
|
|
87
|
+
## What the preset resolves to
|
|
88
|
+
|
|
89
|
+
<!-- paperlint:preset-rules -->
|
|
90
|
+
<!-- prettier-ignore-start -->
|
|
91
|
+
<!-- Generated from msr.jsonc by `npx eslint --fix` (rule preset/card-rules). Edit the preset, not this section. -->
|
|
92
|
+
|
|
93
|
+
**`paperlint:msr`** — venue preset for MSR · call for papers: <https://2027.msrconf.org/track/msr-2027-technical-papers> · extends `paperlint:ieee-conference`
|
|
94
|
+
|
|
95
|
+
No preset of this chain sets a rule: under it, every rule keeps paperlint's default.
|
|
96
|
+
|
|
97
|
+
<!-- prettier-ignore-end -->
|
|
98
|
+
<!-- /paperlint:preset-rules -->
|