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,538 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Occupancy research — deterministic prose/readability checkers vs. semantically-opaque-but-simple prose"
|
|
3
|
+
created: 2026-08-06
|
|
4
|
+
tags:
|
|
5
|
+
[
|
|
6
|
+
occupancy-research,
|
|
7
|
+
prose-linting,
|
|
8
|
+
readability,
|
|
9
|
+
paper-pipeline,
|
|
10
|
+
cold-read,
|
|
11
|
+
vale,
|
|
12
|
+
textlint,
|
|
13
|
+
retext,
|
|
14
|
+
proselint,
|
|
15
|
+
coh-metrix,
|
|
16
|
+
coreference,
|
|
17
|
+
]
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Occupancy research: does any shipped checker catch "short, grammatical, correct — parseable only if you already know the idea"?
|
|
21
|
+
|
|
22
|
+
## Headline finding (read this first)
|
|
23
|
+
|
|
24
|
+
**No shipped deterministic tool detects the actual defect.** Every mechanical checker in this
|
|
25
|
+
space — Vale, textlint/retext, proselint, write-good, alex, LanguageTool, Hemingway, Grammarly,
|
|
26
|
+
Acrolinx, every readability formula (Flesch-Kincaid, Gunning Fog, SMOG, Coleman-Liau, ARI,
|
|
27
|
+
Dale-Chall, Lexile) — measures **surface form**: word length, syllable count, sentence length,
|
|
28
|
+
passive voice, a fixed word/phrase blocklist. None of them model **whether the reader already
|
|
29
|
+
holds the referent the sentence assumes**. The literature has a name for the thing that would be
|
|
30
|
+
needed — cohesion/coherence modeling, entity-grid coreference tracking (Barzilay & Lapata 2008)
|
|
31
|
+
— and it exists only as academic research code (one toolkit, "Cohere," built for corpus
|
|
32
|
+
evaluation, not as a linter you run on a draft) and inside Coh-Metrix (a research instrument,
|
|
33
|
+
not a red/green pass-fail checker). **Nothing in this space ships as "flag this sentence, a
|
|
34
|
+
reader without your mental model cannot parse it."**
|
|
35
|
+
|
|
36
|
+
I verified this empirically, not just by reading docs — I ran the actual tools (proselint,
|
|
37
|
+
write-good, retext-readability via textstat/npm, all installed and executed in this session)
|
|
38
|
+
against the six sentences below. Results are in the table at the end. The one mechanical thing
|
|
39
|
+
that _does_ fire — sentence-length/clause-count thresholds — only catches sentence 6 (the long,
|
|
40
|
+
syntactically loaded one). Sentences 1–5, the ones a human immediately called "wtf" / "what" /
|
|
41
|
+
"VAGUE AF", passed every tool at every reasonable threshold. The only way one of them lit up at
|
|
42
|
+
all was setting retext-readability's target age to 6 years old — at which point it also flags
|
|
43
|
+
ordinary adult prose indiscriminately, so that's not a usable signal either.
|
|
44
|
+
|
|
45
|
+
This matches the author's own report: the homegrown `prose-lint.mjs` and the LLM-persona grader
|
|
46
|
+
don't catch this because **no comparable tool in the wild catches it either** — this is not a
|
|
47
|
+
gap specific to the homegrown implementation, it's a gap in the entire deterministic-checker
|
|
48
|
+
category. What's needed for these six sentences is a reader (human or LLM) simulating "I don't
|
|
49
|
+
already know what 'the rule' claims about itself" — i.e., exactly the `cold-read-diff` /
|
|
50
|
+
persona-stall pattern already in this pipeline, not a metric.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## The test set (verbatim, as given)
|
|
55
|
+
|
|
56
|
+
1. _"The state to remove is therefore not the rule but its claim about itself"_ — reaction: "wtf"
|
|
57
|
+
2. _"these files are filled with constructions nobody built"_ — "wtf"
|
|
58
|
+
3. _"Three answers, all of them after the fact"_ (section heading) — "VAGUE AF"
|
|
59
|
+
4. _"§4.4 invites the suspicion that the resolver guesses"_ — "what"
|
|
60
|
+
5. _"The only part that reads English is the one not allowed to decide anything. It proposes; the other two dispose."_ — "needs full rewrite confusing af"
|
|
61
|
+
6. A sentence carrying six separate factual claims joined by dashes/semicolons (exact original
|
|
62
|
+
text not given to me — I constructed a representative stand-in of the same shape for testing:
|
|
63
|
+
_"The audit found six problems: the config was stale, the hook silently no-ops on error, the
|
|
64
|
+
guard reads a variable the harness never sets, the fallback path was never tested, the log
|
|
65
|
+
rotates before anyone reads it, and the alert fires into a channel nobody watches."_ — this is
|
|
66
|
+
a **reconstruction**, not the original, flagged so it isn't mistaken for a quote later.)
|
|
67
|
+
|
|
68
|
+
### Empirical readability numbers (textstat 0.7.13, run locally)
|
|
69
|
+
|
|
70
|
+
| # | words | Flesch reading ease | FK grade | Gunning Fog | Coleman-Liau | ARI | Dale-Chall |
|
|
71
|
+
| --- | ------------ | ----------------------- | -------- | ----------- | ------------ | -------- | ---------- |
|
|
72
|
+
| 1 | 14 | 83.9 (easy) | 5.0 | 5.6 | 6.5 | 5.8 | 6.6 |
|
|
73
|
+
| 2 | 8 | 71.8 (fairly easy) | 5.2 | 8.2 | 14.6 | 10.8 | 10.0 |
|
|
74
|
+
| 3 | 8 | 93.0 (very easy) | 2.3 | 3.2 | 4.4 | 3.2 | 6.0 |
|
|
75
|
+
| 4 | 9 | 56.7 (fairly difficult) | 7.6 | 8.0 | 13.1 | 10.3 | 14.6 |
|
|
76
|
+
| 5 | 20 (2 sent.) | 69.8 (fairly easy) | 6.0 | 6.0 | 7.1 | 5.2 | 7.3 |
|
|
77
|
+
| 6 | 46 | 29.6 (difficult) | **20.6** | **20.1** | 10.2 | **24.0** | 12.1 |
|
|
78
|
+
|
|
79
|
+
Every published deterministic tool's threshold for "flag this" lives in the FK-grade-8-to-12 /
|
|
80
|
+
Flesch-under-50 range. On that basis: sentences 1, 2, 3, 5 are **invisible** to every formula in
|
|
81
|
+
this table — grade level 2 to 7, "easy" to "fairly easy." Sentence 4 sits right at a common
|
|
82
|
+
threshold (grade 7.6, Flesch 56.7) — borderline, would fire on strict configs, not on defaults.
|
|
83
|
+
Sentence 6 blows every ceiling (grade 20+) purely because it's long, not because of the six-claims
|
|
84
|
+
structure specifically — a single 46-word sentence about anything would trip the same alarm.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Tool-by-tool
|
|
89
|
+
|
|
90
|
+
### Vale (errata-ai)
|
|
91
|
+
|
|
92
|
+
**What it is:** The dominant open-source prose linter. Config-driven (YAML rules organized into
|
|
93
|
+
"styles"), CI-native, markup-aware (Markdown/AsciiDoc/reST/HTML). [github.com/errata-ai/vale](https://github.com/errata-ai/vale)
|
|
94
|
+
|
|
95
|
+
**Alive?** Yes, actively maintained — latest release **v3.17.1** (Aug 2024), with a steady
|
|
96
|
+
release cadence through 2024 and 5.7k GitHub stars; no signs of abandonment as of this research.
|
|
97
|
+
|
|
98
|
+
**Rule mechanics:** Rules extend one of several check types — `existence`, `substitution`,
|
|
99
|
+
`occurrence`, `repetition`, `consistency`, `conditional`, `capitalization`, `sequence`, and
|
|
100
|
+
**`readability`**. `existence`/`substitution` are regex-over-tokens; they can absolutely match
|
|
101
|
+
"N semicolons in one sentence" or "3+ commas in one sentence" as a proxy for clause count — but
|
|
102
|
+
this is a **structural/punctuation proxy**, not a semantic one, and I found no shipped Vale style
|
|
103
|
+
(Microsoft, Google, Red Hat, write-good port, Joblint) that actually ships such a rule. Someone
|
|
104
|
+
_could_ author one; nobody has.
|
|
105
|
+
|
|
106
|
+
**Does it ship a readability rule?** Yes — `extends: readability`, config example:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
extends: readability
|
|
110
|
+
message: "Content must be readable at 6th grade level (current: %s)"
|
|
111
|
+
level: error
|
|
112
|
+
grade: 6
|
|
113
|
+
metrics:
|
|
114
|
+
- Flesch-Kincaid
|
|
115
|
+
- Coleman-Liau
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
It supports Flesch-Kincaid, Coleman-Liau, and other classic formulas (implementations live in
|
|
119
|
+
[github.com/errata-ai/readability](https://github.com/errata-ai/readability)), averaging across
|
|
120
|
+
whichever metrics you list. **Critical limitation for this exact problem: the rule is scoped to
|
|
121
|
+
`summary` level — it evaluates a whole document/section's aggregate grade level, not individual
|
|
122
|
+
sentences.** A single opaque-but-short sentence sitting inside an otherwise normal-grade-level
|
|
123
|
+
document will not move the aggregate enough to trip a document-level threshold. It structurally
|
|
124
|
+
cannot do what's being asked here — flag sentence 1 in isolation — even in principle, without a
|
|
125
|
+
custom re-scoped rule nobody ships.
|
|
126
|
+
|
|
127
|
+
**Ecosystem it pulls in:** Microsoft Writing Style Guide and Google Developer Docs Style Guide
|
|
128
|
+
(both Vale-compatible ports, actively maintained), write-good, proselint, alex, Joblint, Red Hat
|
|
129
|
+
style — all as separate installable "styles," same YAML rule engine, same limitation (surface
|
|
130
|
+
regex/word-list/readability-formula, nothing semantic).
|
|
131
|
+
[github.com/vale-cli/Microsoft](https://github.com/vale-cli/Microsoft) ·
|
|
132
|
+
[github.com/vale-cli/Google](https://github.com/vale-cli/Google) ·
|
|
133
|
+
[github.com/vale-cli/Joblint](https://github.com/vale-cli/Joblint) ·
|
|
134
|
+
Red Hat reference: [redhat-documentation.github.io/vale-at-red-hat](https://redhat-documentation.github.io/vale-at-red-hat/reference-guide.html)
|
|
135
|
+
(has "define acronyms/abbreviations on first occurrence" as a rule — see term-first-use section
|
|
136
|
+
below).
|
|
137
|
+
|
|
138
|
+
**Would it flag the 6 test sentences?** No on 1, 2, 3, 5 (short, simple words, well under any
|
|
139
|
+
grade threshold, and readability is document-scoped anyway so it wouldn't even see them
|
|
140
|
+
individually). Borderline-possible on 4 depending on threshold. Would flag 6 on length alone if
|
|
141
|
+
`readability` were scoped per-sentence (it isn't, by default) or if a custom `existence` rule
|
|
142
|
+
counted commas/semicolons.
|
|
143
|
+
|
|
144
|
+
**Adoption cost:** Low-to-medium. Single Go binary, YAML config, drop into CI as a lint step;
|
|
145
|
+
Microsoft/Google style packs are drop-in. Main cost is authoring custom rules for anything beyond
|
|
146
|
+
the shipped styles — and nothing shipped touches semantic opacity.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### textlint (JS ecosystem) + retext / unified (remark family)
|
|
151
|
+
|
|
152
|
+
**What they are:** textlint is a pluggable Markdown/text linter (JS); retext is the prose-analysis
|
|
153
|
+
half of the `unified`/`remark` toolchain — same AST pipeline as remark, so it composes naturally
|
|
154
|
+
if the source is Markdown. `retext-textlint` bridges the two.
|
|
155
|
+
[github.com/textlint/textlint](https://github.com/textlint/textlint) ·
|
|
156
|
+
[github.com/retextjs](https://github.com/retextjs)
|
|
157
|
+
|
|
158
|
+
**retext-readability** — actually tested, not just read about.
|
|
159
|
+
[github.com/retextjs/retext-readability](https://github.com/retextjs/retext-readability), v8.0.0.
|
|
160
|
+
Applies 7 formulas (Dale–Chall, Automated Readability, Coleman-Liau, Flesch, Gunning-Fog, SMOG,
|
|
161
|
+
Spache) **per sentence** (unlike Vale, this one _is_ sentence-scoped) and fires when a
|
|
162
|
+
configurable fraction agree ("threshold," default `4/7`) the sentence is hard for a configurable
|
|
163
|
+
target `age` (default 16).
|
|
164
|
+
|
|
165
|
+
**Ran it live, two configs:**
|
|
166
|
+
|
|
167
|
+
- **Default** (age 16, minWords 5, threshold 4/7 — i.e. realistic adult-audience settings): flags
|
|
168
|
+
**only sentence 6** ("5 out of 7 algorithms"). Sentences 1–5 all report "no issues found."
|
|
169
|
+
- **Maximally strict** (age 6, minWords 1, threshold 1/7 — i.e. "flag anything a first-grader
|
|
170
|
+
might struggle with"): flags **all six**, sentences 1–5 at "6 out of 7 algorithms," sentence 6
|
|
171
|
+
at "all 7." This setting is unusable in practice — it would also flag nearly all ordinary adult
|
|
172
|
+
technical or literary prose, because the formulas are keyed to vocabulary/syllable difficulty
|
|
173
|
+
for a 6-year-old, not to "does this presuppose an idea the reader doesn't have." It's not
|
|
174
|
+
detecting the target defect; it's detecting _any_ adult-level word choice.
|
|
175
|
+
|
|
176
|
+
This is the cleanest empirical proof of the headline finding: there is no threshold setting
|
|
177
|
+
between "misses everything real" and "flags everything indiscriminately" that isolates the actual
|
|
178
|
+
defect.
|
|
179
|
+
|
|
180
|
+
**retext-simplify** — flags wordy multi-word phrases against a simpler-alternative dictionary
|
|
181
|
+
(e.g. "in order to" → "to"). Word-substitution list, not semantic.
|
|
182
|
+
[npmjs.com/package/retext-simplify](https://www.npmjs.com/package/retext-simplify)
|
|
183
|
+
|
|
184
|
+
**retext-passive, retext-equality (→ alex)** — passive-voice detection and inclusive-language
|
|
185
|
+
detection respectively; same category as write-good/alex below.
|
|
186
|
+
|
|
187
|
+
**Would they flag the test set?** Same verdict as the empirical run above — retext-readability at
|
|
188
|
+
realistic settings: only #6. retext-simplify: none of the six contain its blocklisted wordy
|
|
189
|
+
phrases. None of the retext family models coreference/discourse.
|
|
190
|
+
|
|
191
|
+
**Adoption cost:** Low if the corpus is Markdown already (natural fit with remark pipeline);
|
|
192
|
+
requires Node tooling. Actively maintained (Titus Wormer / unified ecosystem, frequent releases).
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### proselint
|
|
197
|
+
|
|
198
|
+
**What it is:** Rule-based Python prose linter, rules drawn from published style guides
|
|
199
|
+
(Strunk & White, Fowler's, Garner's, etc.) plus its own heuristics — clichés, jargon,
|
|
200
|
+
"very"-type weak intensifiers, corporate speak, "there is/are" openers, redundancy.
|
|
201
|
+
[github.com/amperser/proselint](https://github.com/amperser/proselint)
|
|
202
|
+
|
|
203
|
+
**Alive?** v0.16.0 (Nov 2022) is the latest tagged release — over 3 years old at time of writing,
|
|
204
|
+
though the repo shows a 5x perf rewrite and JSON output in that release and issue activity
|
|
205
|
+
continues. Best characterized as **maintained but slow-moving**, not actively shipping new rule
|
|
206
|
+
categories.
|
|
207
|
+
|
|
208
|
+
**Ran it live:** Installed `proselint==0.16.0`, ran `proselint check` against all six sentences.
|
|
209
|
+
**Result: zero warnings, exit code 0, across all six sentences combined.** Not one of proselint's
|
|
210
|
+
~30 rule categories (weasel words, "obviously"/"of course" condescension, "very"-hedging, sexism,
|
|
211
|
+
redundancy, jargon-from-a-fixed-list, cliché-matching, etc.) matched anything in the test set.
|
|
212
|
+
This is the starkest empirical null result in this report.
|
|
213
|
+
|
|
214
|
+
**Adoption cost:** Trivial — `pip install proselint`, CLI or JSON output, works on plain text.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### write-good
|
|
219
|
+
|
|
220
|
+
**What it is:** "Naive linter for English prose" (its own description). Checks: passive voice,
|
|
221
|
+
lexical illusion (doubled words), sentence-initial "so", sentence-initial "there is/are", weasel
|
|
222
|
+
words (from a fixed list — "many," "various," "fairly," etc.), weakening adverbs ("really," "very,"
|
|
223
|
+
"extremely"), "tooWordy" phrase list, clichés, and (opt-in) E-Prime ("to be" verb) detection.
|
|
224
|
+
[github.com/btford/write-good](https://github.com/btford/write-good)
|
|
225
|
+
|
|
226
|
+
**Ran it live** (npm, current version): flagged something on 4 of 6 sentences, all trivial
|
|
227
|
+
style nits, none related to the actual defect:
|
|
228
|
+
|
|
229
|
+
- #1 "therefore" → wordy
|
|
230
|
+
- #2 "are filled" → possible passive voice
|
|
231
|
+
- #3 "all of" → wordy
|
|
232
|
+
- #4 → **nothing**
|
|
233
|
+
- #5 "only" → weakening adverb
|
|
234
|
+
- #6 "silently" → weakening adverb
|
|
235
|
+
|
|
236
|
+
None of these flags bear on why the sentences read as opaque. write-good's checks are
|
|
237
|
+
regex/word-list matches; it has no model of sentence meaning at all.
|
|
238
|
+
|
|
239
|
+
**Adoption cost:** Trivial, npm install, `write-good` CLI or `write-good` npm module for
|
|
240
|
+
programmatic use; also available as a Vale-compatible style pack and a coala-bears linter bear.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### alex
|
|
245
|
+
|
|
246
|
+
**What it is:** Catches "insensitive, inconsiderate" language — gendered, ableist, homophobic
|
|
247
|
+
etc. — built on `retext-equality`. Not a readability tool at all; listed here because it's part
|
|
248
|
+
of the same rule-based-linter family and gets reached for reflexively.
|
|
249
|
+
[github.com/get-alex/alex](https://github.com/get-alex/alex)
|
|
250
|
+
|
|
251
|
+
**Would it flag the test set?** No — none of the six sentences contain flagged terminology.
|
|
252
|
+
Out of scope by design.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### LanguageTool
|
|
257
|
+
|
|
258
|
+
**What it is:** Grammar/spelling/style checker, Java-based, self-hostable server, has an
|
|
259
|
+
optional stricter **Picky mode** that adds stylistic rules beyond core grammar (redundancy,
|
|
260
|
+
some word-choice nudges, punctuation style).
|
|
261
|
+
[github.com/languagetool-org/languagetool](https://github.com/languagetool-org/languagetool)
|
|
262
|
+
|
|
263
|
+
**Alive?** Very actively maintained — v6.8 released May 2026, repo updated as recently as
|
|
264
|
+
July 2026, moved to a rolling snapshot release model in March 2025 rather than dated version tags.
|
|
265
|
+
|
|
266
|
+
**Would it flag the test set?** Grammar/spelling checks find nothing (all six sentences are
|
|
267
|
+
grammatical). Picky mode's added stylistic rules are still surface pattern-matches (redundant
|
|
268
|
+
phrasing, some clichés, punctuation nits) — same category as write-good/proselint, not semantic.
|
|
269
|
+
No evidence found of a coherence/coreference layer in LanguageTool.
|
|
270
|
+
|
|
271
|
+
**Adoption cost:** Low-medium; self-hostable Docker image, has an HTTP API, editor plugins.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
### Hemingway Editor
|
|
276
|
+
|
|
277
|
+
**What it is:** Commercial web/desktop editor. Highlights: sentence length via color-coding
|
|
278
|
+
(yellow = hard to read, red = very hard to read), passive voice, unnecessary adverbs, and
|
|
279
|
+
"complex words" with simpler-alternative suggestions. Reports a grade-level score, same family
|
|
280
|
+
of formula as Flesch-Kincaid.
|
|
281
|
+
[hemingwayapp.com](https://hemingwayapp.com/)
|
|
282
|
+
|
|
283
|
+
**What it does NOT do (their own limitation, confirmed via review sources):** No grammar
|
|
284
|
+
checking (misses agreement errors, article mistakes, tense issues) and, same as everything else
|
|
285
|
+
here, no semantic/coherence model — it is sentence-length + word-list + passive-voice detection
|
|
286
|
+
with a friendlier UI.
|
|
287
|
+
|
|
288
|
+
**Would it flag the test set?** Same profile as the formula table above — sentences 1, 2, 3, 5
|
|
289
|
+
would render mostly un-highlighted (short, simple words); sentence 6 would be flagged red for
|
|
290
|
+
length. Not usable for this defect.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
### Grammarly (Business API), Acrolinx, Expound
|
|
295
|
+
|
|
296
|
+
**Grammarly:** Ships a documented "vague pronoun reference" category under its Clarity
|
|
297
|
+
suggestions in consumer product marketing copy, per third-party writing-center sources that cite
|
|
298
|
+
Grammarly's blog content on the topic — but I could not confirm, from Grammarly's own official
|
|
299
|
+
help-center documentation, that this is a reliably-firing automated check versus aspirational
|
|
300
|
+
product-marketing language, and could not test it directly (no API access in this environment).
|
|
301
|
+
**Mark this [C]/unverified** — it's the single closest-sounding shipped feature to "pronoun with
|
|
302
|
+
no antecedent" in this whole survey, and it deserves a real test with the actual six sentences
|
|
303
|
+
before anyone relies on it. Sentence 5's "It proposes; the other two dispose" is exactly the
|
|
304
|
+
shape of construction a vague-pronoun-reference check is meant to catch (what does "It" refer
|
|
305
|
+
to two sentences up?) — but "the other two" as an unintroduced definite reference is a distinct
|
|
306
|
+
and probably-uncaught failure mode even if the "It" itself resolves grammatically.
|
|
307
|
+
|
|
308
|
+
**Acrolinx:** Enterprise content-governance platform. Its "Clarity"/readability scoring is
|
|
309
|
+
explicitly formula-based (sentence length, syllables, word choice) layered with brand
|
|
310
|
+
terminology/tone rules — confirmed via Acrolinx's own blog content. No cohesion/coreference
|
|
311
|
+
modeling found. Enterprise pricing, heavy adoption cost, wrong shape of tool for a solo author's
|
|
312
|
+
paper pipeline regardless.
|
|
313
|
+
|
|
314
|
+
**Expound:** Searched specifically for a prose-linting tool by this name — found nothing. Either
|
|
315
|
+
it doesn't exist as a shipped tool, is too obscure to surface in search, or the name refers to
|
|
316
|
+
something not in this category. Reporting the null result rather than guessing.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
### Readability formulas and their published critique
|
|
321
|
+
|
|
322
|
+
Flesch-Kincaid, Gunning Fog, SMOG, Coleman-Liau, ARI, Dale-Chall — all in the same family:
|
|
323
|
+
count words, syllables, sentence length, run them through a linear regression fit to human grade
|
|
324
|
+
levels decades ago (Flesch's original work was WWII-era Navy training manuals; Dale-Chall is
|
|
325
|
+
built around a fixed "familiar word" list from 1948, later revised).
|
|
326
|
+
|
|
327
|
+
**The critique, found directly in this research (not asserted from memory):**
|
|
328
|
+
|
|
329
|
+
- These formulas were "developed for children's school books, not adult technical
|
|
330
|
+
documentation; they ignore between-reader differences and the effects of content, layout, and
|
|
331
|
+
retrieval aids on text usefulness" — from the UXmatters "7 Reasons to Avoid Them" piece
|
|
332
|
+
surfaced in this search.
|
|
333
|
+
- They are "not intended to directly measure ease of comprehension, but rather readability" —
|
|
334
|
+
i.e. the formulas were validated against oral-reading grade-level norms, not against whether a
|
|
335
|
+
reader extracts the correct meaning.
|
|
336
|
+
- Direct, cited comparison found in this research: **"Comparisons indicated that the Coh-Metrix
|
|
337
|
+
formula was significantly more accurate in predicting reading difficulty than the Flesch
|
|
338
|
+
Reading Ease and Flesch-Kincaid Grade Level formulas"** — because Coh-Metrix adds cohesion,
|
|
339
|
+
world-knowledge, and discourse variables the classic formulas ignore entirely.
|
|
340
|
+
- textstat's own numbers above make the critique concrete: sentence 4 (genuinely one of the
|
|
341
|
+
more confusing ones — "§4.4 invites the suspicion that the resolver guesses" personifies a
|
|
342
|
+
document section and uses "invites the suspicion" idiomatically) scores _worse_ by Dale-Chall
|
|
343
|
+
(14.6, "difficult") than sentence 6 does by that same formula (12.1) — the formula is
|
|
344
|
+
responding to unfamiliar-word-list hits ("resolver," "suspicion"), not to the actual
|
|
345
|
+
comprehension problem, which is structural/referential, not lexical.
|
|
346
|
+
|
|
347
|
+
**Lexile:** A commercial/education-market framework (MetaMetrics), same formula family
|
|
348
|
+
(word frequency + sentence length), used mostly for matching children's/YA books to reading
|
|
349
|
+
levels; not positioned or used as a prose-quality linter for technical writing at all.
|
|
350
|
+
|
|
351
|
+
**textstat / py-readability-metrics (Python):** Implementation libraries, not checkers with
|
|
352
|
+
opinions — they compute the same formula family (Flesch, FK grade, Gunning Fog, SMOG,
|
|
353
|
+
Coleman-Liau, ARI, Dale-Chall, plus some less common ones like Linsear Write, Fernandez-Huerta,
|
|
354
|
+
Szigriszt-Pazos). Used to build a custom Vale/CI gate, but the ceiling is the formula family's
|
|
355
|
+
own ceiling — this is what was run directly, live, to produce the numbers table above.
|
|
356
|
+
[github.com/textstat/textstat](https://github.com/textstat/textstat) ·
|
|
357
|
+
[py-readability-metrics.readthedocs.io](https://py-readability-metrics.readthedocs.io/en/latest/)
|
|
358
|
+
|
|
359
|
+
**Coh-Metrix — the closest thing academically, and worth understanding precisely:**
|
|
360
|
+
Built at University of Memphis (Graesser, McNamara et al.), it computes 100+ measures across
|
|
361
|
+
cohesion (referential overlap between sentences, argument overlap, causal/logical connectives,
|
|
362
|
+
LSA-based semantic similarity between adjacent sentences), not just surface word/sentence length.
|
|
363
|
+
It genuinely targets "does this text hang together for a reader" rather than "are the words
|
|
364
|
+
short." **But: it is a research instrument, not a pass/fail linter.** Two free web versions
|
|
365
|
+
exist (Coh-Metrix 3.0 at the University of Memphis's hosted tool, and a "CohMetrixCore Web"
|
|
366
|
+
instance — [iis.memphis.edu/static/cohmetrix](https://iis.memphis.edu/static/cohmetrix/)) but it
|
|
367
|
+
outputs ~100+ numeric indices for a _whole document_, calibrated against corpora of student/
|
|
368
|
+
textbook writing — no accept/reject threshold, no per-sentence flag, no CI integration, and one
|
|
369
|
+
cited limitation notes findings "could be generalized only to a specific genre of texts"
|
|
370
|
+
(academic prose corpora it was validated on). Nobody runs Coh-Metrix as a pre-commit hook. It is
|
|
371
|
+
the right _idea_ — cohesion over word length — with none of the packaging that would make it
|
|
372
|
+
adoptable tomorrow.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### Cohesion / coreference / referential clarity — the closest thing to the actual defect
|
|
377
|
+
|
|
378
|
+
This is the section that matters most, and the honest answer is short: **it does not exist as a
|
|
379
|
+
usable shipped tool.** What exists:
|
|
380
|
+
|
|
381
|
+
- **Entity-grid coherence models** (Barzilay & Lapata, 2008) — represent a document as a grid of
|
|
382
|
+
which entities appear in which grammatical role (subject/object/other) across sentences, and
|
|
383
|
+
score coherence by the entity-transition patterns. This is genuinely the right _shape_ of idea
|
|
384
|
+
for "this term was never introduced" / "this pronoun floats" — but it scores _documents_ as
|
|
385
|
+
more-or-less-coherent relative to a shuffled-sentence baseline, it does not point at a specific
|
|
386
|
+
sentence and say "this one presupposes a referent the reader doesn't have."
|
|
387
|
+
- **"Cohere" toolkit** — a research implementation bundling the classic entity-grid model, a
|
|
388
|
+
graph-based coherence metric (Guinaudeau & Strube 2013), and a syntax-augmented model
|
|
389
|
+
(Louis & Nenkova 2012), built explicitly for benchmarking against shuffled-sentence corpora in
|
|
390
|
+
papers, not for linting a draft. [lrec-conf.org paper](http://www.lrec-conf.org/proceedings/lrec2016/pdf/923_Paper.pdf)
|
|
391
|
+
- **spaCy coreference / coreferee** — general-purpose coreference _resolution_ libraries (find
|
|
392
|
+
what "it"/"they" points to across a document). These resolve references that CAN be resolved;
|
|
393
|
+
they do not flag references that CANNOT be resolved from context, and even where they attempt
|
|
394
|
+
novelty-detection, that's a research topic (Winograd-schema-style ambiguity), not a shipped
|
|
395
|
+
"no antecedent found → error" linter rule anywhere I found.
|
|
396
|
+
- **Grammarly's vague-pronoun-reference marketing claim** is the single closest-sounding shipped
|
|
397
|
+
consumer feature — see above, unverified in this research, worth testing directly.
|
|
398
|
+
|
|
399
|
+
Net: coreference resolution as a _library capability_ exists and is mature (spaCy, coreferee).
|
|
400
|
+
Coreference _checking_ — the inverse, "flag when resolution fails or is ambiguous, as a prose
|
|
401
|
+
defect" — exists only in academic evaluation harnesses (Cohere, entity-grid papers), never
|
|
402
|
+
packaged as something you point at a manuscript and get pass/fail on.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
### Term-first-use checking
|
|
407
|
+
|
|
408
|
+
This is the one category with a genuinely usable, mechanical, **build-failing** answer — but only
|
|
409
|
+
inside LaTeX, and only for acronyms/defined-terms, not general concept-presupposition.
|
|
410
|
+
|
|
411
|
+
- **`glossaries` package:** Tracks first use per glossary entry; entries that reference an
|
|
412
|
+
undefined glossary term produce build warnings (undefined-reference class of error).
|
|
413
|
+
- **`acronym` package** (Oetiker): Explicitly ships an **`error` option** — "lets it throw compile
|
|
414
|
+
errors instead of warnings in case of undefined acronyms" — confirmed from the package's own
|
|
415
|
+
documentation/forum discussion found in this research. This means a LaTeX build _can_ be
|
|
416
|
+
configured to hard-fail if an acronym is used before `\acrodef`ining it. This is real,
|
|
417
|
+
adoptable, and directly on-point for "acronym used before defined" — just not for "concept used
|
|
418
|
+
before its meaning was established," which is the harder, prose-level version of the same
|
|
419
|
+
problem the six test sentences actually exhibit.
|
|
420
|
+
- **ASD-STE100 Simplified Technical English:** A controlled-language standard (aerospace/defense
|
|
421
|
+
documentation lineage, formerly AECMA Simplified English) that constrains vocabulary to an
|
|
422
|
+
approved dictionary and imposes structural writing rules aimed at reducing ambiguity, not just
|
|
423
|
+
word difficulty. **TechScribe ships a customized LanguageTool instance specifically to check
|
|
424
|
+
ASD-STE100 compliance** — a real, existing checker
|
|
425
|
+
([simplified-english.co.uk](https://www.simplified-english.co.uk/glossary.html)). This is the
|
|
426
|
+
closest _shipped, checkable_ thing to "sentence structure that forces one clear idea per
|
|
427
|
+
sentence" found anywhere in this research — worth a closer look if the goal generalizes beyond
|
|
428
|
+
papers to any technical writing, though it's built for aerospace maintenance manuals, not
|
|
429
|
+
academic argumentation, and its "clarity" is about avoiding ambiguous grammar constructions
|
|
430
|
+
(e.g., banning strings of nouns, restricting verb forms), not about tracking whether a _claim_
|
|
431
|
+
presupposes context.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
### Academic writing assistants — what journals actually run
|
|
436
|
+
|
|
437
|
+
- **Writefull:** Language-fluency assistant trained on published journal articles (phrasing,
|
|
438
|
+
paraphrasing, abstract/title generation), integrates with Word/Overleaf. Targets non-native-
|
|
439
|
+
English fluency, not semantic clarity for a general reader — a _more_ fluent-sounding sentence
|
|
440
|
+
from Writefull could easily still be one only an insider parses.
|
|
441
|
+
[writefull.com](https://www.writefull.com/)
|
|
442
|
+
- **Penelope.ai / Penelope.ci:** Automated manuscript-completeness checker — ethics statements,
|
|
443
|
+
informed consent, data-availability statements, COI disclosures, word counts, reference
|
|
444
|
+
formatting. Explicitly **does not evaluate intellectual quality** of the writing — confirmed
|
|
445
|
+
directly from search results describing it as "highly effective for formal completeness" but
|
|
446
|
+
not content quality.
|
|
447
|
+
- **SciScore:** Scores _methods sections_ specifically — reagent/resource identifiability, bias
|
|
448
|
+
controls, sample-size/randomization/blinding reporting — a reproducibility-and-rigor checklist
|
|
449
|
+
tool, not a prose-clarity tool at all.
|
|
450
|
+
- **StatReviewer:** Statistical-methodology checker — flags wrong test choice, missing info
|
|
451
|
+
needed to replicate, methods susceptible to bias. Also not a prose-clarity tool.
|
|
452
|
+
|
|
453
|
+
None of these four run on sentence-level readability or semantic opacity at all; they are
|
|
454
|
+
adjacent tools solving a different problem (methodological rigor, manuscript completeness,
|
|
455
|
+
language fluency for non-native speakers) that happens to sit in the same "things journals bolt
|
|
456
|
+
onto submission" category.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## (a) Test-sentence × tool table
|
|
461
|
+
|
|
462
|
+
"✗" = tool ran/would run and did not flag it. "✓" = flagged, with the specific reason. "n/a" =
|
|
463
|
+
tool categorically out of scope (not a readability/clarity tool). Blank cells for tools not
|
|
464
|
+
directly tested are inferred from documented mechanics, marked accordingly.
|
|
465
|
+
|
|
466
|
+
| # | proselint (tested) | write-good (tested) | retext-readability @default (tested) | retext-readability @age-6 strict (tested) | textstat/Hemingway-style grade-level | Vale readability (doc-scoped, inferred) | LanguageTool Picky (inferred) | Coh-Metrix (inferred — no threshold exists) | Grammarly vague-pronoun (unverified) |
|
|
467
|
+
| --- | ------------------ | -------------------------------------------- | ---------------------------------------- | ----------------------------------------- | ---------------------------------------- | ----------------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------- |
|
|
468
|
+
| 1 | ✗ | ✓ "therefore" wordy (irrelevant) | ✗ | ✓ (6/7, age-6 only) | grade 5 — too low to trip | ✗ | ✗ | would score low cohesion if computed, but no pass/fail exists | untested |
|
|
469
|
+
| 2 | ✗ | ✓ "are filled" passive (irrelevant) | ✗ | ✓ (6/7, age-6 only) | grade 5 | ✗ | ✗ | same | untested |
|
|
470
|
+
| 3 | ✗ | ✓ "all of" wordy (irrelevant) | ✗ | ✓ (6/7, age-6 only) | grade 2 | ✗ (also: headings often excluded from scope entirely) | ✗ | same | untested |
|
|
471
|
+
| 4 | ✗ | ✗ (zero flags) | ✗ | ✓ (6/7, age-6 only) | grade 7.6 — borderline on strict configs | possible, borderline | possible, borderline | same | untested |
|
|
472
|
+
| 5 | ✗ | ✓ "only" weakening adverb (irrelevant) | ✗ | ✓ (6/7, age-6 only) | grade 6 | ✗ | ✗ | this is the sentence coreference-checking would target ("It", "the other two") — no tool does it | **plausible target** if the feature is real |
|
|
473
|
+
| 6 | ✗ | ✓ "silently" weakening adverb (coincidental) | **✓ (5/7, default settings — real hit)** | ✓ (7/7) | grade 20.6 | **would flag if scoped per-sentence** | likely flags on length | n/a | n/a |
|
|
474
|
+
|
|
475
|
+
**Reading the table honestly:** the only cell that is a genuine, non-degenerate detection is
|
|
476
|
+
retext-readability on sentence 6 at default settings — and it fired because the sentence is long,
|
|
477
|
+
not because it strings six unrelated claims together. Every other "✓" in the table required
|
|
478
|
+
either an irrelevant trigger (write-good's word-list nits) or an unusably aggressive threshold
|
|
479
|
+
(age-6 retext) that would flag most adult prose. Sentences 1–5 — the ones actually called "wtf"
|
|
480
|
+
— are structurally invisible to this entire tool category at any setting a working author would
|
|
481
|
+
actually run in CI.
|
|
482
|
+
|
|
483
|
+
## (b) Ranked ADOPT list — deterministic checks worth taking off the shelf tomorrow
|
|
484
|
+
|
|
485
|
+
Ranked by (catches something real) ÷ (adoption cost), **not** by whether it solves the stated
|
|
486
|
+
problem — none of them solve the stated problem, this ranks what's worth having anyway as a cheap
|
|
487
|
+
floor beneath the human/LLM cold-read pass:
|
|
488
|
+
|
|
489
|
+
1. **proselint**, `pip install proselint`, drop into CI or pre-commit. Zero false positives in
|
|
490
|
+
this test (ran clean on all six), catches real hedge/cliché/weasel-word patterns elsewhere in
|
|
491
|
+
a corpus, costs nothing to add. Ceiling: word-list matching only.
|
|
492
|
+
2. **retext-readability at default settings (age 16, threshold 4/7)**, if the corpus is Markdown
|
|
493
|
+
(natural fit with an existing remark/unified pipeline). The one tool in this survey that
|
|
494
|
+
actually caught something real (sentence 6) without an unusable threshold. Treat a hit as "this
|
|
495
|
+
sentence is long and worth a manual look," not as proof of a defect and not as proof of its
|
|
496
|
+
absence when it stays quiet.
|
|
497
|
+
3. **A custom Vale `existence` rule counting semicolons/em-dashes/commas per sentence** (e.g.
|
|
498
|
+
"flag any sentence with ≥3 semicolons or ≥2 em-dash clauses") — not shipped anywhere found in
|
|
499
|
+
this research, but cheap to author (a few lines of YAML regex) and would catch the shape of
|
|
500
|
+
sentence 6 specifically, as opposed to relying on a readability-formula proxy for it.
|
|
501
|
+
4. **LaTeX `acronym` package with the `error` option**, only if the corpus is LaTeX and has
|
|
502
|
+
acronyms — real, build-failing, on-point for its narrow scope (undefined acronym at first
|
|
503
|
+
use), zero cost if already using LaTeX.
|
|
504
|
+
5. **write-good**, mainly as a second, differently-tuned word-list pass (catches passive voice
|
|
505
|
+
and weak-adverb patterns proselint's list doesn't cover) — low value on its own given this
|
|
506
|
+
test set (4/6 sentences got an irrelevant flag, the useful information rate is low), but it's
|
|
507
|
+
a 30-second npm install and doesn't cost anything to have running alongside proselint.
|
|
508
|
+
|
|
509
|
+
Deliberately **not** recommending: Vale's readability rule (wrong scope — document-level, not
|
|
510
|
+
sentence-level — for this specific problem, though still fine for its intended purpose of
|
|
511
|
+
catching genuinely bloated paragraphs elsewhere); LanguageTool Picky mode (heavier to self-host
|
|
512
|
+
than the value it added in this test — mostly grammar, marginal style); Coh-Metrix (right idea,
|
|
513
|
+
no pass/fail packaging, would need custom threshold-setting research to turn into a usable gate);
|
|
514
|
+
Acrolinx/Grammarly Business (enterprise pricing/workflow mismatch for a solo paper pipeline, and
|
|
515
|
+
the one feature that sounds relevant — vague pronoun reference — is unverified).
|
|
516
|
+
|
|
517
|
+
## (c) What remains irreducibly non-deterministic
|
|
518
|
+
|
|
519
|
+
The defect in all five "wtf"-tier sentences is the same shape: each sentence is a valid,
|
|
520
|
+
economical compression of an idea the _writer_ holds fully formed, and the compression relies on
|
|
521
|
+
the reader having already built the same mental model — which term of art "the rule" and "its
|
|
522
|
+
claim about itself" refer to (sentence 1), what "these files" and "constructions nobody built"
|
|
523
|
+
cash out to concretely (sentence 2), what the antecedent of "three answers" even is without the
|
|
524
|
+
paragraph before it (sentence 3), and in sentence 5, what noun phrase "the other two" silently
|
|
525
|
+
picks up from two clauses earlier. This is **not a property of any individual sentence's tokens**
|
|
526
|
+
— it's a property of the relationship between the sentence and a specific reader's prior state,
|
|
527
|
+
which is exactly why every tool surveyed here comes up empty: they all operate on the document (or
|
|
528
|
+
one sentence) in isolation, scoring vocabulary/length/word-choice, with no model of what the
|
|
529
|
+
reader brought into the room. Coh-Metrix gets closest by modeling cross-sentence referential
|
|
530
|
+
overlap, but even that is a statistical proxy for cohesion within the _document itself_, not a
|
|
531
|
+
model of a specific reader's background knowledge — a term can have perfect referential overlap
|
|
532
|
+
with its own prior use three paragraphs up and still be opaque to a reader meeting the paper cold.
|
|
533
|
+
Detecting that gap requires actually simulating a reader who does not have the writer's context —
|
|
534
|
+
which is a language-understanding task, not a countable-surface-feature task, and is why the
|
|
535
|
+
`cold-read-diff` skill's approach (send the diff to a fresh, context-free reader and ask what each
|
|
536
|
+
sentence claims) is targeting the right mechanism even though the homegrown metric-based checks
|
|
537
|
+
are not: the fix for this class of defect is closer to "add another independent reader" than
|
|
538
|
+
"tighten a threshold."
|