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,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-paper-timeline
|
|
3
|
+
description: Turn a venue's CFP dates into a scheduled, buffered plan on the Google Calendar — build the timeline backwards from the AoE submission deadline (harden + panel-review + artifact + anonymized host all land BEFORE it), create calendar events in the author's own time zone for submit-day / deadline / camera-ready, and apply the FILING-SPACING rule so multiple papers don't cluster in the month before a planned external filing. Use right after find-venue hands you real deadlines and before you start drafting. Compose with find-venue (deadline source) and submit-paper.
|
|
4
|
+
allowed-tools: [Read, Write, Grep, Glob, mcp__Google_Calendar__list_events, mcp__Google_Calendar__search_events, mcp__Google_Calendar__create_event, mcp__Google_Calendar__update_event, Bash(node .claude/skills/paper-pipeline/scripts/announce.mjs:*), Bash(node .claude/skills/paper-pipeline/scripts/ledger.mjs:*)]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- vigiles:sha256:9009b62e211cf421 compiled from skills/plan-paper-timeline/SKILL.md.spec.ts -->
|
|
8
|
+
|
|
9
|
+
# plan-paper-timeline — CFP dates → a buffered, filing-aware schedule
|
|
10
|
+
|
|
11
|
+
## Run me
|
|
12
|
+
|
|
13
|
+
🔴 FIRST, before any other step:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
node .claude/skills/paper-pipeline/scripts/announce.mjs plan-paper-timeline <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
|
+
A deadline is not a plan. This skill converts the four dates every CFP gives you — **submission (AoE),
|
|
23
|
+
notification, camera-ready, event** — into calendar events with the buffers that actually keep a
|
|
24
|
+
submission from slipping, and sequences *multiple* papers so the cadence reads as sustained acclaim,
|
|
25
|
+
not a pre-filing burst.
|
|
26
|
+
|
|
27
|
+
## 0. 🔴 CAN YOU PHYSICALLY SUBMIT? — do this in the FIRST week (scorecard row `access`)
|
|
28
|
+
|
|
29
|
+
**This skill owns the question no other unit of work owned**, and it is the one that bites. It is not
|
|
30
|
+
about the paper. It is about whether, on submit-day, there is anywhere to put it. Everything below in
|
|
31
|
+
this skill schedules *work*; this schedules *access*, and access has a lead time you do not control.
|
|
32
|
+
|
|
33
|
+
*Added 2026-08-03, after this was the sole critical-path item on a finished paper at **T−4 days**: the
|
|
34
|
+
science was done, the artifact was built, and the account could not submit.*
|
|
35
|
+
|
|
36
|
+
Concrete steps, all of them today, none of them deferrable:
|
|
37
|
+
|
|
38
|
+
1. **Create the portal account** (OpenReview / HotCRP / EasyChair / the venue's own). Not "find the
|
|
39
|
+
URL" — create the account.
|
|
40
|
+
2. **Drive the profile to ACTIVE.** 🔴 *"Pending moderation" is not an account you can submit from.*
|
|
41
|
+
Fill in every field moderation looks at — full name, affiliation history with dates, an ORCID or
|
|
42
|
+
DBLP/homepage link, and prior publications if the portal imports them; a sparse profile is what
|
|
43
|
+
gets queued rather than approved. Then **check back and confirm the state flipped**, and
|
|
44
|
+
**record the ISO date it went ACTIVE in the `access` row**, not just a tick.
|
|
45
|
+
3. **Confirm the form's fields** — open the actual submission form and read it. Title, abstract
|
|
46
|
+
(character cap?), track/type selector, subject areas, conflicts-of-interest, mandatory
|
|
47
|
+
declarations (GenAI/LLM use, ethics, dual-use), authors' order, and whether upload alone counts as
|
|
48
|
+
submitted or a separate **"ready for review"** click does.
|
|
49
|
+
4. **Confirm whether a supplementary-upload field EXISTS.** If it does not, the artifact needs an
|
|
50
|
+
**external anonymous host** (OSF view-only link / 4open) plus a `\url{}` in Availability — and that
|
|
51
|
+
host has to be minted before submit-day, not on it. This is a real branch in the plan, not a detail.
|
|
52
|
+
5. **Re-check as the deadline approaches.** External state rots without telling you: a profile can be
|
|
53
|
+
flagged, a portal can open late or change its form. The CONTINUOUS trigger on the `access` row exists
|
|
54
|
+
for exactly this.
|
|
55
|
+
|
|
56
|
+
**The lead time, stated plainly:** portal moderation runs **up to two weeks**, and an author with **no
|
|
57
|
+
institutional email has no expedite route** — no support queue jump, no "I'm on a deadline" exception.
|
|
58
|
+
That is why `access` is scheduled in the first week rather than the last: it is the one item where the
|
|
59
|
+
only remedy for being late is having started earlier.
|
|
60
|
+
|
|
61
|
+
`pipeline-check.mjs` reports an `access` row still `☐` inside the moderation window as a finding, and
|
|
62
|
+
`submit-paper` is hard-blocked on `access` being green.
|
|
63
|
+
|
|
64
|
+
## 1. Build the timeline backwards from the AoE deadline
|
|
65
|
+
Everything that must be done *before* you can submit gets its own slot ending before the deadline —
|
|
66
|
+
never "the day of." Working back from the submission AoE date, reserve, in this order:
|
|
67
|
+
|
|
68
|
+
- **Draft frozen** — prose done, `verify-citations` clean. Earliest.
|
|
69
|
+
- **Harden** — `paper-adversarial-review` → `pc-panel-review` venue-fit mode, fix blockers, re-render.
|
|
70
|
+
Loops; give it room.
|
|
71
|
+
- **Panel review** — `pc-panel-review` (multi-reviewer + artifact-runner) as the final gate. 1–2 days.
|
|
72
|
+
- **Artifact built + hosted anonymously** — build the self-checking artifact and mint the OSF/4open
|
|
73
|
+
anonymized link (see `submit-paper` + `paper-pipeline/references/artifact-checklist.md`). This step
|
|
74
|
+
reliably eats more time than expected; put it before, not on, submit-day.
|
|
75
|
+
- **Submit-day = one day before AoE.** The real submission happens here, with slack for a HotCRP
|
|
76
|
+
surprise (no supplementary field, a re-paste, a "ready for review" step you forgot). Never plan to
|
|
77
|
+
submit on the deadline itself.
|
|
78
|
+
|
|
79
|
+
Rule of thumb: if the CFP is <2 weeks out, the artifact + panel review are what you cut scope on, not
|
|
80
|
+
the claim-sizing.
|
|
81
|
+
|
|
82
|
+
## 2. The AoE nuance (don't lose a day to it)
|
|
83
|
+
CFP deadline dates are **Anywhere-on-Earth (UTC−12)**. A deadline written "15 Jul AoE" does *not* expire
|
|
84
|
+
at your local midnight on the 15th — it expires when the last spot on Earth leaves the 15th:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
15 Jul 23:59 AoE = 16 Jul 11:59 UTC ≈ 16 Jul ~17:00 local, in a UTC+5 zone
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
So the calendar date on the CFP is effectively the **next day at home**. This is slack, not a plan —
|
|
91
|
+
treat submit-day as the day before the *printed* date regardless, and let the AoE hours be your safety
|
|
92
|
+
margin, not your runway.
|
|
93
|
+
|
|
94
|
+
## 3. Create the calendar events (in the author's own zone)
|
|
95
|
+
Use `mcp__Google_Calendar__create_event` for three anchors per paper. 🔴 **Read the zone, do not
|
|
96
|
+
assume it** — it is the `timezone` carrier, and it is the author's, not the pipeline's:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
node -p "((p) => p.paperlint ?? p['research-paper-pipeline'])(require('./package.json'))?.timezone ?? 'UTC'"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The example below shows the default, `UTC`; substitute whatever that command prints.
|
|
103
|
+
Title them so the venue and the phase are unmistakable at a glance:
|
|
104
|
+
|
|
105
|
+
- **`<Venue> — SUBMIT`** on submit-day (one day before the printed AoE date). This is the one you act on.
|
|
106
|
+
- **`<Venue> — deadline (AoE)`** on the printed date, as a hard backstop.
|
|
107
|
+
- **`<Venue> — camera-ready`** on the camera-ready date (from the CFP), so acceptance doesn't ambush you
|
|
108
|
+
in a busy week.
|
|
109
|
+
|
|
110
|
+
`summary`, `startTime` **and `endTime`** are all required — the API rejects the call without the end
|
|
111
|
+
time, and a deadline anchor has no natural duration, so give it an hour and move on. Exact shape:
|
|
112
|
+
|
|
113
|
+
<!-- harness:prescribed-call create_event -->
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"summary": "AISec 2026 — SUBMIT",
|
|
117
|
+
"startTime": "2026-07-23T10:00:00",
|
|
118
|
+
"endTime": "2026-07-23T11:00:00",
|
|
119
|
+
"timeZone": "UTC"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Optionally add **notification** and **event/workshop** days as markers with `"allDay": true` — which
|
|
124
|
+
does not excuse you from `startTime`/`endTime`; they are still required and are read as midnight. Keep
|
|
125
|
+
the two review/host milestones (§1) as your own working reminders; the three above are the immovable ones.
|
|
126
|
+
|
|
127
|
+
> The block above is not decoration. `plan-paper-timeline.effects.harness.mjs` parses it out of this
|
|
128
|
+
> file and replays it against a stand-in server carrying the REAL API's schema, so a prescription this
|
|
129
|
+
> section gets wrong fails in the harness rather than on a live run. Edit it like code.
|
|
130
|
+
|
|
131
|
+
## 4. FILING-SPACING rule (the reason this skill exists)
|
|
132
|
+
Where the papers are the authorship pillar of some external filing — a grant, a tenure packet, an
|
|
133
|
+
immigration petition — **do not let multiple submissions or acceptances cluster in the month before
|
|
134
|
+
that filing.** A burst of activity right before a deadline reads as *manufactured* rather than
|
|
135
|
+
*sustained*, and that is a documented reason for refusal, not a stylistic worry. A steady cadence with
|
|
136
|
+
recent-but-not-crammed activity reads far better.
|
|
137
|
+
|
|
138
|
+
When scheduling paper N against papers already on the calendar and a known/likely filing date:
|
|
139
|
+
- Spread submission and (projected) notification dates across months; avoid two acceptances landing in
|
|
140
|
+
the same pre-filing window.
|
|
141
|
+
- If two CFPs force a cluster, stagger which one you *extend* later (workshop → conference) so the
|
|
142
|
+
second, stronger publication lands in a later month on purpose.
|
|
143
|
+
- Prefer a paper with an earlier, safely-past deadline over one that would pile onto the filing month.
|
|
144
|
+
|
|
145
|
+
## 5. Record the verdict
|
|
146
|
+
|
|
147
|
+
🔴 LAST step, once the deliverable exists:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record plan-paper-timeline <paper-dir> FINDING <count> <report-path>
|
|
151
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record plan-paper-timeline <paper-dir> ABSTAINED <reason> "<one line>"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**FINDING** — `<count>` slots have no buffer, or collide with another paper's pre-filing window;
|
|
155
|
+
`<report-path>` is the plan. Add `--blocking` when the deadline cannot be met from here.
|
|
156
|
+
**ABSTAINED** — `no-witness`: the backwards plan is on the calendar, `access` is green and no slot
|
|
157
|
+
is tight. `input-missing`: `find-venue` has produced no dated deadline to plan against.
|
|
158
|
+
|
|
159
|
+
This is the one skill whose blocking finding is a fact about the calendar rather than about the
|
|
160
|
+
paper: portal moderation runs up to two weeks and an author with no institutional email has no
|
|
161
|
+
expedite route, so one recorded today is still true tomorrow no matter how good the science gets.
|
|
162
|
+
|
|
163
|
+
🔴 **There is no PASS**, so "the plan is on the calendar" is not storable here. Put the event ids in
|
|
164
|
+
the `ABSTAINED` note — markdown is the source of truth and the calendar is its projection, and a row
|
|
165
|
+
with neither is a claim about a calendar nobody opened.
|
|
166
|
+
|
|
167
|
+
## Scorecard rows this skill owns
|
|
168
|
+
Two, and they fail differently — see `paper-pipeline/references/pipeline-status-template.md`:
|
|
169
|
+
- **`access`** — *can you physically submit?* (§0). Account · profile ACTIVE since `<ISO>` · portal
|
|
170
|
+
reachable · form fields known · artifact-host requirement known. `submit-paper` is blocked on it.
|
|
171
|
+
- **`schedule`** — the schedule itself (§1–§4): the buffered backwards plan and its calendar events.
|
|
172
|
+
|
|
173
|
+
## Compose with
|
|
174
|
+
- **`find-venue`** — the source of the four CFP dates this skill consumes; run it first.
|
|
175
|
+
- **`submit-paper`** (+ the venue subskill) — what submit-day actually executes; this skill just makes
|
|
176
|
+
sure the runway before it exists, **and that the account it executes through is already ACTIVE**.
|
|
177
|
+
|
|
178
|
+
## Provenance
|
|
179
|
+
This session scheduled two real papers with spacing rather than back-to-back: **AgenticDev 2026 @ ASE**
|
|
180
|
+
(submission 15 Jul, notify 21 Aug, camera-ready 28 Aug, workshop 12 Oct) and **AISec 2026 @ ACM CCS**
|
|
181
|
+
(submission 24 Jul). Nine days apart, deliberately staggered so notifications and any camera-ready work
|
|
182
|
+
don't collapse into one pre-filing month — the FILING-SPACING rule applied in practice, not in theory.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
|
|
2
|
+
//
|
|
3
|
+
// Adopted 2026-08-17 (batch 3). Body carried over VERBATIM so the compiled diff shows
|
|
4
|
+
// only what the compiler adds. No `disallowedTools` fence yet — the field landed on
|
|
5
|
+
// `SkillSpec` in vigiles branch `claude/skill-disallowed-tools` and is not in a release
|
|
6
|
+
// this repo installs, so writing one here would not compile.
|
|
7
|
+
import { experimental_skill } from "vigiles/spec";
|
|
8
|
+
|
|
9
|
+
export default experimental_skill({
|
|
10
|
+
name: "plan-paper-timeline",
|
|
11
|
+
description:
|
|
12
|
+
"Turn a venue's CFP dates into a scheduled, buffered plan on the Google Calendar — build the timeline backwards from the AoE submission deadline (harden + panel-review + artifact + anonymized host all land BEFORE it), create calendar events in the author's own time zone for submit-day / deadline / camera-ready, and apply the FILING-SPACING rule so multiple papers don't cluster in the month before a planned external filing. Use right after find-venue hands you real deadlines and before you start drafting. Compose with find-venue (deadline source) and submit-paper.",
|
|
13
|
+
tools: [
|
|
14
|
+
"Read",
|
|
15
|
+
"Write",
|
|
16
|
+
"Grep",
|
|
17
|
+
"Glob",
|
|
18
|
+
"mcp__Google_Calendar__list_events",
|
|
19
|
+
"mcp__Google_Calendar__search_events",
|
|
20
|
+
"mcp__Google_Calendar__create_event",
|
|
21
|
+
"mcp__Google_Calendar__update_event",
|
|
22
|
+
"Bash(node .claude/skills/paper-pipeline/scripts/announce.mjs:*)",
|
|
23
|
+
"Bash(node .claude/skills/paper-pipeline/scripts/ledger.mjs:*)",
|
|
24
|
+
],
|
|
25
|
+
body: `
|
|
26
|
+
# plan-paper-timeline — CFP dates → a buffered, filing-aware schedule
|
|
27
|
+
|
|
28
|
+
## Run me
|
|
29
|
+
|
|
30
|
+
🔴 FIRST, before any other step:
|
|
31
|
+
|
|
32
|
+
\`\`\`
|
|
33
|
+
node .claude/skills/paper-pipeline/scripts/announce.mjs plan-paper-timeline <paper-dir>
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
An advisory pass cannot be observed failing — silence is both its error state and its normal
|
|
37
|
+
state — so starting is an event, and events get written down.
|
|
38
|
+
|
|
39
|
+
A deadline is not a plan. This skill converts the four dates every CFP gives you — **submission (AoE),
|
|
40
|
+
notification, camera-ready, event** — into calendar events with the buffers that actually keep a
|
|
41
|
+
submission from slipping, and sequences *multiple* papers so the cadence reads as sustained acclaim,
|
|
42
|
+
not a pre-filing burst.
|
|
43
|
+
|
|
44
|
+
## 0. 🔴 CAN YOU PHYSICALLY SUBMIT? — do this in the FIRST week (scorecard row \`access\`)
|
|
45
|
+
|
|
46
|
+
**This skill owns the question no other unit of work owned**, and it is the one that bites. It is not
|
|
47
|
+
about the paper. It is about whether, on submit-day, there is anywhere to put it. Everything below in
|
|
48
|
+
this skill schedules *work*; this schedules *access*, and access has a lead time you do not control.
|
|
49
|
+
|
|
50
|
+
*Added 2026-08-03, after this was the sole critical-path item on a finished paper at **T−4 days**: the
|
|
51
|
+
science was done, the artifact was built, and the account could not submit.*
|
|
52
|
+
|
|
53
|
+
Concrete steps, all of them today, none of them deferrable:
|
|
54
|
+
|
|
55
|
+
1. **Create the portal account** (OpenReview / HotCRP / EasyChair / the venue's own). Not "find the
|
|
56
|
+
URL" — create the account.
|
|
57
|
+
2. **Drive the profile to ACTIVE.** 🔴 *"Pending moderation" is not an account you can submit from.*
|
|
58
|
+
Fill in every field moderation looks at — full name, affiliation history with dates, an ORCID or
|
|
59
|
+
DBLP/homepage link, and prior publications if the portal imports them; a sparse profile is what
|
|
60
|
+
gets queued rather than approved. Then **check back and confirm the state flipped**, and
|
|
61
|
+
**record the ISO date it went ACTIVE in the \`access\` row**, not just a tick.
|
|
62
|
+
3. **Confirm the form's fields** — open the actual submission form and read it. Title, abstract
|
|
63
|
+
(character cap?), track/type selector, subject areas, conflicts-of-interest, mandatory
|
|
64
|
+
declarations (GenAI/LLM use, ethics, dual-use), authors' order, and whether upload alone counts as
|
|
65
|
+
submitted or a separate **"ready for review"** click does.
|
|
66
|
+
4. **Confirm whether a supplementary-upload field EXISTS.** If it does not, the artifact needs an
|
|
67
|
+
**external anonymous host** (OSF view-only link / 4open) plus a \`\\url{}\` in Availability — and that
|
|
68
|
+
host has to be minted before submit-day, not on it. This is a real branch in the plan, not a detail.
|
|
69
|
+
5. **Re-check as the deadline approaches.** External state rots without telling you: a profile can be
|
|
70
|
+
flagged, a portal can open late or change its form. The CONTINUOUS trigger on the \`access\` row exists
|
|
71
|
+
for exactly this.
|
|
72
|
+
|
|
73
|
+
**The lead time, stated plainly:** portal moderation runs **up to two weeks**, and an author with **no
|
|
74
|
+
institutional email has no expedite route** — no support queue jump, no "I'm on a deadline" exception.
|
|
75
|
+
That is why \`access\` is scheduled in the first week rather than the last: it is the one item where the
|
|
76
|
+
only remedy for being late is having started earlier.
|
|
77
|
+
|
|
78
|
+
\`pipeline-check.mjs\` reports an \`access\` row still \`☐\` inside the moderation window as a finding, and
|
|
79
|
+
\`submit-paper\` is hard-blocked on \`access\` being green.
|
|
80
|
+
|
|
81
|
+
## 1. Build the timeline backwards from the AoE deadline
|
|
82
|
+
Everything that must be done *before* you can submit gets its own slot ending before the deadline —
|
|
83
|
+
never "the day of." Working back from the submission AoE date, reserve, in this order:
|
|
84
|
+
|
|
85
|
+
- **Draft frozen** — prose done, \`verify-citations\` clean. Earliest.
|
|
86
|
+
- **Harden** — \`paper-adversarial-review\` → \`pc-panel-review\` venue-fit mode, fix blockers, re-render.
|
|
87
|
+
Loops; give it room.
|
|
88
|
+
- **Panel review** — \`pc-panel-review\` (multi-reviewer + artifact-runner) as the final gate. 1–2 days.
|
|
89
|
+
- **Artifact built + hosted anonymously** — build the self-checking artifact and mint the OSF/4open
|
|
90
|
+
anonymized link (see \`submit-paper\` + \`paper-pipeline/references/artifact-checklist.md\`). This step
|
|
91
|
+
reliably eats more time than expected; put it before, not on, submit-day.
|
|
92
|
+
- **Submit-day = one day before AoE.** The real submission happens here, with slack for a HotCRP
|
|
93
|
+
surprise (no supplementary field, a re-paste, a "ready for review" step you forgot). Never plan to
|
|
94
|
+
submit on the deadline itself.
|
|
95
|
+
|
|
96
|
+
Rule of thumb: if the CFP is <2 weeks out, the artifact + panel review are what you cut scope on, not
|
|
97
|
+
the claim-sizing.
|
|
98
|
+
|
|
99
|
+
## 2. The AoE nuance (don't lose a day to it)
|
|
100
|
+
CFP deadline dates are **Anywhere-on-Earth (UTC−12)**. A deadline written "15 Jul AoE" does *not* expire
|
|
101
|
+
at your local midnight on the 15th — it expires when the last spot on Earth leaves the 15th:
|
|
102
|
+
|
|
103
|
+
\`\`\`
|
|
104
|
+
15 Jul 23:59 AoE = 16 Jul 11:59 UTC ≈ 16 Jul ~17:00 local, in a UTC+5 zone
|
|
105
|
+
\`\`\`
|
|
106
|
+
|
|
107
|
+
So the calendar date on the CFP is effectively the **next day at home**. This is slack, not a plan —
|
|
108
|
+
treat submit-day as the day before the *printed* date regardless, and let the AoE hours be your safety
|
|
109
|
+
margin, not your runway.
|
|
110
|
+
|
|
111
|
+
## 3. Create the calendar events (in the author's own zone)
|
|
112
|
+
Use \`mcp__Google_Calendar__create_event\` for three anchors per paper. 🔴 **Read the zone, do not
|
|
113
|
+
assume it** — it is the \`timezone\` carrier, and it is the author's, not the pipeline's:
|
|
114
|
+
|
|
115
|
+
\`\`\`
|
|
116
|
+
node -p "((p) => p.paperlint ?? p['research-paper-pipeline'])(require('./package.json'))?.timezone ?? 'UTC'"
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
The example below shows the default, \`UTC\`; substitute whatever that command prints.
|
|
120
|
+
Title them so the venue and the phase are unmistakable at a glance:
|
|
121
|
+
|
|
122
|
+
- **\`<Venue> — SUBMIT\`** on submit-day (one day before the printed AoE date). This is the one you act on.
|
|
123
|
+
- **\`<Venue> — deadline (AoE)\`** on the printed date, as a hard backstop.
|
|
124
|
+
- **\`<Venue> — camera-ready\`** on the camera-ready date (from the CFP), so acceptance doesn't ambush you
|
|
125
|
+
in a busy week.
|
|
126
|
+
|
|
127
|
+
\`summary\`, \`startTime\` **and \`endTime\`** are all required — the API rejects the call without the end
|
|
128
|
+
time, and a deadline anchor has no natural duration, so give it an hour and move on. Exact shape:
|
|
129
|
+
|
|
130
|
+
<!-- harness:prescribed-call create_event -->
|
|
131
|
+
\`\`\`json
|
|
132
|
+
{
|
|
133
|
+
"summary": "AISec 2026 — SUBMIT",
|
|
134
|
+
"startTime": "2026-07-23T10:00:00",
|
|
135
|
+
"endTime": "2026-07-23T11:00:00",
|
|
136
|
+
"timeZone": "UTC"
|
|
137
|
+
}
|
|
138
|
+
\`\`\`
|
|
139
|
+
|
|
140
|
+
Optionally add **notification** and **event/workshop** days as markers with \`"allDay": true\` — which
|
|
141
|
+
does not excuse you from \`startTime\`/\`endTime\`; they are still required and are read as midnight. Keep
|
|
142
|
+
the two review/host milestones (§1) as your own working reminders; the three above are the immovable ones.
|
|
143
|
+
|
|
144
|
+
> The block above is not decoration. \`plan-paper-timeline.effects.harness.mjs\` parses it out of this
|
|
145
|
+
> file and replays it against a stand-in server carrying the REAL API's schema, so a prescription this
|
|
146
|
+
> section gets wrong fails in the harness rather than on a live run. Edit it like code.
|
|
147
|
+
|
|
148
|
+
## 4. FILING-SPACING rule (the reason this skill exists)
|
|
149
|
+
Where the papers are the authorship pillar of some external filing — a grant, a tenure packet, an
|
|
150
|
+
immigration petition — **do not let multiple submissions or acceptances cluster in the month before
|
|
151
|
+
that filing.** A burst of activity right before a deadline reads as *manufactured* rather than
|
|
152
|
+
*sustained*, and that is a documented reason for refusal, not a stylistic worry. A steady cadence with
|
|
153
|
+
recent-but-not-crammed activity reads far better.
|
|
154
|
+
|
|
155
|
+
When scheduling paper N against papers already on the calendar and a known/likely filing date:
|
|
156
|
+
- Spread submission and (projected) notification dates across months; avoid two acceptances landing in
|
|
157
|
+
the same pre-filing window.
|
|
158
|
+
- If two CFPs force a cluster, stagger which one you *extend* later (workshop → conference) so the
|
|
159
|
+
second, stronger publication lands in a later month on purpose.
|
|
160
|
+
- Prefer a paper with an earlier, safely-past deadline over one that would pile onto the filing month.
|
|
161
|
+
|
|
162
|
+
## 5. Record the verdict
|
|
163
|
+
|
|
164
|
+
🔴 LAST step, once the deliverable exists:
|
|
165
|
+
|
|
166
|
+
\`\`\`
|
|
167
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record plan-paper-timeline <paper-dir> FINDING <count> <report-path>
|
|
168
|
+
node .claude/skills/paper-pipeline/scripts/ledger.mjs record plan-paper-timeline <paper-dir> ABSTAINED <reason> "<one line>"
|
|
169
|
+
\`\`\`
|
|
170
|
+
|
|
171
|
+
**FINDING** — \`<count>\` slots have no buffer, or collide with another paper's pre-filing window;
|
|
172
|
+
\`<report-path>\` is the plan. Add \`--blocking\` when the deadline cannot be met from here.
|
|
173
|
+
**ABSTAINED** — \`no-witness\`: the backwards plan is on the calendar, \`access\` is green and no slot
|
|
174
|
+
is tight. \`input-missing\`: \`find-venue\` has produced no dated deadline to plan against.
|
|
175
|
+
|
|
176
|
+
This is the one skill whose blocking finding is a fact about the calendar rather than about the
|
|
177
|
+
paper: portal moderation runs up to two weeks and an author with no institutional email has no
|
|
178
|
+
expedite route, so one recorded today is still true tomorrow no matter how good the science gets.
|
|
179
|
+
|
|
180
|
+
🔴 **There is no PASS**, so "the plan is on the calendar" is not storable here. Put the event ids in
|
|
181
|
+
the \`ABSTAINED\` note — markdown is the source of truth and the calendar is its projection, and a row
|
|
182
|
+
with neither is a claim about a calendar nobody opened.
|
|
183
|
+
|
|
184
|
+
## Scorecard rows this skill owns
|
|
185
|
+
Two, and they fail differently — see \`paper-pipeline/references/pipeline-status-template.md\`:
|
|
186
|
+
- **\`access\`** — *can you physically submit?* (§0). Account · profile ACTIVE since \`<ISO>\` · portal
|
|
187
|
+
reachable · form fields known · artifact-host requirement known. \`submit-paper\` is blocked on it.
|
|
188
|
+
- **\`schedule\`** — the schedule itself (§1–§4): the buffered backwards plan and its calendar events.
|
|
189
|
+
|
|
190
|
+
## Compose with
|
|
191
|
+
- **\`find-venue\`** — the source of the four CFP dates this skill consumes; run it first.
|
|
192
|
+
- **\`submit-paper\`** (+ the venue subskill) — what submit-day actually executes; this skill just makes
|
|
193
|
+
sure the runway before it exists, **and that the account it executes through is already ACTIVE**.
|
|
194
|
+
|
|
195
|
+
## Provenance
|
|
196
|
+
This session scheduled two real papers with spacing rather than back-to-back: **AgenticDev 2026 @ ASE**
|
|
197
|
+
(submission 15 Jul, notify 21 Aug, camera-ready 28 Aug, workshop 12 Oct) and **AISec 2026 @ ACM CCS**
|
|
198
|
+
(submission 24 Jul). Nine days apart, deliberately staggered so notifications and any camera-ready work
|
|
199
|
+
don't collapse into one pre-filing month — the FILING-SPACING rule applied in practice, not in theory.`,
|
|
200
|
+
});
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* A stand-in for the Google Calendar MCP server, used by
|
|
4
|
+
* `plan-paper-timeline.effects.harness.mjs` to make §3 of the skill EXECUTABLE in a
|
|
5
|
+
* test. Records every call instead of mutating anything.
|
|
6
|
+
*
|
|
7
|
+
* ── WHY A DOUBLE AND NOT A DENY ─────────────────────────────────────────────────
|
|
8
|
+
* A `PreToolUse` hook can only allow / deny / escalate — it cannot answer a call. A
|
|
9
|
+
* denied call ends the run, so nothing downstream of the effectful step is ever
|
|
10
|
+
* observed. Answering lets the run continue past it, which is the only way to see
|
|
11
|
+
* what the skill does with three events rather than one. Measured 2026-08-17,
|
|
12
|
+
* `vigiles/repro/mcp-double-2026-08-17/`.
|
|
13
|
+
*
|
|
14
|
+
* ── WHY IT IS STRICT, AND WHY THAT IS THE WHOLE POINT ───────────────────────────
|
|
15
|
+
* A permissive double would accept anything and the test would only be replaying its
|
|
16
|
+
* own script — a green light for arguments the real API rejects. So the schemas below
|
|
17
|
+
* are TRANSCRIBED FROM THE REAL SERVER (read off the live tool definitions on
|
|
18
|
+
* 2026-08-17) and the required-field sets are enforced. That makes the double an
|
|
19
|
+
* ORACLE: the unit under test is the CALL THE SKILL PRESCRIBES, and a prescription
|
|
20
|
+
* the real Google Calendar would reject fails here instead of at 3am on a real run.
|
|
21
|
+
*
|
|
22
|
+
* 🔴 If the real server's schema changes, this file is now WRONG in the quiet
|
|
23
|
+
* direction — it will keep passing calls the real API rejects. Re-read the live tool
|
|
24
|
+
* definitions when a calendar call fails in production despite a green harness.
|
|
25
|
+
*
|
|
26
|
+
* ── SAFETY ──────────────────────────────────────────────────────────────────────
|
|
27
|
+
* This process has no network and no credentials. It cannot reach a calendar even if
|
|
28
|
+
* asked. Under `--strict-mcp-config` (which the runner's `.mcp.json` path implies) the
|
|
29
|
+
* real `mcp__Google_Calendar__*` surface does not exist in the session at all, so the
|
|
30
|
+
* real calendar is not blocked here — it is UNREACHABLE. That is a stronger property
|
|
31
|
+
* than a deny rule and it is why this tier may finally call `create_event`, which the
|
|
32
|
+
* absence-pinning run next door deliberately never does.
|
|
33
|
+
*
|
|
34
|
+
* Calls are appended as JSONL to $FAKE_MCP_LOG.
|
|
35
|
+
*/
|
|
36
|
+
import { appendFileSync } from "node:fs";
|
|
37
|
+
|
|
38
|
+
const LOG = process.env.FAKE_MCP_LOG;
|
|
39
|
+
if (!LOG) {
|
|
40
|
+
// Failing closed matters more than it looks: with no log there is nothing to assert
|
|
41
|
+
// on, and a test that asserts on an empty list passes for the wrong reason.
|
|
42
|
+
process.stderr.write(
|
|
43
|
+
"fake-google-calendar: FAKE_MCP_LOG is unset; refusing to run blind\n",
|
|
44
|
+
);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Transcribed from the live tool definitions, 2026-08-17. `required` is the field
|
|
50
|
+
* that carries the weight — everything else is here so an unknown key is detectable.
|
|
51
|
+
*/
|
|
52
|
+
const TOOLS = {
|
|
53
|
+
create_event: {
|
|
54
|
+
description: "Creates an event on the given calendar.",
|
|
55
|
+
required: ["summary", "startTime", "endTime"],
|
|
56
|
+
known: [
|
|
57
|
+
"summary",
|
|
58
|
+
"startTime",
|
|
59
|
+
"endTime",
|
|
60
|
+
"timeZone",
|
|
61
|
+
"allDay",
|
|
62
|
+
"calendarId",
|
|
63
|
+
"description",
|
|
64
|
+
"location",
|
|
65
|
+
"colorId",
|
|
66
|
+
"visibility",
|
|
67
|
+
"availability",
|
|
68
|
+
"eventType",
|
|
69
|
+
"attendees",
|
|
70
|
+
"attachments",
|
|
71
|
+
"recurrenceData",
|
|
72
|
+
"overrideReminders",
|
|
73
|
+
"notificationLevel",
|
|
74
|
+
"addGoogleMeetUrl",
|
|
75
|
+
"googleMeetUrl",
|
|
76
|
+
"guestPermissions",
|
|
77
|
+
"workingLocationProperties",
|
|
78
|
+
"attendeeEmails",
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
update_event: {
|
|
82
|
+
description: "Updates an event on the given calendar.",
|
|
83
|
+
required: ["eventId"],
|
|
84
|
+
known: [
|
|
85
|
+
"eventId",
|
|
86
|
+
"summary",
|
|
87
|
+
"startTime",
|
|
88
|
+
"endTime",
|
|
89
|
+
"timeZone",
|
|
90
|
+
"allDay",
|
|
91
|
+
"calendarId",
|
|
92
|
+
"description",
|
|
93
|
+
"location",
|
|
94
|
+
"colorId",
|
|
95
|
+
"visibility",
|
|
96
|
+
"availability",
|
|
97
|
+
"addedAttendees",
|
|
98
|
+
"removedAttendeeEmails",
|
|
99
|
+
"addedAttachments",
|
|
100
|
+
"removedAttachmentFileUrls",
|
|
101
|
+
"overrideReminders",
|
|
102
|
+
"notificationLevel",
|
|
103
|
+
"addGoogleMeetUrl",
|
|
104
|
+
"googleMeetUrl",
|
|
105
|
+
"guestPermissions",
|
|
106
|
+
"addedAttendeeEmails",
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
list_events: {
|
|
110
|
+
description:
|
|
111
|
+
"Returns events on the given calendar matching all specified constraints.",
|
|
112
|
+
required: [],
|
|
113
|
+
known: [
|
|
114
|
+
"calendarId",
|
|
115
|
+
"startTime",
|
|
116
|
+
"endTime",
|
|
117
|
+
"timeZone",
|
|
118
|
+
"orderBy",
|
|
119
|
+
"pageSize",
|
|
120
|
+
"pageToken",
|
|
121
|
+
"fullText",
|
|
122
|
+
"eventType",
|
|
123
|
+
"eventTypeFilter",
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
search_events: {
|
|
127
|
+
description: "Searches events on the primary calendar by keyword or topic.",
|
|
128
|
+
required: ["query"],
|
|
129
|
+
known: [
|
|
130
|
+
"query",
|
|
131
|
+
"calendarId",
|
|
132
|
+
"startTime",
|
|
133
|
+
"endTime",
|
|
134
|
+
"timeZone",
|
|
135
|
+
"pageSize",
|
|
136
|
+
"pageToken",
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const schemaOf = (spec) => ({
|
|
142
|
+
type: "object",
|
|
143
|
+
properties: Object.fromEntries(spec.known.map((k) => [k, {}])),
|
|
144
|
+
required: spec.required,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
let created = 0;
|
|
148
|
+
|
|
149
|
+
/** @returns {string|null} the reason this call would be rejected, or null if it is well-formed. */
|
|
150
|
+
function reject(name, args) {
|
|
151
|
+
const spec = TOOLS[name];
|
|
152
|
+
if (!spec) return `no such tool: ${name}`;
|
|
153
|
+
const a = args ?? {};
|
|
154
|
+
const missing = spec.required.filter(
|
|
155
|
+
(k) => a[k] === undefined || a[k] === "",
|
|
156
|
+
);
|
|
157
|
+
if (missing.length)
|
|
158
|
+
return `missing required argument(s): ${missing.join(", ")} — the real Google Calendar API rejects this call`;
|
|
159
|
+
const unknown = Object.keys(a).filter((k) => !spec.known.includes(k));
|
|
160
|
+
if (unknown.length)
|
|
161
|
+
return `unknown argument(s): ${unknown.join(", ")} — not fields of ${name} on the real server`;
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let buf = "";
|
|
166
|
+
process.stdin.on("data", (chunk) => {
|
|
167
|
+
buf += chunk;
|
|
168
|
+
let nl;
|
|
169
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
170
|
+
const line = buf.slice(0, nl).trim();
|
|
171
|
+
buf = buf.slice(nl + 1);
|
|
172
|
+
if (!line) continue;
|
|
173
|
+
let msg;
|
|
174
|
+
try {
|
|
175
|
+
msg = JSON.parse(line);
|
|
176
|
+
} catch {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const send = (payload) =>
|
|
180
|
+
process.stdout.write(
|
|
181
|
+
JSON.stringify({ jsonrpc: "2.0", id: msg.id, ...payload }) + "\n",
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (msg.method === "initialize") {
|
|
185
|
+
send({
|
|
186
|
+
result: {
|
|
187
|
+
protocolVersion: "2024-11-05",
|
|
188
|
+
capabilities: { tools: {} },
|
|
189
|
+
serverInfo: { name: "fake-google-calendar", version: "1.0.0" },
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
} else if (msg.method === "tools/list") {
|
|
193
|
+
send({
|
|
194
|
+
result: {
|
|
195
|
+
tools: Object.entries(TOOLS).map(([name, spec]) => ({
|
|
196
|
+
name,
|
|
197
|
+
description: spec.description,
|
|
198
|
+
inputSchema: schemaOf(spec),
|
|
199
|
+
})),
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
} else if (msg.method === "tools/call") {
|
|
203
|
+
const name = msg.params?.name;
|
|
204
|
+
const args = msg.params?.arguments ?? {};
|
|
205
|
+
const why = reject(name, args);
|
|
206
|
+
// Every call is logged, accepted or not. A rejected call that left no trace
|
|
207
|
+
// would be indistinguishable from a call that never happened.
|
|
208
|
+
appendFileSync(
|
|
209
|
+
LOG,
|
|
210
|
+
JSON.stringify({ name, args, ok: why === null, why }) + "\n",
|
|
211
|
+
);
|
|
212
|
+
if (why) {
|
|
213
|
+
send({
|
|
214
|
+
result: {
|
|
215
|
+
isError: true,
|
|
216
|
+
content: [{ type: "text", text: `INVALID CALL: ${why}` }],
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
} else {
|
|
220
|
+
created += 1;
|
|
221
|
+
send({
|
|
222
|
+
result: {
|
|
223
|
+
content: [
|
|
224
|
+
{
|
|
225
|
+
type: "text",
|
|
226
|
+
text: JSON.stringify({
|
|
227
|
+
id: `evt_fake_${String(created)}`,
|
|
228
|
+
status: "confirmed",
|
|
229
|
+
}),
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
} else if (msg.id !== undefined) {
|
|
236
|
+
send({ result: {} });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|