paperlint 7.2.0 โ 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +9 -25
- package/CONTRIBUTING.md +5 -4
- package/README.md +4 -3
- package/dist/adapters/bibtex/index.d.ts +3 -0
- package/dist/adapters/bibtex/index.d.ts.map +1 -0
- package/dist/adapters/bibtex/index.js +103 -0
- package/dist/adapters/bibtex/index.js.map +1 -0
- package/dist/adapters/latex/filecontents.d.ts +33 -0
- package/dist/adapters/latex/filecontents.d.ts.map +1 -0
- package/dist/adapters/latex/filecontents.js +65 -0
- package/dist/adapters/latex/filecontents.js.map +1 -0
- package/dist/adapters/latex/includes.d.ts +3 -3
- package/dist/adapters/latex/includes.d.ts.map +1 -1
- package/dist/adapters/latex/includes.js +18 -10
- package/dist/adapters/latex/includes.js.map +1 -1
- package/dist/adapters/latex/index.d.ts.map +1 -1
- package/dist/adapters/latex/index.js +2 -0
- package/dist/adapters/latex/index.js.map +1 -1
- package/dist/adapters/latex/nodes.d.ts +12 -0
- package/dist/adapters/latex/nodes.d.ts.map +1 -1
- package/dist/adapters/latex/nodes.js +39 -0
- package/dist/adapters/latex/nodes.js.map +1 -1
- package/dist/adapters/latex/parse.d.ts +7 -1
- package/dist/adapters/latex/parse.d.ts.map +1 -1
- package/dist/adapters/latex/parse.js +55 -6
- package/dist/adapters/latex/parse.js.map +1 -1
- package/dist/adapters/memory/index.d.ts +3 -0
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +9 -0
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +27 -24
- package/dist/adapters/references/index.js.map +1 -1
- package/dist/adapters/sources-record/index.d.ts +9 -0
- package/dist/adapters/sources-record/index.d.ts.map +1 -0
- package/dist/adapters/sources-record/index.js +68 -0
- package/dist/adapters/sources-record/index.js.map +1 -0
- package/dist/adapters/tex-output/blg.d.ts +9 -0
- package/dist/adapters/tex-output/blg.d.ts.map +1 -0
- package/dist/adapters/tex-output/blg.js +20 -0
- package/dist/adapters/tex-output/blg.js.map +1 -0
- package/dist/adapters/tex-output/fls.d.ts +8 -0
- package/dist/adapters/tex-output/fls.d.ts.map +1 -0
- package/dist/adapters/tex-output/fls.js +16 -0
- package/dist/adapters/tex-output/fls.js.map +1 -0
- package/dist/adapters/tex-output/index.d.ts +7 -0
- package/dist/adapters/tex-output/index.d.ts.map +1 -0
- package/dist/adapters/tex-output/index.js +7 -0
- package/dist/adapters/tex-output/index.js.map +1 -0
- package/dist/bib-rules.d.ts +47 -0
- package/dist/bib-rules.d.ts.map +1 -0
- package/dist/bib-rules.js +127 -0
- package/dist/bib-rules.js.map +1 -0
- package/dist/build.d.ts +29 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +41 -30
- package/dist/build.js.map +1 -1
- package/dist/claim-provenance.d.ts +2 -2
- package/dist/cli.d.ts +9 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +43 -68
- package/dist/cli.js.map +1 -1
- package/dist/domain/paper-source.d.ts +1 -10
- package/dist/domain/paper-source.d.ts.map +1 -1
- package/dist/domain/paper-source.js +34 -24
- package/dist/domain/paper-source.js.map +1 -1
- package/dist/domain/paper-sources.d.ts +72 -0
- package/dist/domain/paper-sources.d.ts.map +1 -0
- package/dist/domain/paper-sources.js +18 -0
- package/dist/domain/paper-sources.js.map +1 -0
- package/dist/domain/sources-record.d.ts +102 -0
- package/dist/domain/sources-record.d.ts.map +1 -0
- package/dist/domain/sources-record.js +38 -0
- package/dist/domain/sources-record.js.map +1 -0
- package/dist/domain/tex-run.d.ts +25 -0
- package/dist/domain/tex-run.d.ts.map +1 -0
- package/dist/domain/tex-run.js +79 -0
- package/dist/domain/tex-run.js.map +1 -0
- package/dist/eslint-rules/latex-language.d.ts.map +1 -1
- package/dist/eslint-rules/latex-language.js +10 -13
- package/dist/eslint-rules/latex-language.js.map +1 -1
- package/dist/eslint-rules/paper-context.d.ts.map +1 -1
- package/dist/eslint-rules/paper-context.js +6 -5
- package/dist/eslint-rules/paper-context.js.map +1 -1
- package/dist/eslint-rules/paper-typography.d.ts +0 -9
- package/dist/eslint-rules/paper-typography.d.ts.map +1 -1
- package/dist/eslint-rules/paper-typography.js +34 -96
- package/dist/eslint-rules/paper-typography.js.map +1 -1
- package/dist/eslint-rules/papers.d.ts +1 -3
- package/dist/eslint-rules/papers.d.ts.map +1 -1
- package/dist/eslint-rules/papers.js +2 -4
- package/dist/eslint-rules/papers.js.map +1 -1
- package/dist/eslint-rules/tex-build.d.ts.map +1 -1
- package/dist/eslint-rules/tex-build.js +8 -25
- package/dist/eslint-rules/tex-build.js.map +1 -1
- package/dist/init.d.ts +1 -4
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +3 -9
- package/dist/init.js.map +1 -1
- package/dist/latex-log.d.ts +10 -0
- package/dist/latex-log.d.ts.map +1 -1
- package/dist/latex-log.js +10 -0
- package/dist/latex-log.js.map +1 -1
- package/dist/latex-loop.d.ts +2 -0
- package/dist/latex-loop.d.ts.map +1 -1
- package/dist/latex-loop.js.map +1 -1
- package/dist/lib/markdown.d.ts +5 -81
- package/dist/lib/markdown.d.ts.map +1 -1
- package/dist/lib/markdown.js +5 -116
- package/dist/lib/markdown.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +0 -2
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/lib/skill-eval-fixture.d.ts +6 -4
- package/dist/lib/skill-eval-fixture.d.ts.map +1 -1
- package/dist/lib/skill-eval-fixture.js +25 -18
- package/dist/lib/skill-eval-fixture.js.map +1 -1
- package/dist/new-paper.d.ts +5 -11
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +12 -23
- package/dist/new-paper.js.map +1 -1
- package/dist/package-dirs.d.ts.map +1 -1
- package/dist/package-dirs.js +3 -2
- package/dist/package-dirs.js.map +1 -1
- package/dist/paper-files.d.ts +4 -4
- package/dist/paper-includes.d.ts +4 -7
- package/dist/paper-includes.d.ts.map +1 -1
- package/dist/paper-includes.js +29 -21
- package/dist/paper-includes.js.map +1 -1
- package/dist/paper-prose.d.ts +17 -0
- package/dist/paper-prose.d.ts.map +1 -0
- package/dist/paper-prose.js +46 -0
- package/dist/paper-prose.js.map +1 -0
- package/dist/paper-record.d.ts +25 -0
- package/dist/paper-record.d.ts.map +1 -0
- package/dist/paper-record.js +39 -0
- package/dist/paper-record.js.map +1 -0
- package/dist/paper-sources.d.ts +66 -0
- package/dist/paper-sources.d.ts.map +1 -0
- package/dist/paper-sources.js +92 -0
- package/dist/paper-sources.js.map +1 -0
- package/dist/ports/bib-reader.d.ts +18 -0
- package/dist/ports/bib-reader.d.ts.map +1 -0
- package/dist/ports/bib-reader.js +2 -0
- package/dist/ports/bib-reader.js.map +1 -0
- package/dist/ports/check-references.d.ts +9 -4
- package/dist/ports/check-references.d.ts.map +1 -1
- package/dist/ports/latex.d.ts +15 -0
- package/dist/ports/latex.d.ts.map +1 -1
- package/dist/ports/sources-codec.d.ts +11 -0
- package/dist/ports/sources-codec.d.ts.map +1 -0
- package/dist/ports/sources-codec.js +2 -0
- package/dist/ports/sources-codec.js.map +1 -0
- package/dist/ports/tex-output.d.ts +17 -0
- package/dist/ports/tex-output.d.ts.map +1 -0
- package/dist/ports/tex-output.js +2 -0
- package/dist/ports/tex-output.js.map +1 -0
- package/dist/recorded-bibliography.d.ts +89 -0
- package/dist/recorded-bibliography.d.ts.map +1 -0
- package/dist/recorded-bibliography.js +136 -0
- package/dist/recorded-bibliography.js.map +1 -0
- package/dist/reference-rules.d.ts +5 -5
- package/dist/reference-rules.d.ts.map +1 -1
- package/dist/reference-rules.js +150 -77
- package/dist/reference-rules.js.map +1 -1
- package/dist/references.d.ts +71 -16
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +110 -26
- package/dist/references.js.map +1 -1
- package/dist/register-bands.d.ts +3 -3
- package/dist/register-bands.d.ts.map +1 -1
- package/dist/register-bands.js.map +1 -1
- package/dist/register.d.ts +2 -2
- package/dist/sources-record.d.ts +38 -0
- package/dist/sources-record.d.ts.map +1 -0
- package/dist/sources-record.js +123 -0
- package/dist/sources-record.js.map +1 -0
- package/dist/sources-rules.d.ts +44 -0
- package/dist/sources-rules.d.ts.map +1 -0
- package/dist/sources-rules.js +76 -0
- package/dist/sources-rules.js.map +1 -0
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +4 -3
- package/dist/structure.js.map +1 -1
- package/dist/tex-paper.d.ts +10 -15
- package/dist/tex-paper.d.ts.map +1 -1
- package/dist/tex-paper.js +24 -40
- package/dist/tex-paper.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +3 -3
- package/dist/tex-venue-rules.d.ts.map +1 -1
- package/dist/tex-venue-rules.js.map +1 -1
- package/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/configuration.md +18 -12
- package/docs/design/paper-sources.md +197 -0
- package/docs/e2e.md +4 -6
- package/docs/package-shape-options.md +1 -1
- package/docs/prior-art/paper-folder-scaffolding.md +24 -29
- package/docs/references.md +34 -8
- package/docs/rules/bib/reachable-entry.md +64 -0
- package/docs/rules/paper/sources-fresh.md +81 -0
- package/docs/rules/tex/claim-provenance.md +0 -1
- package/docs/rules.md +62 -61
- package/eslint-rules/latex-language.harness.mjs +3 -3
- package/eslint-rules/latex-language.ts +10 -13
- package/eslint-rules/paper-context.ts +6 -5
- package/eslint-rules/paper-typography.test.mjs +29 -157
- package/eslint-rules/paper-typography.ts +35 -104
- package/eslint-rules/papers.harness.mjs +1 -1
- package/eslint-rules/papers.ts +2 -4
- package/eslint-rules/tex-build.harness.mjs +2 -2
- package/eslint-rules/tex-build.ts +8 -25
- package/eslint.config.mjs +22 -1
- package/fixtures/build-e2e/aidc/paper.tex +1 -1
- package/fixtures/build-e2e/anon-ack/paper.tex +1 -1
- package/fixtures/build-e2e/anon-author/paper.tex +1 -1
- package/fixtures/build-e2e/anon-bib/paper.tex +1 -1
- package/fixtures/build-e2e/anon-href/paper.tex +1 -1
- package/fixtures/build-e2e/anon-macro/paper.tex +1 -1
- package/fixtures/build-e2e/anon-pdfauthor/paper.tex +1 -1
- package/fixtures/paper-sources/p1/paper.tex +30 -0
- package/fixtures/paper-sources/p1/refs.bib +6 -0
- package/fixtures/paper-sources/p1/sections/dead.tex +6 -0
- package/fixtures/paper-sources/p1/sections/intro.tex +7 -0
- package/fixtures/paper-sources/p1/sections/parked.tex +6 -0
- package/fixtures/paper-sources/p1/tex-truth.json +37 -0
- package/fixtures/paper-sources/p1/versions/2026-01-01-review.tex +4 -0
- package/fixtures/paper-sources/v1-stale/paper.tex +14 -0
- package/fixtures/paper-sources/v1-stale/refs.bib +6 -0
- package/fixtures/paper-sources/v1-stale/tex-truth.json +32 -0
- package/fixtures/paper-sources/v10-ifthenelse/anon.bib +1 -0
- package/fixtures/paper-sources/v10-ifthenelse/paper.tex +9 -0
- package/fixtures/paper-sources/v10-ifthenelse/real.bib +1 -0
- package/fixtures/paper-sources/v10-ifthenelse/tex-truth.json +28 -0
- package/fixtures/paper-sources/v11-two-blocks/paper.tex +12 -0
- package/fixtures/paper-sources/v11-two-blocks/tex-truth.json +30 -0
- package/fixtures/paper-sources/v13-percent-text/paper.tex +6 -0
- package/fixtures/paper-sources/v13-percent-text/refs.bib +3 -0
- package/fixtures/paper-sources/v13-percent-text/tex-truth.json +30 -0
- package/fixtures/paper-sources/v15-after-end/paper.tex +6 -0
- package/fixtures/paper-sources/v15-after-end/refs.bib +1 -0
- package/fixtures/paper-sources/v15-after-end/tex-truth.json +17 -0
- package/fixtures/paper-sources/v16-included-block/bibblock.tex +3 -0
- package/fixtures/paper-sources/v16-included-block/paper.tex +7 -0
- package/fixtures/paper-sources/v16-included-block/refs.bib +1 -0
- package/fixtures/paper-sources/v16-included-block/tex-truth.json +35 -0
- package/fixtures/paper-sources/v17-include-order/bibsetup.tex +1 -0
- package/fixtures/paper-sources/v17-include-order/first.bib +1 -0
- package/fixtures/paper-sources/v17-include-order/later.bib +1 -0
- package/fixtures/paper-sources/v17-include-order/paper.tex +7 -0
- package/fixtures/paper-sources/v17-include-order/tex-truth.json +40 -0
- package/fixtures/paper-sources/v2-overwrite/paper.tex +14 -0
- package/fixtures/paper-sources/v2-overwrite/refs.bib +6 -0
- package/fixtures/paper-sources/v2-overwrite/tex-truth.json +30 -0
- package/fixtures/paper-sources/v22-parked-thebibliography/paper.tex +7 -0
- package/fixtures/paper-sources/v22-parked-thebibliography/tex-truth.json +17 -0
- package/fixtures/paper-sources/v23-parked-include/old.bib +1 -0
- package/fixtures/paper-sources/v23-parked-include/paper.tex +7 -0
- package/fixtures/paper-sources/v23-parked-include/parked.tex +1 -0
- package/fixtures/paper-sources/v23-parked-include/refs.bib +1 -0
- package/fixtures/paper-sources/v23-parked-include/tex-truth.json +28 -0
- package/fixtures/paper-sources/v24-quoted-fields/paper.tex +6 -0
- package/fixtures/paper-sources/v24-quoted-fields/refs.bib +5 -0
- package/fixtures/paper-sources/v24-quoted-fields/tex-truth.json +32 -0
- package/fixtures/paper-sources/v25-string-differs/paper.tex +10 -0
- package/fixtures/paper-sources/v25-string-differs/refs.bib +2 -0
- package/fixtures/paper-sources/v25-string-differs/tex-truth.json +32 -0
- package/fixtures/paper-sources/v26-comment-in-names/one.bib +1 -0
- package/fixtures/paper-sources/v26-comment-in-names/paper.tex +7 -0
- package/fixtures/paper-sources/v26-comment-in-names/tex-truth.json +32 -0
- package/fixtures/paper-sources/v26-comment-in-names/two.bib +1 -0
- package/fixtures/paper-sources/v27-shared-string/abbreviations.bib +2 -0
- package/fixtures/paper-sources/v27-shared-string/paper.tex +6 -0
- package/fixtures/paper-sources/v27-shared-string/references.bib +6 -0
- package/fixtures/paper-sources/v27-shared-string/tex-truth.json +31 -0
- package/fixtures/paper-sources/v28-shared-string-block/abbreviations.bib +2 -0
- package/fixtures/paper-sources/v28-shared-string-block/paper.tex +14 -0
- package/fixtures/paper-sources/v28-shared-string-block/tex-truth.json +33 -0
- package/fixtures/paper-sources/v29-generated-input/paper.tex +9 -0
- package/fixtures/paper-sources/v29-generated-input/tex-truth.json +24 -0
- package/fixtures/paper-sources/v3-declared/paper.bib +6 -0
- package/fixtures/paper-sources/v3-declared/paper.tex +6 -0
- package/fixtures/paper-sources/v3-declared/tex-truth.json +28 -0
- package/fixtures/paper-sources/v30-name-next-line/paper.tex +14 -0
- package/fixtures/paper-sources/v30-name-next-line/tex-truth.json +30 -0
- package/fixtures/paper-sources/v4-commented/paper.tex +14 -0
- package/fixtures/paper-sources/v4-commented/refs.bib +6 -0
- package/fixtures/paper-sources/v4-commented/tex-truth.json +28 -0
- package/fixtures/paper-sources/v5-percent-entry/paper.tex +20 -0
- package/fixtures/paper-sources/v5-percent-entry/tex-truth.json +37 -0
- package/fixtures/paper-sources/v6-unclosed/paper.tex +6 -0
- package/fixtures/paper-sources/v6-unclosed/refs.bib +5 -0
- package/fixtures/paper-sources/v6-unclosed/tex-truth.json +37 -0
- package/fixtures/paper-sources/v8-jobname/paper.tex +9 -0
- package/fixtures/paper-sources/v8-jobname/tex-truth.json +30 -0
- package/fixtures/paper-sources/v9-two-bibliographies/one.bib +1 -0
- package/fixtures/paper-sources/v9-two-bibliographies/paper.tex +7 -0
- package/fixtures/paper-sources/v9-two-bibliographies/tex-truth.json +35 -0
- package/fixtures/paper-sources/v9-two-bibliographies/two.bib +1 -0
- package/fixtures/paper-typography/clean-paper/paper.tex +1 -1
- package/fixtures/paper-typography/messy-paper/paper.tex +1 -1
- package/hooks/hooks.harness.ts +15 -15
- package/hooks/paper-edit-guard.hook.mjs +5 -8
- package/hooks/paper-edit-guard.test.ts +12 -3
- package/hooks/paper-skills-nudge.hook.mjs +2 -3
- package/hooks/paper-skills-nudge.test.ts +13 -3
- package/hooks/paper-status-gates.hook.mjs +2 -2
- package/hooks/paper-status-gates.test.ts +14 -2
- package/lib/markdown.test.mjs +5 -60
- package/lib/markdown.ts +9 -136
- package/lib/paper-config.ts +0 -2
- package/lib/skill-checks.test.mjs +4 -1
- package/lib/skill-eval-fixture.ts +25 -18
- package/package.json +2 -12
- package/presets/realm.jsonc +1 -1
- package/scripts/check.test.ts +23 -1
- package/scripts/check.ts +7 -3
- package/scripts/coverage-config.test.ts +19 -10
- package/scripts/harness-api.frozen.json +0 -5
- package/scripts/layer-legacy-frozen.test.ts +41 -2
- package/scripts/layer-legacy-frozen.ts +31 -2
- package/skills/cold-read-diff/SKILL.md +3 -3
- package/skills/cold-read-diff/SKILL.md.spec.ts +2 -2
- package/skills/grade-paper-writing/SKILL.md +15 -22
- package/skills/grade-paper-writing/SKILL.md.spec.ts +14 -21
- package/skills/grade-paper-writing/__snapshots__/prose-lint.test.ts.snap +40 -26
- package/skills/grade-paper-writing/prose-lint.mjs +117 -278
- package/skills/grade-paper-writing/prose-lint.test.ts +230 -79
- package/skills/paper-adversarial-review/SKILL.md +2 -2
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -1
- package/skills/paper-pipeline/SKILL.md +9 -12
- package/skills/paper-pipeline/SKILL.md.spec.ts +8 -11
- package/skills/paper-pipeline/description-language.eval.mjs +25 -15
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +25 -15
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +25 -15
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +27 -16
- package/skills/paper-pipeline/pipeline-language.eval.mjs +25 -15
- package/skills/paper-pipeline/references/acceptance-gate.md +16 -20
- package/skills/paper-pipeline/references/artifact-checklist.md +4 -5
- package/skills/paper-pipeline/references/pipeline-status-template.md +1 -1
- package/skills/paper-pipeline/scripts/README.md +0 -4
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +91 -105
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +85 -241
- package/skills/paper-pipeline/scripts/extract-ref-facts.test.mjs +166 -153
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +3 -3
- package/skills/paper-status/SKILL.md +2 -2
- package/skills/paper-status/SKILL.md.spec.ts +1 -1
- package/skills/render-paper/SKILL.md +2 -2
- package/skills/render-paper/SKILL.md.spec.ts +1 -1
- package/skills/render-paper/extract-pdf-facts.mjs +2 -2
- package/skills/tighten-paper/SKILL.md +29 -42
- package/skills/tighten-paper/SKILL.md.spec.ts +28 -41
- package/skills/verify-citations/SKILL.md +7 -4
- package/skills/verify-citations/SKILL.md.spec.ts +6 -3
- package/skills/verify-citations/scripts/bib-authors.check.test.mjs +17 -32
- package/skills/verify-citations/scripts/bib-authors.cli.test.ts +138 -43
- package/skills/verify-citations/scripts/bib-authors.d.mts +22 -2
- package/skills/verify-citations/scripts/bib-authors.mjs +54 -193
- package/skills/verify-citations/scripts/bib-authors.test.mjs +1 -44
- package/skills/verify-citations/scripts/verify-cites.cli.test.ts +16 -0
- package/skills/verify-citations/scripts/verify-cites.d.mts +19 -3
- package/skills/verify-citations/scripts/verify-cites.mjs +42 -108
- package/skills/verify-citations/scripts/verify-cites.test.mjs +23 -36
- package/src/adapters/bibtex/index.test.ts +163 -0
- package/src/adapters/bibtex/index.ts +155 -0
- package/src/adapters/latex/filecontents.ts +114 -0
- package/src/adapters/latex/includes.ts +18 -10
- package/src/adapters/latex/index.test.ts +73 -0
- package/src/adapters/latex/index.ts +2 -0
- package/src/adapters/latex/nodes.ts +64 -0
- package/src/adapters/latex/parse.test.ts +38 -0
- package/src/adapters/latex/parse.ts +67 -6
- package/src/adapters/memory/index.ts +17 -0
- package/src/adapters/references/index.test.ts +75 -21
- package/src/adapters/references/index.ts +37 -32
- package/src/adapters/sources-record/index.test.ts +87 -0
- package/src/adapters/sources-record/index.ts +82 -0
- package/src/adapters/tex-output/blg.ts +27 -0
- package/src/adapters/tex-output/fls.ts +24 -0
- package/src/adapters/tex-output/index.test.ts +171 -0
- package/src/adapters/tex-output/index.ts +12 -0
- package/src/bib-rules.test.ts +356 -0
- package/src/bib-rules.ts +228 -0
- package/src/bibliography-at.test.ts +286 -0
- package/src/build.harness.mjs +2 -2
- package/src/build.test.ts +211 -1
- package/src/build.ts +101 -41
- package/src/claim-provenance.test.ts +33 -7
- package/src/claim-provenance.ts +2 -2
- package/src/cli.harness.mjs +46 -56
- package/src/cli.test.ts +44 -48
- package/src/cli.ts +51 -82
- package/src/domain/paper-source.test.ts +58 -20
- package/src/domain/paper-source.ts +38 -42
- package/src/domain/paper-sources.ts +94 -0
- package/src/domain/sources-record.test.ts +71 -0
- package/src/domain/sources-record.ts +136 -0
- package/src/domain/tex-run.test.ts +228 -0
- package/src/domain/tex-run.ts +139 -0
- package/src/folder-venue-rule.test.ts +1 -1
- package/src/heading-case.test.ts +24 -10
- package/src/init.test.ts +6 -7
- package/src/init.ts +3 -22
- package/src/latex-log.ts +20 -0
- package/src/latex-loop.harness.ts +1 -0
- package/src/latex-loop.ts +2 -0
- package/src/lint-fix.test.ts +10 -4
- package/src/linted-set.test.ts +9 -1
- package/src/new-paper.harness.mjs +12 -30
- package/src/new-paper.test.ts +15 -11
- package/src/new-paper.ts +11 -30
- package/src/package-dirs.ts +3 -2
- package/src/paper-files.test.ts +5 -4
- package/src/paper-files.ts +4 -4
- package/src/paper-includes.test.ts +157 -38
- package/src/paper-includes.ts +39 -35
- package/src/paper-prose.test.ts +78 -0
- package/src/paper-prose.ts +67 -0
- package/src/paper-record.test.ts +173 -0
- package/src/paper-record.ts +66 -0
- package/src/paper-settings-commands.test.ts +5 -2
- package/src/paper-sources.ts +151 -0
- package/src/parse-args.test.ts +0 -1
- package/src/ports/bib-reader.ts +27 -0
- package/src/ports/check-references.ts +7 -3
- package/src/ports/latex.ts +19 -0
- package/src/ports/sources-codec.ts +11 -0
- package/src/ports/tex-output.ts +17 -0
- package/src/recorded-bibliography.ts +297 -0
- package/src/reference-rules.ts +217 -104
- package/src/references.test.ts +520 -177
- package/src/references.ts +185 -37
- package/src/register-bands.test.ts +5 -1
- package/src/register-bands.ts +3 -5
- package/src/register.test.ts +6 -1
- package/src/register.ts +2 -2
- package/src/rule-cases.test.ts +68 -12
- package/src/rule-docs.test.ts +0 -1
- package/src/sources-record.test.ts +308 -0
- package/src/sources-record.ts +231 -0
- package/src/sources-rules.test.ts +152 -0
- package/src/sources-rules.ts +117 -0
- package/src/structure.harness.ts +5 -11
- package/src/structure.ts +4 -3
- package/src/tex-paper.test.ts +148 -78
- package/src/tex-paper.ts +31 -61
- package/src/tex-venue-rules.test.ts +36 -8
- package/src/tex-venue-rules.ts +3 -5
- package/src/types.ts +0 -2
- package/dist/eslint-rules/bib-reachable-entry.d.ts +0 -22
- package/dist/eslint-rules/bib-reachable-entry.d.ts.map +0 -1
- package/dist/eslint-rules/bib-reachable-entry.js +0 -75
- package/dist/eslint-rules/bib-reachable-entry.js.map +0 -1
- package/eslint-rules/bib-reachable-entry.ts +0 -76
- package/fixtures/real-markdown-paper/baseline.json +0 -22
- package/fixtures/real-markdown-paper/baseline.ts +0 -70
- package/skills/paper-pipeline/PIPELINE-MAP.md +0 -381
- package/skills/paper-pipeline/pipeline-firing.baseline.json +0 -270
- package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +0 -585
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +0 -492
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +0 -397
- package/skills/paper-pipeline/scripts/artifact-coverage.test.ts +0 -86
- package/skills/paper-pipeline/scripts/check-provenance.mjs +0 -184
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +0 -135
- package/skills/paper-pipeline/scripts/population-map.mjs +0 -188
- package/skills/paper-pipeline/scripts/population-map.test.mjs +0 -154
- package/skills/paper-pipeline/scripts/provenance.harness.mjs +0 -266
- package/skills/paper-pipeline/scripts/round-diff.harness.ts +0 -907
- package/skills/paper-pipeline/scripts/round-diff.mjs +0 -583
- package/skills/paper-pipeline/scripts/round-diff.test.mjs +0 -159
- package/skills/tighten-paper/__snapshots__/structure.test.ts.snap +0 -133
- package/skills/tighten-paper/structure.mjs +0 -364
- package/skills/tighten-paper/structure.test.ts +0 -117
- package/templates/paper/paper.md +0 -4
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* population-map.harness.mjs โ the population gate, made visible to the metric, plus the layer
|
|
3
|
-
* its own self-test cannot reach. `npx vigiles test .claude/skills/paper-pipeline/scripts/population-map.harness.mjs`.
|
|
4
|
-
*
|
|
5
|
-
* ๐ด SCOPE NARROWED 2026-08-26. Two findings out of four (`untied`, `undeclared`) moved to ESLint
|
|
6
|
-
* rules โ `paper/population-untied` and `paper/population-undeclared`, tests for them in
|
|
7
|
-
* `eslint-rules/paper-registry.harness.mjs`. Two remain here: `stale` and `badref`, both are about
|
|
8
|
-
* THE REGISTRY ITSELF (`repro/populations.tsv`), both have no address in the paper, and so cannot be expressed by ESLint,
|
|
9
|
-
* which reports only to the linted file.
|
|
10
|
-
*
|
|
11
|
-
* The findings themselves are planted in `population-map.test.mjs` (vitest; until #52 a
|
|
12
|
-
* self-test script this harness spawned). This file keeps what only the command shows: finding
|
|
13
|
-
* paper.md and repro/populations.tsv, and `--flags-only` staying silent on a clean paper โ the
|
|
14
|
-
* wiring the CI step actually invokes.
|
|
15
|
-
*/
|
|
16
|
-
import assert from "node:assert/strict";
|
|
17
|
-
import { execFileSync } from "node:child_process";
|
|
18
|
-
import {
|
|
19
|
-
mkdtempSync,
|
|
20
|
-
mkdirSync,
|
|
21
|
-
writeFileSync,
|
|
22
|
-
rmSync,
|
|
23
|
-
realpathSync,
|
|
24
|
-
} from "node:fs";
|
|
25
|
-
import { tmpdir } from "node:os";
|
|
26
|
-
import { join, dirname } from "node:path";
|
|
27
|
-
import { fileURLToPath } from "node:url";
|
|
28
|
-
import { consumerRoot } from "./consumer.mjs";
|
|
29
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
30
|
-
|
|
31
|
-
const ROOT = consumerRoot();
|
|
32
|
-
const SCRIPT = join(HERE, "population-map.mjs");
|
|
33
|
-
const tmp = realpathSync(mkdtempSync(join(tmpdir(), "popmap-harness-")));
|
|
34
|
-
|
|
35
|
-
/** Run a node script; never throws on a non-zero exit. */
|
|
36
|
-
function run(argv) {
|
|
37
|
-
try {
|
|
38
|
-
return {
|
|
39
|
-
code: 0,
|
|
40
|
-
out: execFileSync("node", argv, {
|
|
41
|
-
cwd: ROOT,
|
|
42
|
-
encoding: "utf8",
|
|
43
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
44
|
-
}),
|
|
45
|
-
};
|
|
46
|
-
} catch (e) {
|
|
47
|
-
return { code: e.status ?? 1, out: (e.stdout || "") + (e.stderr || "") };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** A paper dir carrying `body`, and optionally a population registry. */
|
|
52
|
-
function paper(name, body, tsv) {
|
|
53
|
-
const d = join(tmp, name);
|
|
54
|
-
mkdirSync(join(d, "repro"), { recursive: true });
|
|
55
|
-
writeFileSync(
|
|
56
|
-
join(d, "paper.md"),
|
|
57
|
-
`## Abstract\n\n${body}\n\n## References\n\n[1] x.\n`,
|
|
58
|
-
);
|
|
59
|
-
if (tsv !== undefined)
|
|
60
|
-
writeFileSync(join(d, "repro", "populations.tsv"), tsv);
|
|
61
|
-
return d;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const REG = [
|
|
65
|
-
"id\tprinted\trelation\trelated_to\tgloss",
|
|
66
|
-
"broad\t1,921\troot\t\tthe corpus",
|
|
67
|
-
"census\t134\tdisjoint\tbroad\ta separate sample",
|
|
68
|
-
].join("\n");
|
|
69
|
-
|
|
70
|
-
// โโ 2. the CLI finds the paper and the registry, and fires on a stale registry row โโโโโ
|
|
71
|
-
// ๐ด FIXTURE REWRITTEN 2026-08-26. Before that it planted an UNLINKED POPULATION, and that
|
|
72
|
-
// finding moved to `paper/population-untied` โ meaning the old ยซdirtyยป input became clean, and
|
|
73
|
-
// the block would silently stop checking the argv โ findings() wiring while staying green. Exactly that
|
|
74
|
-
// class of failure this file was written for.
|
|
75
|
-
{
|
|
76
|
-
const dirty = paper(
|
|
77
|
-
"cli-stale",
|
|
78
|
-
"The resolver ran over all 1,921 repositories at pinned commits.",
|
|
79
|
-
REG,
|
|
80
|
-
);
|
|
81
|
-
const r = run([SCRIPT, dirty, "--flags-only"]);
|
|
82
|
-
assert.match(
|
|
83
|
-
r.out,
|
|
84
|
-
/134 \(census\) is declared and the body no longer prints it/,
|
|
85
|
-
"the CLI did not report a stale registry row โ the self-test proves findings() sees it, so what " +
|
|
86
|
-
"is broken is the path from argv to findings():\n" +
|
|
87
|
-
r.out,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// โโ 3. โฆand says NOTHING when every declared population is printed โโโโโโโโโโโโโโโโโโโโโโ
|
|
92
|
-
// The direction that matters more. A gate that fires on a paper which already obeys the rule gets
|
|
93
|
-
// muted the same week, and a muted gate is indistinguishable from an absent one.
|
|
94
|
-
{
|
|
95
|
-
const clean = paper(
|
|
96
|
-
"cli-clean",
|
|
97
|
-
"The resolver ran over all 1,921 repositories at pinned commits, and a census of 134\nrepositories is a separate sample from those 1,921, overlapping in seven.",
|
|
98
|
-
REG,
|
|
99
|
-
);
|
|
100
|
-
const r = run([SCRIPT, clean, "--flags-only"]);
|
|
101
|
-
assert.equal(
|
|
102
|
-
r.out.trim(),
|
|
103
|
-
"",
|
|
104
|
-
"--flags-only printed something about a paper whose registry matches its body:\n" +
|
|
105
|
-
r.out,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// โโ 4. KNOWN GAP, asserted so it stays visible โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
110
|
-
// ๐ด A paper with NO repro/populations.tsv exits 0 in silence, which reads as a pass for
|
|
111
|
-
// draft-paper. So a paper that never declared its populations scores
|
|
112
|
-
// identically to one that declared them and tied every one. Absence is invisible again โ the same
|
|
113
|
-
// shape artifact-coverage.mjs was written to close for the released bundle.
|
|
114
|
-
//
|
|
115
|
-
// This asserts the CURRENT behaviour. When population-map learns to say "this paper has no
|
|
116
|
-
// registry", this assertion flips and must be updated; writing the gap down is how it stops being
|
|
117
|
-
// mistaken for coverage.
|
|
118
|
-
{
|
|
119
|
-
const bare = paper(
|
|
120
|
-
"cli-no-registry",
|
|
121
|
-
"We measured 1,921 repositories and a census of 134 repositories.",
|
|
122
|
-
undefined,
|
|
123
|
-
);
|
|
124
|
-
const r = run([SCRIPT, bare, "--flags-only"]);
|
|
125
|
-
assert.equal(
|
|
126
|
-
r.out.trim(),
|
|
127
|
-
"",
|
|
128
|
-
"population-map now says something about a paper with no registry โ good; update this assertion",
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
133
|
-
console.log(
|
|
134
|
-
"โ population-map: self-test owned (7 cases), CLI wiring fires on a stale row and stays quiet, 1 known gap recorded",
|
|
135
|
-
);
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* population-map.mjs โ does the population registry keep its link to the body of the paper?
|
|
4
|
-
*
|
|
5
|
-
* (Before 2026-08-26 this file answered the question "can the reader tell WHICH SET each number
|
|
6
|
-
* counts" in full; half of the answer now lives in ESLint rules โ see below.)
|
|
7
|
-
*
|
|
8
|
-
* node population-map.mjs <paper-dir> report
|
|
9
|
-
* node population-map.mjs <paper-dir> --flags-only for hooks and pre-commit
|
|
10
|
-
*
|
|
11
|
-
* ๐ด WHY THIS EXISTS. `papers/CLAUDE.md` has carried this as writing rule #3 since 2026-08-05:
|
|
12
|
-
*
|
|
13
|
-
* "A number arrives together with what it counts, and out of what. [โฆ] If two numbers come
|
|
14
|
-
* from different experiments โ say so IN THE SAME SENTENCE."
|
|
15
|
-
*
|
|
16
|
-
* It was written after a cold reader gave up tracking the abstract's populations halfway through.
|
|
17
|
-
* It is prose. Nothing enforced it. On 2026-08-06 the author read the finished paper and said he
|
|
18
|
-
* could not follow his own ยง4 โ and the cause was not the count of measurements, it was that ยง4
|
|
19
|
-
* moves between TWO SAMPLES THAT BARELY OVERLAP (a targeted census of 134 repositories and a broad
|
|
20
|
-
* corpus of 1,921; seven repositories are in both) and never says so. ยง4.1's rate and ยง4.3's rate
|
|
21
|
-
* read as if one replicated the other. They cannot: they are different populations.
|
|
22
|
-
*
|
|
23
|
-
* That is this repository's own thesis turned on its own manuscript โ a rule written in a rules
|
|
24
|
-
* file, with no mechanism behind it, that therefore did nothing for a year of edits. So the rule
|
|
25
|
-
* gets a leg.
|
|
26
|
-
*
|
|
27
|
-
* ๐ด TWO OF THE FOUR FINDINGS MOVED INTO ESLint RULES ON 2026-08-26. What is left here is only
|
|
28
|
-
* what speaks about THE REGISTRY ITSELF, not about the paper:
|
|
29
|
-
*
|
|
30
|
-
* stale a registry row for a quantity the body NO LONGER PRINTS. The registry shrinks together
|
|
31
|
-
* with the paper and does not rot.
|
|
32
|
-
* badref a row points at a `related_to` that is not a row anywhere.
|
|
33
|
-
*
|
|
34
|
-
* Both are inseparable from the file `repro/populations.tsv` and HAVE NO ADDRESS IN THE PAPER:
|
|
35
|
-
* `stale` by definition speaks about a number that is not in the paper, and `badref` about two
|
|
36
|
-
* fields of one TSV row. An ESLint rule can only report into the file being linted, so moving them
|
|
37
|
-
* would mean pointing a finger at the paper while talking about a different file.
|
|
38
|
-
*
|
|
39
|
-
* MOVED INTO `eslint-rules/paper-registry.mjs` (the rules `paper/population-untied` and
|
|
40
|
-
* `paper/population-undeclared`):
|
|
41
|
-
* untied โ a population is not named IN THE SAME SENTENCE as the one it is derived from;
|
|
42
|
-
* undeclared โ a number is printed in the shape of a population, and no registry row declares it.
|
|
43
|
-
* Both speak about a place IN THE PAPER, and for them the registry is configuration, exactly like a
|
|
44
|
-
* venue profile for `pdf/profile`. Parity was proved before the deletion (the real paper + 17
|
|
45
|
-
* fixtures), the write-up is in `the author's private research notes`.
|
|
46
|
-
*
|
|
47
|
-
* Advisory.
|
|
48
|
-
*/
|
|
49
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
50
|
-
import { join } from "node:path";
|
|
51
|
-
import { headings as mdHeadings, requireMarkdown } from "#lib/markdown";
|
|
52
|
-
import { isMain } from "./consumer.mjs";
|
|
53
|
-
|
|
54
|
-
// Markup is parsed with a parser (`CLAUDE.md`, 2026-08-11). We fail rather than degrade: without
|
|
55
|
-
// the body boundaries `bodyOf()` would return an empty string, and out of an empty string this
|
|
56
|
-
// check concludes "not a single registry number is printed", that is, ALL rows stale โ a confident
|
|
57
|
-
// list of findings about a paper nobody read.
|
|
58
|
-
requireMarkdown();
|
|
59
|
-
|
|
60
|
-
/** The body is everything before the bibliography; appendices sit after it in this paper and are
|
|
61
|
-
* not under the page limit, so a relation stated only there does not reach the reader who stops
|
|
62
|
-
* at the References. That asymmetry is the whole point of checking the body separately. */
|
|
63
|
-
export function bodyOf(md) {
|
|
64
|
-
const stripped = md.replace(/<!--[\s\S]*?-->/g, "");
|
|
65
|
-
// 2026-08-11: both body boundaries come from the parser. `/^##\s+References\s*$/m` opened and
|
|
66
|
-
// closed the body on hashes at the start of a line โ including hashes inside a ```-block, and this
|
|
67
|
-
// paper quotes whole chunks of other people's papers. The `-1` convention and the `< 0`
|
|
68
|
-
// comparisons are left as they were.
|
|
69
|
-
const at = (re) => {
|
|
70
|
-
const h = mdHeadings(stripped).find(
|
|
71
|
-
(x) => x.depth === 2 && re.test(x.text),
|
|
72
|
-
);
|
|
73
|
-
return h ? h.offset : -1;
|
|
74
|
-
};
|
|
75
|
-
const cut = at(/^References$/u);
|
|
76
|
-
const start = at(/^Abstract$/u);
|
|
77
|
-
return stripped.slice(start < 0 ? 0 : start, cut < 0 ? stripped.length : cut);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const asLiteral = (n) => n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
81
|
-
/** A printed quantity, not a substring of a longer one: 189 must not match inside 1,189 or 1893.
|
|
82
|
-
* The trailing guard must still allow ORDINARY PUNCTUATION after the number โ "of the 1,921, we
|
|
83
|
-
* could enumerate 189" and a sentence-final "...over all 1,921." are both the number being
|
|
84
|
-
* printed. Forbidding any following `.` or `,` silently loses exactly the positions a summary
|
|
85
|
-
* figure lands in; only a DIGIT after the separator makes it part of a longer quantity. */
|
|
86
|
-
const printed = (n) => new RegExp(`(?<![\\d,.])${asLiteral(n)}(?!\\d|[,.]\\d)`);
|
|
87
|
-
|
|
88
|
-
export function parseRegistry(tsv) {
|
|
89
|
-
const rows = [];
|
|
90
|
-
for (const line of tsv.split("\n")) {
|
|
91
|
-
if (!line.trim() || line.startsWith("#")) continue;
|
|
92
|
-
const [id, print, relation, relatedTo, gloss] = line
|
|
93
|
-
.split("\t")
|
|
94
|
-
.map((c) => c.trim()); // split yields strings; a missing column is `undefined` in the destructuring
|
|
95
|
-
if (!id || id === "id") continue;
|
|
96
|
-
rows.push({ id, print, relation, relatedTo, gloss });
|
|
97
|
-
}
|
|
98
|
-
return rows;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function findings(md, tsv) {
|
|
102
|
-
const body = bodyOf(md);
|
|
103
|
-
const reg = parseRegistry(tsv);
|
|
104
|
-
const byId = new Map(reg.map((r) => [r.id, r]));
|
|
105
|
-
const out = [];
|
|
106
|
-
|
|
107
|
-
for (const row of reg) {
|
|
108
|
-
// A row with no printed quantity has nothing to look for in the body. It used to reach
|
|
109
|
-
// `printed(undefined)` and crash the checker; it is a defect of the TSV, reported as one.
|
|
110
|
-
if (!row.print) {
|
|
111
|
-
out.push({ kind: "incomplete", row });
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const appears = printed(row.print).test(body);
|
|
115
|
-
if (!appears) {
|
|
116
|
-
// A registry row for a quantity the body no longer prints. Same discipline as the
|
|
117
|
-
// grandfathered numbers list: the registry shrinks when the paper does, and never rots.
|
|
118
|
-
if (row.relation !== "retired") out.push({ kind: "stale", row });
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
if (row.relation === "root" || row.relation === "external") continue;
|
|
122
|
-
// The order is preserved from the original: `untied` was computed AFTER this check and moved
|
|
123
|
-
// into `paper/population-untied`; the dangling reference stayed here because it is about a TSV
|
|
124
|
-
// row.
|
|
125
|
-
if (!byId.get(row.relatedTo)) out.push({ kind: "badref", row });
|
|
126
|
-
}
|
|
127
|
-
return out;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/* Importable above this line; the CLI only runs when this file is the entry point, so the tests
|
|
131
|
-
* can exercise findings() without the argv handling firing. */
|
|
132
|
-
if (!isMain(import.meta.url)) {
|
|
133
|
-
// imported โ nothing to do
|
|
134
|
-
} else main();
|
|
135
|
-
|
|
136
|
-
function main() {
|
|
137
|
-
const args = process.argv.slice(2);
|
|
138
|
-
const dir = args.find((a) => !a.startsWith("--"));
|
|
139
|
-
const flagsOnly = args.includes("--flags-only");
|
|
140
|
-
if (!dir) {
|
|
141
|
-
console.error("usage: node population-map.mjs <paper-dir> [--flags-only]");
|
|
142
|
-
process.exit(0);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const paperPath = ["paper.md", "draft.md"]
|
|
146
|
-
.map((f) => join(dir, f))
|
|
147
|
-
.find(existsSync);
|
|
148
|
-
const regPath = join(dir, "repro", "populations.tsv");
|
|
149
|
-
// Same silent-skip class as artifact-coverage.mjs โ see the note there (measured 2026-08-25).
|
|
150
|
-
if (!paperPath || !existsSync(regPath)) {
|
|
151
|
-
const why = !paperPath
|
|
152
|
-
? "no paper.md/draft.md โ this checker reads markdown only, a .tex paper is NOT covered"
|
|
153
|
-
: `no registry at ${regPath}`;
|
|
154
|
-
console.error(`โญ๏ธ population map SKIPPED for ${dir} โ ${why}.`);
|
|
155
|
-
process.exit(0);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const found = findings(
|
|
159
|
-
readFileSync(paperPath, "utf8"),
|
|
160
|
-
readFileSync(regPath, "utf8"),
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
if (!found.length) {
|
|
164
|
-
if (!flagsOnly)
|
|
165
|
-
console.log(
|
|
166
|
-
"population map: the registry matches the body โ no stale rows, no dangling related_to.",
|
|
167
|
-
);
|
|
168
|
-
process.exit(0);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
console.log(`population map โ ${found.length} finding(s) in ${paperPath}`);
|
|
172
|
-
for (const f of found) {
|
|
173
|
-
if (f.kind === "stale") {
|
|
174
|
-
console.log(
|
|
175
|
-
` ยท ${f.row.print} (${f.row.id}) is declared and the body no longer prints it โ drop the row or mark it retired`,
|
|
176
|
-
);
|
|
177
|
-
} else if (f.kind === "badref") {
|
|
178
|
-
console.log(
|
|
179
|
-
` ๐ด ${f.row.id} says it relates to "${f.row.relatedTo}", which is not a row in populations.tsv`,
|
|
180
|
-
);
|
|
181
|
-
} else {
|
|
182
|
-
console.log(
|
|
183
|
-
` ๐ด ${f.row.id} has no printed quantity โ the row cannot be checked against the body`,
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
process.exit(0);
|
|
188
|
-
}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* population-map.mjs โ the registry's own findings (`stale`, `badref`), planted in both directions,
|
|
3
|
-
* and the command around them. Until #52 the seven cases below were `population-map.selftest.mjs`,
|
|
4
|
-
* a script the harness spawned and whose "N passed" line it parsed; they are vitest cases now.
|
|
5
|
-
*
|
|
6
|
-
* ๐ด ONE CASE WAS DELETED BEFORE THE MOVE, NOT MOVED, and that is worth remembering: it ran a
|
|
7
|
-
* HAND-COPIED COPY of the checker's regex over a string. A change to the real `printed()` cannot
|
|
8
|
-
* touch such a test by construction. The property is pinned by behaviour instead (case 6).
|
|
9
|
-
*/
|
|
10
|
-
import assert from "node:assert/strict";
|
|
11
|
-
import { dirname, join } from "node:path";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
|
-
import { test } from "vitest";
|
|
14
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.ts";
|
|
15
|
-
import { bodyOf, findings } from "./population-map.mjs";
|
|
16
|
-
|
|
17
|
-
const SCRIPT = join(
|
|
18
|
-
dirname(fileURLToPath(import.meta.url)),
|
|
19
|
-
"population-map.mjs",
|
|
20
|
-
);
|
|
21
|
-
const doc = (bodyLines) =>
|
|
22
|
-
`## Abstract\n\n${bodyLines}\n\n## References\n\n[1] x.\n`;
|
|
23
|
-
const kinds = (md, reg) =>
|
|
24
|
-
findings(md, reg).map((f) => `${f.kind}:${f.row.print}`);
|
|
25
|
-
const REG = [
|
|
26
|
-
"id\tprinted\trelation\trelated_to\tgloss",
|
|
27
|
-
"broad\t1,921\troot\t\tthe corpus",
|
|
28
|
-
"sub\t1,836\tsubset\tbroad\tthose it could read",
|
|
29
|
-
].join("\n");
|
|
30
|
-
const HEAD = "id\tprinted\trelation\trelated_to\tgloss\n";
|
|
31
|
-
|
|
32
|
-
// 1. The direction that matters more: a checker firing on a paper that already obeys gets muted.
|
|
33
|
-
test("a registry that matches the body is silent", () => {
|
|
34
|
-
assert.deepEqual(
|
|
35
|
-
kinds(
|
|
36
|
-
doc(
|
|
37
|
-
"The resolver ran over all 1,921 repositories, and read 1,836 of them.",
|
|
38
|
-
),
|
|
39
|
-
REG,
|
|
40
|
-
),
|
|
41
|
-
[],
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// 2. A row for a quantity the paper no longer prints is a claim nobody can check.
|
|
46
|
-
test("a stale registry row fires", () => {
|
|
47
|
-
assert.deepEqual(
|
|
48
|
-
kinds(doc("The resolver ran over all 1,921 repositories."), REG),
|
|
49
|
-
["stale:1,836"],
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// 3. `retired` is what keeps a set declared after it was cut from the paper.
|
|
54
|
-
test("a retired row does not fire", () => {
|
|
55
|
-
assert.deepEqual(
|
|
56
|
-
kinds(
|
|
57
|
-
doc("The resolver ran over all 1,921 repositories, and read 1,836."),
|
|
58
|
-
`${REG}\ngold\t7,310\tretired\t\ta public gold set`,
|
|
59
|
-
),
|
|
60
|
-
[],
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// 4. A relation pointing at an id that is not a row โ a defect of the TSV alone.
|
|
65
|
-
test("a dangling related_to fires", () => {
|
|
66
|
-
assert.deepEqual(
|
|
67
|
-
kinds(
|
|
68
|
-
doc("We read 1,836 repositories."),
|
|
69
|
-
`${HEAD}sub\t1,836\tsubset\tnosuch\tx`,
|
|
70
|
-
),
|
|
71
|
-
["badref:1,836"],
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// 5. A row whose number is absent is `stale`, never also `badref`.
|
|
76
|
-
test("a row that is absent is stale, not badref", () => {
|
|
77
|
-
assert.deepEqual(
|
|
78
|
-
kinds(doc("Nothing numeric here."), `${HEAD}sub\t1,836\tsubset\tnosuch\tx`),
|
|
79
|
-
["stale:1,836"],
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// 6. `printed()` boundaries through behaviour: 189 is not printed inside 1,189.
|
|
84
|
-
test('189 is not "printed" inside 1,189', () => {
|
|
85
|
-
assert.deepEqual(
|
|
86
|
-
kinds(
|
|
87
|
-
doc("A follow-up read covered 1,189 records, of all 1,921."),
|
|
88
|
-
`${HEAD}broad\t1,921\troot\t\tthe corpus\nspread\t189\tsubset\tbroad\tenumerable`,
|
|
89
|
-
),
|
|
90
|
-
["stale:189"],
|
|
91
|
-
);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// 7. The body stops at the bibliography; with no Abstract it starts at the top, with no
|
|
95
|
-
// References it runs to the end.
|
|
96
|
-
test("bodyOf: from Abstract to References, or the whole text when either is missing", () => {
|
|
97
|
-
assert.deepEqual(
|
|
98
|
-
[
|
|
99
|
-
bodyOf(doc("nothing here")).includes("[1] x."),
|
|
100
|
-
bodyOf("pre\n\n## References\n\n[1] x.\n"),
|
|
101
|
-
bodyOf("## Abstract\n\nall of it\n"),
|
|
102
|
-
],
|
|
103
|
-
[false, "pre\n\n", "## Abstract\n\nall of it\n"],
|
|
104
|
-
);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("a registry row with no printed quantity is reported, not a crash", () => {
|
|
108
|
-
assert.deepEqual(
|
|
109
|
-
findings(doc("x"), `${HEAD}short\n`).map((f) => [f.kind, f.row.id]),
|
|
110
|
-
[["incomplete", "short"]],
|
|
111
|
-
);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// โโ the command โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
115
|
-
const root = useTempDir("population-map-");
|
|
116
|
-
const paper = (name, body, tsv) =>
|
|
117
|
-
writeTree(join(root, name), {
|
|
118
|
-
"paper.md": doc(body),
|
|
119
|
-
...(tsv === undefined ? {} : { "repro/populations.tsv": tsv }),
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("the command: usage, a paper without markdown, a clean registry, and every finding kind", () => {
|
|
123
|
-
assert.deepEqual(runNode(SCRIPT, []), {
|
|
124
|
-
status: 0,
|
|
125
|
-
stdout: "",
|
|
126
|
-
stderr: "usage: node population-map.mjs <paper-dir> [--flags-only]\n",
|
|
127
|
-
});
|
|
128
|
-
const tex = writeTree(join(root, "tex"), { "paper.tex": "x" });
|
|
129
|
-
assert.match(
|
|
130
|
-
runNode(SCRIPT, [tex]).stderr,
|
|
131
|
-
/population map SKIPPED for .* โ no paper\.md\/draft\.md โ this checker reads markdown only/,
|
|
132
|
-
);
|
|
133
|
-
const clean = paper(
|
|
134
|
-
"clean",
|
|
135
|
-
"All 1,921 of them.",
|
|
136
|
-
`${HEAD}broad\t1,921\troot\t\tx`,
|
|
137
|
-
);
|
|
138
|
-
assert.equal(
|
|
139
|
-
runNode(SCRIPT, [clean]).stdout,
|
|
140
|
-
"population map: the registry matches the body โ no stale rows, no dangling related_to.\n",
|
|
141
|
-
);
|
|
142
|
-
assert.equal(runNode(SCRIPT, [clean, "--flags-only"]).stdout, "");
|
|
143
|
-
const bad = paper(
|
|
144
|
-
"bad",
|
|
145
|
-
"We read 1,836.",
|
|
146
|
-
`${HEAD}sub\t1,836\tsubset\tnosuch\tx\nold\t7,310\tsubset\tsub\tx\nshort\n`,
|
|
147
|
-
);
|
|
148
|
-
assert.deepEqual(runNode(SCRIPT, [bad]).stdout.split("\n").slice(1), [
|
|
149
|
-
' ๐ด sub says it relates to "nosuch", which is not a row in populations.tsv',
|
|
150
|
-
" ยท 7,310 (old) is declared and the body no longer prints it โ drop the row or mark it retired",
|
|
151
|
-
" ๐ด short has no printed quantity โ the row cannot be checked against the body",
|
|
152
|
-
"",
|
|
153
|
-
]);
|
|
154
|
-
});
|