paperlint 3.1.1 → 3.1.2

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 (52) hide show
  1. package/CLAUDE.md +18 -97
  2. package/CONTRIBUTING.md +7 -21
  3. package/README.md +11 -7
  4. package/dist/adapters/references/clock.io.d.ts +5 -0
  5. package/dist/adapters/references/clock.io.d.ts.map +1 -0
  6. package/dist/adapters/references/clock.io.js +7 -0
  7. package/dist/adapters/references/clock.io.js.map +1 -0
  8. package/dist/adapters/references/index.d.ts +24 -2
  9. package/dist/adapters/references/index.d.ts.map +1 -1
  10. package/dist/adapters/references/index.js +125 -15
  11. package/dist/adapters/references/index.js.map +1 -1
  12. package/dist/build.d.ts +4 -0
  13. package/dist/build.d.ts.map +1 -1
  14. package/dist/build.js +10 -3
  15. package/dist/build.js.map +1 -1
  16. package/dist/domain/lookup-cache.d.ts +75 -0
  17. package/dist/domain/lookup-cache.d.ts.map +1 -0
  18. package/dist/domain/lookup-cache.js +137 -0
  19. package/dist/domain/lookup-cache.js.map +1 -0
  20. package/dist/ports/check-references.d.ts +12 -2
  21. package/dist/ports/check-references.d.ts.map +1 -1
  22. package/dist/ports/check-references.js +0 -5
  23. package/dist/ports/check-references.js.map +1 -1
  24. package/dist/references.d.ts +11 -3
  25. package/dist/references.d.ts.map +1 -1
  26. package/dist/references.js +63 -15
  27. package/dist/references.js.map +1 -1
  28. package/docs/prior-art/README.md +11 -10
  29. package/docs/prior-art/citation-checkers.md +174 -0
  30. package/docs/references.md +126 -0
  31. package/docs/testing.md +118 -0
  32. package/docs/toolchain.md +6 -4
  33. package/package.json +1 -1
  34. package/skills/paper-pipeline/references/artifact-checklist.md +7 -7
  35. package/skills/render-paper/checkers-requirements.txt +30 -19
  36. package/skills/render-paper/ensure-checkers.sh +20 -4
  37. package/skills/verify-citations/SKILL.md +26 -10
  38. package/skills/verify-citations/SKILL.md.spec.ts +25 -9
  39. package/skills/verify-citations/scripts/__snapshots__/verify-cites.net.test.mjs.snap +28 -10
  40. package/skills/verify-citations/scripts/bib-authors.mjs +5 -6
  41. package/skills/verify-citations/scripts/verify-cites.mjs +285 -140
  42. package/skills/verify-citations/scripts/verify-cites.net.test.mjs +321 -20
  43. package/skills/verify-citations/scripts/verify-cites.test.mjs +4 -2
  44. package/src/adapters/references/clock.io.ts +8 -0
  45. package/src/adapters/references/index.test.ts +341 -9
  46. package/src/adapters/references/index.ts +198 -29
  47. package/src/build.ts +10 -3
  48. package/src/domain/lookup-cache.test.ts +178 -0
  49. package/src/domain/lookup-cache.ts +202 -0
  50. package/src/ports/check-references.ts +16 -2
  51. package/src/references.test.ts +160 -10
  52. package/src/references.ts +93 -17
package/CLAUDE.md CHANGED
@@ -75,7 +75,7 @@ nodes.
75
75
  **3. Every check needs BOTH halves, or it is not tested.** It must FIRE on a planted defect
76
76
  and stay QUIET on a clean fixture. A check that has only been seen quiet is
77
77
  indistinguishable from a dead one — silence is its success state. Prove the fire half by
78
- seeing the test go RED before the fix lands (§ Testing — how a test is written here).
78
+ seeing the test go RED before the fix lands ([`docs/testing.md`](docs/testing.md)).
79
79
 
80
80
  **4. `exit 0` with empty output is NOT "clean".** A rule whose glob matched no files reports
81
81
  exactly like a rule that passed. Any rule shipped here must be loud when its input set is
@@ -188,6 +188,12 @@ the instruction and never the evidence — the same split as rules 9 and 10 and
188
188
  🔴 The argument "we need another command for X" is, in every tool examined, an argument that
189
189
  the CONFIG is not declaring something. Check that before adding a verb.
190
190
 
191
+ Rejected on 2026-09-27, so it is not proposed again: a separate `paperlint refs` command for the
192
+ reference check. The slowness it would have moved (#107) was a cache thrown away after every build,
193
+ not a missing verb. The fix keeps the check in `build` and commits what the services answered in
194
+ `<paper>/repro/references-cache.json` — **raw responses, never verdicts**: verdicts are derived
195
+ again on every build, so a checker fix reaches every paper ([`docs/references.md`](docs/references.md)).
196
+
191
197
  ## Distribution — one install path: npm, then `paperlint init`
192
198
 
193
199
  `npm i -D paperlint` brings all the code — rules, skills, hooks, scripts. `paperlint init`
@@ -487,102 +493,17 @@ justified two hundred lines above precisely by these minutes being free.
487
493
 
488
494
  ## Testing
489
495
 
490
- ```bash
491
- npm test # vitest over *.test.ts, then the vigiles harnesses
492
- npm run coverage # the same run under c8; fails below the thresholds in .c8rc.json
493
- npx vitest run <file> # one unit test
494
- npx vigiles test <file> # one harness
495
- ```
496
-
497
- **Two kinds of test, told apart by what the file imports.** A `*.harness.*` file tests the agent
498
- surface and imports `runHook`, `runHarnessTest` or `runEval` from vigiles; everything else is a plain
499
- unit test run by vitest, beside the module it tests: `<module>.test.ts` for a `.ts` module, and
500
- `<module>.test.mjs` for a `.mjs` one (TypeScript has no types to check a JS module against, and
501
- `allowJs` was measured to break a dozen existing `@ts-expect-error` imports). Older harnesses that
502
- import none of the three are frozen in `scripts/harness-api.frozen.json`, which only shrinks;
503
- `scripts/harness-api.test.ts` parses every harness's imports and holds both halves (#77). vitest
504
- exits 1 when no file matches, and it transpiles without type-checking, so `npm run check` runs
505
- `tsc -p tsconfig.test.json` as its own gate.
506
-
507
- **While working: the fast gates on what you touched. Before every push: `npm run check`.** While
508
- editing, run vitest on the touched test files (`npx vitest run <file or folder>`), `npx tsc --noEmit`,
509
- `npx eslint <touched files>` and `npm run fmt:check`. Before pushing, run the full `npm run check`
510
- (about three minutes) and read its exit code: it includes the 100% coverage gate, which a
511
- single-file run cannot judge. CI runs the same command plus the TeX e2e that cannot run locally.
512
-
513
- ⚠️ **Not `vigiles test .`** — the `.` is read as a FILE, the runner dies with
514
- `ERR_UNSUPPORTED_DIR_IMPORT`, and it still exits 0. See the measured table below.
515
-
516
- Skills are tested **through vigiles** — a colocated `<skill>.harness.mjs` beside the skill.
517
- (This read «Skills, if and when they arrive» until 2026-09-17; there are 24 of them under
518
- `skills/` carrying a `SKILL.md`, and the README's opening line claimed the repository was
519
- empty — issue #6.) Not through a bespoke script: a home-grown runner here once printed
520
- confident, byte-identical "clean" verdicts for three different skills that had never loaded.
521
-
522
- ### How a test is written here
523
-
524
- 1. **Red first.** A new test is seen FAILING before the change that makes it pass — run it on
525
- the unfixed code, watch it go red at its own assertion, then fix. A test that has only ever
526
- been green is indistinguishable from one that cannot fail. Never add a file that patches
527
- source to prove a test can fail — seeing it red once, here, is that proof.
528
- 2. **Assert the whole value.** Compare the entire returned value (`assert.deepEqual`,
529
- `expect(x).toEqual(…)`), not a substring of it or one field. A substring assertion passes on
530
- output that is wrong everywhere else — a defect found here over and over
531
- (`"that is the"` matching two different messages, a bare word the usage block always prints).
532
- A substring is right only when the value is prose whose wording is not the subject; then say
533
- so in a comment.
534
- 3. **Test what the code DOES, never what its source SAYS.** A test that reads a source file (a
535
- `.mjs`, a `SKILL.md`, a config) and asserts it contains some text restates the file: rewording
536
- turns it red while a real regression stays green. Assert behaviour instead: a return value, the
537
- output and exit code of a run, what landed on disk, what a parser reports. Text is a legitimate
538
- subject only when it IS the output (a message the program prints, a file it generates).
539
- 4. **One assertion helper for harnesses: `lib/check.mjs`.** `const check = createChecker();` then
540
- `check(label, cond, detail)`. A failure prints the label and the detail (a value is rendered
541
- with `util.inspect`, a function is called only on failure), every call is counted
542
- (`check.count`, for the summary line) and reported to vigiles. Do not define a local `check`.
543
- 5. **Coverage is a gate.** `npm run check` and CI run `npm run coverage` — `npm test` under c8,
544
- `--check-coverage` against `.c8rc.json`. c8 reads `NODE_V8_COVERAGE`, so a CLI a harness
545
- spawns is measured too — unless the harness hands the child a fresh `env` without it. vitest
546
- runs in the `threads` pool with native `import` (`vitest.config.ts` says why): under its
547
- defaults c8 saw nothing vitest ran. The run preloads `test/coverage-src.mjs`, which answers
548
- every import of `dist/*.js` with `src/*.ts`: otherwise a module the tests import directly AND
549
- the spawned CLI loads compiled is measured twice, and its branches and functions stay red in
550
- whichever copy did not run them. `npm test` without coverage still runs `dist/`.
551
- 6. **No `c8 ignore`, and no guard deleted to reach 100%.** An effect a test cannot reach — a
552
- race, a permission root is never denied, a broken install, a 270 MB download — is made
553
- INJECTABLE (a `readdir`, an fs object, a manifest reader, a toolchain function) and the test
554
- passes a fake. A precondition about an argument becomes the signature: the function takes the
555
- value it needs, so a call without it cannot be written. A guard whose input can really occur
556
- stays, with the test that reaches it. `scripts/coverage-config.test.ts` fails on any
557
- coverage-ignore comment in a measured file (it reads comments off the parsed tree), and pins
558
- `.c8rc.json`'s `exclude` list: a new exclusion fails there until it is added on purpose, with
559
- its reason. Thresholds are 100 for lines, statements, functions and branches.
560
-
561
- ## `npm test` — `--min=1` stays, and here is what it is for
562
-
563
- The script is `vigiles test --min=1`. It went green on 2026-09-11 when the first harnesses
564
- landed; before that it correctly exited 1:
565
-
566
- ```
567
- ✗ vigiles test: --min=1 but only 0 test file(s) matched — evals never executed
568
- (check the paths/globs, or that the run was reached).
569
- ```
570
-
571
- Do **not** "fix" a future red by dropping `--min` — the flag is the only thing standing
572
- between "every test passed" and "no test ran", which is rule 4 applied to the test runner
573
- itself.
574
-
575
- 🔴 **Two ways this command lies if written differently, both measured 2026-09-11:**
576
-
577
- | form | what happens | exit |
578
- | ---------------------- | --------------------------------------------------------------------------- | ----- |
579
- | `vigiles test .` | `.` is read as a FILE — `ERR_UNSUPPORTED_DIR_IMPORT`, uncaught, runner dies | **0** |
580
- | `vigiles test` | `No **/*.harness.{mjs,cjs,js,mts,cts,ts} files found.` | **0** |
581
- | `vigiles test --min=1` | names the empty match and fails | **1** |
582
-
583
- The first row is the worse one: the runner crashed with a stack trace and still reported
584
- success. `package.json` shipped `vigiles test .` from the initial scaffold until this was
585
- measured — so the repo's own test command had never once executed a test, and said nothing.
496
+ | you are testing | kind |
497
+ | -------------------------------------------------------------------------- | --------------------------------------------- |
498
+ | a pure function | unit — vitest, `<module>.test.ts` beside it |
499
+ | a use case or adapter that reaches disk, a process, the network, the clock | integration — vitest, fakes through the ports |
500
+ | a hook's decision, a skill's contract | harness — vigiles, `<surface>.harness.mjs` |
501
+ | the installed package, a real TeX build | e2e — `test/e2e/*.mjs` |
502
+
503
+ Red first · assert the whole value · test what the code does, never what its source says · no test
504
+ touches the real network · 100% coverage, no `c8 ignore`. **Before every push: `npm run check`,
505
+ exit code read without a pipe.** Everything else — where files live, how fakes are injected, the
506
+ `--min=1` trap: [`docs/testing.md`](docs/testing.md).
586
507
 
587
508
  ## Commits
588
509
 
package/CONTRIBUTING.md CHANGED
@@ -10,27 +10,10 @@ it is below.
10
10
 
11
11
  ## How this is tested
12
12
 
13
- Every rule ships with a **harness**: a test that runs the rule twice. Once on a file with a defect
14
- planted in it, where the rule must find it. Once on a clean file, where the rule must say nothing.
15
-
16
- The second run is the one people skip, and it is the one that matters. A rule that is broken and
17
- finds nothing passes the first kind of test by accident — from outside, "there is nothing wrong
18
- here" and "this check never ran" look exactly the same.
19
-
20
- Three rules for writing the test itself:
21
-
22
- 1. **Red first.** Run a new test on the code BEFORE the fix and watch it fail at its own
23
- assertion. A test that has only ever been green is indistinguishable from one that cannot fail.
24
- 2. **Assert the whole value** — `assert.deepEqual` / `toEqual` on the entire result, not a
25
- substring or one field. A substring passes on output that is wrong everywhere else. The
26
- exception is prose whose wording is not the subject; say so in a comment.
27
- 3. **Test what the code does, not what its source says.** A test that reads a source file and
28
- asserts it contains some text restates the file: rewording turns it red, a real regression
29
- stays green. Assert a return value, a run's output and exit code, or what landed on disk.
30
-
31
- Say what an assertion guards in a comment directly above it (`// Guards: …`). A harness asserts
32
- through the shared `lib/check.mjs` (`const check = createChecker()`), which prints the label and
33
- the detail on failure and counts every call; a new harness does not define its own `check`.
13
+ Unit and integration tests run under vitest beside the module they test; harnesses run under
14
+ vigiles and cover what an agent sees; end-to-end runs install the package and build real PDFs.
15
+ Every test is seen red first, asserts the whole value, and tests what the code does rather than
16
+ what a file says. [`docs/testing.md`](docs/testing.md) says which kind to write and how.
34
17
 
35
18
  A harness runs in this tree, against this working copy. That is the wrong shape for a defect that
36
19
  only exists once somebody else has installed the package — a path written inside a skill, a file
@@ -85,6 +68,7 @@ docs/ evidence that would otherwise bloat CLAUDE.md:
85
68
  incidents.md what broke, measured
86
69
  install.md the install contract
87
70
  e2e.md the end-to-end runs, and when a change owes one
71
+ testing.md which kind of test to write, and the rules for all of them
88
72
  ```
89
73
 
90
74
  Most of the package's rules run on users' papers and are described for users in
@@ -101,6 +85,8 @@ The README links only what a user needs. These are for people changing the packa
101
85
  `init` writes, supported package managers, troubleshooting, and why it is shaped this way
102
86
  - [`docs/e2e.md`](docs/e2e.md) — the end-to-end runs: what each proves, what they do not cover,
103
87
  and when a change owes one
88
+ - [`docs/testing.md`](docs/testing.md) — the kinds of test, which one a change needs, and the rules
89
+ for every one
104
90
  - [`docs/incidents.md`](docs/incidents.md) — what broke, measured
105
91
  - [`docs/package-shape-options.md`](docs/package-shape-options.md) — the options for the
106
92
  package's shape, and the ranking
package/README.md CHANGED
@@ -27,7 +27,7 @@ before you submit.** It comes in two parts:
27
27
 
28
28
  Smaller slips too: `§` for "Section", `.05` for `0.05` — fixed for you.
29
29
 
30
- - 🧠 **Skills for [Claude Code](https://claude.com/claude-code)** — optional, 24 of them, covering the
30
+ - 🧠 **Skills for [Claude Code](https://claude.com/claude-code)** — optional, covering the
31
31
  whole pipeline: the idea, the venue, the study, the draft, the reviews, submission.
32
32
 
33
33
  ## Contents
@@ -173,17 +173,20 @@ what it does — "is this idea worth a paper?", "find me a venue for this". `ini
173
173
  - **A ready / not ready verdict before you submit**, worst problem first. `harden-paper`
174
174
  - **Where your paper stands**, measured from the real build. `paper-status`
175
175
 
176
- All 24, by stage: [`docs/skills.md`](docs/skills.md).
176
+ Every skill, by stage: [`docs/skills.md`](docs/skills.md).
177
177
 
178
178
  ## 🔍 Lint and build
179
179
 
180
- | | `paperlint build` | `paperlint lint` |
181
- | ------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
182
- | needs | Node, TeX Live, the network | Node |
183
- | does | compiles `paper.tex`, measures the PDF, checks each reference online (exists, right authors) | checks the source, and judges what build recorded: page limit, fonts, the reference results — offline |
184
- | writes | `paper.pdf`, and in `_build/` the measurements and the reference results | nothing (`--fix`: the three fixable slips) |
180
+ | | `paperlint build` | `paperlint lint` |
181
+ | ------ | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
182
+ | needs | Node, TeX Live, the network | Node |
183
+ | does | compiles `paper.tex`, measures the PDF, checks each reference online (exists, right authors) | checks the source, and judges what build recorded: page limit, fonts, the reference results — offline |
184
+ | writes | `paper.pdf`, in `_build/` the measurements and the reference results, and `repro/references-cache.json` | nothing (`--fix`: the three fixable slips) |
185
185
 
186
186
  - If `paper.pdf` or the bibliography changed since the last build, lint fails and tells you to rebuild.
187
+ - Commit `repro/references-cache.json`: it keeps what the citation services answered, so a build
188
+ asks only about new or edited entries (and answers older than 30 days), so an unchanged
189
+ bibliography usually builds without the network ([`docs/references.md`](docs/references.md)).
187
190
  - Lint also checks the pipeline's own records: `PIPELINE-STATUS.md`, reviews, notes on related
188
191
  papers ([`docs/rules.md`](docs/rules.md)).
189
192
  - The rules run on ESLint, so a deliberate exception is a comment on the line above:
@@ -295,6 +298,7 @@ Only `paperlint lint --fix`, and only three rules: `paper/section-word` (`§`
295
298
  - [`docs/install.md`](docs/install.md) — what `init` does, the hooks, package managers, troubleshooting
296
299
  - [`docs/configuration.md`](docs/configuration.md) — every setting, how `build` compiles, using your own ESLint
297
300
  - [`docs/rules.md`](docs/rules.md) — every check, venue presets, recording a submitted PDF
301
+ - [`docs/references.md`](docs/references.md) — the reference check, and the cache file to commit
298
302
  - [`docs/optional-rules.md`](docs/optional-rules.md) — checks only some venues need
299
303
  - [`docs/toolchain.md`](docs/toolchain.md) — TeX Live, and Banal (HotCRP's page-geometry checker, GPL)
300
304
  - [`CONTRIBUTING.md`](CONTRIBUTING.md) — how the package is tested and released, and adding a venue to it
@@ -0,0 +1,5 @@
1
+ /** The clock, for the lookup cache: the day an answer was fetched, in UTC. */
2
+ export declare const todayUtc: () => string;
3
+ /** Wait `ms` — DBLP's pace between requests. */
4
+ export declare const sleep: (ms: number) => Promise<void>;
5
+ //# sourceMappingURL=clock.io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.io.d.ts","sourceRoot":"","sources":["../../../src/adapters/references/clock.io.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,QAAQ,QAAO,MAA+C,CAAC;AAE5E,gDAAgD;AAChD,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CAG3C,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** The clock, for the lookup cache: the day an answer was fetched, in UTC. */
2
+ export const todayUtc = () => new Date().toISOString().slice(0, 10);
3
+ /** Wait `ms` — DBLP's pace between requests. */
4
+ export const sleep = (ms) => new Promise((r) => {
5
+ setTimeout(r, ms);
6
+ });
7
+ //# sourceMappingURL=clock.io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.io.js","sourceRoot":"","sources":["../../../src/adapters/references/clock.io.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAE5E,gDAAgD;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;IAChB,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -2,12 +2,34 @@
2
2
  * The online reference checks, as the `CheckReferences` port: `verify-cites` (the cited work
3
3
  * exists, the title matches — Crossref, OpenAlex, Semantic Scholar, arXiv) and `bib-authors` (the
4
4
  * authors are the published version's — DBLP). Both ship in this package's verify-citations skill;
5
- * this adapter only runs them and shapes their answers.
5
+ * this adapter only runs them, shapes their answers, and serves them from the paper's lookup cache.
6
+ *
7
+ * 🔴 THE CACHE HOLDS ANSWERS, AND ONLY THE CHECKERS' OWN SEAMS TOUCH IT. verify-cites takes a
8
+ * `cache` object keyed per resolver × identifier and stores only successful responses; it is
9
+ * handed the paper's cached responses and whatever it adds is new. bib-authors takes a `lookup`
10
+ * (title → DBLP hits) and a `pause`; the lookup is wrapped to answer from the cache, and the pause
11
+ * is skipped after a cached answer — DBLP's 900 ms pace and its retries run only for titles never
12
+ * answered. Neither checker's logic changes. Verdicts are derived from the answers on every build
13
+ * (`domain/lookup-cache.ts` says why).
6
14
  *
7
15
  * "Not checked" is decided up front, by one request: when Crossref cannot be reached at all, the
8
16
  * checkers would degrade every entry to `unresolvable` / `unchecked`, which reads like a result.
9
- * Saying `not-checked` with the reason is the honest record.
17
+ * Saying `not-checked` with the reason is the honest record. That request is skipped when every
18
+ * question this bibliography would ask is already answered in the cache: a warm build is offline.
10
19
  */
11
20
  import type { CheckReferences } from "../../ports/check-references.ts";
21
+ /**
22
+ * The key a DBLP answer is stored under in the lookup cache: the title's identity (verify-cites'
23
+ * `titleIdentity` — the same rule its own title keys use, so the two caches cannot drift), hashed.
24
+ * A re-cased or re-braced title keeps its answer; `C` and `C++` do not share one.
25
+ */
26
+ export declare const dblpTitleKey: (title: string) => string;
27
+ export interface ReferencesCheckerOptions {
28
+ /** The day a new answer is stamped with, YYYY-MM-DD. */
29
+ readonly today: () => string;
30
+ }
31
+ /** The checker, with its clock injected; `onlineReferences` is the one the CLI wires. */
32
+ export declare const referencesChecker: ({ today }: ReferencesCheckerOptions) => CheckReferences;
33
+ /** The checker the CLI wires: the real clock. */
12
34
  export declare const onlineReferences: CheckReferences;
13
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/references/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,iCAAiC,CAAC;AA4EzC,eAAO,MAAM,gBAAgB,EAAE,eA2B9B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/references/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,iCAAiC,CAAC;AA+HzC;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MACiC,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACvC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,MAAM,CAAC;CAC9B;AAsED,yFAAyF;AACzF,eAAO,MAAM,iBAAiB,GAC3B,WAAW,wBAAwB,KAAG,eAgDtC,CAAC;AAEJ,iDAAiD;AACjD,eAAO,MAAM,gBAAgB,EAAE,eAE7B,CAAC"}
@@ -1,5 +1,8 @@
1
+ import { freshPart, } from "../../domain/lookup-cache.js";
2
+ import { sha256Hex } from "../../domain/sha256.js";
1
3
  import { mapLimit } from "./pool.js";
2
4
  import { unreachable } from "./reach.io.js";
5
+ import { sleep, todayUtc } from "./clock.io.js";
3
6
  /** Citations looked up at once (#107). */
4
7
  const LOOKUPS_IN_FLIGHT = 6;
5
8
  // @ts-expect-error — a skill script in .mjs, it has no types
@@ -20,12 +23,20 @@ const authorsOf = (key, a) => a.findings.some((f) => f.key === key)
20
23
  : a.matched.includes(key)
21
24
  ? "match"
22
25
  : "skipped";
26
+ /**
27
+ * Why a work was not confirmed: verify-cites' reason, then — when some registry refused — which
28
+ * one, so "unresolvable" is not read as "every registry looked and found nothing". Nothing for a
29
+ * confirmed work: a refusal after a confirmation changed nothing.
30
+ */
31
+ const unconfirmed = (c) => c && c.verdict !== "true"
32
+ ? [c.reason, ...(c.refused ?? []).map((r) => `not asked: ${r}`)]
33
+ : [];
23
34
  /** One entry's verdict from the two checkers' answers. */
24
35
  function entryVerdict(key, found, a) {
25
36
  const c = found.find((x) => x.id === key);
26
37
  const mismatch = a.findings.find((f) => f.key === key);
27
38
  const why = [
28
- c && c.verdict !== "true" ? c.reason : undefined,
39
+ ...unconfirmed(c),
29
40
  mismatch ? describeAuthors(mismatch) : undefined,
30
41
  a.unchecked.find((u) => u.key === key)?.why,
31
42
  ]
@@ -38,27 +49,126 @@ function entryVerdict(key, found, a) {
38
49
  ...(why ? { why } : {}),
39
50
  };
40
51
  }
41
- export const onlineReferences = async (bib) => {
42
- const why = await unreachable();
43
- if (why !== null)
44
- return { kind: "not-checked", why };
45
- // 🔴 #107: the lookups were one at a time — 27 references took 217 s. They now run
46
- // LOOKUPS_IN_FLIGHT at a time, and the DBLP author pass runs beside them (it keeps its own
47
- // serial pace and 900 ms pause, which DBLP asks for). Each citation's own requests go to four
48
- // different services one after another, so a pool of 6 is at most 6 requests to any one of
49
- // them. The cache is shared: two citations with the same identifier may both miss it and ask
50
- // twice — an extra request, never a different answer.
51
- const cache = {};
52
+ /** Whether bib-authors will ask DBLP about this entry — the filter its `checkAuthors` applies. */
53
+ const asksDblp = (e) => Boolean(e.title && e.author) &&
54
+ authors.claimsPublished(e) &&
55
+ !authors.truncated(e.author);
56
+ /** Is every question this bibliography would ask already answered in `cache`? */
57
+ async function fullyCached(citations, entries, cache, store) {
58
+ const asks = await Promise.all(citations.map((c) => cites.wouldAsk(c, store)));
59
+ return (!asks.includes(true) &&
60
+ entries.filter(asksDblp).every((e) => cache.dblp.has(dblpTitleKey(e.title))));
61
+ }
62
+ /**
63
+ * The key a DBLP answer is stored under in the lookup cache: the title's identity (verify-cites'
64
+ * `titleIdentity` — the same rule its own title keys use, so the two caches cannot drift), hashed.
65
+ * A re-cased or re-braced title keeps its answer; `C` and `C++` do not share one.
66
+ */
67
+ export const dblpTitleKey = (title) => sha256Hex(new TextEncoder().encode(cites.titleIdentity(title))).slice(0, 16);
68
+ /**
69
+ * bib-authors' `lookup` and `pause`, answering from the cached DBLP hits first.
70
+ *
71
+ * 🔴 DBLP IS ASKED UNTIL IT REFUSES ONCE, THEN NOT AT ALL FOR THE REST OF THE RUN (#120). A 429, an
72
+ * HTML page where JSON was asked, a timeout: bib-authors would retry each title three times with
73
+ * backoff, and move on to the next title to do it again — 51 titles × 3 × up to 15 s. After the
74
+ * first refusal every lookup fails at once with the reason, and no pause is waited, so each entry
75
+ * lands in bib-authors' `unchecked` bucket ("never a pass") for the price of ONE request.
76
+ *
77
+ * The 900 ms pace protects DBLP, so it is kept only after an answer DBLP actually gave: not after a
78
+ * cached answer, and not once DBLP is off.
79
+ */
80
+ function cachedDblp(cache, today) {
81
+ const dblp = new Map(cache.dblp);
82
+ let lastWasCached = false;
83
+ let refused = null;
84
+ return {
85
+ dblp,
86
+ lookup: async (title) => {
87
+ const hit = dblp.get(dblpTitleKey(title));
88
+ lastWasCached = hit !== undefined;
89
+ if (hit)
90
+ return hit.hits;
91
+ if (refused !== null)
92
+ throw new Error(`DBLP refused earlier in this run (${refused})`);
93
+ try {
94
+ const hits = (await authors.dblpHits(title));
95
+ dblp.set(dblpTitleKey(title), { fetched: today(), title, hits });
96
+ return hits;
97
+ }
98
+ catch (e) {
99
+ refused = e.message;
100
+ throw new Error(`DBLP refused earlier in this run (${refused})`);
101
+ }
102
+ },
103
+ pause: (ms) => lastWasCached || refused !== null ? Promise.resolve() : sleep(ms),
104
+ };
105
+ }
106
+ /**
107
+ * The cache after a run: the old answers with every new one laid over them, dated today — or the
108
+ * very object passed in when nothing was fetched, so the caller can tell there is nothing to write.
109
+ * "New" is measured against `usable`, the part the run answered from: an answer too old to use was
110
+ * asked again, and its fresh copy replaces the old one. An old answer the run could not refresh
111
+ * (the service refused) stays, and is asked again next build.
112
+ */
113
+ function grown(loaded, run, today) {
114
+ const { cache, usable } = loaded;
115
+ const { store, dblp } = run;
116
+ const fresh = Object.entries(store).filter(([k]) => !usable.citations.has(k));
117
+ const freshDblp = [...dblp].filter(([k]) => !usable.dblp.has(k));
118
+ if (fresh.length === 0 && freshDblp.length === 0)
119
+ return cache;
120
+ const dated = fresh.map(([k, response]) => [
121
+ k,
122
+ { fetched: today(), response: response },
123
+ ]);
124
+ return {
125
+ citations: new Map([...cache.citations, ...dated]),
126
+ dblp: new Map([...cache.dblp, ...freshDblp]),
127
+ };
128
+ }
129
+ /** The checker, with its clock injected; `onlineReferences` is the one the CLI wires. */
130
+ export const referencesChecker = ({ today }) => async (bib, cache) => {
131
+ // Answers past MAX_AGE_DAYS are left out, so the run asks them again (and `grown` re-dates them).
132
+ const usable = freshPart(cache, today());
52
133
  const citations = cites.parseBib(bib).filter((c) => c.id);
134
+ const parsed = authors.parseBib(bib);
135
+ const store = Object.fromEntries([...usable.citations].map(([k, v]) => [k, v.response]));
136
+ if (!(await fullyCached(citations, parsed, usable, store))) {
137
+ const why = await unreachable();
138
+ if (why !== null)
139
+ return { check: { kind: "not-checked", why }, cache };
140
+ }
141
+ // 🔴 #107: the lookups run LOOKUPS_IN_FLIGHT at a time, and the DBLP author pass runs beside
142
+ // them. Each citation's own requests go to four different services one after another, so a
143
+ // pool of 6 is at most 6 requests to any one of them. The store is shared: two citations with
144
+ // the same identifier may both miss it and ask twice — an extra request, never a different
145
+ // answer.
146
+ // One breaker for the run: a service that refuses is not asked again, not once per citation
147
+ // (#120). Requests already in flight when it starts refusing still land — at most six.
148
+ const breaker = cites.createBreaker();
149
+ const d = cachedDblp(usable, today);
53
150
  const [found, a] = await Promise.all([
54
- mapLimit(citations, LOOKUPS_IN_FLIGHT, (c) => cites.verifyCitationLive(c, { cache })),
55
- authors.checkAuthors(authors.parseBib(bib)),
151
+ mapLimit(citations, LOOKUPS_IN_FLIGHT, (c) => cites.verifyCitationLive(c, {
152
+ cache: store,
153
+ breaker,
154
+ })),
155
+ authors.checkAuthors(parsed, {
156
+ lookup: d.lookup,
157
+ pause: d.pause,
158
+ }),
56
159
  ]);
57
160
  const keys = new Set([
58
161
  ...found.map((c) => c.id),
59
162
  ...a.findings.map((f) => f.key),
60
163
  ]);
61
164
  const entries = [...keys].map((key) => entryVerdict(key, found, a));
62
- return { kind: "checked", entries };
165
+ return {
166
+ check: { kind: "checked", entries },
167
+ cache: grown({ cache, usable }, { store, dblp: d.dblp }, today),
168
+ };
63
169
  };
170
+ /** The checker the CLI wires: the real clock. */
171
+ export const onlineReferences = referencesChecker({
172
+ today: todayUtc,
173
+ });
64
174
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/references/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/references/index.ts"],"names":[],"mappings":"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"}
package/dist/build.d.ts CHANGED
@@ -115,6 +115,10 @@ export declare const measureStep: BuildStep;
115
115
  * authors are the published version's (bib-authors) — and record the verdicts in
116
116
  * `_build/references.json` for the offline lint rules (`reference-rules.ts`). OPTIONAL and NEVER
117
117
  * FAILING: without network the PDF is still built, and the record says `not-checked`.
118
+ *
119
+ * What the services answered is read from and added to `<paper>/repro/references-cache.json`
120
+ * (`references.ts`, `domain/lookup-cache.ts`), committed with the paper, so only a new or edited
121
+ * entry is asked, and an unchanged bibliography is checked with no network at all (#107).
118
122
  */
119
123
  export declare const referencesStep: BuildStep;
120
124
  /** The build, in order. A new step is one entry here. */
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAyCA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYpE,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAOxE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AASnE,OAAO,EAIL,KAAK,QAAQ,EAGb,KAAK,IAAI,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExD,mGAAmG;AACnG,eAAO,MAAM,aAAa,UAKzB,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,IAAI,cAAc,CAAC;AAChC,eAAO,MAAM,GAAG,UAAU,CAAC;AAE3B;;;GAGG;AACH,eAAO,MAAM,eAAe,UAA4C,CAAC;AAEzE,4FAA4F;AAC5F,eAAO,MAAM,cAAc,UAI1B,CAAC;AAEF,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;KACrC,GAAG,IAAI,CAAC;IACT,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED,iFAAiF;AACjF,MAAM,MAAM,MAAM,GAAG,OAAO,SAAS,CAAC;AAEtC,iGAAiG;AACjG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AAED,MAAM,MAAM,WAAW,GACnB;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC5D;AAID;;;;GAIG;AACH,KAAK,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAqCnE;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,EAAE,KAAK,EAAE,GAAE;IAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAA;CAAO,GACrD,UAAU,CAAC,eAAe,CAAC,CAE7B;AAiBD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAatD;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,MAAM,CAAC,UAAU,CAKnB;AAED,eAAO,MAAM,UAAU,EAAE,SAWxB,CAAC;AAoBF,6DAA6D;AAC7D,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAiBnD;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAQrD;AAWD,KAAK,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAoFnE,uDAAuD;AACvD,wBAAgB,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG;IAC1C,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAmBA;AAOD,eAAO,MAAM,WAAW,EAAE,SAwDzB,CAAC;AAaF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,SAgCzB,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,SAc5B,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,KAAK,EAAE,SAAS,SAAS,EAKrC,CAAC;AAIF,wBAAgB,OAAO,CACrB,KAAK,EAAE,UAAU,EACjB,KAAK,GAAE,SAAS,SAAS,EAAU,GAClC,QAAQ,EAAE,CAKZ;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,EAAE,CAI9D;AAaD,wFAAwF;AACxF,eAAO,MAAM,WAAW,sEAAkE,CAAC;AAE3F,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,kGAAkG;IAClG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,0DAA0D;IAC1D,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAqGD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAyBtB;AAED,gGAAgG;AAChG,MAAM,MAAM,QAAQ,GAChB;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;CAAE,CAAC;AAEvE;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,EACE,MAAM,EACN,GAAG,OAAO,EACX,EAAE,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;CAAE,GACpE,OAAO,CAAC,QAAQ,CAAC,CAkBnB;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,SAAS,MAAM,EAAkB,GACzC,MAAM,EAAE,CASV;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAMnD;AAkBD;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,SAAS,SAAS,WAAW,EAAE,KAAG,OACjB,CAAC;AAE5C,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAQjE"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
package/dist/build.js CHANGED
@@ -397,6 +397,10 @@ export const measureStep = {
397
397
  * authors are the published version's (bib-authors) — and record the verdicts in
398
398
  * `_build/references.json` for the offline lint rules (`reference-rules.ts`). OPTIONAL and NEVER
399
399
  * FAILING: without network the PDF is still built, and the record says `not-checked`.
400
+ *
401
+ * What the services answered is read from and added to `<paper>/repro/references-cache.json`
402
+ * (`references.ts`, `domain/lookup-cache.ts`), committed with the paper, so only a new or edited
403
+ * entry is asked, and an unchanged bibliography is checked with no network at all (#107).
400
404
  */
401
405
  export const referencesStep = {
402
406
  name: "references",
@@ -458,9 +462,12 @@ dryRun = false, readPdf = pdfjsReader, projectRoot = env["CLAUDE_PROJECT_DIR"] |
458
462
  return { run, cwd, env, steps, log, dryRun, readPdf, projectRoot };
459
463
  }
460
464
  /** Without a checker the record says so — never a pass. The CLI wires the real one. */
461
- const notWired = async () => ({
462
- kind: "not-checked",
463
- why: "no reference checker was wired into this build",
465
+ const notWired = async (_bib, cache) => ({
466
+ check: {
467
+ kind: "not-checked",
468
+ why: "no reference checker was wired into this build",
469
+ },
470
+ cache,
464
471
  });
465
472
  /** banal as the measurer, wired from the build's environment: the one piece of root work left here (#76). */
466
473
  function defaultMeasurer(b) {