paperlint 2.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/.github/dependabot.yml +72 -0
- package/.github/workflows/ci.yml +297 -0
- package/.github/workflows/dependabot-automerge.yml +70 -0
- package/.github/workflows/pr-title.yml +59 -0
- package/.github/workflows/release.yml +54 -0
- package/CLAUDE.md +598 -0
- package/CONTRIBUTING.md +159 -0
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/action.harness.mjs +287 -0
- package/action.mutations.mjs +162 -0
- package/action.yml +138 -0
- package/bin/rpp.mjs +43 -0
- package/dist/action-ref.d.ts +12 -0
- package/dist/action-ref.d.ts.map +1 -0
- package/dist/action-ref.js +16 -0
- package/dist/action-ref.js.map +1 -0
- package/dist/adapters/banal/failure.d.ts +73 -0
- package/dist/adapters/banal/failure.d.ts.map +1 -0
- package/dist/adapters/banal/failure.js +58 -0
- package/dist/adapters/banal/failure.js.map +1 -0
- package/dist/adapters/banal/index.d.ts +17 -0
- package/dist/adapters/banal/index.d.ts.map +1 -0
- package/dist/adapters/banal/index.js +56 -0
- package/dist/adapters/banal/index.js.map +1 -0
- package/dist/adapters/banal/install.d.ts +26 -0
- package/dist/adapters/banal/install.d.ts.map +1 -0
- package/dist/adapters/banal/install.js +15 -0
- package/dist/adapters/banal/install.js.map +1 -0
- package/dist/adapters/banal/invocation.d.ts +48 -0
- package/dist/adapters/banal/invocation.d.ts.map +1 -0
- package/dist/adapters/banal/invocation.js +43 -0
- package/dist/adapters/banal/invocation.js.map +1 -0
- package/dist/adapters/banal/locate.d.ts +50 -0
- package/dist/adapters/banal/locate.d.ts.map +1 -0
- package/dist/adapters/banal/locate.js +34 -0
- package/dist/adapters/banal/locate.js.map +1 -0
- package/dist/adapters/banal/output.d.ts +27 -0
- package/dist/adapters/banal/output.d.ts.map +1 -0
- package/dist/adapters/banal/output.js +112 -0
- package/dist/adapters/banal/output.js.map +1 -0
- package/dist/adapters/banal/pin.d.ts +19 -0
- package/dist/adapters/banal/pin.d.ts.map +1 -0
- package/dist/adapters/banal/pin.js +15 -0
- package/dist/adapters/banal/pin.js.map +1 -0
- package/dist/adapters/banal/probe.d.ts +12 -0
- package/dist/adapters/banal/probe.d.ts.map +1 -0
- package/dist/adapters/banal/probe.js +27 -0
- package/dist/adapters/banal/probe.js.map +1 -0
- package/dist/adapters/banal/run.d.ts +89 -0
- package/dist/adapters/banal/run.d.ts.map +1 -0
- package/dist/adapters/banal/run.js +104 -0
- package/dist/adapters/banal/run.js.map +1 -0
- package/dist/adapters/banal/settings.d.ts +18 -0
- package/dist/adapters/banal/settings.d.ts.map +1 -0
- package/dist/adapters/banal/settings.js +29 -0
- package/dist/adapters/banal/settings.js.map +1 -0
- package/dist/adapters/banal/xml.d.ts +48 -0
- package/dist/adapters/banal/xml.d.ts.map +1 -0
- package/dist/adapters/banal/xml.js +67 -0
- package/dist/adapters/banal/xml.js.map +1 -0
- package/dist/adapters/curl/download.io.d.ts +14 -0
- package/dist/adapters/curl/download.io.d.ts.map +1 -0
- package/dist/adapters/curl/download.io.js +69 -0
- package/dist/adapters/curl/download.io.js.map +1 -0
- package/dist/adapters/curl/index.d.ts +6 -0
- package/dist/adapters/curl/index.d.ts.map +1 -0
- package/dist/adapters/curl/index.js +6 -0
- package/dist/adapters/curl/index.js.map +1 -0
- package/dist/adapters/memory/index.d.ts +43 -0
- package/dist/adapters/memory/index.d.ts.map +1 -0
- package/dist/adapters/memory/index.js +79 -0
- package/dist/adapters/memory/index.js.map +1 -0
- package/dist/adapters/node/files.io.d.ts +3 -0
- package/dist/adapters/node/files.io.d.ts.map +1 -0
- package/dist/adapters/node/files.io.js +31 -0
- package/dist/adapters/node/files.io.js.map +1 -0
- package/dist/adapters/node/host.io.d.ts +3 -0
- package/dist/adapters/node/host.io.d.ts.map +1 -0
- package/dist/adapters/node/host.io.js +14 -0
- package/dist/adapters/node/host.io.js.map +1 -0
- package/dist/adapters/node/index.d.ts +25 -0
- package/dist/adapters/node/index.d.ts.map +1 -0
- package/dist/adapters/node/index.js +14 -0
- package/dist/adapters/node/index.js.map +1 -0
- package/dist/adapters/node/process.io.d.ts +14 -0
- package/dist/adapters/node/process.io.d.ts.map +1 -0
- package/dist/adapters/node/process.io.js +41 -0
- package/dist/adapters/node/process.io.js.map +1 -0
- package/dist/adapters/node/workspace.io.d.ts +4 -0
- package/dist/adapters/node/workspace.io.d.ts.map +1 -0
- package/dist/adapters/node/workspace.io.js +33 -0
- package/dist/adapters/node/workspace.io.js.map +1 -0
- package/dist/adapters/pdfjs/fill.d.ts +42 -0
- package/dist/adapters/pdfjs/fill.d.ts.map +1 -0
- package/dist/adapters/pdfjs/fill.js +91 -0
- package/dist/adapters/pdfjs/fill.js.map +1 -0
- package/dist/build-engine.d.ts +48 -0
- package/dist/build-engine.d.ts.map +1 -0
- package/dist/build-engine.js +148 -0
- package/dist/build-engine.js.map +1 -0
- package/dist/build.d.ts +163 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +575 -0
- package/dist/build.js.map +1 -0
- package/dist/cli.d.ts +151 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +951 -0
- package/dist/cli.js.map +1 -0
- package/dist/doctor.d.ts +42 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +280 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domain/geometry.d.ts +71 -0
- package/dist/domain/geometry.d.ts.map +1 -0
- package/dist/domain/geometry.js +35 -0
- package/dist/domain/geometry.js.map +1 -0
- package/dist/domain/host.d.ts +16 -0
- package/dist/domain/host.d.ts.map +1 -0
- package/dist/domain/host.js +8 -0
- package/dist/domain/host.js.map +1 -0
- package/dist/domain/page-layout.d.ts +34 -0
- package/dist/domain/page-layout.d.ts.map +1 -0
- package/dist/domain/page-layout.js +8 -0
- package/dist/domain/page-layout.js.map +1 -0
- package/dist/domain/paths.d.ts +5 -0
- package/dist/domain/paths.d.ts.map +1 -0
- package/dist/domain/paths.js +2 -0
- package/dist/domain/paths.js.map +1 -0
- package/dist/domain/result.d.ts +23 -0
- package/dist/domain/result.d.ts.map +1 -0
- package/dist/domain/result.js +10 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/domain/sha256.d.ts +7 -0
- package/dist/domain/sha256.d.ts.map +1 -0
- package/dist/domain/sha256.js +14 -0
- package/dist/domain/sha256.js.map +1 -0
- package/dist/domain/text.d.ts +6 -0
- package/dist/domain/text.d.ts.map +1 -0
- package/dist/domain/text.js +7 -0
- package/dist/domain/text.js.map +1 -0
- package/dist/engine.d.ts +93 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +119 -0
- package/dist/engine.js.map +1 -0
- package/dist/exit-code.d.ts +22 -0
- package/dist/exit-code.d.ts.map +1 -0
- package/dist/exit-code.js +10 -0
- package/dist/exit-code.js.map +1 -0
- package/dist/facts-file.d.ts +96 -0
- package/dist/facts-file.d.ts.map +1 -0
- package/dist/facts-file.js +134 -0
- package/dist/facts-file.js.map +1 -0
- package/dist/hooks-settings.d.ts +141 -0
- package/dist/hooks-settings.d.ts.map +1 -0
- package/dist/hooks-settings.js +306 -0
- package/dist/hooks-settings.js.map +1 -0
- package/dist/init.d.ts +201 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +579 -0
- package/dist/init.js.map +1 -0
- package/dist/latex-log.d.ts +80 -0
- package/dist/latex-log.d.ts.map +1 -0
- package/dist/latex-log.js +187 -0
- package/dist/latex-log.js.map +1 -0
- package/dist/latex-loop.d.ts +129 -0
- package/dist/latex-loop.d.ts.map +1 -0
- package/dist/latex-loop.js +113 -0
- package/dist/latex-loop.js.map +1 -0
- package/dist/link-skills.d.ts +51 -0
- package/dist/link-skills.d.ts.map +1 -0
- package/dist/link-skills.js +199 -0
- package/dist/link-skills.js.map +1 -0
- package/dist/new-paper.d.ts +48 -0
- package/dist/new-paper.d.ts.map +1 -0
- package/dist/new-paper.js +110 -0
- package/dist/new-paper.js.map +1 -0
- package/dist/pdf-facts.d.ts +44 -0
- package/dist/pdf-facts.d.ts.map +1 -0
- package/dist/pdf-facts.js +239 -0
- package/dist/pdf-facts.js.map +1 -0
- package/dist/pdf-geometry.d.ts +170 -0
- package/dist/pdf-geometry.d.ts.map +1 -0
- package/dist/pdf-geometry.js +158 -0
- package/dist/pdf-geometry.js.map +1 -0
- package/dist/ports/download.d.ts +9 -0
- package/dist/ports/download.d.ts.map +1 -0
- package/dist/ports/download.js +2 -0
- package/dist/ports/download.js.map +1 -0
- package/dist/ports/files.d.ts +11 -0
- package/dist/ports/files.d.ts.map +1 -0
- package/dist/ports/files.js +2 -0
- package/dist/ports/files.js.map +1 -0
- package/dist/ports/measure-geometry.d.ts +8 -0
- package/dist/ports/measure-geometry.d.ts.map +1 -0
- package/dist/ports/measure-geometry.js +2 -0
- package/dist/ports/measure-geometry.js.map +1 -0
- package/dist/ports/process.d.ts +45 -0
- package/dist/ports/process.d.ts.map +1 -0
- package/dist/ports/process.js +2 -0
- package/dist/ports/process.js.map +1 -0
- package/dist/ports/tool-installer.d.ts +29 -0
- package/dist/ports/tool-installer.d.ts.map +1 -0
- package/dist/ports/tool-installer.js +2 -0
- package/dist/ports/tool-installer.js.map +1 -0
- package/dist/ports/workspace.d.ts +18 -0
- package/dist/ports/workspace.d.ts.map +1 -0
- package/dist/ports/workspace.js +2 -0
- package/dist/ports/workspace.js.map +1 -0
- package/dist/rules-config.d.ts +34 -0
- package/dist/rules-config.d.ts.map +1 -0
- package/dist/rules-config.js +132 -0
- package/dist/rules-config.js.map +1 -0
- package/dist/structure.d.ts +34 -0
- package/dist/structure.d.ts.map +1 -0
- package/dist/structure.js +149 -0
- package/dist/structure.js.map +1 -0
- package/dist/tex-requirements.d.ts +43 -0
- package/dist/tex-requirements.d.ts.map +1 -0
- package/dist/tex-requirements.js +127 -0
- package/dist/tex-requirements.js.map +1 -0
- package/dist/toolchain.d.ts +159 -0
- package/dist/toolchain.d.ts.map +1 -0
- package/dist/toolchain.js +542 -0
- package/dist/toolchain.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docs/configuration.md +235 -0
- package/docs/e2e.md +152 -0
- package/docs/incidents.md +59 -0
- package/docs/install.md +170 -0
- package/docs/optional-rules.md +107 -0
- package/docs/package-shape-options.md +262 -0
- package/docs/prior-art/README.md +76 -0
- package/docs/prior-art/blocking-vs-advisory.md +83 -0
- package/docs/prior-art/content-delivery.md +124 -0
- package/docs/prior-art/multi-mode-tools.md +106 -0
- package/docs/prior-art/nondeterministic-checks.md +99 -0
- package/docs/prior-art/package-location.md +422 -0
- package/docs/prior-art/paper-folder-scaffolding.md +538 -0
- package/docs/prior-art/readme-structure.md +69 -0
- package/docs/prior-art/repro/README.md +92 -0
- package/docs/prior-art/repro/claim1-allowedtools.mjs +66 -0
- package/docs/prior-art/repro/claim1-at2.mjs +40 -0
- package/docs/prior-art/repro/claim1-crosschannel.mjs +54 -0
- package/docs/prior-art/repro/claim1-frontmatter.mjs +76 -0
- package/docs/prior-art/repro/claim1-hook-payload-reporter.mjs +10 -0
- package/docs/prior-art/repro/claim1-plugin-frontmatter.mjs +27 -0
- package/docs/prior-art/repro/claim1-plugin-skill.mjs +52 -0
- package/docs/prior-art/repro/claim1-project-skill.mjs +81 -0
- package/docs/prior-art/repro/claim2-marketplace-flat-asclaimed.json +1 -0
- package/docs/prior-art/repro/claim2-marketplace-negative-control.json +1 -0
- package/docs/prior-art/repro/claim2-marketplace-nested-exact.json +9 -0
- package/docs/prior-art/repro/claim2-marketplace-nested-noversion.json +9 -0
- package/docs/prior-art/repro/claim2-marketplace-nested-range.json +1 -0
- package/docs/prior-art/repro/claim3-imports.mjs +50 -0
- package/docs/prior-art/repro/claim4-find-package-json.mjs +8 -0
- package/docs/prior-art/repro/claim4-package-dir.mjs +39 -0
- package/docs/prior-art/repro/claim4-parent-arg.mjs +17 -0
- package/docs/prior-art/repro/claim4-resolve-apis.mjs +21 -0
- package/docs/prior-art/repro/claim4-setup-consumers.mjs +45 -0
- package/docs/prior-art/repro/claim4-yarn-pnp.mjs +70 -0
- package/docs/prior-art/repro/claim5-bin-launch.mjs +39 -0
- package/docs/prior-art/repro/claim5-exports-mutation.mjs +57 -0
- package/docs/prior-art/repro/claim5-resolved-location-and-bin.mjs +33 -0
- package/docs/prior-art/repro/claim6-candidate-ambiguity.mjs +17 -0
- package/docs/prior-art/repro/claim6-doc-path-candidates.mjs +27 -0
- package/docs/prior-art/test-tooling.md +131 -0
- package/docs/rules.md +58 -0
- package/docs/texlive-install-decision.md +230 -0
- package/docs/toolchain.md +152 -0
- package/eslint-rules/doc-fields.harness.mjs +336 -0
- package/eslint-rules/doc-fields.mjs +186 -0
- package/eslint-rules/doc-fields.mutations.mjs +96 -0
- package/eslint-rules/install-path-literals.harness.mjs +121 -0
- package/eslint-rules/install-path-literals.mjs +108 -0
- package/eslint-rules/install-path-literals.mutations.mjs +62 -0
- package/eslint-rules/latex-language.harness.mjs +599 -0
- package/eslint-rules/latex-language.mjs +591 -0
- package/eslint-rules/latex-language.mutations.mjs +196 -0
- package/eslint-rules/paper-research-question.harness.mjs +146 -0
- package/eslint-rules/paper-research-question.mjs +180 -0
- package/eslint-rules/paper-research-question.mutations.mjs +127 -0
- package/eslint-rules/paper-stages.harness.mjs +356 -0
- package/eslint-rules/paper-stages.mjs +455 -0
- package/eslint-rules/paper-stages.mutations.mjs +157 -0
- package/eslint-rules/paper-typography.harness.mjs +291 -0
- package/eslint-rules/paper-typography.mjs +313 -0
- package/eslint-rules/paper-typography.mutations.mjs +131 -0
- package/eslint-rules/papers.harness.mjs +259 -0
- package/eslint-rules/papers.mjs +166 -0
- package/eslint-rules/papers.mutations.mjs +186 -0
- package/eslint-rules/pdf-last-page-balance.harness.mjs +206 -0
- package/eslint-rules/pdf-last-page-balance.mjs +208 -0
- package/eslint-rules/review-findings-cause.harness.mjs +228 -0
- package/eslint-rules/review-findings-cause.mjs +135 -0
- package/eslint-rules/review-findings-cause.mutations.mjs +72 -0
- package/eslint-rules/temp-root-realpath.harness.mjs +176 -0
- package/eslint-rules/temp-root-realpath.mjs +129 -0
- package/eslint-rules/temp-root-realpath.mutations.mjs +99 -0
- package/eslint-rules/tex-build.harness.mjs +753 -0
- package/eslint-rules/tex-build.mjs +322 -0
- package/eslint-rules/tex-build.mutations.mjs +258 -0
- package/eslint.config.mjs +521 -0
- package/fixtures/build-e2e/acmart/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/acmart/paper.tex +11 -0
- package/fixtures/build-e2e/acmart/venue.json +1 -0
- package/fixtures/build-e2e/broken/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/broken/paper.tex +7 -0
- package/fixtures/build-e2e/cite/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/cite/build.sh +5 -0
- package/fixtures/build-e2e/cite/paper.tex +10 -0
- package/fixtures/build-e2e/cite/refs.bib +9 -0
- package/fixtures/build-e2e/empty/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/empty/paper.tex +6 -0
- package/fixtures/build-e2e/fallback/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/fallback/paper.tex +11 -0
- package/fixtures/build-e2e/guards/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/guards/paper.tex +10 -0
- package/fixtures/build-e2e/no-source/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/unbalanced/PIPELINE-STATUS.md +3 -0
- package/fixtures/build-e2e/unbalanced/paper.tex +28 -0
- package/fixtures/build-e2e/unbalanced/refs.bib +269 -0
- package/fixtures/install-path-literals/clean.fixture.mjs +3 -0
- package/fixtures/install-path-literals/clean.md +15 -0
- package/fixtures/install-path-literals/defect.fixture.mjs +3 -0
- package/fixtures/install-path-literals/defect.md +14 -0
- package/fixtures/latex-language/clean.tex +50 -0
- package/fixtures/latex-language/defect.tex +52 -0
- package/fixtures/paper-research-question/comment-only/PIPELINE-STATUS.md +9 -0
- package/fixtures/paper-research-question/comment-only/paper.tex +7 -0
- package/fixtures/paper-research-question/declared-not-in-paper/PIPELINE-STATUS.md +10 -0
- package/fixtures/paper-research-question/declared-not-in-paper/paper.tex +6 -0
- package/fixtures/paper-research-question/draft/PIPELINE-STATUS.md +6 -0
- package/fixtures/paper-research-question/draft/paper.tex +2 -0
- package/fixtures/paper-research-question/markdown-no-rq/PIPELINE-STATUS.md +9 -0
- package/fixtures/paper-research-question/markdown-no-rq/paper.md +4 -0
- package/fixtures/paper-research-question/shipped-no-rq/PIPELINE-STATUS.md +12 -0
- package/fixtures/paper-research-question/shipped-no-rq/paper.tex +3 -0
- package/fixtures/paper-research-question/shipped-with-rq/PIPELINE-STATUS.md +10 -0
- package/fixtures/paper-research-question/shipped-with-rq/paper.tex +2 -0
- package/fixtures/paper-stages/authors-ran/PIPELINE-STATUS.md +16 -0
- package/fixtures/paper-stages/marker-in-prose/PIPELINE-STATUS.md +17 -0
- package/fixtures/paper-stages/nofile/PIPELINE-STATUS.md +8 -0
- package/fixtures/paper-stages/noheader/PIPELINE-STATUS.md +1 -0
- package/fixtures/paper-stages/noheader/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-stages/nothing/PIPELINE-STATUS.md +3 -0
- package/fixtures/paper-stages/ok/PIPELINE-STATUS.md +9 -0
- package/fixtures/paper-stages/ok/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-stages/stale/PIPELINE-STATUS.md +1 -0
- package/fixtures/paper-stages/stale/versions/2026-07-22-submitted.STALE-WRONG-FILE.pdf +0 -0
- package/fixtures/paper-stages/twice/PIPELINE-STATUS.md +14 -0
- package/fixtures/paper-stages/twice/versions/2026-08-06-submitted.pdf +0 -0
- package/fixtures/paper-stages/twice/versions/2026-10-24-submitted.pdf +0 -0
- package/fixtures/paper-stages/undeclared/PIPELINE-STATUS.md +8 -0
- package/fixtures/paper-stages/undeclared/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-stages/undeclared/versions/2026-08-29-camera-ready.pdf +0 -0
- package/fixtures/paper-stages/wrongsize/PIPELINE-STATUS.md +8 -0
- package/fixtures/paper-stages/wrongsize/versions/2026-07-22-submitted.pdf +0 -0
- package/fixtures/paper-typography/clean-paper/paper.tex +29 -0
- package/fixtures/paper-typography/messy-paper/paper.tex +27 -0
- package/fixtures/pdf-facts/README.md +22 -0
- package/fixtures/pdf-facts/corrupt-font.pdf +0 -0
- package/fixtures/pdf-facts/encrypted.pdf +0 -0
- package/fixtures/pdf-facts/hidden-text.pdf +0 -0
- package/fixtures/pdf-facts/hidden-text.tex +28 -0
- package/fixtures/pdf-facts/t3-all.pdf +0 -0
- package/fixtures/pdf-facts/t3-all.tex +8 -0
- package/fixtures/pdf-facts/t3-mixed.pdf +0 -0
- package/fixtures/pdf-facts/t3-mixed.tex +9 -0
- package/fixtures/pdf-facts/ttf.pdf +2240 -1
- package/fixtures/pdf-facts/ttf.tex +6 -0
- package/fixtures/real-markdown-paper/baseline.json +24 -0
- package/fixtures/real-markdown-paper/baseline.mjs +48 -0
- package/fixtures/render-paper/build-clean.sh +25 -0
- package/fixtures/render-paper/build-defect.sh +15 -0
- package/fixtures/review-findings-cause/clean.md +17 -0
- package/fixtures/review-findings-cause/defect.md +14 -0
- package/fixtures/review-findings-cause/old-debt.md +14 -0
- package/fixtures/review-findings-cause/quiet-in-fence.md +16 -0
- package/fixtures/tex-build/clean.tex +21 -0
- package/fixtures/tex-build/defect.tex +24 -0
- package/fixtures/tex-build/frontmatter-clean.tex +25 -0
- package/fixtures/tex-build/frontmatter-defect.tex +23 -0
- package/fixtures/toolchain-mirror/catalog.txt +5 -0
- package/fixtures/toolchain-mirror/install-tl +27 -0
- package/fixtures/toolchain-mirror/release-texlive.txt +3 -0
- package/fixtures/toolchain-mirror/release-year +1 -0
- package/fixtures/toolchain-mirror/stub-kpsewhich +8 -0
- package/fixtures/toolchain-mirror/stub-pdflatex +3 -0
- package/fixtures/toolchain-mirror/stub-tlmgr +44 -0
- package/hooks/hooks.harness.mjs +713 -0
- package/hooks/hooks.mutations.mjs +337 -0
- package/hooks/paper-edit-guard.hook.d.mts +13 -0
- package/hooks/paper-edit-guard.hook.mjs +457 -0
- package/hooks/paper-skills-nudge.hook.mjs +136 -0
- package/hooks/paper-status-gates.hook.mjs +156 -0
- package/hooks/paper-status-gates.sh +91 -0
- package/lib/agent-cli-version.harness.mjs +165 -0
- package/lib/agent-cli-version.mjs +106 -0
- package/lib/agent-cli-version.mutations.mjs +109 -0
- package/lib/markdown.mjs +386 -0
- package/lib/mutation-driver.harness.mjs +227 -0
- package/lib/mutation-driver.mjs +397 -0
- package/lib/mutation-driver.mutations.mjs +68 -0
- package/lib/paper-config.d.mts +34 -0
- package/lib/paper-config.harness.mjs +286 -0
- package/lib/paper-config.mjs +142 -0
- package/lib/paper-config.mutations.mjs +143 -0
- package/lib/skill-checks.mjs +701 -0
- package/lib/skill-corpus.mjs +403 -0
- package/lib/skill-eval-fixture.mjs +63 -0
- package/lib/skill-eval-kit.mjs +257 -0
- package/lib/skill-trigger-cases.harness.mjs +170 -0
- package/lib/skill-trigger-cases.mjs +446 -0
- package/lib/skill-trigger-cases.mutations.mjs +65 -0
- package/lib/trigger-ledger.mjs +215 -0
- package/package.json +97 -0
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/hooks/hooks.json +30 -0
- package/scripts/check.harness.mjs +177 -0
- package/scripts/check.mjs +239 -0
- package/scripts/check.mutations.mjs +110 -0
- package/scripts/eslint-report-guard.mjs +82 -0
- package/scripts/exclusive.mjs +138 -0
- package/scripts/harness-api.frozen.json +76 -0
- package/scripts/harness-api.test.ts +175 -0
- package/scripts/layer-legacy-frozen.d.mts +28 -0
- package/scripts/layer-legacy-frozen.mjs +152 -0
- package/scripts/layer-legacy-frozen.test.ts +115 -0
- package/scripts/layer-legacy.frozen.json +50 -0
- package/scripts/mutation-batteries-frozen.harness.mjs +204 -0
- package/scripts/mutation-batteries-frozen.mjs +238 -0
- package/scripts/mutation-batteries.frozen.json +117 -0
- package/scripts/release-config.test.ts +90 -0
- package/scripts/rules-are-content-only.harness.mjs +113 -0
- package/scripts/rules-are-content-only.mjs +138 -0
- package/scripts/rules-are-content-only.mutations.mjs +81 -0
- package/scripts/rules-see-files.harness.mjs +115 -0
- package/scripts/rules-see-files.mjs +99 -0
- package/scripts/rules-see-files.mutations.mjs +131 -0
- package/scripts/run-mutations.mjs +100 -0
- package/scripts/semantic-release-plugins.d.ts +16 -0
- package/skills/README.md +15 -0
- package/skills/analyze-sibling-paper/SKILL.md +170 -0
- package/skills/analyze-sibling-paper/SKILL.md.spec.ts +186 -0
- package/skills/analyze-sibling-paper/analyze-sibling-paper.eval.mjs +19 -0
- package/skills/analyze-sibling-paper/analyze-sibling-paper.harness.mjs +23 -0
- package/skills/argument-arc/SKILL.md +177 -0
- package/skills/argument-arc/SKILL.md.spec.ts +192 -0
- package/skills/argument-arc/argument-arc.eval.mjs +19 -0
- package/skills/argument-arc/argument-arc.harness.mjs +23 -0
- package/skills/build-benchmark/SKILL.md +213 -0
- package/skills/build-benchmark/SKILL.md.spec.ts +220 -0
- package/skills/build-benchmark/build-benchmark.eval.mjs +19 -0
- package/skills/build-benchmark/build-benchmark.harness.mjs +23 -0
- package/skills/build-benchmark/references/adversarial-cold-repro.md +68 -0
- package/skills/camera-ready/SKILL.md +148 -0
- package/skills/camera-ready/SKILL.md.spec.ts +164 -0
- package/skills/camera-ready/camera-ready.eval.mjs +19 -0
- package/skills/camera-ready/camera-ready.harness.mjs +23 -0
- package/skills/cold-read-diff/SKILL.md +160 -0
- package/skills/cold-read-diff/SKILL.md.spec.ts +166 -0
- package/skills/cold-read-diff/cold-read-diff.eval.mjs +19 -0
- package/skills/cold-read-diff/cold-read-diff.harness.mjs +23 -0
- package/skills/draft-paper/SKILL.md +152 -0
- package/skills/draft-paper/SKILL.md.spec.ts +169 -0
- package/skills/draft-paper/draft-paper.eval.mjs +19 -0
- package/skills/draft-paper/draft-paper.harness.mjs +23 -0
- package/skills/extend-paper/SKILL.md +99 -0
- package/skills/extend-paper/SKILL.md.spec.ts +116 -0
- package/skills/extend-paper/extend-paper.eval.mjs +19 -0
- package/skills/extend-paper/extend-paper.harness.mjs +23 -0
- package/skills/find-venue/SKILL.md +128 -0
- package/skills/find-venue/SKILL.md.spec.ts +145 -0
- package/skills/find-venue/find-venue.eval.mjs +19 -0
- package/skills/find-venue/find-venue.harness.mjs +23 -0
- package/skills/grade-paper-writing/SKILL.md +436 -0
- package/skills/grade-paper-writing/SKILL.md.spec.ts +453 -0
- package/skills/grade-paper-writing/fixtures/control_gopen.txt +1 -0
- package/skills/grade-paper-writing/fixtures/control_human_paper.txt +1 -0
- package/skills/grade-paper-writing/fixtures/rewrite.txt +1 -0
- package/skills/grade-paper-writing/fixtures/specimen.txt +1 -0
- package/skills/grade-paper-writing/fixtures/structure-checks.md +22 -0
- package/skills/grade-paper-writing/grade-paper-writing.eval.mjs +19 -0
- package/skills/grade-paper-writing/grade-paper-writing.harness.mjs +23 -0
- package/skills/grade-paper-writing/prose-lint.mjs +713 -0
- package/skills/harden-paper/SKILL.md +318 -0
- package/skills/harden-paper/SKILL.md.spec.ts +336 -0
- package/skills/harden-paper/check-numbers.sh +33 -0
- package/skills/harden-paper/check-release-claims.sh +35 -0
- package/skills/harden-paper/fixtures/uncited-assertions-sample.md +43 -0
- package/skills/harden-paper/fixtures/uncited-assertions-sample.tex +77 -0
- package/skills/harden-paper/harden-paper.eval.mjs +19 -0
- package/skills/harden-paper/harden-paper.harness.mjs +23 -0
- package/skills/map-prior-work/SKILL.md +211 -0
- package/skills/map-prior-work/SKILL.md.spec.ts +227 -0
- package/skills/map-prior-work/map-prior-work.eval.mjs +19 -0
- package/skills/map-prior-work/map-prior-work.harness.mjs +23 -0
- package/skills/osf-artifact-upload/SKILL.md +52 -0
- package/skills/osf-artifact-upload/SKILL.md.spec.ts +59 -0
- package/skills/osf-artifact-upload/osf-artifact-upload.eval.mjs +22 -0
- package/skills/osf-artifact-upload/osf-artifact-upload.harness.mjs +103 -0
- package/skills/paper-adversarial-review/SKILL.md +126 -0
- package/skills/paper-adversarial-review/SKILL.md.spec.ts +142 -0
- package/skills/paper-adversarial-review/paper-adversarial-review.eval.mjs +19 -0
- package/skills/paper-adversarial-review/paper-adversarial-review.harness.mjs +23 -0
- package/skills/paper-pipeline/PIPELINE-MAP.md +371 -0
- package/skills/paper-pipeline/SKILL.md +499 -0
- package/skills/paper-pipeline/SKILL.md.spec.ts +517 -0
- package/skills/paper-pipeline/description-language.eval.mjs +347 -0
- package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +891 -0
- package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +1254 -0
- package/skills/paper-pipeline/paper-pipeline.eval.mjs +22 -0
- package/skills/paper-pipeline/paper-pipeline.harness.mjs +143 -0
- package/skills/paper-pipeline/pipeline-firing.baseline.json +270 -0
- package/skills/paper-pipeline/pipeline-firing.eval.mjs +664 -0
- package/skills/paper-pipeline/pipeline-language.eval.mjs +672 -0
- package/skills/paper-pipeline/references/acceptance-gate.md +329 -0
- package/skills/paper-pipeline/references/acl-venue-rules.md +142 -0
- package/skills/paper-pipeline/references/anonymization.md +68 -0
- package/skills/paper-pipeline/references/artifact-checklist.md +93 -0
- package/skills/paper-pipeline/references/body-vs-appendix.md +97 -0
- package/skills/paper-pipeline/references/credit-criteria.md +69 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/README.md +35 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/run_retext.mjs +24 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/sentences.txt +11 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/test_sentences.py +25 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-prose-checkers.md +538 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-reproducible-tooling.md +431 -0
- package/skills/paper-pipeline/references/occupancy-2026-08-06-staleness-and-orchestration.md +592 -0
- package/skills/paper-pipeline/references/pipeline-status-template.md +162 -0
- package/skills/paper-pipeline/references/review-ratchet.md +36 -0
- package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +585 -0
- package/skills/paper-pipeline/references/writing-craft.md +448 -0
- package/skills/paper-pipeline/repro/2026-08-07-description-language-control.log +63 -0
- package/skills/paper-pipeline/repro/2026-08-07-fork-check.log +52 -0
- package/skills/paper-pipeline/repro/2026-08-07-fork-check2.log +33 -0
- package/skills/paper-pipeline/repro/2026-08-07-language-eval-pilot.log +33 -0
- package/skills/paper-pipeline/repro/2026-08-07-language-eval-raw.log +166 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.json +338 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.log +118 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-raw.log +245 -0
- package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary.json +776 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-oracle.log +53 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-raw.log +89 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.json +450 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.log +136 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-raw.log +242 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-setupdiff.log +59 -0
- package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation.json +1032 -0
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.json +139 -0
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.log +98 -0
- package/skills/paper-pipeline/repro/2026-08-08-parent-replication.mjs +92 -0
- package/skills/paper-pipeline/repro/README.md +129 -0
- package/skills/paper-pipeline/repro/analyze-language-eval.py +116 -0
- package/skills/paper-pipeline/scripts/README.md +344 -0
- package/skills/paper-pipeline/scripts/announce.mjs +67 -0
- package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +496 -0
- package/skills/paper-pipeline/scripts/artifact-coverage.mjs +397 -0
- package/skills/paper-pipeline/scripts/artifact-coverage.mutations.mjs +218 -0
- package/skills/paper-pipeline/scripts/check-provenance.mjs +184 -0
- package/skills/paper-pipeline/scripts/consumer.d.mts +32 -0
- package/skills/paper-pipeline/scripts/consumer.harness.mjs +562 -0
- package/skills/paper-pipeline/scripts/consumer.mjs +535 -0
- package/skills/paper-pipeline/scripts/consumer.mutations.mjs +190 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +457 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +656 -0
- package/skills/paper-pipeline/scripts/extract-ref-facts.mutations.mjs +54 -0
- package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +51 -0
- package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +52 -0
- package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +6 -0
- package/skills/paper-pipeline/scripts/fixtures/real-bib/refs.bib +153 -0
- package/skills/paper-pipeline/scripts/generated-code.harness.mjs +466 -0
- package/skills/paper-pipeline/scripts/generated-code.mjs +338 -0
- package/skills/paper-pipeline/scripts/generated-code.mutations.mjs +254 -0
- package/skills/paper-pipeline/scripts/ledger.mjs +623 -0
- package/skills/paper-pipeline/scripts/ledger.selftest.mjs +286 -0
- package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +389 -0
- package/skills/paper-pipeline/scripts/pipeline-check.mjs +737 -0
- package/skills/paper-pipeline/scripts/pipeline-check.mutations.mjs +54 -0
- package/skills/paper-pipeline/scripts/pipeline-edges.mjs +169 -0
- package/skills/paper-pipeline/scripts/population-map.harness.mjs +178 -0
- package/skills/paper-pipeline/scripts/population-map.mjs +181 -0
- package/skills/paper-pipeline/scripts/population-map.mutations.mjs +65 -0
- package/skills/paper-pipeline/scripts/population-map.selftest.mjs +122 -0
- package/skills/paper-pipeline/scripts/provenance.harness.mjs +240 -0
- package/skills/paper-pipeline/scripts/provenance.mutations.mjs +59 -0
- package/skills/paper-pipeline/scripts/round-diff.harness.mjs +881 -0
- package/skills/paper-pipeline/scripts/round-diff.mjs +576 -0
- package/skills/paper-pipeline/scripts/round-diff.mutations.mjs +276 -0
- package/skills/paper-pipeline/scripts/run-mechanical.mjs +633 -0
- package/skills/paper-pipeline/scripts/status.mjs +295 -0
- package/skills/paper-status/SKILL.md +183 -0
- package/skills/paper-status/SKILL.md.spec.ts +190 -0
- package/skills/paper-status/paper-status.eval.mjs +22 -0
- package/skills/paper-status/paper-status.harness.mjs +25 -0
- package/skills/pc-panel-review/SKILL.md +263 -0
- package/skills/pc-panel-review/SKILL.md.spec.ts +280 -0
- package/skills/pc-panel-review/pc-panel-review.eval.mjs +19 -0
- package/skills/pc-panel-review/pc-panel-review.harness.mjs +23 -0
- package/skills/plan-paper-timeline/SKILL.md +182 -0
- package/skills/plan-paper-timeline/SKILL.md.spec.ts +200 -0
- package/skills/plan-paper-timeline/fixtures/fake-google-calendar.mjs +239 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +431 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +65 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.eval.mjs +19 -0
- package/skills/plan-paper-timeline/plan-paper-timeline.harness.mjs +23 -0
- package/skills/render-paper/SKILL.md +159 -0
- package/skills/render-paper/SKILL.md.spec.ts +166 -0
- package/skills/render-paper/check-render.sh +419 -0
- package/skills/render-paper/checkers-requirements.txt +55 -0
- package/skills/render-paper/ensure-checkers.sh +69 -0
- package/skills/render-paper/extract-pdf-facts.harness.mjs +166 -0
- package/skills/render-paper/extract-pdf-facts.mjs +144 -0
- package/skills/render-paper/render-paper.eval.mjs +19 -0
- package/skills/render-paper/render-paper.harness.mjs +339 -0
- package/skills/research-ideate/SKILL.md +136 -0
- package/skills/research-ideate/SKILL.md.spec.ts +152 -0
- package/skills/research-ideate/research-ideate.eval.mjs +19 -0
- package/skills/research-ideate/research-ideate.harness.mjs +23 -0
- package/skills/skill-contract.mutations.mjs +179 -0
- package/skills/study-accepted-papers/SKILL.md +206 -0
- package/skills/study-accepted-papers/SKILL.md.spec.ts +223 -0
- package/skills/study-accepted-papers/study-accepted-papers.eval.mjs +19 -0
- package/skills/study-accepted-papers/study-accepted-papers.harness.mjs +23 -0
- package/skills/submit-paper/SKILL.md +182 -0
- package/skills/submit-paper/SKILL.md.spec.ts +199 -0
- package/skills/submit-paper/check-deanon.sh +149 -0
- package/skills/submit-paper/references/publishers/acm.md +92 -0
- package/skills/submit-paper/references/venues/agenticdev.jsonc +108 -0
- package/skills/submit-paper/references/venues/agenticdev.md +139 -0
- package/skills/submit-paper/references/venues/agenticdev.tex +19 -0
- package/skills/submit-paper/references/venues/aisec.jsonc +101 -0
- package/skills/submit-paper/references/venues/aisec.md +105 -0
- package/skills/submit-paper/references/venues/paper-guards.tex +41 -0
- package/skills/submit-paper/references/venues/realm.jsonc +81 -0
- package/skills/submit-paper/references/venues/realm.md +155 -0
- package/skills/submit-paper/references/venues/tex-base.jsonc +50 -0
- package/skills/submit-paper/references/venues/venue-profile.schema.json +74 -0
- package/skills/submit-paper/submit-paper.eval.mjs +19 -0
- package/skills/submit-paper/submit-paper.harness.mjs +23 -0
- package/skills/sweep-design-space/SKILL.md +269 -0
- package/skills/sweep-design-space/SKILL.md.spec.ts +285 -0
- package/skills/sweep-design-space/sweep-design-space.eval.mjs +19 -0
- package/skills/sweep-design-space/sweep-design-space.harness.mjs +23 -0
- package/skills/tighten-paper/SKILL.md +368 -0
- package/skills/tighten-paper/SKILL.md.spec.ts +384 -0
- package/skills/tighten-paper/structure.mjs +371 -0
- package/skills/tighten-paper/tighten-paper.eval.mjs +19 -0
- package/skills/tighten-paper/tighten-paper.harness.mjs +23 -0
- package/skills/verify-citations/SKILL.md +328 -0
- package/skills/verify-citations/SKILL.md.spec.ts +345 -0
- package/skills/verify-citations/scripts/bib-authors.mjs +479 -0
- package/skills/verify-citations/scripts/bib-authors.test.mjs +175 -0
- package/skills/verify-citations/scripts/verify-cites.mjs +1108 -0
- package/skills/verify-citations/scripts/verify-cites.test.mjs +735 -0
- package/skills/verify-citations/verify-citations.eval.mjs +19 -0
- package/skills/verify-citations/verify-citations.harness.mjs +23 -0
- package/src/CLAUDE.md +51 -0
- package/src/action-ref.test.ts +26 -0
- package/src/action-ref.ts +15 -0
- package/src/adapters/banal/failure.test.ts +63 -0
- package/src/adapters/banal/failure.ts +118 -0
- package/src/adapters/banal/index.test.ts +119 -0
- package/src/adapters/banal/index.ts +100 -0
- package/src/adapters/banal/install.test.ts +20 -0
- package/src/adapters/banal/install.ts +41 -0
- package/src/adapters/banal/invocation.test.ts +74 -0
- package/src/adapters/banal/invocation.ts +95 -0
- package/src/adapters/banal/locate.test.ts +52 -0
- package/src/adapters/banal/locate.ts +84 -0
- package/src/adapters/banal/output.test.ts +140 -0
- package/src/adapters/banal/output.ts +141 -0
- package/src/adapters/banal/pin.ts +30 -0
- package/src/adapters/banal/probe.ts +35 -0
- package/src/adapters/banal/run.test.ts +191 -0
- package/src/adapters/banal/run.ts +244 -0
- package/src/adapters/banal/settings.test.ts +31 -0
- package/src/adapters/banal/settings.ts +55 -0
- package/src/adapters/banal/xml.test.ts +111 -0
- package/src/adapters/banal/xml.ts +112 -0
- package/src/adapters/curl/download.io.ts +73 -0
- package/src/adapters/curl/download.test.ts +55 -0
- package/src/adapters/curl/index.ts +5 -0
- package/src/adapters/memory/index.ts +131 -0
- package/src/adapters/node/files.io.ts +39 -0
- package/src/adapters/node/files.test.ts +28 -0
- package/src/adapters/node/host.io.ts +15 -0
- package/src/adapters/node/index.ts +36 -0
- package/src/adapters/node/process.io.ts +49 -0
- package/src/adapters/node/process.test.ts +46 -0
- package/src/adapters/node/workspace.io.ts +40 -0
- package/src/adapters/node/workspace.test.ts +58 -0
- package/src/adapters/pdfjs/fill.test.ts +111 -0
- package/src/adapters/pdfjs/fill.ts +141 -0
- package/src/build-engine.harness.mjs +314 -0
- package/src/build-engine.ts +219 -0
- package/src/build.harness.mjs +631 -0
- package/src/build.mutations.mjs +195 -0
- package/src/build.ts +793 -0
- package/src/cli.harness.mjs +2007 -0
- package/src/cli.mutations.mjs +448 -0
- package/src/cli.ts +1189 -0
- package/src/doctor.harness.mjs +396 -0
- package/src/doctor.mutations.mjs +175 -0
- package/src/doctor.ts +356 -0
- package/src/domain/geometry.ts +108 -0
- package/src/domain/host.ts +23 -0
- package/src/domain/page-layout.ts +32 -0
- package/src/domain/paths.ts +5 -0
- package/src/domain/result.test.ts +26 -0
- package/src/domain/result.ts +29 -0
- package/src/domain/sha256.test.ts +12 -0
- package/src/domain/sha256.ts +21 -0
- package/src/domain/text.ts +11 -0
- package/src/engine.harness.mjs +252 -0
- package/src/engine.ts +176 -0
- package/src/exit-code.test.ts +21 -0
- package/src/exit-code.ts +38 -0
- package/src/facts-file.test.ts +240 -0
- package/src/facts-file.ts +241 -0
- package/src/hooks-settings.harness.mjs +386 -0
- package/src/hooks-settings.mutations.mjs +116 -0
- package/src/hooks-settings.ts +434 -0
- package/src/init.ts +900 -0
- package/src/latex-log.harness.mjs +226 -0
- package/src/latex-log.ts +234 -0
- package/src/latex-loop.harness.mjs +449 -0
- package/src/latex-loop.ts +211 -0
- package/src/link-skills.harness.mjs +273 -0
- package/src/link-skills.mutations.mjs +136 -0
- package/src/link-skills.ts +258 -0
- package/src/new-paper.harness.mjs +216 -0
- package/src/new-paper.mutations.mjs +79 -0
- package/src/new-paper.ts +158 -0
- package/src/pdf-facts.harness.mjs +188 -0
- package/src/pdf-facts.ts +327 -0
- package/src/pdf-geometry.harness.mjs +254 -0
- package/src/pdf-geometry.ts +300 -0
- package/src/ports/download.ts +10 -0
- package/src/ports/files.ts +11 -0
- package/src/ports/measure-geometry.ts +8 -0
- package/src/ports/process.ts +46 -0
- package/src/ports/tool-installer.ts +33 -0
- package/src/ports/workspace.ts +20 -0
- package/src/rules-config.harness.mjs +114 -0
- package/src/rules-config.ts +178 -0
- package/src/structure.harness.mjs +179 -0
- package/src/structure.mutations.mjs +83 -0
- package/src/structure.ts +166 -0
- package/src/tex-requirements.harness.mjs +238 -0
- package/src/tex-requirements.ts +181 -0
- package/src/toolchain.harness.mjs +651 -0
- package/src/toolchain.ts +755 -0
- package/src/types.ts +106 -0
- package/templates/paper/PIPELINE-STATUS.md +72 -0
- package/templates/paper/paper.md +4 -0
- package/templates/paper/paper.tex +8 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,295 @@
|
|
|
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
|
+
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);
|
|
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));
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: paper-status
|
|
3
|
+
description: Answer "what's the status of the paper?" in one pass — MEASURE what is measurable (page count from the real build, git state, which gates were run against the CURRENT text), then read the judgement rows, then print blockers worst-first split into mine and the author's. Use whenever the author asks "what's up with the paper / status / what's left / is it ready", at the start of a session touching a paper, or before deciding what to work on next. Not a review skill — it reports state, it does not grade, cut, or fix.
|
|
4
|
+
allowed-tools: [Bash, Read, Grep, Glob]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- vigiles:sha256:51bc50b2485782e4 compiled from skills/paper-status/SKILL.md.spec.ts -->
|
|
8
|
+
|
|
9
|
+
# paper-status — state, measured before it is narrated
|
|
10
|
+
|
|
11
|
+
## Run me
|
|
12
|
+
|
|
13
|
+
🔴 FIRST, before any other step:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
node .claude/skills/paper-pipeline/scripts/announce.mjs paper-status <paper-dir>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
An advisory pass cannot be observed failing — silence is both its error state and its normal
|
|
20
|
+
state — so starting is an event, and events get written down.
|
|
21
|
+
|
|
22
|
+
The author asks "what's the status there?" constantly, and the answer keeps coming from the wrong place: my
|
|
23
|
+
memory of the session, which drifts, or a 200-line scorecard he cannot skim. Both fail the same way —
|
|
24
|
+
**they narrate state instead of measuring it.**
|
|
25
|
+
|
|
26
|
+
Grounding failure, 2026-08-04 (`compile-rules-2026`, day before deadline): a status line in chat said
|
|
27
|
+
the review panel was running. It had never been launched. Another said the paper was 8 pages while the
|
|
28
|
+
real build said 9 and BLOCKED — steering a whole day of cuts by the wrong instrument. Both would have
|
|
29
|
+
been caught by running two commands instead of recalling two facts.
|
|
30
|
+
|
|
31
|
+
## The rule this skill exists to enforce
|
|
32
|
+
|
|
33
|
+
**Anything a command can answer is not allowed to come from memory or from prose.** Measure first,
|
|
34
|
+
read the scorecard second, and mark clearly which is which. A claim in `PIPELINE-STATUS.md` is a claim
|
|
35
|
+
about the past; the build is the present.
|
|
36
|
+
|
|
37
|
+
## 🔴 The second rule: status is PUSHED, never waited for
|
|
38
|
+
|
|
39
|
+
The corpus owner, 2026-08-05: *"I have to constantly ask for the paper's status and direct you so you tell me what we can do next"*. Building a skill that answers when asked fixed the wrong half —
|
|
40
|
+
the work he was complaining about is **the asking**, and a pull-only skill leaves all of it with him.
|
|
41
|
+
|
|
42
|
+
So on any turn that touched a paper, the reply ends with **three lines, unprompted**:
|
|
43
|
+
|
|
44
|
+
1. **where it stands** — the build's own verdict line, page count, deadline countdown;
|
|
45
|
+
2. **the single next action, with an owner** — not a menu. If it is mine, it is already started or
|
|
46
|
+
started in the same reply. If it is his, it says exactly what to click.
|
|
47
|
+
3. **what is stale** — a gate whose verdict predates the current text, named.
|
|
48
|
+
|
|
49
|
+
Three failures make this a rule rather than a preference, all in one session:
|
|
50
|
+
- I finished a page-fit cut and stopped, so he asked what the status was;
|
|
51
|
+
- I left artifact hosting on his side of the split for a day and a half while the credential to clear
|
|
52
|
+
it sat in the environment (see `credential-available` in `pipeline-check.mjs`);
|
|
53
|
+
- three consecutive panels returned Weak Accept and the ceiling they named was never the next task,
|
|
54
|
+
because nothing turned "here is the score" into "here is what to do about it".
|
|
55
|
+
|
|
56
|
+
**Never end a paper turn on a completed sub-task alone.** "Fits in 8 pages" is a measurement, not a
|
|
57
|
+
status; the status is what that measurement makes possible next.
|
|
58
|
+
|
|
59
|
+
**Enforcement leg.** `pipeline-check.mjs` prints its banner **unconditionally**, including when it has
|
|
60
|
+
zero findings — deadline countdown, verdict row, and `➡️ NEXT`. It runs from `paper-status-gates.sh`
|
|
61
|
+
on every edit to a paper source, so the state arrives without anyone pulling it. If that banner and
|
|
62
|
+
this section ever disagree, the banner is a measurement and this is prose: believe the banner.
|
|
63
|
+
|
|
64
|
+
## How to run it
|
|
65
|
+
|
|
66
|
+
### 1. Measure (no reading yet)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd <paper-dir>
|
|
70
|
+
bash repro/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
|
|
71
|
+
git status --porcelain # uncommitted work
|
|
72
|
+
git log --oneline @{u}..HEAD # unpushed commits
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- **The build is the only page-count authority.** If the repo has an approximate measurer, do not use
|
|
76
|
+
it and say so. In this project `measure.sh` was gutted on 2026-08-04 for exactly this reason.
|
|
77
|
+
- Report the build's own verdict line verbatim. Do not paraphrase `BLOCKED` into "nearly there".
|
|
78
|
+
|
|
79
|
+
### 2. Detect stale gates — the part memory always gets wrong
|
|
80
|
+
|
|
81
|
+
A gate is stale if the paper changed after the gate ran. Check it mechanically, not by recall:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git log -1 --format=%cd --date=short -- paper.md # when the text last moved
|
|
85
|
+
ls -la reviews/ | tail -20 # when each gate last reported
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Compare against the dates in `PIPELINE-STATUS.md`. If the paper moved after a gate's date, that
|
|
89
|
+
gate's verdict **does not describe the current paper** — say so explicitly, and say what changed since.
|
|
90
|
+
An accept-probability from a superseded draft is not evidence about this one; carrying it forward is
|
|
91
|
+
the single most common way a status report lies.
|
|
92
|
+
|
|
93
|
+
If the project ships a checker (`.claude/skills/paper-pipeline/scripts/pipeline-check.mjs`), run it.
|
|
94
|
+
|
|
95
|
+
### 3. Read the judgement rows — from BOTH checklists, they answer different questions
|
|
96
|
+
|
|
97
|
+
The project already carries the checklists this skill should report against. Do not invent a new list
|
|
98
|
+
and do not report from one of them alone:
|
|
99
|
+
|
|
100
|
+
| source | the question it answers | what to pull |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| **`<paper-dir>/PIPELINE-STATUS.md`** | were the QUALITY stages run, and what did they conclude | per-stage `☑`/`◐`/`☐`/`⚠`, dates, the one-line submit-ready verdict |
|
|
103
|
+
| **`<paper-dir>/SUBMIT-CHECKLIST.md`** | does it comply with the VENUE's format, and is the submission mechanics understood | page limit, template, blind model, mandatory sections, portal URL, whether a supplementary-upload field exists, the deadline converted to the author's own zone |
|
|
104
|
+
| **`.claude/hooks/paper-skills-nudge.hook.ts`** | which gates EXIST at all | the canonical pre-submit gate list — use it to spot a gate nobody has ever run, which no scorecard row will show because the row was never added |
|
|
105
|
+
| `<paper-dir>/CLAIMS.md` | what may still be claimed | 🔴 retired claims — flag if the current text asserts one |
|
|
106
|
+
| `<paper-dir>/CLAUDE.md` | what this venue rewards | only when it changes what to do next |
|
|
107
|
+
|
|
108
|
+
🔴 **Both checklists must be green before upload, and they fail differently.** A paper can pass every
|
|
109
|
+
quality gate and still be unsubmittable (no active account, no supplementary field so the artifact
|
|
110
|
+
needs external hosting, deadline misconverted from AoE). Reporting only the quality side is how a
|
|
111
|
+
"ready" paper misses its deadline. The compliance side usually contains the blockers that are *his*,
|
|
112
|
+
which is exactly why they belong at the top of the output.
|
|
113
|
+
|
|
114
|
+
### 4. Print it, in this shape and this order
|
|
115
|
+
|
|
116
|
+
Short. He is asking because he wants to decide what to do next, not to read a report.
|
|
117
|
+
|
|
118
|
+
1. **One line: can it be submitted right now?** The build verdict plus the hard blockers, nothing else.
|
|
119
|
+
2. **Blockers, worst first, split by owner** — 🔴 his (accounts, hosting, anything needing a human or a
|
|
120
|
+
login) vs 🔵 mine (text, gates, artifacts). His come first: he can start them while I work.
|
|
121
|
+
3. **Gates** (`PIPELINE-STATUS.md`), each marked ✅ ran against current text · ⚠️ ran against an older
|
|
122
|
+
text (name what changed) · ☐ never run. Cross-check against the hook's canonical gate list so a
|
|
123
|
+
gate with no row at all shows up as ☐ rather than vanishing.
|
|
124
|
+
4. **Format compliance** (`SUBMIT-CHECKLIST.md`) — one line: green, or the specific item that is not.
|
|
125
|
+
Page limit and blind model come from the measured build, not from the checklist's memory of them.
|
|
126
|
+
5. **What moved since he last asked**, three lines maximum.
|
|
127
|
+
6. **The deadline, in his timezone**, and what is on the critical path to it.
|
|
128
|
+
|
|
129
|
+
## Record the verdict
|
|
130
|
+
|
|
131
|
+
🔴 LAST step, once the deliverable exists:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> FINDING <count> <report-path>
|
|
135
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> ABSTAINED <reason> "<one line>"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This skill reports state and does not judge the paper, so what it records is about the **status run**:
|
|
139
|
+
**FINDING** — `<count>` blockers printed, `<report-path>` the status output.
|
|
140
|
+
**ABSTAINED** — `no-witness`: the status run measured everything it can and printed zero blockers.
|
|
141
|
+
`crashed`: the build did not run, so nothing was measured.
|
|
142
|
+
|
|
143
|
+
🔴 `crashed` is the one outcome that must never be narrated as a status. This skill exists because
|
|
144
|
+
state was being narrated instead of measured; a status report built on a build that did not happen
|
|
145
|
+
is that same failure with a fresh timestamp on it. Under the old vocabulary this was `ERROR`, which
|
|
146
|
+
sat in the same column as a verdict about the paper — it does not any more.
|
|
147
|
+
|
|
148
|
+
🔴 **There is no PASS**, so "zero blockers" cannot be stored. Print it, and let the reader draw the
|
|
149
|
+
conclusion from an empty blocker list they can see.
|
|
150
|
+
|
|
151
|
+
## Rules
|
|
152
|
+
|
|
153
|
+
- **Never report a gate as run because I intended to run it.** Predicting a background agent's result,
|
|
154
|
+
or calling a queued task "running" when nothing was launched, is the failure this skill was written
|
|
155
|
+
after. If a task was not launched, the honest line is "not started".
|
|
156
|
+
- **Owner-split is not decoration.** A blocker only he can clear (an account, an upload, a phone call)
|
|
157
|
+
belongs at the top, because every hour it sits is an hour of pure schedule loss.
|
|
158
|
+
- **Numbers, not adjectives.** "8/8 pages, fits" not "about right"; "78 stalls over 8 pages against a
|
|
159
|
+
threshold of 2" not "readable enough".
|
|
160
|
+
- **Say what is NOT known.** A gate never run is a real answer and more useful than an optimistic one.
|
|
161
|
+
- 🔴 **Send the built PDF with the report, every time, without being asked** (`SendUserFile`, from the
|
|
162
|
+
outdir the report's page count came from — never an older copy). The corpus owner, 2026-08-05: *"and I often ask for the PDF to be delivered"*. He reads the paper, not the scorecard; a status report that makes him ask for the
|
|
163
|
+
artifact costs a round trip for nothing. The caption states the build time and the page count, so
|
|
164
|
+
the file cannot be mistaken for an earlier one.
|
|
165
|
+
- 🔴 **Never let "the gates are stale" be heard as "the measurements are stale."** They are different
|
|
166
|
+
objects and conflating them destroys trust in real data: a *measurement* is an experiment on the
|
|
167
|
+
tool or corpus and stays valid until the tool changes; a *gate* is a judgement of the paper text and
|
|
168
|
+
expires the moment the text moves. Name which one you mean, every time. On 2026-08-05 a one-word
|
|
169
|
+
slip here made a four-hour experiment sound like wasted work.
|
|
170
|
+
- Do not fix anything while reporting. Status and work are different turns — mixing them is how the
|
|
171
|
+
status stops being trustworthy.
|
|
172
|
+
|
|
173
|
+
## Compose with
|
|
174
|
+
|
|
175
|
+
- `paper-pipeline` — owns the stage contract this reads.
|
|
176
|
+
- `harden-paper` — the decision to submit; this only reports the inputs to it.
|
|
177
|
+
- `handoff` — end-of-session preservation; this is the start-of-session counterpart.
|
|
178
|
+
|
|
179
|
+
## Provenance
|
|
180
|
+
|
|
181
|
+
Built 2026-08-04, the day before the `compile-rules-2026` deadline, after the author asked for paper status
|
|
182
|
+
for the fourth time in one session and pointed out it should be a command: *"I ask this so often... there should be a skill"*. He was right, and the two things the skill measures first are the two
|
|
183
|
+
things chat had most recently gotten wrong.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
|
|
2
|
+
//
|
|
3
|
+
// Adopted 2026-08-17 as part of the second batch. The body is the previous SKILL.md
|
|
4
|
+
// VERBATIM, so the compiled diff shows only what the compiler adds. No `disallowedTools`
|
|
5
|
+
// fence yet: the field exists on `SkillSpec` as of the branch `claude/skill-disallowed-tools`
|
|
6
|
+
// but is not in a release `mine` installs, so adding it here would not compile.
|
|
7
|
+
import { experimental_skill } from "vigiles/spec";
|
|
8
|
+
|
|
9
|
+
export default experimental_skill({
|
|
10
|
+
name: "paper-status",
|
|
11
|
+
description:
|
|
12
|
+
"Answer \"what's the status of the paper?\" in one pass — MEASURE what is measurable (page count from the real build, git state, which gates were run against the CURRENT text), then read the judgement rows, then print blockers worst-first split into mine and the author's. Use whenever the author asks \"what's up with the paper / status / what's left / is it ready\", at the start of a session touching a paper, or before deciding what to work on next. Not a review skill — it reports state, it does not grade, cut, or fix.",
|
|
13
|
+
tools: ["Bash", "Read", "Grep", "Glob"],
|
|
14
|
+
body: `
|
|
15
|
+
# paper-status — state, measured before it is narrated
|
|
16
|
+
|
|
17
|
+
## Run me
|
|
18
|
+
|
|
19
|
+
🔴 FIRST, before any other step:
|
|
20
|
+
|
|
21
|
+
\`\`\`
|
|
22
|
+
node .claude/skills/paper-pipeline/scripts/announce.mjs paper-status <paper-dir>
|
|
23
|
+
\`\`\`
|
|
24
|
+
|
|
25
|
+
An advisory pass cannot be observed failing — silence is both its error state and its normal
|
|
26
|
+
state — so starting is an event, and events get written down.
|
|
27
|
+
|
|
28
|
+
The author asks "what's the status there?" constantly, and the answer keeps coming from the wrong place: my
|
|
29
|
+
memory of the session, which drifts, or a 200-line scorecard he cannot skim. Both fail the same way —
|
|
30
|
+
**they narrate state instead of measuring it.**
|
|
31
|
+
|
|
32
|
+
Grounding failure, 2026-08-04 (\`compile-rules-2026\`, day before deadline): a status line in chat said
|
|
33
|
+
the review panel was running. It had never been launched. Another said the paper was 8 pages while the
|
|
34
|
+
real build said 9 and BLOCKED — steering a whole day of cuts by the wrong instrument. Both would have
|
|
35
|
+
been caught by running two commands instead of recalling two facts.
|
|
36
|
+
|
|
37
|
+
## The rule this skill exists to enforce
|
|
38
|
+
|
|
39
|
+
**Anything a command can answer is not allowed to come from memory or from prose.** Measure first,
|
|
40
|
+
read the scorecard second, and mark clearly which is which. A claim in \`PIPELINE-STATUS.md\` is a claim
|
|
41
|
+
about the past; the build is the present.
|
|
42
|
+
|
|
43
|
+
## 🔴 The second rule: status is PUSHED, never waited for
|
|
44
|
+
|
|
45
|
+
The corpus owner, 2026-08-05: *"I have to constantly ask for the paper's status and direct you so you tell me what we can do next"*. Building a skill that answers when asked fixed the wrong half —
|
|
46
|
+
the work he was complaining about is **the asking**, and a pull-only skill leaves all of it with him.
|
|
47
|
+
|
|
48
|
+
So on any turn that touched a paper, the reply ends with **three lines, unprompted**:
|
|
49
|
+
|
|
50
|
+
1. **where it stands** — the build's own verdict line, page count, deadline countdown;
|
|
51
|
+
2. **the single next action, with an owner** — not a menu. If it is mine, it is already started or
|
|
52
|
+
started in the same reply. If it is his, it says exactly what to click.
|
|
53
|
+
3. **what is stale** — a gate whose verdict predates the current text, named.
|
|
54
|
+
|
|
55
|
+
Three failures make this a rule rather than a preference, all in one session:
|
|
56
|
+
- I finished a page-fit cut and stopped, so he asked what the status was;
|
|
57
|
+
- I left artifact hosting on his side of the split for a day and a half while the credential to clear
|
|
58
|
+
it sat in the environment (see \`credential-available\` in \`pipeline-check.mjs\`);
|
|
59
|
+
- three consecutive panels returned Weak Accept and the ceiling they named was never the next task,
|
|
60
|
+
because nothing turned "here is the score" into "here is what to do about it".
|
|
61
|
+
|
|
62
|
+
**Never end a paper turn on a completed sub-task alone.** "Fits in 8 pages" is a measurement, not a
|
|
63
|
+
status; the status is what that measurement makes possible next.
|
|
64
|
+
|
|
65
|
+
**Enforcement leg.** \`pipeline-check.mjs\` prints its banner **unconditionally**, including when it has
|
|
66
|
+
zero findings — deadline countdown, verdict row, and \`➡️ NEXT\`. It runs from \`paper-status-gates.sh\`
|
|
67
|
+
on every edit to a paper source, so the state arrives without anyone pulling it. If that banner and
|
|
68
|
+
this section ever disagree, the banner is a measurement and this is prose: believe the banner.
|
|
69
|
+
|
|
70
|
+
## How to run it
|
|
71
|
+
|
|
72
|
+
### 1. Measure (no reading yet)
|
|
73
|
+
|
|
74
|
+
\`\`\`bash
|
|
75
|
+
cd <paper-dir>
|
|
76
|
+
bash repro/build-submission.sh 2>&1 | grep -Ei 'body pages|VERDICT|Overfull|undefined|anonymity'
|
|
77
|
+
git status --porcelain # uncommitted work
|
|
78
|
+
git log --oneline @{u}..HEAD # unpushed commits
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
- **The build is the only page-count authority.** If the repo has an approximate measurer, do not use
|
|
82
|
+
it and say so. In this project \`measure.sh\` was gutted on 2026-08-04 for exactly this reason.
|
|
83
|
+
- Report the build's own verdict line verbatim. Do not paraphrase \`BLOCKED\` into "nearly there".
|
|
84
|
+
|
|
85
|
+
### 2. Detect stale gates — the part memory always gets wrong
|
|
86
|
+
|
|
87
|
+
A gate is stale if the paper changed after the gate ran. Check it mechanically, not by recall:
|
|
88
|
+
|
|
89
|
+
\`\`\`bash
|
|
90
|
+
git log -1 --format=%cd --date=short -- paper.md # when the text last moved
|
|
91
|
+
ls -la reviews/ | tail -20 # when each gate last reported
|
|
92
|
+
\`\`\`
|
|
93
|
+
|
|
94
|
+
Compare against the dates in \`PIPELINE-STATUS.md\`. If the paper moved after a gate's date, that
|
|
95
|
+
gate's verdict **does not describe the current paper** — say so explicitly, and say what changed since.
|
|
96
|
+
An accept-probability from a superseded draft is not evidence about this one; carrying it forward is
|
|
97
|
+
the single most common way a status report lies.
|
|
98
|
+
|
|
99
|
+
If the project ships a checker (\`.claude/skills/paper-pipeline/scripts/pipeline-check.mjs\`), run it.
|
|
100
|
+
|
|
101
|
+
### 3. Read the judgement rows — from BOTH checklists, they answer different questions
|
|
102
|
+
|
|
103
|
+
The project already carries the checklists this skill should report against. Do not invent a new list
|
|
104
|
+
and do not report from one of them alone:
|
|
105
|
+
|
|
106
|
+
| source | the question it answers | what to pull |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| **\`<paper-dir>/PIPELINE-STATUS.md\`** | were the QUALITY stages run, and what did they conclude | per-stage \`☑\`/\`◐\`/\`☐\`/\`⚠\`, dates, the one-line submit-ready verdict |
|
|
109
|
+
| **\`<paper-dir>/SUBMIT-CHECKLIST.md\`** | does it comply with the VENUE's format, and is the submission mechanics understood | page limit, template, blind model, mandatory sections, portal URL, whether a supplementary-upload field exists, the deadline converted to the author's own zone |
|
|
110
|
+
| **\`.claude/hooks/paper-skills-nudge.hook.ts\`** | which gates EXIST at all | the canonical pre-submit gate list — use it to spot a gate nobody has ever run, which no scorecard row will show because the row was never added |
|
|
111
|
+
| \`<paper-dir>/CLAIMS.md\` | what may still be claimed | 🔴 retired claims — flag if the current text asserts one |
|
|
112
|
+
| \`<paper-dir>/CLAUDE.md\` | what this venue rewards | only when it changes what to do next |
|
|
113
|
+
|
|
114
|
+
🔴 **Both checklists must be green before upload, and they fail differently.** A paper can pass every
|
|
115
|
+
quality gate and still be unsubmittable (no active account, no supplementary field so the artifact
|
|
116
|
+
needs external hosting, deadline misconverted from AoE). Reporting only the quality side is how a
|
|
117
|
+
"ready" paper misses its deadline. The compliance side usually contains the blockers that are *his*,
|
|
118
|
+
which is exactly why they belong at the top of the output.
|
|
119
|
+
|
|
120
|
+
### 4. Print it, in this shape and this order
|
|
121
|
+
|
|
122
|
+
Short. He is asking because he wants to decide what to do next, not to read a report.
|
|
123
|
+
|
|
124
|
+
1. **One line: can it be submitted right now?** The build verdict plus the hard blockers, nothing else.
|
|
125
|
+
2. **Blockers, worst first, split by owner** — 🔴 his (accounts, hosting, anything needing a human or a
|
|
126
|
+
login) vs 🔵 mine (text, gates, artifacts). His come first: he can start them while I work.
|
|
127
|
+
3. **Gates** (\`PIPELINE-STATUS.md\`), each marked ✅ ran against current text · ⚠️ ran against an older
|
|
128
|
+
text (name what changed) · ☐ never run. Cross-check against the hook's canonical gate list so a
|
|
129
|
+
gate with no row at all shows up as ☐ rather than vanishing.
|
|
130
|
+
4. **Format compliance** (\`SUBMIT-CHECKLIST.md\`) — one line: green, or the specific item that is not.
|
|
131
|
+
Page limit and blind model come from the measured build, not from the checklist's memory of them.
|
|
132
|
+
5. **What moved since he last asked**, three lines maximum.
|
|
133
|
+
6. **The deadline, in his timezone**, and what is on the critical path to it.
|
|
134
|
+
|
|
135
|
+
## Record the verdict
|
|
136
|
+
|
|
137
|
+
🔴 LAST step, once the deliverable exists:
|
|
138
|
+
|
|
139
|
+
\`\`\`
|
|
140
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> FINDING <count> <report-path>
|
|
141
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record paper-status <paper-dir> ABSTAINED <reason> "<one line>"
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
This skill reports state and does not judge the paper, so what it records is about the **status run**:
|
|
145
|
+
**FINDING** — \`<count>\` blockers printed, \`<report-path>\` the status output.
|
|
146
|
+
**ABSTAINED** — \`no-witness\`: the status run measured everything it can and printed zero blockers.
|
|
147
|
+
\`crashed\`: the build did not run, so nothing was measured.
|
|
148
|
+
|
|
149
|
+
🔴 \`crashed\` is the one outcome that must never be narrated as a status. This skill exists because
|
|
150
|
+
state was being narrated instead of measured; a status report built on a build that did not happen
|
|
151
|
+
is that same failure with a fresh timestamp on it. Under the old vocabulary this was \`ERROR\`, which
|
|
152
|
+
sat in the same column as a verdict about the paper — it does not any more.
|
|
153
|
+
|
|
154
|
+
🔴 **There is no PASS**, so "zero blockers" cannot be stored. Print it, and let the reader draw the
|
|
155
|
+
conclusion from an empty blocker list they can see.
|
|
156
|
+
|
|
157
|
+
## Rules
|
|
158
|
+
|
|
159
|
+
- **Never report a gate as run because I intended to run it.** Predicting a background agent's result,
|
|
160
|
+
or calling a queued task "running" when nothing was launched, is the failure this skill was written
|
|
161
|
+
after. If a task was not launched, the honest line is "not started".
|
|
162
|
+
- **Owner-split is not decoration.** A blocker only he can clear (an account, an upload, a phone call)
|
|
163
|
+
belongs at the top, because every hour it sits is an hour of pure schedule loss.
|
|
164
|
+
- **Numbers, not adjectives.** "8/8 pages, fits" not "about right"; "78 stalls over 8 pages against a
|
|
165
|
+
threshold of 2" not "readable enough".
|
|
166
|
+
- **Say what is NOT known.** A gate never run is a real answer and more useful than an optimistic one.
|
|
167
|
+
- 🔴 **Send the built PDF with the report, every time, without being asked** (\`SendUserFile\`, from the
|
|
168
|
+
outdir the report's page count came from — never an older copy). The corpus owner, 2026-08-05: *"and I often ask for the PDF to be delivered"*. He reads the paper, not the scorecard; a status report that makes him ask for the
|
|
169
|
+
artifact costs a round trip for nothing. The caption states the build time and the page count, so
|
|
170
|
+
the file cannot be mistaken for an earlier one.
|
|
171
|
+
- 🔴 **Never let "the gates are stale" be heard as "the measurements are stale."** They are different
|
|
172
|
+
objects and conflating them destroys trust in real data: a *measurement* is an experiment on the
|
|
173
|
+
tool or corpus and stays valid until the tool changes; a *gate* is a judgement of the paper text and
|
|
174
|
+
expires the moment the text moves. Name which one you mean, every time. On 2026-08-05 a one-word
|
|
175
|
+
slip here made a four-hour experiment sound like wasted work.
|
|
176
|
+
- Do not fix anything while reporting. Status and work are different turns — mixing them is how the
|
|
177
|
+
status stops being trustworthy.
|
|
178
|
+
|
|
179
|
+
## Compose with
|
|
180
|
+
|
|
181
|
+
- \`paper-pipeline\` — owns the stage contract this reads.
|
|
182
|
+
- \`harden-paper\` — the decision to submit; this only reports the inputs to it.
|
|
183
|
+
- \`handoff\` — end-of-session preservation; this is the start-of-session counterpart.
|
|
184
|
+
|
|
185
|
+
## Provenance
|
|
186
|
+
|
|
187
|
+
Built 2026-08-04, the day before the \`compile-rules-2026\` deadline, after the author asked for paper status
|
|
188
|
+
for the fourth time in one session and pointed out it should be a command: *"I ask this so often... there should be a skill"*. He was right, and the two things the skill measures first are the two
|
|
189
|
+
things chat had most recently gotten wrong.`,
|
|
190
|
+
});
|