paperlint 3.2.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +16 -23
- package/CLAUDE.md +33 -13
- package/CONTRIBUTING.md +23 -7
- package/README.md +11 -8
- package/dist/adapters/banal/failure.d.ts +1 -7
- package/dist/adapters/banal/failure.d.ts.map +1 -1
- package/dist/adapters/banal/failure.js +5 -7
- package/dist/adapters/banal/failure.js.map +1 -1
- package/dist/adapters/banal/index.d.ts.map +1 -1
- package/dist/adapters/banal/index.js +8 -11
- package/dist/adapters/banal/index.js.map +1 -1
- package/dist/adapters/banal/install.d.ts.map +1 -1
- package/dist/adapters/banal/install.js +4 -3
- package/dist/adapters/banal/install.js.map +1 -1
- package/dist/adapters/banal/invocation.d.ts +10 -5
- package/dist/adapters/banal/invocation.d.ts.map +1 -1
- package/dist/adapters/banal/invocation.js +13 -1
- package/dist/adapters/banal/invocation.js.map +1 -1
- package/dist/adapters/banal/locate.d.ts +12 -9
- package/dist/adapters/banal/locate.d.ts.map +1 -1
- package/dist/adapters/banal/locate.js +19 -12
- package/dist/adapters/banal/locate.js.map +1 -1
- package/dist/adapters/banal/run.d.ts +10 -1
- package/dist/adapters/banal/run.d.ts.map +1 -1
- package/dist/adapters/banal/run.js +8 -4
- package/dist/adapters/banal/run.js.map +1 -1
- package/dist/adapters/banal/settings.d.ts +1 -1
- package/dist/adapters/banal/settings.d.ts.map +1 -1
- package/dist/adapters/banal/settings.js +2 -1
- package/dist/adapters/banal/settings.js.map +1 -1
- package/dist/adapters/latex/document-class.d.ts +22 -0
- package/dist/adapters/latex/document-class.d.ts.map +1 -0
- package/dist/adapters/latex/document-class.js +102 -0
- package/dist/adapters/latex/document-class.js.map +1 -0
- package/dist/adapters/latex/hidden.d.ts +16 -0
- package/dist/adapters/latex/hidden.d.ts.map +1 -0
- package/dist/adapters/latex/hidden.js +49 -0
- package/dist/adapters/latex/hidden.js.map +1 -0
- package/dist/adapters/latex/index.d.ts +29 -0
- package/dist/adapters/latex/index.d.ts.map +1 -0
- package/dist/adapters/latex/index.js +18 -0
- package/dist/adapters/latex/index.js.map +1 -0
- package/dist/adapters/latex/nodes.d.ts +54 -0
- package/dist/adapters/latex/nodes.d.ts.map +1 -0
- package/dist/adapters/latex/nodes.js +93 -0
- package/dist/adapters/latex/nodes.js.map +1 -0
- package/dist/adapters/latex/outline.d.ts +10 -0
- package/dist/adapters/latex/outline.d.ts.map +1 -0
- package/dist/adapters/latex/outline.js +39 -0
- package/dist/adapters/latex/outline.js.map +1 -0
- package/dist/adapters/latex/parse.d.ts +42 -0
- package/dist/adapters/latex/parse.d.ts.map +1 -0
- package/dist/adapters/latex/parse.js +94 -0
- package/dist/adapters/latex/parse.js.map +1 -0
- package/dist/adapters/latex/rendered.d.ts +10 -0
- package/dist/adapters/latex/rendered.d.ts.map +1 -0
- package/dist/adapters/latex/rendered.js +39 -0
- package/dist/adapters/latex/rendered.js.map +1 -0
- package/dist/adapters/memory/index.d.ts.map +1 -1
- package/dist/adapters/memory/index.js +8 -2
- package/dist/adapters/memory/index.js.map +1 -1
- package/dist/adapters/node/process.io.d.ts +6 -3
- package/dist/adapters/node/process.io.d.ts.map +1 -1
- package/dist/adapters/node/process.io.js.map +1 -1
- package/dist/adapters/node/workspace.io.d.ts.map +1 -1
- package/dist/adapters/node/workspace.io.js +4 -2
- package/dist/adapters/node/workspace.io.js.map +1 -1
- package/dist/adapters/pdfjs/fill.d.ts.map +1 -1
- package/dist/adapters/pdfjs/fill.js +12 -12
- package/dist/adapters/pdfjs/fill.js.map +1 -1
- package/dist/adapters/references/index.d.ts.map +1 -1
- package/dist/adapters/references/index.js +4 -2
- package/dist/adapters/references/index.js.map +1 -1
- package/dist/build-engine.d.ts +1 -1
- package/dist/build-engine.d.ts.map +1 -1
- package/dist/build-engine.js +8 -1
- package/dist/build-engine.js.map +1 -1
- package/dist/build.d.ts +2 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +9 -10
- package/dist/build.js.map +1 -1
- package/dist/caller-path.d.ts +3 -0
- package/dist/caller-path.d.ts.map +1 -0
- package/dist/caller-path.js +13 -0
- package/dist/caller-path.js.map +1 -0
- package/dist/cli.d.ts +10 -17
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +91 -17
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts +12 -3
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +2 -1
- package/dist/doctor.js.map +1 -1
- package/dist/domain/paths.d.ts +8 -2
- package/dist/domain/paths.d.ts.map +1 -1
- package/dist/domain/paths.js +12 -1
- package/dist/domain/paths.js.map +1 -1
- package/dist/domain/ready.d.ts +24 -0
- package/dist/domain/ready.d.ts.map +1 -0
- package/dist/domain/ready.js +11 -0
- package/dist/domain/ready.js.map +1 -0
- package/dist/domain/record.d.ts +8 -0
- package/dist/domain/record.d.ts.map +1 -0
- package/dist/domain/record.js +8 -0
- package/dist/domain/record.js.map +1 -0
- package/dist/domain/sha256.d.ts.map +1 -1
- package/dist/domain/sha256.js +4 -2
- package/dist/domain/sha256.js.map +1 -1
- package/dist/domain/tex-document.d.ts +84 -0
- package/dist/domain/tex-document.d.ts.map +1 -0
- package/dist/domain/tex-document.js +43 -0
- package/dist/domain/tex-document.js.map +1 -0
- package/dist/engine.d.ts +23 -22
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/eslint-rules/bib-reachable-entry.d.ts +1 -1
- package/dist/eslint-rules/bib-reachable-entry.js.map +1 -1
- package/dist/eslint-rules/install-path-literals.d.ts +2 -2
- package/dist/eslint-rules/install-path-literals.js.map +1 -1
- package/dist/eslint-rules/paper-research-question.d.ts +1 -1
- package/dist/eslint-rules/paper-research-question.js.map +1 -1
- package/dist/eslint-rules/paper-stages.d.ts +2 -2
- package/dist/eslint-rules/paper-stages.js.map +1 -1
- package/dist/eslint-rules/paper-typography.d.ts +6 -6
- package/dist/eslint-rules/paper-typography.js.map +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.d.ts +1 -1
- package/dist/eslint-rules/pdf-last-page-balance.js.map +1 -1
- package/dist/eslint-rules/review-frontmatter.d.ts +2 -2
- package/dist/eslint-rules/review-frontmatter.js.map +1 -1
- package/dist/eslint-rules/sibling-frontmatter.d.ts +1 -1
- package/dist/eslint-rules/sibling-frontmatter.d.ts.map +1 -1
- package/dist/eslint-rules/temp-root-realpath.d.ts +1 -1
- package/dist/eslint-rules/temp-root-realpath.js.map +1 -1
- package/dist/eslint-rules/tex-build.d.ts +2 -2
- package/dist/eslint-rules/tex-build.js.map +1 -1
- package/dist/facts-file.d.ts.map +1 -1
- package/dist/facts-file.js +31 -28
- package/dist/facts-file.js.map +1 -1
- package/dist/hooks-settings.d.ts.map +1 -1
- package/dist/hooks-settings.js +17 -2
- package/dist/hooks-settings.js.map +1 -1
- package/dist/init.d.ts +3 -4
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +18 -8
- package/dist/init.js.map +1 -1
- package/dist/lib/paper-config.d.ts.map +1 -1
- package/dist/lib/paper-config.js +1 -5
- package/dist/lib/paper-config.js.map +1 -1
- package/dist/new-paper.d.ts +5 -0
- package/dist/new-paper.d.ts.map +1 -1
- package/dist/new-paper.js +8 -1
- package/dist/new-paper.js.map +1 -1
- package/dist/package-dirs.d.ts +5 -0
- package/dist/package-dirs.d.ts.map +1 -0
- package/dist/package-dirs.js +14 -0
- package/dist/package-dirs.js.map +1 -0
- package/dist/paper-files.d.ts +4 -4
- package/dist/paper-files.d.ts.map +1 -1
- package/dist/paper-files.js +6 -6
- package/dist/paper-files.js.map +1 -1
- package/dist/paper-settings.js +3 -3
- package/dist/paper-settings.js.map +1 -1
- package/dist/pdf-facts.d.ts +51 -1
- package/dist/pdf-facts.d.ts.map +1 -1
- package/dist/pdf-facts.js +23 -15
- package/dist/pdf-facts.js.map +1 -1
- package/dist/pdf-geometry.d.ts.map +1 -1
- package/dist/pdf-geometry.js +2 -3
- package/dist/pdf-geometry.js.map +1 -1
- package/dist/ports/latex.d.ts +24 -0
- package/dist/ports/latex.d.ts.map +1 -0
- package/dist/ports/latex.js +2 -0
- package/dist/ports/latex.js.map +1 -0
- package/dist/ports/tool-installer.d.ts +2 -14
- package/dist/ports/tool-installer.d.ts.map +1 -1
- package/dist/presets.d.ts +15 -2
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +35 -10
- package/dist/presets.js.map +1 -1
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +4 -4
- package/dist/references.js.map +1 -1
- package/dist/rules-config.d.ts +26 -1
- package/dist/rules-config.d.ts.map +1 -1
- package/dist/rules-config.js +9 -9
- package/dist/rules-config.js.map +1 -1
- package/dist/tex-requirements.d.ts +15 -0
- package/dist/tex-requirements.d.ts.map +1 -1
- package/dist/tex-requirements.js +28 -10
- package/dist/tex-requirements.js.map +1 -1
- package/dist/tex-venue-rules.d.ts +83 -0
- package/dist/tex-venue-rules.d.ts.map +1 -0
- package/dist/tex-venue-rules.js +254 -0
- package/dist/tex-venue-rules.js.map +1 -0
- package/dist/types.d.ts +5 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/venue-rules.d.ts +1 -1
- package/dist/venue-rules.d.ts.map +1 -1
- package/dist/venue-rules.js +20 -7
- package/dist/venue-rules.js.map +1 -1
- package/docs/configuration.md +5 -4
- package/docs/e2e.md +69 -40
- package/docs/install.md +1 -1
- package/docs/prior-art/README.md +1 -1
- package/docs/prior-art/package-location.md +5 -5
- package/docs/prior-art/repro/README.md +1 -1
- package/docs/prior-art/test-tooling.md +21 -10
- package/docs/rules/tex/required-section.md +73 -0
- package/docs/rules/tex/template.md +62 -0
- package/docs/rules/tex/venue-leftover.md +71 -0
- package/docs/rules.md +70 -48
- package/docs/testing.md +17 -4
- package/docs/texlive-install-decision.md +1 -1
- package/docs/toolchain.md +2 -2
- package/eslint-rules/bib-reachable-entry.ts +1 -1
- package/eslint-rules/install-path-literals.ts +2 -2
- package/eslint-rules/paper-research-question.ts +1 -1
- package/eslint-rules/paper-stages.ts +2 -2
- package/eslint-rules/paper-typography.ts +2 -2
- package/eslint-rules/pdf-last-page-balance.ts +1 -1
- package/eslint-rules/review-frontmatter.ts +1 -1
- package/eslint-rules/temp-root-realpath.ts +1 -1
- package/eslint-rules/tex-build.ts +2 -2
- package/eslint.config.mjs +162 -15
- package/fixtures/build-e2e/acmart/expect.json +26 -0
- package/fixtures/build-e2e/aidc/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/aidc/expect.json +14 -0
- package/fixtures/build-e2e/aidc/paper.tex +46 -0
- package/fixtures/build-e2e/aidc/paperlint.json +1 -0
- package/fixtures/build-e2e/broken/expect.json +11 -0
- package/fixtures/build-e2e/cite/expect.json +27 -0
- package/fixtures/build-e2e/empty/expect.json +12 -0
- package/fixtures/build-e2e/fallback/expect.json +53 -0
- package/fixtures/build-e2e/guards/expect.json +6 -0
- package/fixtures/build-e2e/no-source/expect.json +10 -0
- package/fixtures/build-e2e/unbalanced/expect.json +60 -0
- package/fixtures/install-path-literals/clean.fixture.mjs +1 -1
- package/fixtures/install-path-literals/clean.md +2 -2
- package/fixtures/install-path-literals/defect.fixture.mjs +1 -1
- package/fixtures/install-path-literals/defect.md +2 -2
- package/fixtures/pdf-facts/README.md +1 -1
- package/fixtures/real-markdown-paper/baseline.ts +1 -1
- package/fixtures/render-paper/build-clean.sh +3 -5
- package/hooks/paper-status-gates.sh +9 -19
- package/lib/paper-config.harness.mjs +1 -1
- package/lib/paper-config.ts +1 -5
- package/lib/skill-checks.mjs +24 -381
- package/lib/skill-checks.test.mjs +63 -115
- package/lib/skill-corpus.mjs +10 -251
- package/lib/skill-corpus.test.mjs +2 -13
- package/lib/skill-trigger-cases.mjs +1 -1
- package/package.json +13 -2
- package/{skills/submit-paper/references/venues → presets}/acm-sigconf.jsonc +4 -1
- package/{skills/submit-paper/references/venues → presets}/agenticdev.jsonc +4 -0
- package/presets/aidc.jsonc +73 -0
- package/{skills/submit-paper/references/venues → presets}/aisec.jsonc +4 -0
- package/presets/ieee-conference.jsonc +66 -0
- package/{skills/submit-paper/references/venues → presets}/realm.jsonc +8 -1
- package/{skills/submit-paper/references/venues → presets/tex}/paper-guards.tex +1 -1
- package/{skills/submit-paper/references/venues → presets}/venue-profile.schema.json +30 -2
- package/scripts/check.harness.ts +64 -10
- package/scripts/check.test.ts +60 -13
- package/scripts/check.ts +83 -30
- package/scripts/coverage-config.test.ts +0 -1
- package/scripts/harness-api.frozen.json +0 -1
- package/scripts/test.test.ts +1 -1
- package/scripts/test.ts +1 -1
- package/skills/analyze-sibling-paper/SKILL.md +1 -39
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +0 -38
- package/skills/argument-arc/SKILL.md +2 -36
- package/skills/argument-arc/SKILL.md.spec.ts +1 -43
- package/skills/build-benchmark/SKILL.md +1 -41
- package/skills/build-benchmark/SKILL.md.spec.ts +0 -40
- package/skills/camera-ready/SKILL.md +1 -34
- package/skills/camera-ready/SKILL.md.spec.ts +0 -33
- package/skills/cold-read-diff/SKILL.md +1 -35
- package/skills/cold-read-diff/SKILL.md.spec.ts +0 -34
- package/skills/draft-paper/SKILL.md +2 -41
- package/skills/draft-paper/SKILL.md.spec.ts +1 -50
- package/skills/extend-paper/SKILL.md +2 -33
- package/skills/extend-paper/SKILL.md.spec.ts +1 -42
- package/skills/find-venue/SKILL.md +2 -38
- package/skills/find-venue/SKILL.md.spec.ts +1 -47
- package/skills/grade-paper-writing/SKILL.md +3 -38
- package/skills/grade-paper-writing/SKILL.md.spec.ts +2 -47
- package/skills/grade-paper-writing/prose-lint.mjs +2 -3
- package/skills/grade-paper-writing/prose-lint.test.ts +1 -1
- package/skills/harden-paper/SKILL.md +1 -39
- package/skills/harden-paper/SKILL.md.spec.ts +0 -38
- package/skills/map-prior-work/SKILL.md +1 -35
- package/skills/map-prior-work/SKILL.md.spec.ts +0 -34
- package/skills/osf-artifact-upload/osf-artifact-upload.harness.ts +3 -4
- package/skills/paper-adversarial-review/SKILL.md +2 -35
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +1 -43
- package/skills/paper-pipeline/PIPELINE-MAP.md +2 -2
- package/skills/paper-pipeline/SKILL.md +3 -29
- package/skills/paper-pipeline/SKILL.md.spec.ts +2 -28
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +1 -1
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +25 -40
- package/skills/paper-pipeline/references/acceptance-gate.md +1 -6
- package/skills/paper-pipeline/references/pipeline-status-template.md +8 -35
- package/skills/paper-pipeline/scripts/README.md +30 -225
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +4 -8
- package/skills/paper-pipeline/scripts/consumer.d.mts +0 -2
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +6 -104
- package/skills/paper-pipeline/scripts/consumer.mjs +24 -119
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +2 -3
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +3 -3
- package/skills/paper-status/SKILL.md +2 -42
- package/skills/paper-status/SKILL.md.spec.ts +1 -41
- package/skills/pc-panel-review/SKILL.md +2 -46
- package/skills/pc-panel-review/SKILL.md.spec.ts +1 -45
- package/skills/plan-paper-timeline/SKILL.md +2 -36
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +0 -36
- package/skills/render-paper/SKILL.md +2 -38
- package/skills/render-paper/SKILL.md.spec.ts +1 -37
- package/skills/render-paper/check-render.sh +16 -63
- package/skills/render-paper/render-paper.harness.mjs +17 -59
- package/skills/research-ideate/SKILL.md +2 -39
- package/skills/research-ideate/SKILL.md.spec.ts +1 -47
- package/skills/study-accepted-papers/SKILL.md +1 -34
- package/skills/study-accepted-papers/SKILL.md.spec.ts +0 -33
- package/skills/submit-paper/SKILL.md +1 -33
- package/skills/submit-paper/SKILL.md.spec.ts +0 -32
- package/skills/sweep-design-space/SKILL.md +1 -38
- package/skills/sweep-design-space/SKILL.md.spec.ts +0 -37
- package/skills/tighten-paper/SKILL.md +2 -39
- package/skills/tighten-paper/SKILL.md.spec.ts +1 -47
- package/skills/tighten-paper/structure.mjs +4 -11
- package/skills/verify-citations/SKILL.md +2 -38
- package/skills/verify-citations/SKILL.md.spec.ts +1 -37
- package/src/adapters/banal/failure.ts +9 -10
- package/src/adapters/banal/index.test.ts +3 -3
- package/src/adapters/banal/index.ts +8 -10
- package/src/adapters/banal/install.ts +9 -4
- package/src/adapters/banal/invocation.test.ts +20 -8
- package/src/adapters/banal/invocation.ts +24 -9
- package/src/adapters/banal/locate.test.ts +2 -2
- package/src/adapters/banal/locate.ts +27 -21
- package/src/adapters/banal/output.test.ts +1 -1
- package/src/adapters/banal/run.test.ts +3 -3
- package/src/adapters/banal/run.ts +16 -10
- package/src/adapters/banal/settings.ts +2 -2
- package/src/adapters/banal/xml.test.ts +1 -1
- package/src/adapters/curl/download.test.ts +4 -4
- package/src/adapters/latex/document-class.ts +147 -0
- package/src/adapters/latex/hidden.ts +70 -0
- package/src/adapters/latex/index.test.ts +361 -0
- package/src/adapters/latex/index.ts +55 -0
- package/src/adapters/latex/nodes.ts +141 -0
- package/src/adapters/latex/outline.ts +64 -0
- package/src/adapters/latex/parse.ts +136 -0
- package/src/adapters/latex/rendered.ts +59 -0
- package/src/adapters/memory/index.ts +4 -3
- package/src/adapters/node/files.test.ts +5 -3
- package/src/adapters/node/process.io.ts +9 -2
- package/src/adapters/node/process.test.ts +4 -4
- package/src/adapters/node/workspace.io.ts +9 -4
- package/src/adapters/pdfjs/fill.test.ts +1 -1
- package/src/adapters/pdfjs/fill.ts +18 -10
- package/src/adapters/references/index.ts +7 -2
- package/src/build-engine.test.ts +11 -6
- package/src/build-engine.ts +10 -5
- package/src/build.harness.mjs +5 -7
- package/src/build.test.ts +10 -11
- package/src/build.ts +12 -13
- package/src/caller-path.ts +13 -0
- package/src/cli.harness.mjs +1 -3
- package/src/cli.test.ts +21 -16
- package/src/cli.ts +115 -33
- package/src/doctor.test.ts +1 -1
- package/src/doctor.ts +14 -5
- package/src/domain/paths.test.ts +15 -0
- package/src/domain/paths.ts +20 -1
- package/src/domain/ready.ts +31 -0
- package/src/domain/record.test.ts +20 -0
- package/src/domain/record.ts +12 -0
- package/src/domain/sha256.ts +5 -3
- package/src/domain/tex-document.test.ts +80 -0
- package/src/domain/tex-document.ts +110 -0
- package/src/engine.harness.mjs +1 -1
- package/src/engine.ts +30 -2
- package/src/facts-file.test.ts +4 -7
- package/src/facts-file.ts +45 -30
- package/src/hooks-settings.harness.ts +17 -0
- package/src/hooks-settings.ts +28 -4
- package/src/init.test.ts +25 -5
- package/src/init.ts +26 -12
- package/src/latex-loop.harness.ts +1 -1
- package/src/new-paper.harness.mjs +7 -23
- package/src/new-paper.test.ts +28 -3
- package/src/new-paper.ts +15 -3
- package/src/package-dirs.ts +17 -0
- package/src/paper-files.test.ts +22 -19
- package/src/paper-files.ts +16 -27
- package/src/paper-settings-commands.test.ts +6 -1
- package/src/paper-settings.test.ts +2 -2
- package/src/paper-settings.ts +5 -5
- package/src/pdf-facts.test.ts +16 -5
- package/src/pdf-facts.ts +79 -22
- package/src/pdf-geometry.ts +5 -3
- package/src/ports/latex.ts +29 -0
- package/src/ports/tool-installer.ts +2 -17
- package/src/presets.test.ts +65 -4
- package/src/presets.ts +65 -28
- package/src/references.test.ts +25 -19
- package/src/references.ts +4 -5
- package/src/rule-cases.test.ts +474 -0
- package/src/rule-docs.test.ts +159 -0
- package/src/rules-config.ts +40 -11
- package/src/tex-requirements.harness.ts +13 -23
- package/src/tex-requirements.test.ts +21 -0
- package/src/tex-requirements.ts +64 -14
- package/src/tex-venue-rules.test.ts +659 -0
- package/src/tex-venue-rules.ts +429 -0
- package/src/toolchain.harness.mjs +1 -1
- package/src/toolchain.test.ts +9 -5
- package/src/toolchain.ts +2 -2
- package/src/types.ts +5 -3
- package/src/venue-rules.test.ts +104 -8
- package/src/venue-rules.ts +22 -12
- package/templates/paper/paper.tex +2 -1
- package/skills/paper-pipeline/scripts/announce.mjs +0 -67
- package/skills/paper-pipeline/scripts/announce.test.mjs +0 -102
- package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +0 -51
- package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +0 -52
- package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +0 -6
- package/skills/paper-pipeline/scripts/fixtures/scorecard.ts +0 -100
- package/skills/paper-pipeline/scripts/ledger.cli.test.mjs +0 -302
- package/skills/paper-pipeline/scripts/ledger.mjs +0 -623
- package/skills/paper-pipeline/scripts/ledger.test.mjs +0 -254
- package/skills/paper-pipeline/scripts/pipeline-check.cli.test.mjs +0 -474
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +0 -328
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +0 -750
- package/skills/paper-pipeline/scripts/pipeline-edges.mjs +0 -169
- package/skills/paper-pipeline/scripts/pipeline-edges.test.mjs +0 -73
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +0 -648
- package/skills/paper-pipeline/scripts/run-mechanical.test.mjs +0 -468
- package/skills/paper-pipeline/scripts/status.mjs +0 -295
- package/skills/paper-pipeline/scripts/status.test.mjs +0 -232
- /package/{skills/submit-paper/references/venues → presets/tex}/agenticdev.tex +0 -0
- /package/{skills/submit-paper/references/venues → presets}/tex-base.jsonc +0 -0
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
// status.mjs — the one status view, computed. Replaces the table nobody could trust.
|
|
2
|
-
//
|
|
3
|
-
// node .claude/skills/paper-pipeline/scripts/status.mjs <papers-root>/<paper-a>
|
|
4
|
-
//
|
|
5
|
-
// Everything printed here is derived from the ledger plus the bytes currently on disk. There is
|
|
6
|
-
// no field a human can set, which is the entire point: the table it replaces was accurate only
|
|
7
|
-
// for as long as someone remembered to un-tick it, and nobody ever did.
|
|
8
|
-
//
|
|
9
|
-
// 🔴 NOTHING IN THIS VIEW SAYS A PAPER PASSED, AND THAT IS ENFORCED, NOT INTENDED.
|
|
10
|
-
// The ledger has no `PASS` constructor (see ledger.mjs), so this reader has nothing to render as
|
|
11
|
-
// an acquittal. It reports, per check: how many findings the last run recorded, or — when the run
|
|
12
|
-
// recorded none — the ABSTENTION reason it gave. `no-witness` means "ran, found nothing, and has
|
|
13
|
-
// no witness for the negative"; it is displayed as an abstention and never as green.
|
|
14
|
-
// `gates.harness.mjs` asserts that this file's output contains no word meaning "passed", because
|
|
15
|
-
// a rule about tone that nothing checks is a rule that lasts one refactor.
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
status,
|
|
19
|
-
readLedger,
|
|
20
|
-
rowKey,
|
|
21
|
-
parseGate,
|
|
22
|
-
ABSTENTIONS,
|
|
23
|
-
} from "./ledger.mjs";
|
|
24
|
-
import { resolve, basename } from "node:path";
|
|
25
|
-
import { isMain } from "./consumer.mjs";
|
|
26
|
-
|
|
27
|
-
// The checks a paper is expected to have been put through. Listed explicitly so a check that has
|
|
28
|
-
// NEVER run shows up as a row rather than as an absence — the difference between "we looked and
|
|
29
|
-
// recorded nothing" and "nobody asked" is the whole failure this pipeline keeps having.
|
|
30
|
-
//
|
|
31
|
-
// 🔴 ENTRIES ARE CHECKS, NOT SKILLS. `skill` names a skill's own single pass; `skill/check` names
|
|
32
|
-
// one mechanical check filed under that skill. Before 2026-08-10 the key was the skill, and
|
|
33
|
-
// `status()` took the LAST row per skill — so two checks under one name took turns being the
|
|
34
|
-
// answer and a clean run of one erased a finding of the other from every derived view. Three
|
|
35
|
-
// checks now sit under `build-benchmark` and none of them can overwrite the others.
|
|
36
|
-
export const EXPECTED_GATES = [
|
|
37
|
-
// — before a word is written —
|
|
38
|
-
"research-ideate",
|
|
39
|
-
"sweep-design-space",
|
|
40
|
-
"map-prior-work",
|
|
41
|
-
"find-venue",
|
|
42
|
-
"plan-paper-timeline",
|
|
43
|
-
// — building the evidence —
|
|
44
|
-
"build-benchmark",
|
|
45
|
-
"build-benchmark/check-provenance",
|
|
46
|
-
"build-benchmark/arm-permutation",
|
|
47
|
-
"build-benchmark/delivered-pdf",
|
|
48
|
-
"build-benchmark/generated-code",
|
|
49
|
-
"argument-arc",
|
|
50
|
-
"draft-paper",
|
|
51
|
-
"draft-paper/population-map",
|
|
52
|
-
// — the loop —
|
|
53
|
-
"cold-read-diff",
|
|
54
|
-
"tighten-paper",
|
|
55
|
-
"tighten-paper/structure",
|
|
56
|
-
"tighten-paper/round-diff",
|
|
57
|
-
"grade-paper-writing",
|
|
58
|
-
"grade-paper-writing/prose-lint",
|
|
59
|
-
// TeXtidote. Filed here because this skill owns the paper's PROSE surface and `prose-lint` is the
|
|
60
|
-
// other instrument reading it — style thresholds there, spelling and grammar here.
|
|
61
|
-
"grade-paper-writing/textidote",
|
|
62
|
-
"render-paper",
|
|
63
|
-
"render-paper/report-submission",
|
|
64
|
-
// — checking against the world —
|
|
65
|
-
"verify-citations",
|
|
66
|
-
"verify-citations/verify-cites",
|
|
67
|
-
// checkcites, the bibliography read backwards: verify-cites asks whether an entry names a real
|
|
68
|
-
// work, this asks whether anything cites the entry. Same surface, opposite arrow, same skill.
|
|
69
|
-
"verify-citations/uncited-refs",
|
|
70
|
-
"analyze-sibling-paper",
|
|
71
|
-
"study-accepted-papers",
|
|
72
|
-
// — the gates —
|
|
73
|
-
"paper-adversarial-review",
|
|
74
|
-
"pc-panel-review",
|
|
75
|
-
"harden-paper",
|
|
76
|
-
"harden-paper/artifact-coverage",
|
|
77
|
-
"submit-paper",
|
|
78
|
-
// — after —
|
|
79
|
-
"camera-ready",
|
|
80
|
-
"extend-paper",
|
|
81
|
-
];
|
|
82
|
-
// 🔴 This list is the table. A check that records a row but is absent here writes rows nobody
|
|
83
|
-
// ever sees — it ran, and the status view says nothing, which is the precise failure this whole
|
|
84
|
-
// directory was built to end. Found 2026-08-07, hours after the first version shipped with 12 of
|
|
85
|
-
// the 22 wired skills listed. `paper-status` is deliberately absent: it REPORTS state rather than
|
|
86
|
-
// producing a verdict about the paper, so a row for it would be the table grading itself.
|
|
87
|
-
// Any new paper skill: wire it, then add it here. Any new mechanical check in `run-mechanical.mjs`:
|
|
88
|
-
// add its `skill/check` key here. `unlistedGates()` below catches the omission.
|
|
89
|
-
|
|
90
|
-
/** Checks that have recorded rows for this paper but are missing from the table above. */
|
|
91
|
-
export function unlistedGates(rows) {
|
|
92
|
-
const listed = new Set(EXPECTED_GATES);
|
|
93
|
-
return [...new Set(rows.map(rowKey))].filter(
|
|
94
|
-
(k) => !listed.has(k) && parseGate(k).skill !== "paper-status",
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const ICON = {
|
|
99
|
-
FRESH: "🟢",
|
|
100
|
-
"STALE-PAPER": "🟠",
|
|
101
|
-
"STALE-SKILL": "🟡",
|
|
102
|
-
"NEVER-RUN": "⬜",
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const WHY = {
|
|
106
|
-
FRESH: "ran against these exact bytes",
|
|
107
|
-
"STALE-PAPER":
|
|
108
|
-
"the paper changed since it ran — its answer is about a document that is gone",
|
|
109
|
-
"STALE-SKILL":
|
|
110
|
-
"the check itself changed since it ran — that answer came from a different tool",
|
|
111
|
-
"NEVER-RUN": "nobody has asked this question about this paper",
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
/** What the last run of this check produced. Never a word that could be read as an acquittal. */
|
|
115
|
-
function produced(r) {
|
|
116
|
-
if (r.state === "NEVER-RUN") return "—";
|
|
117
|
-
if (r.findings > 0) return `${r.blocking ? "🔴" : "•"} ${r.findings} found`;
|
|
118
|
-
if (r.legacy) return `legacy:${r.legacy}`;
|
|
119
|
-
if (r.abstained) return `abstained:${r.abstained.reason}`;
|
|
120
|
-
return "no row";
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function main(argv) {
|
|
124
|
-
const dir = resolve(argv[2] || ".");
|
|
125
|
-
const rows = status(dir, { gates: EXPECTED_GATES });
|
|
126
|
-
|
|
127
|
-
console.log(`\n ${basename(dir)}\n`);
|
|
128
|
-
const pad = (s, n) => String(s).padEnd(n); // every cell is a string or a count
|
|
129
|
-
console.log(
|
|
130
|
-
` ${pad("check", 36)}${pad("freshness", 14)}${pad("last run produced", 22)}${pad("runs", 6)}when`,
|
|
131
|
-
);
|
|
132
|
-
console.log(` ${"-".repeat(92)}`);
|
|
133
|
-
|
|
134
|
-
for (const r of rows) {
|
|
135
|
-
const when = r.ts ? r.ts.slice(0, 16).replace("T", " ") : "—";
|
|
136
|
-
console.log(
|
|
137
|
-
` ${ICON[r.state]} ${pad(r.key, 34)}${pad(r.state, 14)}${pad(produced(r), 22)}${pad(r.runs, 6)}${when}`,
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const stale = rows.filter(
|
|
142
|
-
(r) => r.state === "STALE-PAPER" || r.state === "STALE-SKILL",
|
|
143
|
-
);
|
|
144
|
-
const never = rows.filter((r) => r.state === "NEVER-RUN");
|
|
145
|
-
const mute = rows.filter((r) => r.runs > 0 && !r.everFound);
|
|
146
|
-
|
|
147
|
-
console.log("");
|
|
148
|
-
for (const r of stale)
|
|
149
|
-
console.log(` ${ICON[r.state]} ${r.key}: ${WHY[r.state]}`);
|
|
150
|
-
if (never.length) {
|
|
151
|
-
console.log(` ⬜ never run: ${never.map((r) => r.key).join(", ")}`);
|
|
152
|
-
console.log(
|
|
153
|
-
` ${WHY["NEVER-RUN"]} — an unasked question reads exactly like a clean one in prose.`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// 🔴 THE ABSENCE OF FINDINGS IS NOT A RESULT, AND THIS IS WHERE THAT IS SAID OUT LOUD.
|
|
158
|
-
// Under the old vocabulary these checks recorded PASS and this block was a footnote about a
|
|
159
|
-
// suspicious gate. With PASS deleted, "recorded no finding" is ALL that a clean run ever
|
|
160
|
-
// produces, so this is now the primary reading of the table rather than a warning about it.
|
|
161
|
-
if (mute.length) {
|
|
162
|
-
console.log(
|
|
163
|
-
`\n 🔇 has run and has NEVER recorded a finding: ${mute.map((r) => r.key).join(", ")}`,
|
|
164
|
-
);
|
|
165
|
-
console.log(
|
|
166
|
-
` Borrowed from mutation testing: a test that kills no mutant is not a test. This is`,
|
|
167
|
-
);
|
|
168
|
-
console.log(
|
|
169
|
-
` not proof the check is broken — it is the reason to go plant a defect and watch.`,
|
|
170
|
-
);
|
|
171
|
-
console.log(
|
|
172
|
-
` Precedent here: a tightening pass returned KEEP on 80 of 81 sections and a`,
|
|
173
|
-
);
|
|
174
|
-
console.log(
|
|
175
|
-
` justification pass never once recommended a deletion. Both "ran".`,
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const legacy = rows.filter((r) => r.legacy);
|
|
180
|
-
if (legacy.length) {
|
|
181
|
-
const acquittals = legacy.filter(
|
|
182
|
-
(r) => !["FINDINGS", "FAIL"].includes(r.legacy),
|
|
183
|
-
);
|
|
184
|
-
console.log(
|
|
185
|
-
`\n 🏷️ answered in the RETIRED vocabulary: ${legacy.map((r) => `${r.key}=${r.legacy}`).join(", ")}`,
|
|
186
|
-
);
|
|
187
|
-
console.log(
|
|
188
|
-
` Rows written before 2026-08-10 are kept verbatim and are NOT translated into the`,
|
|
189
|
-
);
|
|
190
|
-
console.log(
|
|
191
|
-
` current constructors — a silent reinterpretation is the class of defect this`,
|
|
192
|
-
);
|
|
193
|
-
console.log(
|
|
194
|
-
` pipeline removed. A retired FINDINGS/FAIL row still shows its count above, because`,
|
|
195
|
-
);
|
|
196
|
-
console.log(
|
|
197
|
-
` it carries evidence and discarding evidence is the destructive direction.`,
|
|
198
|
-
);
|
|
199
|
-
if (acquittals.length) {
|
|
200
|
-
console.log(
|
|
201
|
-
` ${acquittals.map((r) => `${r.key}=${r.legacy}`).join(", ")} carry NOTHING forward:`,
|
|
202
|
-
);
|
|
203
|
-
console.log(
|
|
204
|
-
` they recorded that nothing was wrong, with no evidence attached, which is exactly`,
|
|
205
|
-
);
|
|
206
|
-
console.log(
|
|
207
|
-
` the value that was deleted. Re-run those checks for an answer in a live vocabulary.`,
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const orphans = unlistedGates(
|
|
213
|
-
readLedger().filter((r) => r.paper === basename(dir)),
|
|
214
|
-
);
|
|
215
|
-
if (orphans.length) {
|
|
216
|
-
console.log(`\n ❗ recording but NOT IN THE TABLE: ${orphans.join(", ")}`);
|
|
217
|
-
console.log(
|
|
218
|
-
` These ran and said something, and this view showed you nothing. Add them to`,
|
|
219
|
-
);
|
|
220
|
-
console.log(
|
|
221
|
-
` EXPECTED_GATES — an invisible row is the failure this directory exists to end.`,
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// 🔴 OPEN FINDINGS. The ledger has recorded a findings COUNT and a REPORT PATH on every row since
|
|
226
|
-
// it was written, and this view never showed either — a check could record "7 findings, report at
|
|
227
|
-
// <path>" and the table printed a single word. The number and the path went nowhere, so the one
|
|
228
|
-
// thing a check actually produces was the one thing you could not see without opening runs.jsonl
|
|
229
|
-
// by hand.
|
|
230
|
-
//
|
|
231
|
-
// NB this reports what the LEDGER holds. It cannot tell whether anyone acted on a finding — that
|
|
232
|
-
// lives in the session's task list, which is not a file and cannot be checked from the repo. So
|
|
233
|
-
// this makes findings VISIBLE and durable; it does not and cannot make them assigned.
|
|
234
|
-
const open = rows.filter((r) => r.findings > 0 && r.state !== "NEVER-RUN");
|
|
235
|
-
if (open.length) {
|
|
236
|
-
const total = open.reduce((s, r) => s + r.findings, 0);
|
|
237
|
-
console.log(
|
|
238
|
-
`\n 📌 open findings: ${total} across ${open.length} check(s)`,
|
|
239
|
-
);
|
|
240
|
-
for (const r of open) {
|
|
241
|
-
const where = r.report
|
|
242
|
-
? ` → ${r.report}`
|
|
243
|
-
: " (no report path recorded — the count is all there is)";
|
|
244
|
-
const fresh =
|
|
245
|
-
r.state === "FRESH"
|
|
246
|
-
? ""
|
|
247
|
-
: ` [${r.state}: this count describes an older text]`;
|
|
248
|
-
console.log(
|
|
249
|
-
` ${r.blocking ? "🔴" : "•"} ${r.key}: ${r.findings}${where}${fresh}`,
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
console.log(
|
|
253
|
-
` Nothing here proves anyone acted on these. The ledger records what a check SAID,`,
|
|
254
|
-
);
|
|
255
|
-
console.log(
|
|
256
|
-
` never what was done about it — that lives in the session, not in a file.`,
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const quiet = rows.filter(
|
|
261
|
-
(r) => r.state === "FRESH" && r.findings === 0 && r.abstained,
|
|
262
|
-
);
|
|
263
|
-
if (quiet.length) {
|
|
264
|
-
console.log(
|
|
265
|
-
`\n 🤍 ran against the current bytes and recorded nothing: ${quiet.length} check(s)`,
|
|
266
|
-
);
|
|
267
|
-
console.log(
|
|
268
|
-
` ${quiet.map((r) => `${r.key} (${r.abstained.reason})`).join(", ")}`,
|
|
269
|
-
);
|
|
270
|
-
console.log(
|
|
271
|
-
` Read this as the ABSENCE of a finding, which is what it is. \`no-witness\` means the`,
|
|
272
|
-
);
|
|
273
|
-
console.log(
|
|
274
|
-
` check ran and has no witness for the negative answer — unlike a certifying`,
|
|
275
|
-
);
|
|
276
|
-
console.log(
|
|
277
|
-
` algorithm (McConnell et al. 2011), which ships one for both answers. Our discipline`,
|
|
278
|
-
);
|
|
279
|
-
console.log(
|
|
280
|
-
` is strictly weaker than theirs and this line is where that shows.`,
|
|
281
|
-
);
|
|
282
|
-
for (const [reason, meaning] of ABSTENTIONS) {
|
|
283
|
-
if (quiet.some((r) => r.abstained.reason === reason))
|
|
284
|
-
console.log(` ${reason}: ${meaning}`);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const blocking = stale.length + never.length;
|
|
289
|
-
console.log(
|
|
290
|
-
`\n ${blocking === 0 ? "🟢 every expected check answered for the current text" : `🔴 ${blocking} check(s) not answering for the current text`}\n`,
|
|
291
|
-
);
|
|
292
|
-
return 0; // advisory: this reports, it does not block
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (isMain(import.meta.url)) process.exit(main(process.argv));
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* status.mjs — the paper's status view, derived from the ledger. Every section it can print is
|
|
3
|
-
* driven by rows written for the purpose: fresh and stale answers, open findings with and without
|
|
4
|
-
* a report path, retired-vocabulary rows (an acquittal and a counted one), an orphan check, a check
|
|
5
|
-
* that has run and never found anything, and the all-answered footer.
|
|
6
|
-
*/
|
|
7
|
-
import assert from "node:assert/strict";
|
|
8
|
-
import { rmSync, writeFileSync } from "node:fs";
|
|
9
|
-
import { dirname, join } from "node:path";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
|
-
import { afterEach, test, vi } from "vitest";
|
|
12
|
-
import { runNode, useTempDir, writeTree } from "../../../test/support.ts";
|
|
13
|
-
|
|
14
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
const root = useTempDir("status-");
|
|
16
|
-
const consumer = join(root, "consumer");
|
|
17
|
-
const LEDGER = join(root, "runs.jsonl");
|
|
18
|
-
const paper = join(consumer, "papers", "p");
|
|
19
|
-
writeTree(paper, { "paper.md": "# P\n\ntext\n" });
|
|
20
|
-
Object.assign(process.env, {
|
|
21
|
-
CLAUDE_PROJECT_DIR: consumer,
|
|
22
|
-
PIPELINE_LEDGER: LEDGER,
|
|
23
|
-
});
|
|
24
|
-
const { inputHash } = await import("./ledger.mjs");
|
|
25
|
-
const { EXPECTED_GATES, main, unlistedGates } = await import("./status.mjs");
|
|
26
|
-
afterEach(() => rmSync(LEDGER, { force: true }));
|
|
27
|
-
|
|
28
|
-
const NOW = inputHash(paper);
|
|
29
|
-
const TS = "2026-09-01T10:30:00.000Z";
|
|
30
|
-
/** A ledger row for `key` on paper p. No skill is installed here, so its current hash is null. */
|
|
31
|
-
const row = (key, fields) => {
|
|
32
|
-
const [skill, check] = key.split("/");
|
|
33
|
-
return {
|
|
34
|
-
ts: TS,
|
|
35
|
-
skill,
|
|
36
|
-
check: check ?? skill,
|
|
37
|
-
paper: "p",
|
|
38
|
-
inputSha: NOW,
|
|
39
|
-
skillSha: null,
|
|
40
|
-
...fields,
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
const NO_WITNESS = { kind: "ABSTAINED", reason: "no-witness", findings: 0 };
|
|
44
|
-
|
|
45
|
-
function view(rows) {
|
|
46
|
-
writeFileSync(LEDGER, rows.map((r) => JSON.stringify(r)).join("\n") + "\n");
|
|
47
|
-
const lines = [];
|
|
48
|
-
const spy = vi
|
|
49
|
-
.spyOn(console, "log")
|
|
50
|
-
.mockImplementation((...a) => lines.push(a.join(" ")));
|
|
51
|
-
let code;
|
|
52
|
-
try {
|
|
53
|
-
code = main(["node", "status.mjs", paper]);
|
|
54
|
-
} finally {
|
|
55
|
-
spy.mockRestore();
|
|
56
|
-
}
|
|
57
|
-
return { code, text: lines.join("\n") };
|
|
58
|
-
}
|
|
59
|
-
/** The table line for one check, with its padding collapsed. */
|
|
60
|
-
const tableLine = (text, key) =>
|
|
61
|
-
text
|
|
62
|
-
.split("\n")
|
|
63
|
-
.find((l) => l.includes(` ${key} `))
|
|
64
|
-
?.trim()
|
|
65
|
-
.replace(/\s{2,}/g, " | ");
|
|
66
|
-
/** A section: from the line that starts with `head` to the next blank line. */
|
|
67
|
-
const section = (text, head) => {
|
|
68
|
-
const lines = text.split("\n");
|
|
69
|
-
const i = lines.findIndex((l) => l.trim().startsWith(head));
|
|
70
|
-
if (i < 0) return null;
|
|
71
|
-
const end = lines.findIndex((l, j) => j > i && l.trim() === "");
|
|
72
|
-
return lines.slice(i, end < 0 ? undefined : end).map((l) => l.trim());
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const RAN = [
|
|
76
|
-
"research-ideate",
|
|
77
|
-
"find-venue",
|
|
78
|
-
"map-prior-work",
|
|
79
|
-
"sweep-design-space",
|
|
80
|
-
"plan-paper-timeline",
|
|
81
|
-
"build-benchmark",
|
|
82
|
-
"draft-paper",
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
test("every kind of row, and every section it triggers", () => {
|
|
86
|
-
const { code, text } = view([
|
|
87
|
-
row("research-ideate", NO_WITNESS),
|
|
88
|
-
row("find-venue", {
|
|
89
|
-
kind: "FINDING",
|
|
90
|
-
findings: 3,
|
|
91
|
-
blocking: true,
|
|
92
|
-
report: "r.md",
|
|
93
|
-
}),
|
|
94
|
-
row("map-prior-work", { kind: "FINDING", findings: 2, inputSha: "older" }),
|
|
95
|
-
row("sweep-design-space", { ...NO_WITNESS, skillSha: "a-different-skill" }),
|
|
96
|
-
row("plan-paper-timeline", { verdict: "PASS" }),
|
|
97
|
-
row("build-benchmark", { verdict: "FINDINGS", findings: 2 }),
|
|
98
|
-
row("draft-paper", { kind: "FINDING", findings: 0 }),
|
|
99
|
-
row("mystery-check", NO_WITNESS),
|
|
100
|
-
row("paper-status", NO_WITNESS),
|
|
101
|
-
]);
|
|
102
|
-
assert.deepEqual(
|
|
103
|
-
{
|
|
104
|
-
code,
|
|
105
|
-
rows: [
|
|
106
|
-
"research-ideate",
|
|
107
|
-
"find-venue",
|
|
108
|
-
"map-prior-work",
|
|
109
|
-
"sweep-design-space",
|
|
110
|
-
"plan-paper-timeline",
|
|
111
|
-
"build-benchmark",
|
|
112
|
-
"draft-paper",
|
|
113
|
-
"camera-ready",
|
|
114
|
-
].map((k) => tableLine(text, k)),
|
|
115
|
-
stale: text
|
|
116
|
-
.split("\n")
|
|
117
|
-
.filter((l) => /^\s+(🟠|🟡) [\w/-]+: /.test(l))
|
|
118
|
-
.map((l) => l.trim()),
|
|
119
|
-
never: section(text, "⬜ never run:"),
|
|
120
|
-
mute: section(text, "🔇"),
|
|
121
|
-
legacy: section(text, "🏷️"),
|
|
122
|
-
orphans: section(text, "❗"),
|
|
123
|
-
open: section(text, "📌"),
|
|
124
|
-
quiet: section(text, "🤍"),
|
|
125
|
-
footer: text.trim().split("\n").pop().trim(),
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
code: 0,
|
|
129
|
-
rows: [
|
|
130
|
-
"🟢 research-ideate | FRESH | abstained:no-witness | 1 | 2026-09-01 10:30",
|
|
131
|
-
"🟢 find-venue | FRESH | 🔴 3 found | 1 | 2026-09-01 10:30",
|
|
132
|
-
"🟠 map-prior-work | STALE-PAPER | • 2 found | 1 | 2026-09-01 10:30",
|
|
133
|
-
"🟡 sweep-design-space | STALE-SKILL | abstained:no-witness | 1 | 2026-09-01 10:30",
|
|
134
|
-
"🟢 plan-paper-timeline | FRESH | legacy:PASS | 1 | 2026-09-01 10:30",
|
|
135
|
-
"🟢 build-benchmark | FRESH | • 2 found | 1 | 2026-09-01 10:30",
|
|
136
|
-
"🟢 draft-paper | FRESH | no row | 1 | 2026-09-01 10:30",
|
|
137
|
-
"⬜ camera-ready | NEVER-RUN | — | 0 | —",
|
|
138
|
-
],
|
|
139
|
-
stale: [
|
|
140
|
-
// In EXPECTED_GATES order.
|
|
141
|
-
"🟡 sweep-design-space: the check itself changed since it ran — that answer came from a different tool",
|
|
142
|
-
"🟠 map-prior-work: the paper changed since it ran — its answer is about a document that is gone",
|
|
143
|
-
],
|
|
144
|
-
never: [
|
|
145
|
-
`⬜ never run: ${EXPECTED_GATES.filter((k) => !RAN.includes(k)).join(", ")}`,
|
|
146
|
-
"nobody has asked this question about this paper — an unasked question reads exactly like a clean one in prose.",
|
|
147
|
-
],
|
|
148
|
-
mute: [
|
|
149
|
-
"🔇 has run and has NEVER recorded a finding: research-ideate, sweep-design-space, plan-paper-timeline",
|
|
150
|
-
"Borrowed from mutation testing: a test that kills no mutant is not a test. This is",
|
|
151
|
-
"not proof the check is broken — it is the reason to go plant a defect and watch.",
|
|
152
|
-
"Precedent here: a tightening pass returned KEEP on 80 of 81 sections and a",
|
|
153
|
-
'justification pass never once recommended a deletion. Both "ran".',
|
|
154
|
-
],
|
|
155
|
-
legacy: [
|
|
156
|
-
"🏷️ answered in the RETIRED vocabulary: plan-paper-timeline=PASS, build-benchmark=FINDINGS",
|
|
157
|
-
"Rows written before 2026-08-10 are kept verbatim and are NOT translated into the",
|
|
158
|
-
"current constructors — a silent reinterpretation is the class of defect this",
|
|
159
|
-
"pipeline removed. A retired FINDINGS/FAIL row still shows its count above, because",
|
|
160
|
-
"it carries evidence and discarding evidence is the destructive direction.",
|
|
161
|
-
"plan-paper-timeline=PASS carry NOTHING forward:",
|
|
162
|
-
"they recorded that nothing was wrong, with no evidence attached, which is exactly",
|
|
163
|
-
"the value that was deleted. Re-run those checks for an answer in a live vocabulary.",
|
|
164
|
-
],
|
|
165
|
-
// `paper-status` records too, but is the view itself, so it is never an orphan.
|
|
166
|
-
orphans: [
|
|
167
|
-
"❗ recording but NOT IN THE TABLE: mystery-check",
|
|
168
|
-
"These ran and said something, and this view showed you nothing. Add them to",
|
|
169
|
-
"EXPECTED_GATES — an invisible row is the failure this directory exists to end.",
|
|
170
|
-
],
|
|
171
|
-
open: [
|
|
172
|
-
"📌 open findings: 7 across 3 check(s)",
|
|
173
|
-
"• map-prior-work: 2 (no report path recorded — the count is all there is) [STALE-PAPER: this count describes an older text]",
|
|
174
|
-
"🔴 find-venue: 3 → r.md",
|
|
175
|
-
"• build-benchmark: 2 (no report path recorded — the count is all there is)",
|
|
176
|
-
"Nothing here proves anyone acted on these. The ledger records what a check SAID,",
|
|
177
|
-
"never what was done about it — that lives in the session, not in a file.",
|
|
178
|
-
],
|
|
179
|
-
quiet: [
|
|
180
|
-
"🤍 ran against the current bytes and recorded nothing: 1 check(s)",
|
|
181
|
-
"research-ideate (no-witness)",
|
|
182
|
-
"Read this as the ABSENCE of a finding, which is what it is. `no-witness` means the",
|
|
183
|
-
"check ran and has no witness for the negative answer — unlike a certifying",
|
|
184
|
-
"algorithm (McConnell et al. 2011), which ships one for both answers. Our discipline",
|
|
185
|
-
"is strictly weaker than theirs and this line is where that shows.",
|
|
186
|
-
"no-witness: ran to completion, produced no finding — NOT a claim that nothing is wrong",
|
|
187
|
-
],
|
|
188
|
-
footer: "🔴 29 check(s) not answering for the current text",
|
|
189
|
-
},
|
|
190
|
-
);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
test("every expected check answered on the current bytes: the green footer, and nothing to flag", () => {
|
|
194
|
-
const { code, text } = view(
|
|
195
|
-
EXPECTED_GATES.map((k) =>
|
|
196
|
-
row(k, { kind: "FINDING", findings: 1, report: "r.md" }),
|
|
197
|
-
),
|
|
198
|
-
);
|
|
199
|
-
assert.deepEqual(
|
|
200
|
-
{
|
|
201
|
-
code,
|
|
202
|
-
sections: ["🟠", "🟡", "⬜ never", "🔇", "🏷️", "❗", "🤍"].map((h) =>
|
|
203
|
-
section(text, h),
|
|
204
|
-
),
|
|
205
|
-
footer: text.trim().split("\n").pop().trim(),
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
code: 0,
|
|
209
|
-
sections: [null, null, null, null, null, null, null],
|
|
210
|
-
footer: "🟢 every expected check answered for the current text",
|
|
211
|
-
},
|
|
212
|
-
);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
test("unlistedGates names checks the table does not list, except the view's own rows", () => {
|
|
216
|
-
assert.deepEqual(
|
|
217
|
-
unlistedGates([
|
|
218
|
-
{ skill: "find-venue", check: "find-venue" },
|
|
219
|
-
{ skill: "x", check: "y" },
|
|
220
|
-
{ skill: "paper-status", check: "paper-status" },
|
|
221
|
-
]),
|
|
222
|
-
["x/y"],
|
|
223
|
-
);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test("as a process, with no argument, it reads the current directory and exits 0", () => {
|
|
227
|
-
const r = runNode(join(HERE, "status.mjs"), [], {
|
|
228
|
-
cwd: paper,
|
|
229
|
-
env: { CLAUDE_PROJECT_DIR: consumer, PIPELINE_LEDGER: LEDGER },
|
|
230
|
-
});
|
|
231
|
-
assert.deepEqual([r.status, r.stdout.split("\n")[1]], [0, " p"]);
|
|
232
|
-
});
|
|
File without changes
|
|
File without changes
|