paperlint 7.1.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.
Files changed (119) hide show
  1. package/.github/workflows/ci.yml +3 -0
  2. package/.github/workflows/deadlines.yml +100 -0
  3. package/README.md +6 -0
  4. package/dist/adapters/hotcrp/deadlines.d.ts +8 -0
  5. package/dist/adapters/hotcrp/deadlines.d.ts.map +1 -0
  6. package/dist/adapters/hotcrp/deadlines.io.d.ts +6 -0
  7. package/dist/adapters/hotcrp/deadlines.io.d.ts.map +1 -0
  8. package/dist/adapters/hotcrp/deadlines.io.js +26 -0
  9. package/dist/adapters/hotcrp/deadlines.io.js.map +1 -0
  10. package/dist/adapters/hotcrp/deadlines.js +134 -0
  11. package/dist/adapters/hotcrp/deadlines.js.map +1 -0
  12. package/dist/adapters/hotcrp/index.d.ts +2 -0
  13. package/dist/adapters/hotcrp/index.d.ts.map +1 -1
  14. package/dist/adapters/hotcrp/index.js +2 -0
  15. package/dist/adapters/hotcrp/index.js.map +1 -1
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +40 -5
  18. package/dist/cli.js.map +1 -1
  19. package/dist/cycle-rules.d.ts +24 -0
  20. package/dist/cycle-rules.d.ts.map +1 -0
  21. package/dist/cycle-rules.js +212 -0
  22. package/dist/cycle-rules.js.map +1 -0
  23. package/dist/domain/cycle.d.ts +148 -0
  24. package/dist/domain/cycle.d.ts.map +1 -0
  25. package/dist/domain/cycle.js +281 -0
  26. package/dist/domain/cycle.js.map +1 -0
  27. package/dist/domain/deadline.d.ts +128 -0
  28. package/dist/domain/deadline.d.ts.map +1 -0
  29. package/dist/domain/deadline.js +281 -0
  30. package/dist/domain/deadline.js.map +1 -0
  31. package/dist/eslint-rules/cycle-stage.d.ts +39 -0
  32. package/dist/eslint-rules/cycle-stage.d.ts.map +1 -0
  33. package/dist/eslint-rules/cycle-stage.js +119 -0
  34. package/dist/eslint-rules/cycle-stage.js.map +1 -0
  35. package/dist/lib/paper-config.d.ts.map +1 -1
  36. package/dist/lib/paper-config.js +2 -0
  37. package/dist/lib/paper-config.js.map +1 -1
  38. package/dist/paper-settings.d.ts +7 -0
  39. package/dist/paper-settings.d.ts.map +1 -1
  40. package/dist/paper-settings.js +61 -8
  41. package/dist/paper-settings.js.map +1 -1
  42. package/dist/ports/venue-deadlines.d.ts +14 -0
  43. package/dist/ports/venue-deadlines.d.ts.map +1 -0
  44. package/dist/ports/venue-deadlines.js +2 -0
  45. package/dist/ports/venue-deadlines.js.map +1 -0
  46. package/dist/presets.d.ts +12 -0
  47. package/dist/presets.d.ts.map +1 -1
  48. package/dist/presets.js +19 -11
  49. package/dist/presets.js.map +1 -1
  50. package/dist/submission.d.ts +8 -0
  51. package/dist/submission.d.ts.map +1 -1
  52. package/dist/submission.js +41 -10
  53. package/dist/submission.js.map +1 -1
  54. package/dist/tex-requirements.d.ts +3 -0
  55. package/dist/tex-requirements.d.ts.map +1 -1
  56. package/dist/tex-requirements.js +19 -0
  57. package/dist/tex-requirements.js.map +1 -1
  58. package/dist/tex-venue-rules.d.ts +19 -0
  59. package/dist/tex-venue-rules.d.ts.map +1 -1
  60. package/dist/tex-venue-rules.js +69 -0
  61. package/dist/tex-venue-rules.js.map +1 -1
  62. package/dist/venue-rules.d.ts +10 -0
  63. package/dist/venue-rules.d.ts.map +1 -1
  64. package/dist/venue-rules.js +26 -10
  65. package/dist/venue-rules.js.map +1 -1
  66. package/docs/configuration.md +139 -11
  67. package/docs/rules/cycle/evidence.md +87 -0
  68. package/docs/rules/cycle/port-done.md +75 -0
  69. package/docs/rules/cycle/record.md +152 -0
  70. package/docs/rules/cycle/stage.md +85 -0
  71. package/docs/rules.md +48 -43
  72. package/docs/submission.md +5 -0
  73. package/eslint-rules/cycle-stage.test.mjs +131 -0
  74. package/eslint-rules/cycle-stage.ts +141 -0
  75. package/eslint.config.mjs +41 -1
  76. package/lib/paper-config.ts +3 -0
  77. package/package.json +1 -1
  78. package/presets/aidc.jsonc +24 -3
  79. package/presets/aidc.md +6 -3
  80. package/presets/msr.jsonc +25 -1
  81. package/presets/msr.md +5 -1
  82. package/presets/venue-profile.schema.json +39 -0
  83. package/scripts/check.ts +4 -0
  84. package/scripts/refresh-deadlines.test.ts +431 -0
  85. package/scripts/refresh-deadlines.ts +387 -0
  86. package/src/adapters/hotcrp/cassette/README.md +22 -0
  87. package/src/adapters/hotcrp/cassette/deadlines-aidc26.html +17 -0
  88. package/src/adapters/hotcrp/cassette/deadlines-fse2027.html +24 -0
  89. package/src/adapters/hotcrp/cassette/deadlines-icse2027.html +25 -0
  90. package/src/adapters/hotcrp/cassette/deadlines-msr2027.html +25 -0
  91. package/src/adapters/hotcrp/cassette/deadlines-nosuch.html +18 -0
  92. package/src/adapters/hotcrp/cassette/deadlines-sosp26.html +26 -0
  93. package/src/adapters/hotcrp/deadlines.io.test.ts +86 -0
  94. package/src/adapters/hotcrp/deadlines.io.ts +27 -0
  95. package/src/adapters/hotcrp/deadlines.test.ts +170 -0
  96. package/src/adapters/hotcrp/deadlines.ts +161 -0
  97. package/src/adapters/hotcrp/index.ts +2 -0
  98. package/src/cli.test.ts +9 -0
  99. package/src/cli.ts +43 -4
  100. package/src/cycle-rules.test.ts +278 -0
  101. package/src/cycle-rules.ts +273 -0
  102. package/src/domain/cycle.test.ts +456 -0
  103. package/src/domain/cycle.ts +432 -0
  104. package/src/domain/deadline.test.ts +386 -0
  105. package/src/domain/deadline.ts +472 -0
  106. package/src/new-paper.test.ts +1 -0
  107. package/src/paper-settings.test.ts +167 -0
  108. package/src/paper-settings.ts +85 -11
  109. package/src/ports/venue-deadlines.ts +14 -0
  110. package/src/presets.test.ts +105 -0
  111. package/src/presets.ts +43 -10
  112. package/src/rule-cases.test.ts +144 -0
  113. package/src/submission.test.ts +105 -1
  114. package/src/submission.ts +73 -12
  115. package/src/tex-requirements.ts +31 -0
  116. package/src/tex-venue-rules.test.ts +76 -0
  117. package/src/tex-venue-rules.ts +85 -0
  118. package/src/venue-rules.test.ts +82 -0
  119. package/src/venue-rules.ts +44 -12
@@ -44,6 +44,9 @@ on:
44
44
  # with zero checks. macOS is a cell of the build-e2e matrix below.
45
45
  pull_request:
46
46
  types: [opened, synchronize, reopened, ready_for_review]
47
+ # The deadlines bot's pull request (deadlines.yml) is opened with GITHUB_TOKEN, which starts no
48
+ # other workflow; that job dispatches this one on its branch, so the PR's head commit gets checks.
49
+ workflow_dispatch:
47
50
 
48
51
  # A newer push supersedes an older one on the same ref. Note this does NOT make the cancelled
49
52
  # run free — cancellation arrives after the expensive steps have already run and been billed —
@@ -0,0 +1,100 @@
1
+ # THE VENUE PRESETS' DEADLINES, RE-READ FROM THEIR PORTALS ONCE A DAY.
2
+ #
3
+ # A shipped venue preset (presets/msr.jsonc, presets/aidc.jsonc) carries its portal's deadlines,
4
+ # each with the day it was read. Chairs move deadlines; a paper only learns it if the preset does.
5
+ # So this job reads every preset's portal (`scripts/refresh-deadlines.ts`, through the HotCRP adapter
6
+ # in src/adapters/hotcrp/ — the public deadlines page, no account, no secret) and, when a value
7
+ # changed, opens ONE pull request with the new values, or updates the one already open. Its commit
8
+ # and title are `fix(presets): …`, which semantic-release (.releaserc.json, conventionalcommits)
9
+ # releases as a PATCH; a paper's normal dependency update (Dependabot) then brings the new dates.
10
+ # Nothing in a paper's own lint reads the network or the clock.
11
+ #
12
+ # 🔴 IT REPORTS, IT DOES NOT BLOCK. A portal that is down or gone is a `::warning::` annotation and a
13
+ # line in the pull request's body, and the script exits 0: the venue's outage is not a defect of this
14
+ # repository, and tomorrow's run reads it again. Only a preset that does not parse fails the run
15
+ # (exit 1) — that one IS ours, and `ci` fails on it too. `ci` itself never touches the network for
16
+ # this: scripts/refresh-deadlines.test.ts replays the pages recorded in src/adapters/hotcrp/cassette/.
17
+ #
18
+ # ⚠️ A pull request opened with GITHUB_TOKEN does not start other workflows (GitHub's rule against
19
+ # loops), so `ci` would never run on it and the PR could not show green. The last step therefore
20
+ # dispatches `ci` on the branch (ci.yml declares `workflow_dispatch` for this); its checks land on
21
+ # the branch's head commit, which is what the pull request shows. Two repository settings are
22
+ # needed, and both are switches in Settings → Actions → General, not in this file: workflows may
23
+ # have "Read and write permissions", and "Allow GitHub Actions to create and approve pull requests".
24
+ #
25
+ # ⛽ The repository is public, so the minutes are free (CLAUDE.md, "Cost"). Measured locally
26
+ # 2026-10-05: the script reads both portals in about 2 s; `npm ci` dominates.
27
+ name: deadlines
28
+
29
+ on:
30
+ schedule:
31
+ # 05:17 UTC daily: off the top of the hour, when GitHub's scheduler is busiest and runs late.
32
+ - cron: "17 5 * * *"
33
+ workflow_dispatch:
34
+
35
+ # One run at a time: two runs pushing the same branch would race.
36
+ concurrency:
37
+ group: deadlines
38
+ cancel-in-progress: false
39
+
40
+ # Push the bot's branch · open or edit its pull request · dispatch `ci` on it. Nothing else.
41
+ permissions:
42
+ contents: write
43
+ pull-requests: write
44
+ actions: write
45
+
46
+ jobs:
47
+ refresh:
48
+ runs-on: ubuntu-latest
49
+ timeout-minutes: 10
50
+ env:
51
+ BRANCH: bot/preset-deadlines
52
+ steps:
53
+ - uses: actions/checkout@v7
54
+
55
+ - uses: actions/setup-node@v7
56
+ with:
57
+ node-version: "22"
58
+ cache: npm
59
+
60
+ # `--ignore-scripts`: the script runs from source (Node strips the types); `prepare`'s tsc
61
+ # build is not needed to read a page and rewrite a JSONC file.
62
+ - name: npm ci
63
+ run: npm ci --ignore-scripts
64
+ timeout-minutes: 5
65
+
66
+ - name: read every preset's portal
67
+ run: node scripts/refresh-deadlines.ts --summary "$RUNNER_TEMP/deadlines.md"
68
+ timeout-minutes: 3
69
+
70
+ - name: open or update the pull request
71
+ env:
72
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73
+ REPO: ${{ github.repository }}
74
+ run: |
75
+ set -euo pipefail
76
+ if git diff --quiet -- presets; then
77
+ echo "no deadline changed — nothing to propose"
78
+ exit 0
79
+ fi
80
+ git config user.name "github-actions[bot]"
81
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
82
+ git switch -C "$BRANCH"
83
+ # Only the presets: the script writes nothing else, and nothing else may ride along.
84
+ git add -- presets
85
+ git commit -F - <<'MSG'
86
+ fix(presets): venue deadlines as their portals publish them now
87
+
88
+ Re-read by .github/workflows/deadlines.yml (scripts/refresh-deadlines.ts); the pull
89
+ request's body lists each value that changed and where it was read.
90
+ MSG
91
+ # The branch is the bot's own and is rebuilt from main on every run: force is the point.
92
+ git push --force origin "$BRANCH"
93
+ title="fix(presets): venue deadlines as their portals publish them now"
94
+ open=$(gh pr list --repo "$REPO" --head "$BRANCH" --state open --json number --jq '.[0].number // empty')
95
+ if [ -z "$open" ]; then
96
+ gh pr create --repo "$REPO" --base main --head "$BRANCH" --title "$title" --body-file "$RUNNER_TEMP/deadlines.md"
97
+ else
98
+ gh pr edit "$open" --repo "$REPO" --title "$title" --body-file "$RUNNER_TEMP/deadlines.md"
99
+ fi
100
+ gh workflow run ci.yml --repo "$REPO" --ref "$BRANCH"
package/README.md CHANGED
@@ -228,6 +228,12 @@ papers/my-paper/paperlint.json one paper: its venue preset ("extends"), its ki
228
228
  - The paper's venue preset is its `"extends"` key — the one `new --venue` writes.
229
229
  - A paper's `paperlint.json` overrides the project's, key by key.
230
230
  - **An unknown key is an error**, so a typo cannot silently turn a setting off.
231
+ - A paper that moves between venues keeps a list of attempts, `cycles`, instead of `"extends"`; each
232
+ records its deadlines as read from the portal and the call, plus any override the chairs granted,
233
+ and the earlier reading binds ([`docs/configuration.md`](docs/configuration.md#deadlines)).
234
+ - **Deadlines of a shipped venue preset stay current on their own:** paperlint's repository re-reads
235
+ each preset's portal daily and releases a patch when a date moves, so your normal dependency update
236
+ (Dependabot, Renovate) brings it. `paperlint lint` itself never reads the clock or the network.
231
237
 
232
238
  Every key: [`docs/configuration.md`](docs/configuration.md). Already use ESLint for other files? See
233
239
  [`docs/configuration.md`](docs/configuration.md#using-the-rules-from-an-existing-eslint-config).
@@ -0,0 +1,8 @@
1
+ import { type DeadlineWhat, type PortalDeadlines } from "../../domain/deadline.ts";
2
+ import { type Result } from "../../domain/result.ts";
3
+ import type { PortalFailure } from "../../domain/submission.ts";
4
+ /** What a listed deadline's label names, in paperlint's words; null for one paperlint does not name. */
5
+ export declare function whatOf(label: string): DeadlineWhat | null;
6
+ /** `GET /deadlines` → the portal's deadlines, or why the page is not them. */
7
+ export declare function parseDeadlinesPage(httpStatus: number, html: string): Result<PortalDeadlines, PortalFailure>;
8
+ //# sourceMappingURL=deadlines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadlines.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/deadlines.ts"],"names":[],"mappings":"AAuBA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AA2BhE,wGAAwG;AACxG,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAOzD;AA+ED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,CAYxC"}
@@ -0,0 +1,6 @@
1
+ import type { VenueDeadlines } from "../../ports/venue-deadlines.ts";
2
+ /** The deadlines of the HotCRP site at `url` (no trailing slash). */
3
+ export declare function hotcrpDeadlines(o: {
4
+ readonly url: string;
5
+ }): VenueDeadlines;
6
+ //# sourceMappingURL=deadlines.io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadlines.io.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/deadlines.io.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAKrE,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAc3E"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * HotCRP's deadlines page over Node's `fetch`: `GET <site>/deadlines`, no token — the page is
3
+ * public, and a deadline is nobody's secret.
4
+ */
5
+ import { messageOf } from "../../domain/text.js";
6
+ import { err } from "../../domain/result.js";
7
+ import { parseDeadlinesPage } from "./deadlines.js";
8
+ const READ_TIMEOUT_MS = 60_000;
9
+ /** The deadlines of the HotCRP site at `url` (no trailing slash). */
10
+ export function hotcrpDeadlines(o) {
11
+ return {
12
+ async read() {
13
+ try {
14
+ const r = await fetch(`${o.url}/deadlines`, {
15
+ headers: { Accept: "text/html" },
16
+ signal: AbortSignal.timeout(READ_TIMEOUT_MS),
17
+ });
18
+ return parseDeadlinesPage(r.status, await r.text());
19
+ }
20
+ catch (e) {
21
+ return err({ kind: "unreachable", detail: messageOf(e) });
22
+ }
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=deadlines.io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadlines.io.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/deadlines.io.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,qEAAqE;AACrE,MAAM,UAAU,eAAe,CAAC,CAA2B;IACzD,OAAO;QACL,KAAK,CAAC,IAAI;YACR,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,YAAY,EAAE;oBAC1C,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE;oBAChC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC;iBAC7C,CAAC,CAAC;gBACH,OAAO,kBAAkB,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * HotCRP's deadlines page (`<site>/deadlines`), parsed at the boundary into paperlint's
3
+ * `PortalDeadlines`. Pure.
4
+ *
5
+ * ── WHAT THE PAGE IS, measured 2026-10-05 on five live sites (`cassette/deadlines-*.html`) ───────
6
+ * The page is HTML, public, no account needed; the API endpoint of the same name (`/api/deadlines`)
7
+ * answers 401 «Missing credentials» without a token. The machine-readable part is the argument of
8
+ * `hotcrp.init_deadlines({…})` in the page's last script: the author's `status_json()`
9
+ * (kohler/hotcrp, src/contact.php), of which an anonymous visitor gets
10
+ *
11
+ * now the server's clock, Unix seconds with a fraction
12
+ * sub.open whether the submission round is open now
13
+ * sub.sub the submission deadline, Unix seconds (SubmissionRound::$submit)
14
+ * sub.reg the registration deadline, when it is earlier (SubmissionRound::$register)
15
+ * sub.blind true | "optional" | "until-review" (Conf::submission_blindness)
16
+ * final.done the final-version (camera-ready) deadline (final_deadline_for_display)
17
+ *
18
+ * The RESUBMISSION deadline (updates allowed until, `SubmissionRound::$resubmit`) is not in that
19
+ * object; the page lists it only in its `<dl>`, each entry a `<dt>` with the deadline's label and a
20
+ * `<span data-ts="…">` holding the same Unix seconds (pages/p_deadlines.php, `dl1`). So both are
21
+ * read: the JSON for what it names, the list for every deadline the page shows, matched by label.
22
+ */
23
+ import { z } from "zod";
24
+ import { instantOfUnix, } from "../../domain/deadline.js";
25
+ import { err, ok } from "../../domain/result.js";
26
+ const Blind = z.union([
27
+ z.boolean(),
28
+ z.literal("optional"),
29
+ z.literal("until-review"),
30
+ ]);
31
+ const Status = z.looseObject({
32
+ now: z.number(),
33
+ sub: z
34
+ .looseObject({
35
+ open: z.boolean().optional(),
36
+ sub: z.number().optional(),
37
+ reg: z.number().optional(),
38
+ blind: Blind.optional(),
39
+ })
40
+ .optional(),
41
+ final: z.looseObject({ done: z.number().optional() }).optional(),
42
+ });
43
+ /** The script call that carries the status object; the argument is JSON. */
44
+ const INIT = /hotcrp\.init_deadlines\((\{.*?\})\)/s;
45
+ /** One listed deadline: its label in `<strong>`, its time in `data-ts`. */
46
+ const ENTRY = /<dt><strong>([^<]*)<\/strong>:\s*<span[^>]*\bdata-ts="(\d+)"/g;
47
+ /** The page's title, for a page that is no deadlines page (a site that does not exist). */
48
+ const TITLE = /<h1 id="h-title">([^<]*)</;
49
+ /** What a listed deadline's label names, in paperlint's words; null for one paperlint does not name. */
50
+ export function whatOf(label) {
51
+ const l = label.toLowerCase();
52
+ if (/\bresubmission deadline\b/.test(l))
53
+ return "resubmission";
54
+ if (/\bregistration deadline\b/.test(l))
55
+ return "registration";
56
+ if (/\bsubmission deadline\b/.test(l))
57
+ return "submission";
58
+ if (/\bfinal\b|\bcamera[- ]ready\b/.test(l))
59
+ return "camera-ready";
60
+ return null;
61
+ }
62
+ function fromStatus(s) {
63
+ const named = [
64
+ ["registration", s.sub?.reg],
65
+ ["submission", s.sub?.sub],
66
+ ["camera-ready", s.final?.done],
67
+ ];
68
+ return named.flatMap(([what, at]) => at === undefined ? [] : [{ what, label: what, at: instantOfUnix(at) }]);
69
+ }
70
+ /** Every deadline the page lists, with its label as the page spells it. */
71
+ function fromList(html) {
72
+ return [...html.matchAll(ENTRY)].map((m) => {
73
+ // Both groups always participate in a match of ENTRY: there is no fallback to take.
74
+ const label = String(m[1]).trim();
75
+ return { what: whatOf(label), label, at: instantOfUnix(Number(m[2])) };
76
+ });
77
+ }
78
+ /** Listed entries first (they carry the page's label); a status entry only when the list lacks its kind. */
79
+ function merged(listed, named) {
80
+ const extra = named.filter((n) => !listed.some((l) => l.what === n.what && l.at === n.at));
81
+ return [...listed, ...extra].toSorted((a, b) => a.at.localeCompare(b.at));
82
+ }
83
+ const refused = (httpStatus, html) => {
84
+ const title = TITLE.exec(html)?.[1]?.trim();
85
+ return {
86
+ kind: "refused",
87
+ httpStatus,
88
+ messages: title === undefined
89
+ ? []
90
+ : [{ message: title, field: null, status: null }],
91
+ };
92
+ };
93
+ /** The status object in the page's `init_deadlines` call, or why there is none. */
94
+ function statusOf(httpStatus, html) {
95
+ const m = INIT.exec(html);
96
+ if (m === null)
97
+ return err({
98
+ kind: "malformed",
99
+ httpStatus,
100
+ detail: "the page has no `hotcrp.init_deadlines(…)` call — not a HotCRP deadlines page",
101
+ });
102
+ const json = (() => {
103
+ try {
104
+ return JSON.parse(String(m[1])); // the group always participates in a match of INIT
105
+ }
106
+ catch {
107
+ return undefined;
108
+ }
109
+ })();
110
+ const parsed = Status.safeParse(json);
111
+ return parsed.success
112
+ ? ok(parsed.data)
113
+ : err({
114
+ kind: "malformed",
115
+ httpStatus,
116
+ detail: "the `init_deadlines` argument is not the status object HotCRP documents",
117
+ });
118
+ }
119
+ /** `GET /deadlines` → the portal's deadlines, or why the page is not them. */
120
+ export function parseDeadlinesPage(httpStatus, html) {
121
+ if (httpStatus < 200 || httpStatus >= 300)
122
+ return err(refused(httpStatus, html));
123
+ const status = statusOf(httpStatus, html);
124
+ if (!status.ok)
125
+ return status;
126
+ const s = status.value;
127
+ return ok({
128
+ now: s.now,
129
+ open: s.sub?.open ?? false,
130
+ blind: s.sub?.blind ?? null,
131
+ deadlines: merged(fromList(html), fromStatus(s)),
132
+ });
133
+ }
134
+ //# sourceMappingURL=deadlines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadlines.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/deadlines.ts"],"names":[],"mappings":"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"}
@@ -4,4 +4,6 @@
4
4
  */
5
5
  export { CONTENT_FIELD, changeObject, hotcrpPortal, type HotcrpOptions, } from "./portal.io.ts";
6
6
  export { parseShow, parseUpdate, sha256OfHash } from "./response.ts";
7
+ export { hotcrpDeadlines } from "./deadlines.io.ts";
8
+ export { parseDeadlinesPage, whatOf } from "./deadlines.ts";
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
@@ -4,4 +4,6 @@
4
4
  */
5
5
  export { CONTENT_FIELD, changeObject, hotcrpPortal, } from "./portal.io.js";
6
6
  export { parseShow, parseUpdate, sha256OfHash } from "./response.js";
7
+ export { hotcrpDeadlines } from "./deadlines.io.js";
8
+ export { parseDeadlinesPage, whatOf } from "./deadlines.js";
7
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,GAEb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/hotcrp/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,GAEb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -49,7 +49,7 @@ import { imageSize } from "./adapters/png/index.js";
49
49
  import { captions } from "./adapters/srt/index.js";
50
50
  import { TALK_RULE_LEVELS, talkRules } from "./talk-rules.js";
51
51
  import { ANONYMITY_RULE_LEVELS, anonymityRules, PAGE_LIMIT_RULE_LEVELS, pageLimitRules, VENUE_RULE_LEVELS, venueRules, } from "./venue-rules.js";
52
- import { FORMAT_RULE_LEVELS, formatRules, TEX_VENUE_RULE_LEVELS, texVenueRules, } from "./tex-venue-rules.js";
52
+ import { FORMAT_RULE_LEVELS, formatRules, CYCLE_PORT_RULE_LEVELS, cyclePortRules, TEX_VENUE_RULE_LEVELS, texVenueRules, } from "./tex-venue-rules.js";
53
53
  import { claimProvenanceRule } from "./claim-provenance.js";
54
54
  import { registerRule } from "./register.js";
55
55
  import { REGISTER_BAND_RULE_LEVELS, registerBandRules, } from "./register-bands.js";
@@ -73,6 +73,8 @@ import { parseRuleBlocks, parseRuleEntries, shippedRuleIds, unknownKeys, } from
73
73
  export { init };
74
74
  export { nextSteps } from "./init.js";
75
75
  import paperStages from "#eslint-rules/paper-stages";
76
+ import cycleStage from "#eslint-rules/cycle-stage";
77
+ import { CYCLE_RULE_LEVELS, cycleRules } from "./cycle-rules.js";
76
78
  import { FOLDER_VENUE_RULE_LEVELS, folderVenueRules, } from "./folder-venue-rule.js";
77
79
  import typography from "#eslint-rules/paper-typography";
78
80
  import texBuild from "#eslint-rules/tex-build";
@@ -184,6 +186,24 @@ settings — paperlint.json, at two levels, one schema. Both are optional.
184
186
  "extends" names a venue preset: paperlint:<name> (shipped: ${SHIPPED_VENUES().join(", ")})
185
187
  or ./path.jsonc, relative to the paperlint.json. npm presets are not supported yet.
186
188
 
189
+ cycles and deadlines — a paper's attempts at venues, oldest first, instead of "extends",
190
+ "kind" and "submission" (those are then the current attempt's, and refused beside "cycles"):
191
+
192
+ { "cycles": [ { "id": "msr-2027", "venue": { "kind": "preset", "extends": "paperlint:msr" },
193
+ "kind": "technical", "opened": "2026-10-05",
194
+ "deadlines": [ { "what": "submission",
195
+ "observed": [ { "at": "2026-10-23 AoE", "source": "call",
196
+ "url": "<the call>", "read": "2026-10-05" } ] } ] } ] }
197
+
198
+ A venue preset carries the portal's deadlines, read and dated; the package updates them and
199
+ your dependency update brings them. A paper adds what the call says ("source": "call") and,
200
+ for a deadline moved by the chairs, "override": { "at", "reason", "evidence" } — evidence a
201
+ file in the paper folder. The override wins; otherwise the earlier reading binds. "what":
202
+ registration (the call's abstract), submission (the full paper), resubmission, notification,
203
+ camera-ready. A venue without a preset: "venue": { "kind": "named", "name", "url" }, every
204
+ deadline typed from its call. Lint never reads the clock: it checks the record, not the time
205
+ left. docs/configuration.md#the-papers-cycles
206
+
187
207
  "rules" is { "<rule>": "<severity>" } for every paper file in scope, or ESLint flat-config
188
208
  blocks (files, ignores, rules) with globs relative to that file. Order, later wins: paperlint's
189
209
  own, the venue preset's, the root file's, the paper's. Optional rules (off unless turned on):
@@ -204,6 +224,20 @@ const REGISTER_AND_CASE_RULES = {
204
224
  ...registerBandRules(TEX_RULE_DEPS),
205
225
  "heading-case": headingCaseRule(TEX_RULE_DEPS),
206
226
  };
227
+ /**
228
+ * The paper's attempts (`cycles` in paperlint.json), judged on `PIPELINE-STATUS.md`: the record itself
229
+ * and its evidence (src/cycle-rules.ts), and the stages that name a cycle (eslint-rules/cycle-stage.ts).
230
+ * The `cycle` plugin's other rule, `port-done`, reads `paper.tex` (src/tex-venue-rules.ts).
231
+ */
232
+ /** The markdown language with YAML frontmatter: what every markdown block of the config lints as. */
233
+ const MARKDOWN_WITH_FRONTMATTER = {
234
+ language: "markdown/gfm",
235
+ languageOptions: { frontmatter: "yaml" },
236
+ };
237
+ const CYCLE_STATUS_RULES = {
238
+ ...cycleRules({ files: nodeFiles, venuesDir: presetsDir() }),
239
+ ...cycleStage.rules,
240
+ };
207
241
  /** The rules of the files `paper.tex` includes, each read on its own as a fragment (#144). */
208
242
  const FRAGMENT_RULES = {
209
243
  "future-promise": texBuild["future-promise"],
@@ -229,10 +263,7 @@ export function buildConfig(opts = {}, texLanguage) {
229
263
  "paper/section-word": "warn",
230
264
  "paper/leading-zero": "warn",
231
265
  };
232
- const md = {
233
- language: "markdown/gfm",
234
- languageOptions: { frontmatter: "yaml" },
235
- };
266
+ const md = MARKDOWN_WITH_FRONTMATTER;
236
267
  const cfg = [
237
268
  // 🔴 THE PROJECT'S PAPER TEMPLATE IS NOT A PAPER. `paperlint new` reads `<papers>/.template/`, and
238
269
  // its files carry every marker a paper does. Flat config does NOT ignore dot-directories by
@@ -269,12 +300,14 @@ export function buildConfig(opts = {}, texLanguage) {
269
300
  ...folderVenueRules({ files: nodeFiles, venuesDir: presetsDir() }),
270
301
  },
271
302
  },
303
+ cycle: { rules: CYCLE_STATUS_RULES },
272
304
  },
273
305
  ...md,
274
306
  rules: {
275
307
  "paper/stages": "error",
276
308
  "paper/source": "error",
277
309
  ...FOLDER_VENUE_RULE_LEVELS,
310
+ ...CYCLE_RULE_LEVELS,
278
311
  },
279
312
  },
280
313
  {
@@ -326,6 +359,7 @@ export function buildConfig(opts = {}, texLanguage) {
326
359
  ...pageLimitRules({ files: nodeFiles, venuesDir: presetsDir() }),
327
360
  },
328
361
  },
362
+ cycle: { rules: cyclePortRules(TEX_RULE_DEPS) },
329
363
  },
330
364
  language: "tex/latex",
331
365
  rules: {
@@ -348,6 +382,7 @@ export function buildConfig(opts = {}, texLanguage) {
348
382
  ...TEX_VENUE_RULE_LEVELS,
349
383
  ...FORMAT_RULE_LEVELS,
350
384
  ...PAGE_LIMIT_RULE_LEVELS,
385
+ ...CYCLE_PORT_RULE_LEVELS,
351
386
  // Silent for a paper that declares no `talk` (src/talk-rules.ts), but talk/undeclared.
352
387
  ...TALK_RULE_LEVELS,
353
388
  },