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.
Files changed (762) hide show
  1. package/.github/dependabot.yml +72 -0
  2. package/.github/workflows/ci.yml +297 -0
  3. package/.github/workflows/dependabot-automerge.yml +70 -0
  4. package/.github/workflows/pr-title.yml +59 -0
  5. package/.github/workflows/release.yml +54 -0
  6. package/CLAUDE.md +598 -0
  7. package/CONTRIBUTING.md +159 -0
  8. package/LICENSE +21 -0
  9. package/README.md +240 -0
  10. package/action.harness.mjs +287 -0
  11. package/action.mutations.mjs +162 -0
  12. package/action.yml +138 -0
  13. package/bin/rpp.mjs +43 -0
  14. package/dist/action-ref.d.ts +12 -0
  15. package/dist/action-ref.d.ts.map +1 -0
  16. package/dist/action-ref.js +16 -0
  17. package/dist/action-ref.js.map +1 -0
  18. package/dist/adapters/banal/failure.d.ts +73 -0
  19. package/dist/adapters/banal/failure.d.ts.map +1 -0
  20. package/dist/adapters/banal/failure.js +58 -0
  21. package/dist/adapters/banal/failure.js.map +1 -0
  22. package/dist/adapters/banal/index.d.ts +17 -0
  23. package/dist/adapters/banal/index.d.ts.map +1 -0
  24. package/dist/adapters/banal/index.js +56 -0
  25. package/dist/adapters/banal/index.js.map +1 -0
  26. package/dist/adapters/banal/install.d.ts +26 -0
  27. package/dist/adapters/banal/install.d.ts.map +1 -0
  28. package/dist/adapters/banal/install.js +15 -0
  29. package/dist/adapters/banal/install.js.map +1 -0
  30. package/dist/adapters/banal/invocation.d.ts +48 -0
  31. package/dist/adapters/banal/invocation.d.ts.map +1 -0
  32. package/dist/adapters/banal/invocation.js +43 -0
  33. package/dist/adapters/banal/invocation.js.map +1 -0
  34. package/dist/adapters/banal/locate.d.ts +50 -0
  35. package/dist/adapters/banal/locate.d.ts.map +1 -0
  36. package/dist/adapters/banal/locate.js +34 -0
  37. package/dist/adapters/banal/locate.js.map +1 -0
  38. package/dist/adapters/banal/output.d.ts +27 -0
  39. package/dist/adapters/banal/output.d.ts.map +1 -0
  40. package/dist/adapters/banal/output.js +112 -0
  41. package/dist/adapters/banal/output.js.map +1 -0
  42. package/dist/adapters/banal/pin.d.ts +19 -0
  43. package/dist/adapters/banal/pin.d.ts.map +1 -0
  44. package/dist/adapters/banal/pin.js +15 -0
  45. package/dist/adapters/banal/pin.js.map +1 -0
  46. package/dist/adapters/banal/probe.d.ts +12 -0
  47. package/dist/adapters/banal/probe.d.ts.map +1 -0
  48. package/dist/adapters/banal/probe.js +27 -0
  49. package/dist/adapters/banal/probe.js.map +1 -0
  50. package/dist/adapters/banal/run.d.ts +89 -0
  51. package/dist/adapters/banal/run.d.ts.map +1 -0
  52. package/dist/adapters/banal/run.js +104 -0
  53. package/dist/adapters/banal/run.js.map +1 -0
  54. package/dist/adapters/banal/settings.d.ts +18 -0
  55. package/dist/adapters/banal/settings.d.ts.map +1 -0
  56. package/dist/adapters/banal/settings.js +29 -0
  57. package/dist/adapters/banal/settings.js.map +1 -0
  58. package/dist/adapters/banal/xml.d.ts +48 -0
  59. package/dist/adapters/banal/xml.d.ts.map +1 -0
  60. package/dist/adapters/banal/xml.js +67 -0
  61. package/dist/adapters/banal/xml.js.map +1 -0
  62. package/dist/adapters/curl/download.io.d.ts +14 -0
  63. package/dist/adapters/curl/download.io.d.ts.map +1 -0
  64. package/dist/adapters/curl/download.io.js +69 -0
  65. package/dist/adapters/curl/download.io.js.map +1 -0
  66. package/dist/adapters/curl/index.d.ts +6 -0
  67. package/dist/adapters/curl/index.d.ts.map +1 -0
  68. package/dist/adapters/curl/index.js +6 -0
  69. package/dist/adapters/curl/index.js.map +1 -0
  70. package/dist/adapters/memory/index.d.ts +43 -0
  71. package/dist/adapters/memory/index.d.ts.map +1 -0
  72. package/dist/adapters/memory/index.js +79 -0
  73. package/dist/adapters/memory/index.js.map +1 -0
  74. package/dist/adapters/node/files.io.d.ts +3 -0
  75. package/dist/adapters/node/files.io.d.ts.map +1 -0
  76. package/dist/adapters/node/files.io.js +31 -0
  77. package/dist/adapters/node/files.io.js.map +1 -0
  78. package/dist/adapters/node/host.io.d.ts +3 -0
  79. package/dist/adapters/node/host.io.d.ts.map +1 -0
  80. package/dist/adapters/node/host.io.js +14 -0
  81. package/dist/adapters/node/host.io.js.map +1 -0
  82. package/dist/adapters/node/index.d.ts +25 -0
  83. package/dist/adapters/node/index.d.ts.map +1 -0
  84. package/dist/adapters/node/index.js +14 -0
  85. package/dist/adapters/node/index.js.map +1 -0
  86. package/dist/adapters/node/process.io.d.ts +14 -0
  87. package/dist/adapters/node/process.io.d.ts.map +1 -0
  88. package/dist/adapters/node/process.io.js +41 -0
  89. package/dist/adapters/node/process.io.js.map +1 -0
  90. package/dist/adapters/node/workspace.io.d.ts +4 -0
  91. package/dist/adapters/node/workspace.io.d.ts.map +1 -0
  92. package/dist/adapters/node/workspace.io.js +33 -0
  93. package/dist/adapters/node/workspace.io.js.map +1 -0
  94. package/dist/adapters/pdfjs/fill.d.ts +42 -0
  95. package/dist/adapters/pdfjs/fill.d.ts.map +1 -0
  96. package/dist/adapters/pdfjs/fill.js +91 -0
  97. package/dist/adapters/pdfjs/fill.js.map +1 -0
  98. package/dist/build-engine.d.ts +48 -0
  99. package/dist/build-engine.d.ts.map +1 -0
  100. package/dist/build-engine.js +148 -0
  101. package/dist/build-engine.js.map +1 -0
  102. package/dist/build.d.ts +163 -0
  103. package/dist/build.d.ts.map +1 -0
  104. package/dist/build.js +575 -0
  105. package/dist/build.js.map +1 -0
  106. package/dist/cli.d.ts +151 -0
  107. package/dist/cli.d.ts.map +1 -0
  108. package/dist/cli.js +951 -0
  109. package/dist/cli.js.map +1 -0
  110. package/dist/doctor.d.ts +42 -0
  111. package/dist/doctor.d.ts.map +1 -0
  112. package/dist/doctor.js +280 -0
  113. package/dist/doctor.js.map +1 -0
  114. package/dist/domain/geometry.d.ts +71 -0
  115. package/dist/domain/geometry.d.ts.map +1 -0
  116. package/dist/domain/geometry.js +35 -0
  117. package/dist/domain/geometry.js.map +1 -0
  118. package/dist/domain/host.d.ts +16 -0
  119. package/dist/domain/host.d.ts.map +1 -0
  120. package/dist/domain/host.js +8 -0
  121. package/dist/domain/host.js.map +1 -0
  122. package/dist/domain/page-layout.d.ts +34 -0
  123. package/dist/domain/page-layout.d.ts.map +1 -0
  124. package/dist/domain/page-layout.js +8 -0
  125. package/dist/domain/page-layout.js.map +1 -0
  126. package/dist/domain/paths.d.ts +5 -0
  127. package/dist/domain/paths.d.ts.map +1 -0
  128. package/dist/domain/paths.js +2 -0
  129. package/dist/domain/paths.js.map +1 -0
  130. package/dist/domain/result.d.ts +23 -0
  131. package/dist/domain/result.d.ts.map +1 -0
  132. package/dist/domain/result.js +10 -0
  133. package/dist/domain/result.js.map +1 -0
  134. package/dist/domain/sha256.d.ts +7 -0
  135. package/dist/domain/sha256.d.ts.map +1 -0
  136. package/dist/domain/sha256.js +14 -0
  137. package/dist/domain/sha256.js.map +1 -0
  138. package/dist/domain/text.d.ts +6 -0
  139. package/dist/domain/text.d.ts.map +1 -0
  140. package/dist/domain/text.js +7 -0
  141. package/dist/domain/text.js.map +1 -0
  142. package/dist/engine.d.ts +93 -0
  143. package/dist/engine.d.ts.map +1 -0
  144. package/dist/engine.js +119 -0
  145. package/dist/engine.js.map +1 -0
  146. package/dist/exit-code.d.ts +22 -0
  147. package/dist/exit-code.d.ts.map +1 -0
  148. package/dist/exit-code.js +10 -0
  149. package/dist/exit-code.js.map +1 -0
  150. package/dist/facts-file.d.ts +96 -0
  151. package/dist/facts-file.d.ts.map +1 -0
  152. package/dist/facts-file.js +134 -0
  153. package/dist/facts-file.js.map +1 -0
  154. package/dist/hooks-settings.d.ts +141 -0
  155. package/dist/hooks-settings.d.ts.map +1 -0
  156. package/dist/hooks-settings.js +306 -0
  157. package/dist/hooks-settings.js.map +1 -0
  158. package/dist/init.d.ts +201 -0
  159. package/dist/init.d.ts.map +1 -0
  160. package/dist/init.js +579 -0
  161. package/dist/init.js.map +1 -0
  162. package/dist/latex-log.d.ts +80 -0
  163. package/dist/latex-log.d.ts.map +1 -0
  164. package/dist/latex-log.js +187 -0
  165. package/dist/latex-log.js.map +1 -0
  166. package/dist/latex-loop.d.ts +129 -0
  167. package/dist/latex-loop.d.ts.map +1 -0
  168. package/dist/latex-loop.js +113 -0
  169. package/dist/latex-loop.js.map +1 -0
  170. package/dist/link-skills.d.ts +51 -0
  171. package/dist/link-skills.d.ts.map +1 -0
  172. package/dist/link-skills.js +199 -0
  173. package/dist/link-skills.js.map +1 -0
  174. package/dist/new-paper.d.ts +48 -0
  175. package/dist/new-paper.d.ts.map +1 -0
  176. package/dist/new-paper.js +110 -0
  177. package/dist/new-paper.js.map +1 -0
  178. package/dist/pdf-facts.d.ts +44 -0
  179. package/dist/pdf-facts.d.ts.map +1 -0
  180. package/dist/pdf-facts.js +239 -0
  181. package/dist/pdf-facts.js.map +1 -0
  182. package/dist/pdf-geometry.d.ts +170 -0
  183. package/dist/pdf-geometry.d.ts.map +1 -0
  184. package/dist/pdf-geometry.js +158 -0
  185. package/dist/pdf-geometry.js.map +1 -0
  186. package/dist/ports/download.d.ts +9 -0
  187. package/dist/ports/download.d.ts.map +1 -0
  188. package/dist/ports/download.js +2 -0
  189. package/dist/ports/download.js.map +1 -0
  190. package/dist/ports/files.d.ts +11 -0
  191. package/dist/ports/files.d.ts.map +1 -0
  192. package/dist/ports/files.js +2 -0
  193. package/dist/ports/files.js.map +1 -0
  194. package/dist/ports/measure-geometry.d.ts +8 -0
  195. package/dist/ports/measure-geometry.d.ts.map +1 -0
  196. package/dist/ports/measure-geometry.js +2 -0
  197. package/dist/ports/measure-geometry.js.map +1 -0
  198. package/dist/ports/process.d.ts +45 -0
  199. package/dist/ports/process.d.ts.map +1 -0
  200. package/dist/ports/process.js +2 -0
  201. package/dist/ports/process.js.map +1 -0
  202. package/dist/ports/tool-installer.d.ts +29 -0
  203. package/dist/ports/tool-installer.d.ts.map +1 -0
  204. package/dist/ports/tool-installer.js +2 -0
  205. package/dist/ports/tool-installer.js.map +1 -0
  206. package/dist/ports/workspace.d.ts +18 -0
  207. package/dist/ports/workspace.d.ts.map +1 -0
  208. package/dist/ports/workspace.js +2 -0
  209. package/dist/ports/workspace.js.map +1 -0
  210. package/dist/rules-config.d.ts +34 -0
  211. package/dist/rules-config.d.ts.map +1 -0
  212. package/dist/rules-config.js +132 -0
  213. package/dist/rules-config.js.map +1 -0
  214. package/dist/structure.d.ts +34 -0
  215. package/dist/structure.d.ts.map +1 -0
  216. package/dist/structure.js +149 -0
  217. package/dist/structure.js.map +1 -0
  218. package/dist/tex-requirements.d.ts +43 -0
  219. package/dist/tex-requirements.d.ts.map +1 -0
  220. package/dist/tex-requirements.js +127 -0
  221. package/dist/tex-requirements.js.map +1 -0
  222. package/dist/toolchain.d.ts +159 -0
  223. package/dist/toolchain.d.ts.map +1 -0
  224. package/dist/toolchain.js +542 -0
  225. package/dist/toolchain.js.map +1 -0
  226. package/dist/types.d.ts +110 -0
  227. package/dist/types.d.ts.map +1 -0
  228. package/dist/types.js +2 -0
  229. package/dist/types.js.map +1 -0
  230. package/docs/configuration.md +235 -0
  231. package/docs/e2e.md +152 -0
  232. package/docs/incidents.md +59 -0
  233. package/docs/install.md +170 -0
  234. package/docs/optional-rules.md +107 -0
  235. package/docs/package-shape-options.md +262 -0
  236. package/docs/prior-art/README.md +76 -0
  237. package/docs/prior-art/blocking-vs-advisory.md +83 -0
  238. package/docs/prior-art/content-delivery.md +124 -0
  239. package/docs/prior-art/multi-mode-tools.md +106 -0
  240. package/docs/prior-art/nondeterministic-checks.md +99 -0
  241. package/docs/prior-art/package-location.md +422 -0
  242. package/docs/prior-art/paper-folder-scaffolding.md +538 -0
  243. package/docs/prior-art/readme-structure.md +69 -0
  244. package/docs/prior-art/repro/README.md +92 -0
  245. package/docs/prior-art/repro/claim1-allowedtools.mjs +66 -0
  246. package/docs/prior-art/repro/claim1-at2.mjs +40 -0
  247. package/docs/prior-art/repro/claim1-crosschannel.mjs +54 -0
  248. package/docs/prior-art/repro/claim1-frontmatter.mjs +76 -0
  249. package/docs/prior-art/repro/claim1-hook-payload-reporter.mjs +10 -0
  250. package/docs/prior-art/repro/claim1-plugin-frontmatter.mjs +27 -0
  251. package/docs/prior-art/repro/claim1-plugin-skill.mjs +52 -0
  252. package/docs/prior-art/repro/claim1-project-skill.mjs +81 -0
  253. package/docs/prior-art/repro/claim2-marketplace-flat-asclaimed.json +1 -0
  254. package/docs/prior-art/repro/claim2-marketplace-negative-control.json +1 -0
  255. package/docs/prior-art/repro/claim2-marketplace-nested-exact.json +9 -0
  256. package/docs/prior-art/repro/claim2-marketplace-nested-noversion.json +9 -0
  257. package/docs/prior-art/repro/claim2-marketplace-nested-range.json +1 -0
  258. package/docs/prior-art/repro/claim3-imports.mjs +50 -0
  259. package/docs/prior-art/repro/claim4-find-package-json.mjs +8 -0
  260. package/docs/prior-art/repro/claim4-package-dir.mjs +39 -0
  261. package/docs/prior-art/repro/claim4-parent-arg.mjs +17 -0
  262. package/docs/prior-art/repro/claim4-resolve-apis.mjs +21 -0
  263. package/docs/prior-art/repro/claim4-setup-consumers.mjs +45 -0
  264. package/docs/prior-art/repro/claim4-yarn-pnp.mjs +70 -0
  265. package/docs/prior-art/repro/claim5-bin-launch.mjs +39 -0
  266. package/docs/prior-art/repro/claim5-exports-mutation.mjs +57 -0
  267. package/docs/prior-art/repro/claim5-resolved-location-and-bin.mjs +33 -0
  268. package/docs/prior-art/repro/claim6-candidate-ambiguity.mjs +17 -0
  269. package/docs/prior-art/repro/claim6-doc-path-candidates.mjs +27 -0
  270. package/docs/prior-art/test-tooling.md +131 -0
  271. package/docs/rules.md +58 -0
  272. package/docs/texlive-install-decision.md +230 -0
  273. package/docs/toolchain.md +152 -0
  274. package/eslint-rules/doc-fields.harness.mjs +336 -0
  275. package/eslint-rules/doc-fields.mjs +186 -0
  276. package/eslint-rules/doc-fields.mutations.mjs +96 -0
  277. package/eslint-rules/install-path-literals.harness.mjs +121 -0
  278. package/eslint-rules/install-path-literals.mjs +108 -0
  279. package/eslint-rules/install-path-literals.mutations.mjs +62 -0
  280. package/eslint-rules/latex-language.harness.mjs +599 -0
  281. package/eslint-rules/latex-language.mjs +591 -0
  282. package/eslint-rules/latex-language.mutations.mjs +196 -0
  283. package/eslint-rules/paper-research-question.harness.mjs +146 -0
  284. package/eslint-rules/paper-research-question.mjs +180 -0
  285. package/eslint-rules/paper-research-question.mutations.mjs +127 -0
  286. package/eslint-rules/paper-stages.harness.mjs +356 -0
  287. package/eslint-rules/paper-stages.mjs +455 -0
  288. package/eslint-rules/paper-stages.mutations.mjs +157 -0
  289. package/eslint-rules/paper-typography.harness.mjs +291 -0
  290. package/eslint-rules/paper-typography.mjs +313 -0
  291. package/eslint-rules/paper-typography.mutations.mjs +131 -0
  292. package/eslint-rules/papers.harness.mjs +259 -0
  293. package/eslint-rules/papers.mjs +166 -0
  294. package/eslint-rules/papers.mutations.mjs +186 -0
  295. package/eslint-rules/pdf-last-page-balance.harness.mjs +206 -0
  296. package/eslint-rules/pdf-last-page-balance.mjs +208 -0
  297. package/eslint-rules/review-findings-cause.harness.mjs +228 -0
  298. package/eslint-rules/review-findings-cause.mjs +135 -0
  299. package/eslint-rules/review-findings-cause.mutations.mjs +72 -0
  300. package/eslint-rules/temp-root-realpath.harness.mjs +176 -0
  301. package/eslint-rules/temp-root-realpath.mjs +129 -0
  302. package/eslint-rules/temp-root-realpath.mutations.mjs +99 -0
  303. package/eslint-rules/tex-build.harness.mjs +753 -0
  304. package/eslint-rules/tex-build.mjs +322 -0
  305. package/eslint-rules/tex-build.mutations.mjs +258 -0
  306. package/eslint.config.mjs +521 -0
  307. package/fixtures/build-e2e/acmart/PIPELINE-STATUS.md +3 -0
  308. package/fixtures/build-e2e/acmart/paper.tex +11 -0
  309. package/fixtures/build-e2e/acmart/venue.json +1 -0
  310. package/fixtures/build-e2e/broken/PIPELINE-STATUS.md +3 -0
  311. package/fixtures/build-e2e/broken/paper.tex +7 -0
  312. package/fixtures/build-e2e/cite/PIPELINE-STATUS.md +3 -0
  313. package/fixtures/build-e2e/cite/build.sh +5 -0
  314. package/fixtures/build-e2e/cite/paper.tex +10 -0
  315. package/fixtures/build-e2e/cite/refs.bib +9 -0
  316. package/fixtures/build-e2e/empty/PIPELINE-STATUS.md +3 -0
  317. package/fixtures/build-e2e/empty/paper.tex +6 -0
  318. package/fixtures/build-e2e/fallback/PIPELINE-STATUS.md +3 -0
  319. package/fixtures/build-e2e/fallback/paper.tex +11 -0
  320. package/fixtures/build-e2e/guards/PIPELINE-STATUS.md +3 -0
  321. package/fixtures/build-e2e/guards/paper.tex +10 -0
  322. package/fixtures/build-e2e/no-source/PIPELINE-STATUS.md +3 -0
  323. package/fixtures/build-e2e/unbalanced/PIPELINE-STATUS.md +3 -0
  324. package/fixtures/build-e2e/unbalanced/paper.tex +28 -0
  325. package/fixtures/build-e2e/unbalanced/refs.bib +269 -0
  326. package/fixtures/install-path-literals/clean.fixture.mjs +3 -0
  327. package/fixtures/install-path-literals/clean.md +15 -0
  328. package/fixtures/install-path-literals/defect.fixture.mjs +3 -0
  329. package/fixtures/install-path-literals/defect.md +14 -0
  330. package/fixtures/latex-language/clean.tex +50 -0
  331. package/fixtures/latex-language/defect.tex +52 -0
  332. package/fixtures/paper-research-question/comment-only/PIPELINE-STATUS.md +9 -0
  333. package/fixtures/paper-research-question/comment-only/paper.tex +7 -0
  334. package/fixtures/paper-research-question/declared-not-in-paper/PIPELINE-STATUS.md +10 -0
  335. package/fixtures/paper-research-question/declared-not-in-paper/paper.tex +6 -0
  336. package/fixtures/paper-research-question/draft/PIPELINE-STATUS.md +6 -0
  337. package/fixtures/paper-research-question/draft/paper.tex +2 -0
  338. package/fixtures/paper-research-question/markdown-no-rq/PIPELINE-STATUS.md +9 -0
  339. package/fixtures/paper-research-question/markdown-no-rq/paper.md +4 -0
  340. package/fixtures/paper-research-question/shipped-no-rq/PIPELINE-STATUS.md +12 -0
  341. package/fixtures/paper-research-question/shipped-no-rq/paper.tex +3 -0
  342. package/fixtures/paper-research-question/shipped-with-rq/PIPELINE-STATUS.md +10 -0
  343. package/fixtures/paper-research-question/shipped-with-rq/paper.tex +2 -0
  344. package/fixtures/paper-stages/authors-ran/PIPELINE-STATUS.md +16 -0
  345. package/fixtures/paper-stages/marker-in-prose/PIPELINE-STATUS.md +17 -0
  346. package/fixtures/paper-stages/nofile/PIPELINE-STATUS.md +8 -0
  347. package/fixtures/paper-stages/noheader/PIPELINE-STATUS.md +1 -0
  348. package/fixtures/paper-stages/noheader/versions/2026-07-22-submitted.pdf +0 -0
  349. package/fixtures/paper-stages/nothing/PIPELINE-STATUS.md +3 -0
  350. package/fixtures/paper-stages/ok/PIPELINE-STATUS.md +9 -0
  351. package/fixtures/paper-stages/ok/versions/2026-07-22-submitted.pdf +0 -0
  352. package/fixtures/paper-stages/stale/PIPELINE-STATUS.md +1 -0
  353. package/fixtures/paper-stages/stale/versions/2026-07-22-submitted.STALE-WRONG-FILE.pdf +0 -0
  354. package/fixtures/paper-stages/twice/PIPELINE-STATUS.md +14 -0
  355. package/fixtures/paper-stages/twice/versions/2026-08-06-submitted.pdf +0 -0
  356. package/fixtures/paper-stages/twice/versions/2026-10-24-submitted.pdf +0 -0
  357. package/fixtures/paper-stages/undeclared/PIPELINE-STATUS.md +8 -0
  358. package/fixtures/paper-stages/undeclared/versions/2026-07-22-submitted.pdf +0 -0
  359. package/fixtures/paper-stages/undeclared/versions/2026-08-29-camera-ready.pdf +0 -0
  360. package/fixtures/paper-stages/wrongsize/PIPELINE-STATUS.md +8 -0
  361. package/fixtures/paper-stages/wrongsize/versions/2026-07-22-submitted.pdf +0 -0
  362. package/fixtures/paper-typography/clean-paper/paper.tex +29 -0
  363. package/fixtures/paper-typography/messy-paper/paper.tex +27 -0
  364. package/fixtures/pdf-facts/README.md +22 -0
  365. package/fixtures/pdf-facts/corrupt-font.pdf +0 -0
  366. package/fixtures/pdf-facts/encrypted.pdf +0 -0
  367. package/fixtures/pdf-facts/hidden-text.pdf +0 -0
  368. package/fixtures/pdf-facts/hidden-text.tex +28 -0
  369. package/fixtures/pdf-facts/t3-all.pdf +0 -0
  370. package/fixtures/pdf-facts/t3-all.tex +8 -0
  371. package/fixtures/pdf-facts/t3-mixed.pdf +0 -0
  372. package/fixtures/pdf-facts/t3-mixed.tex +9 -0
  373. package/fixtures/pdf-facts/ttf.pdf +2240 -1
  374. package/fixtures/pdf-facts/ttf.tex +6 -0
  375. package/fixtures/real-markdown-paper/baseline.json +24 -0
  376. package/fixtures/real-markdown-paper/baseline.mjs +48 -0
  377. package/fixtures/render-paper/build-clean.sh +25 -0
  378. package/fixtures/render-paper/build-defect.sh +15 -0
  379. package/fixtures/review-findings-cause/clean.md +17 -0
  380. package/fixtures/review-findings-cause/defect.md +14 -0
  381. package/fixtures/review-findings-cause/old-debt.md +14 -0
  382. package/fixtures/review-findings-cause/quiet-in-fence.md +16 -0
  383. package/fixtures/tex-build/clean.tex +21 -0
  384. package/fixtures/tex-build/defect.tex +24 -0
  385. package/fixtures/tex-build/frontmatter-clean.tex +25 -0
  386. package/fixtures/tex-build/frontmatter-defect.tex +23 -0
  387. package/fixtures/toolchain-mirror/catalog.txt +5 -0
  388. package/fixtures/toolchain-mirror/install-tl +27 -0
  389. package/fixtures/toolchain-mirror/release-texlive.txt +3 -0
  390. package/fixtures/toolchain-mirror/release-year +1 -0
  391. package/fixtures/toolchain-mirror/stub-kpsewhich +8 -0
  392. package/fixtures/toolchain-mirror/stub-pdflatex +3 -0
  393. package/fixtures/toolchain-mirror/stub-tlmgr +44 -0
  394. package/hooks/hooks.harness.mjs +713 -0
  395. package/hooks/hooks.mutations.mjs +337 -0
  396. package/hooks/paper-edit-guard.hook.d.mts +13 -0
  397. package/hooks/paper-edit-guard.hook.mjs +457 -0
  398. package/hooks/paper-skills-nudge.hook.mjs +136 -0
  399. package/hooks/paper-status-gates.hook.mjs +156 -0
  400. package/hooks/paper-status-gates.sh +91 -0
  401. package/lib/agent-cli-version.harness.mjs +165 -0
  402. package/lib/agent-cli-version.mjs +106 -0
  403. package/lib/agent-cli-version.mutations.mjs +109 -0
  404. package/lib/markdown.mjs +386 -0
  405. package/lib/mutation-driver.harness.mjs +227 -0
  406. package/lib/mutation-driver.mjs +397 -0
  407. package/lib/mutation-driver.mutations.mjs +68 -0
  408. package/lib/paper-config.d.mts +34 -0
  409. package/lib/paper-config.harness.mjs +286 -0
  410. package/lib/paper-config.mjs +142 -0
  411. package/lib/paper-config.mutations.mjs +143 -0
  412. package/lib/skill-checks.mjs +701 -0
  413. package/lib/skill-corpus.mjs +403 -0
  414. package/lib/skill-eval-fixture.mjs +63 -0
  415. package/lib/skill-eval-kit.mjs +257 -0
  416. package/lib/skill-trigger-cases.harness.mjs +170 -0
  417. package/lib/skill-trigger-cases.mjs +446 -0
  418. package/lib/skill-trigger-cases.mutations.mjs +65 -0
  419. package/lib/trigger-ledger.mjs +215 -0
  420. package/package.json +97 -0
  421. package/plugin/.claude-plugin/plugin.json +8 -0
  422. package/plugin/hooks/hooks.json +30 -0
  423. package/scripts/check.harness.mjs +177 -0
  424. package/scripts/check.mjs +239 -0
  425. package/scripts/check.mutations.mjs +110 -0
  426. package/scripts/eslint-report-guard.mjs +82 -0
  427. package/scripts/exclusive.mjs +138 -0
  428. package/scripts/harness-api.frozen.json +76 -0
  429. package/scripts/harness-api.test.ts +175 -0
  430. package/scripts/layer-legacy-frozen.d.mts +28 -0
  431. package/scripts/layer-legacy-frozen.mjs +152 -0
  432. package/scripts/layer-legacy-frozen.test.ts +115 -0
  433. package/scripts/layer-legacy.frozen.json +50 -0
  434. package/scripts/mutation-batteries-frozen.harness.mjs +204 -0
  435. package/scripts/mutation-batteries-frozen.mjs +238 -0
  436. package/scripts/mutation-batteries.frozen.json +117 -0
  437. package/scripts/release-config.test.ts +90 -0
  438. package/scripts/rules-are-content-only.harness.mjs +113 -0
  439. package/scripts/rules-are-content-only.mjs +138 -0
  440. package/scripts/rules-are-content-only.mutations.mjs +81 -0
  441. package/scripts/rules-see-files.harness.mjs +115 -0
  442. package/scripts/rules-see-files.mjs +99 -0
  443. package/scripts/rules-see-files.mutations.mjs +131 -0
  444. package/scripts/run-mutations.mjs +100 -0
  445. package/scripts/semantic-release-plugins.d.ts +16 -0
  446. package/skills/README.md +15 -0
  447. package/skills/analyze-sibling-paper/SKILL.md +170 -0
  448. package/skills/analyze-sibling-paper/SKILL.md.spec.ts +186 -0
  449. package/skills/analyze-sibling-paper/analyze-sibling-paper.eval.mjs +19 -0
  450. package/skills/analyze-sibling-paper/analyze-sibling-paper.harness.mjs +23 -0
  451. package/skills/argument-arc/SKILL.md +177 -0
  452. package/skills/argument-arc/SKILL.md.spec.ts +192 -0
  453. package/skills/argument-arc/argument-arc.eval.mjs +19 -0
  454. package/skills/argument-arc/argument-arc.harness.mjs +23 -0
  455. package/skills/build-benchmark/SKILL.md +213 -0
  456. package/skills/build-benchmark/SKILL.md.spec.ts +220 -0
  457. package/skills/build-benchmark/build-benchmark.eval.mjs +19 -0
  458. package/skills/build-benchmark/build-benchmark.harness.mjs +23 -0
  459. package/skills/build-benchmark/references/adversarial-cold-repro.md +68 -0
  460. package/skills/camera-ready/SKILL.md +148 -0
  461. package/skills/camera-ready/SKILL.md.spec.ts +164 -0
  462. package/skills/camera-ready/camera-ready.eval.mjs +19 -0
  463. package/skills/camera-ready/camera-ready.harness.mjs +23 -0
  464. package/skills/cold-read-diff/SKILL.md +160 -0
  465. package/skills/cold-read-diff/SKILL.md.spec.ts +166 -0
  466. package/skills/cold-read-diff/cold-read-diff.eval.mjs +19 -0
  467. package/skills/cold-read-diff/cold-read-diff.harness.mjs +23 -0
  468. package/skills/draft-paper/SKILL.md +152 -0
  469. package/skills/draft-paper/SKILL.md.spec.ts +169 -0
  470. package/skills/draft-paper/draft-paper.eval.mjs +19 -0
  471. package/skills/draft-paper/draft-paper.harness.mjs +23 -0
  472. package/skills/extend-paper/SKILL.md +99 -0
  473. package/skills/extend-paper/SKILL.md.spec.ts +116 -0
  474. package/skills/extend-paper/extend-paper.eval.mjs +19 -0
  475. package/skills/extend-paper/extend-paper.harness.mjs +23 -0
  476. package/skills/find-venue/SKILL.md +128 -0
  477. package/skills/find-venue/SKILL.md.spec.ts +145 -0
  478. package/skills/find-venue/find-venue.eval.mjs +19 -0
  479. package/skills/find-venue/find-venue.harness.mjs +23 -0
  480. package/skills/grade-paper-writing/SKILL.md +436 -0
  481. package/skills/grade-paper-writing/SKILL.md.spec.ts +453 -0
  482. package/skills/grade-paper-writing/fixtures/control_gopen.txt +1 -0
  483. package/skills/grade-paper-writing/fixtures/control_human_paper.txt +1 -0
  484. package/skills/grade-paper-writing/fixtures/rewrite.txt +1 -0
  485. package/skills/grade-paper-writing/fixtures/specimen.txt +1 -0
  486. package/skills/grade-paper-writing/fixtures/structure-checks.md +22 -0
  487. package/skills/grade-paper-writing/grade-paper-writing.eval.mjs +19 -0
  488. package/skills/grade-paper-writing/grade-paper-writing.harness.mjs +23 -0
  489. package/skills/grade-paper-writing/prose-lint.mjs +713 -0
  490. package/skills/harden-paper/SKILL.md +318 -0
  491. package/skills/harden-paper/SKILL.md.spec.ts +336 -0
  492. package/skills/harden-paper/check-numbers.sh +33 -0
  493. package/skills/harden-paper/check-release-claims.sh +35 -0
  494. package/skills/harden-paper/fixtures/uncited-assertions-sample.md +43 -0
  495. package/skills/harden-paper/fixtures/uncited-assertions-sample.tex +77 -0
  496. package/skills/harden-paper/harden-paper.eval.mjs +19 -0
  497. package/skills/harden-paper/harden-paper.harness.mjs +23 -0
  498. package/skills/map-prior-work/SKILL.md +211 -0
  499. package/skills/map-prior-work/SKILL.md.spec.ts +227 -0
  500. package/skills/map-prior-work/map-prior-work.eval.mjs +19 -0
  501. package/skills/map-prior-work/map-prior-work.harness.mjs +23 -0
  502. package/skills/osf-artifact-upload/SKILL.md +52 -0
  503. package/skills/osf-artifact-upload/SKILL.md.spec.ts +59 -0
  504. package/skills/osf-artifact-upload/osf-artifact-upload.eval.mjs +22 -0
  505. package/skills/osf-artifact-upload/osf-artifact-upload.harness.mjs +103 -0
  506. package/skills/paper-adversarial-review/SKILL.md +126 -0
  507. package/skills/paper-adversarial-review/SKILL.md.spec.ts +142 -0
  508. package/skills/paper-adversarial-review/paper-adversarial-review.eval.mjs +19 -0
  509. package/skills/paper-adversarial-review/paper-adversarial-review.harness.mjs +23 -0
  510. package/skills/paper-pipeline/PIPELINE-MAP.md +371 -0
  511. package/skills/paper-pipeline/SKILL.md +499 -0
  512. package/skills/paper-pipeline/SKILL.md.spec.ts +517 -0
  513. package/skills/paper-pipeline/description-language.eval.mjs +347 -0
  514. package/skills/paper-pipeline/framing-vs-vocabulary.eval.mjs +891 -0
  515. package/skills/paper-pipeline/grade-paper-writing-ablation.eval.mjs +1254 -0
  516. package/skills/paper-pipeline/paper-pipeline.eval.mjs +22 -0
  517. package/skills/paper-pipeline/paper-pipeline.harness.mjs +143 -0
  518. package/skills/paper-pipeline/pipeline-firing.baseline.json +270 -0
  519. package/skills/paper-pipeline/pipeline-firing.eval.mjs +664 -0
  520. package/skills/paper-pipeline/pipeline-language.eval.mjs +672 -0
  521. package/skills/paper-pipeline/references/acceptance-gate.md +329 -0
  522. package/skills/paper-pipeline/references/acl-venue-rules.md +142 -0
  523. package/skills/paper-pipeline/references/anonymization.md +68 -0
  524. package/skills/paper-pipeline/references/artifact-checklist.md +93 -0
  525. package/skills/paper-pipeline/references/body-vs-appendix.md +97 -0
  526. package/skills/paper-pipeline/references/credit-criteria.md +69 -0
  527. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/README.md +35 -0
  528. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/run_retext.mjs +24 -0
  529. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/sentences.txt +11 -0
  530. package/skills/paper-pipeline/references/occupancy-2026-08-06-probe/test_sentences.py +25 -0
  531. package/skills/paper-pipeline/references/occupancy-2026-08-06-prose-checkers.md +538 -0
  532. package/skills/paper-pipeline/references/occupancy-2026-08-06-reproducible-tooling.md +431 -0
  533. package/skills/paper-pipeline/references/occupancy-2026-08-06-staleness-and-orchestration.md +592 -0
  534. package/skills/paper-pipeline/references/pipeline-status-template.md +162 -0
  535. package/skills/paper-pipeline/references/review-ratchet.md +36 -0
  536. package/skills/paper-pipeline/references/sweep-2026-08-09-ideal-pipeline.md +585 -0
  537. package/skills/paper-pipeline/references/writing-craft.md +448 -0
  538. package/skills/paper-pipeline/repro/2026-08-07-description-language-control.log +63 -0
  539. package/skills/paper-pipeline/repro/2026-08-07-fork-check.log +52 -0
  540. package/skills/paper-pipeline/repro/2026-08-07-fork-check2.log +33 -0
  541. package/skills/paper-pipeline/repro/2026-08-07-language-eval-pilot.log +33 -0
  542. package/skills/paper-pipeline/repro/2026-08-07-language-eval-raw.log +166 -0
  543. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.json +338 -0
  544. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-oracle.log +118 -0
  545. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary-raw.log +245 -0
  546. package/skills/paper-pipeline/repro/2026-08-08-framing-vs-vocabulary.json +776 -0
  547. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-oracle.log +53 -0
  548. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-A6-raw.log +89 -0
  549. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.json +450 -0
  550. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-oracle.log +136 -0
  551. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-raw.log +242 -0
  552. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation-setupdiff.log +59 -0
  553. package/skills/paper-pipeline/repro/2026-08-08-grade-paper-writing-ablation.json +1032 -0
  554. package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.json +139 -0
  555. package/skills/paper-pipeline/repro/2026-08-08-parent-replication-gpw.log +98 -0
  556. package/skills/paper-pipeline/repro/2026-08-08-parent-replication.mjs +92 -0
  557. package/skills/paper-pipeline/repro/README.md +129 -0
  558. package/skills/paper-pipeline/repro/analyze-language-eval.py +116 -0
  559. package/skills/paper-pipeline/scripts/README.md +344 -0
  560. package/skills/paper-pipeline/scripts/announce.mjs +67 -0
  561. package/skills/paper-pipeline/scripts/artifact-coverage.harness.mjs +496 -0
  562. package/skills/paper-pipeline/scripts/artifact-coverage.mjs +397 -0
  563. package/skills/paper-pipeline/scripts/artifact-coverage.mutations.mjs +218 -0
  564. package/skills/paper-pipeline/scripts/check-provenance.mjs +184 -0
  565. package/skills/paper-pipeline/scripts/consumer.d.mts +32 -0
  566. package/skills/paper-pipeline/scripts/consumer.harness.mjs +562 -0
  567. package/skills/paper-pipeline/scripts/consumer.mjs +535 -0
  568. package/skills/paper-pipeline/scripts/consumer.mutations.mjs +190 -0
  569. package/skills/paper-pipeline/scripts/extract-ref-facts.harness.mjs +457 -0
  570. package/skills/paper-pipeline/scripts/extract-ref-facts.mjs +656 -0
  571. package/skills/paper-pipeline/scripts/extract-ref-facts.mutations.mjs +54 -0
  572. package/skills/paper-pipeline/scripts/fixtures/clean/PIPELINE-STATUS.md +51 -0
  573. package/skills/paper-pipeline/scripts/fixtures/dirty/PIPELINE-STATUS.md +52 -0
  574. package/skills/paper-pipeline/scripts/fixtures/dirty/paper.md +6 -0
  575. package/skills/paper-pipeline/scripts/fixtures/real-bib/refs.bib +153 -0
  576. package/skills/paper-pipeline/scripts/generated-code.harness.mjs +466 -0
  577. package/skills/paper-pipeline/scripts/generated-code.mjs +338 -0
  578. package/skills/paper-pipeline/scripts/generated-code.mutations.mjs +254 -0
  579. package/skills/paper-pipeline/scripts/ledger.mjs +623 -0
  580. package/skills/paper-pipeline/scripts/ledger.selftest.mjs +286 -0
  581. package/skills/paper-pipeline/scripts/pipeline-check.harness.mjs +389 -0
  582. package/skills/paper-pipeline/scripts/pipeline-check.mjs +737 -0
  583. package/skills/paper-pipeline/scripts/pipeline-check.mutations.mjs +54 -0
  584. package/skills/paper-pipeline/scripts/pipeline-edges.mjs +169 -0
  585. package/skills/paper-pipeline/scripts/population-map.harness.mjs +178 -0
  586. package/skills/paper-pipeline/scripts/population-map.mjs +181 -0
  587. package/skills/paper-pipeline/scripts/population-map.mutations.mjs +65 -0
  588. package/skills/paper-pipeline/scripts/population-map.selftest.mjs +122 -0
  589. package/skills/paper-pipeline/scripts/provenance.harness.mjs +240 -0
  590. package/skills/paper-pipeline/scripts/provenance.mutations.mjs +59 -0
  591. package/skills/paper-pipeline/scripts/round-diff.harness.mjs +881 -0
  592. package/skills/paper-pipeline/scripts/round-diff.mjs +576 -0
  593. package/skills/paper-pipeline/scripts/round-diff.mutations.mjs +276 -0
  594. package/skills/paper-pipeline/scripts/run-mechanical.mjs +633 -0
  595. package/skills/paper-pipeline/scripts/status.mjs +295 -0
  596. package/skills/paper-status/SKILL.md +183 -0
  597. package/skills/paper-status/SKILL.md.spec.ts +190 -0
  598. package/skills/paper-status/paper-status.eval.mjs +22 -0
  599. package/skills/paper-status/paper-status.harness.mjs +25 -0
  600. package/skills/pc-panel-review/SKILL.md +263 -0
  601. package/skills/pc-panel-review/SKILL.md.spec.ts +280 -0
  602. package/skills/pc-panel-review/pc-panel-review.eval.mjs +19 -0
  603. package/skills/pc-panel-review/pc-panel-review.harness.mjs +23 -0
  604. package/skills/plan-paper-timeline/SKILL.md +182 -0
  605. package/skills/plan-paper-timeline/SKILL.md.spec.ts +200 -0
  606. package/skills/plan-paper-timeline/fixtures/fake-google-calendar.mjs +239 -0
  607. package/skills/plan-paper-timeline/plan-paper-timeline.effects.harness.mjs +431 -0
  608. package/skills/plan-paper-timeline/plan-paper-timeline.effects.mutations.mjs +65 -0
  609. package/skills/plan-paper-timeline/plan-paper-timeline.eval.mjs +19 -0
  610. package/skills/plan-paper-timeline/plan-paper-timeline.harness.mjs +23 -0
  611. package/skills/render-paper/SKILL.md +159 -0
  612. package/skills/render-paper/SKILL.md.spec.ts +166 -0
  613. package/skills/render-paper/check-render.sh +419 -0
  614. package/skills/render-paper/checkers-requirements.txt +55 -0
  615. package/skills/render-paper/ensure-checkers.sh +69 -0
  616. package/skills/render-paper/extract-pdf-facts.harness.mjs +166 -0
  617. package/skills/render-paper/extract-pdf-facts.mjs +144 -0
  618. package/skills/render-paper/render-paper.eval.mjs +19 -0
  619. package/skills/render-paper/render-paper.harness.mjs +339 -0
  620. package/skills/research-ideate/SKILL.md +136 -0
  621. package/skills/research-ideate/SKILL.md.spec.ts +152 -0
  622. package/skills/research-ideate/research-ideate.eval.mjs +19 -0
  623. package/skills/research-ideate/research-ideate.harness.mjs +23 -0
  624. package/skills/skill-contract.mutations.mjs +179 -0
  625. package/skills/study-accepted-papers/SKILL.md +206 -0
  626. package/skills/study-accepted-papers/SKILL.md.spec.ts +223 -0
  627. package/skills/study-accepted-papers/study-accepted-papers.eval.mjs +19 -0
  628. package/skills/study-accepted-papers/study-accepted-papers.harness.mjs +23 -0
  629. package/skills/submit-paper/SKILL.md +182 -0
  630. package/skills/submit-paper/SKILL.md.spec.ts +199 -0
  631. package/skills/submit-paper/check-deanon.sh +149 -0
  632. package/skills/submit-paper/references/publishers/acm.md +92 -0
  633. package/skills/submit-paper/references/venues/agenticdev.jsonc +108 -0
  634. package/skills/submit-paper/references/venues/agenticdev.md +139 -0
  635. package/skills/submit-paper/references/venues/agenticdev.tex +19 -0
  636. package/skills/submit-paper/references/venues/aisec.jsonc +101 -0
  637. package/skills/submit-paper/references/venues/aisec.md +105 -0
  638. package/skills/submit-paper/references/venues/paper-guards.tex +41 -0
  639. package/skills/submit-paper/references/venues/realm.jsonc +81 -0
  640. package/skills/submit-paper/references/venues/realm.md +155 -0
  641. package/skills/submit-paper/references/venues/tex-base.jsonc +50 -0
  642. package/skills/submit-paper/references/venues/venue-profile.schema.json +74 -0
  643. package/skills/submit-paper/submit-paper.eval.mjs +19 -0
  644. package/skills/submit-paper/submit-paper.harness.mjs +23 -0
  645. package/skills/sweep-design-space/SKILL.md +269 -0
  646. package/skills/sweep-design-space/SKILL.md.spec.ts +285 -0
  647. package/skills/sweep-design-space/sweep-design-space.eval.mjs +19 -0
  648. package/skills/sweep-design-space/sweep-design-space.harness.mjs +23 -0
  649. package/skills/tighten-paper/SKILL.md +368 -0
  650. package/skills/tighten-paper/SKILL.md.spec.ts +384 -0
  651. package/skills/tighten-paper/structure.mjs +371 -0
  652. package/skills/tighten-paper/tighten-paper.eval.mjs +19 -0
  653. package/skills/tighten-paper/tighten-paper.harness.mjs +23 -0
  654. package/skills/verify-citations/SKILL.md +328 -0
  655. package/skills/verify-citations/SKILL.md.spec.ts +345 -0
  656. package/skills/verify-citations/scripts/bib-authors.mjs +479 -0
  657. package/skills/verify-citations/scripts/bib-authors.test.mjs +175 -0
  658. package/skills/verify-citations/scripts/verify-cites.mjs +1108 -0
  659. package/skills/verify-citations/scripts/verify-cites.test.mjs +735 -0
  660. package/skills/verify-citations/verify-citations.eval.mjs +19 -0
  661. package/skills/verify-citations/verify-citations.harness.mjs +23 -0
  662. package/src/CLAUDE.md +51 -0
  663. package/src/action-ref.test.ts +26 -0
  664. package/src/action-ref.ts +15 -0
  665. package/src/adapters/banal/failure.test.ts +63 -0
  666. package/src/adapters/banal/failure.ts +118 -0
  667. package/src/adapters/banal/index.test.ts +119 -0
  668. package/src/adapters/banal/index.ts +100 -0
  669. package/src/adapters/banal/install.test.ts +20 -0
  670. package/src/adapters/banal/install.ts +41 -0
  671. package/src/adapters/banal/invocation.test.ts +74 -0
  672. package/src/adapters/banal/invocation.ts +95 -0
  673. package/src/adapters/banal/locate.test.ts +52 -0
  674. package/src/adapters/banal/locate.ts +84 -0
  675. package/src/adapters/banal/output.test.ts +140 -0
  676. package/src/adapters/banal/output.ts +141 -0
  677. package/src/adapters/banal/pin.ts +30 -0
  678. package/src/adapters/banal/probe.ts +35 -0
  679. package/src/adapters/banal/run.test.ts +191 -0
  680. package/src/adapters/banal/run.ts +244 -0
  681. package/src/adapters/banal/settings.test.ts +31 -0
  682. package/src/adapters/banal/settings.ts +55 -0
  683. package/src/adapters/banal/xml.test.ts +111 -0
  684. package/src/adapters/banal/xml.ts +112 -0
  685. package/src/adapters/curl/download.io.ts +73 -0
  686. package/src/adapters/curl/download.test.ts +55 -0
  687. package/src/adapters/curl/index.ts +5 -0
  688. package/src/adapters/memory/index.ts +131 -0
  689. package/src/adapters/node/files.io.ts +39 -0
  690. package/src/adapters/node/files.test.ts +28 -0
  691. package/src/adapters/node/host.io.ts +15 -0
  692. package/src/adapters/node/index.ts +36 -0
  693. package/src/adapters/node/process.io.ts +49 -0
  694. package/src/adapters/node/process.test.ts +46 -0
  695. package/src/adapters/node/workspace.io.ts +40 -0
  696. package/src/adapters/node/workspace.test.ts +58 -0
  697. package/src/adapters/pdfjs/fill.test.ts +111 -0
  698. package/src/adapters/pdfjs/fill.ts +141 -0
  699. package/src/build-engine.harness.mjs +314 -0
  700. package/src/build-engine.ts +219 -0
  701. package/src/build.harness.mjs +631 -0
  702. package/src/build.mutations.mjs +195 -0
  703. package/src/build.ts +793 -0
  704. package/src/cli.harness.mjs +2007 -0
  705. package/src/cli.mutations.mjs +448 -0
  706. package/src/cli.ts +1189 -0
  707. package/src/doctor.harness.mjs +396 -0
  708. package/src/doctor.mutations.mjs +175 -0
  709. package/src/doctor.ts +356 -0
  710. package/src/domain/geometry.ts +108 -0
  711. package/src/domain/host.ts +23 -0
  712. package/src/domain/page-layout.ts +32 -0
  713. package/src/domain/paths.ts +5 -0
  714. package/src/domain/result.test.ts +26 -0
  715. package/src/domain/result.ts +29 -0
  716. package/src/domain/sha256.test.ts +12 -0
  717. package/src/domain/sha256.ts +21 -0
  718. package/src/domain/text.ts +11 -0
  719. package/src/engine.harness.mjs +252 -0
  720. package/src/engine.ts +176 -0
  721. package/src/exit-code.test.ts +21 -0
  722. package/src/exit-code.ts +38 -0
  723. package/src/facts-file.test.ts +240 -0
  724. package/src/facts-file.ts +241 -0
  725. package/src/hooks-settings.harness.mjs +386 -0
  726. package/src/hooks-settings.mutations.mjs +116 -0
  727. package/src/hooks-settings.ts +434 -0
  728. package/src/init.ts +900 -0
  729. package/src/latex-log.harness.mjs +226 -0
  730. package/src/latex-log.ts +234 -0
  731. package/src/latex-loop.harness.mjs +449 -0
  732. package/src/latex-loop.ts +211 -0
  733. package/src/link-skills.harness.mjs +273 -0
  734. package/src/link-skills.mutations.mjs +136 -0
  735. package/src/link-skills.ts +258 -0
  736. package/src/new-paper.harness.mjs +216 -0
  737. package/src/new-paper.mutations.mjs +79 -0
  738. package/src/new-paper.ts +158 -0
  739. package/src/pdf-facts.harness.mjs +188 -0
  740. package/src/pdf-facts.ts +327 -0
  741. package/src/pdf-geometry.harness.mjs +254 -0
  742. package/src/pdf-geometry.ts +300 -0
  743. package/src/ports/download.ts +10 -0
  744. package/src/ports/files.ts +11 -0
  745. package/src/ports/measure-geometry.ts +8 -0
  746. package/src/ports/process.ts +46 -0
  747. package/src/ports/tool-installer.ts +33 -0
  748. package/src/ports/workspace.ts +20 -0
  749. package/src/rules-config.harness.mjs +114 -0
  750. package/src/rules-config.ts +178 -0
  751. package/src/structure.harness.mjs +179 -0
  752. package/src/structure.mutations.mjs +83 -0
  753. package/src/structure.ts +166 -0
  754. package/src/tex-requirements.harness.mjs +238 -0
  755. package/src/tex-requirements.ts +181 -0
  756. package/src/toolchain.harness.mjs +651 -0
  757. package/src/toolchain.ts +755 -0
  758. package/src/types.ts +106 -0
  759. package/templates/paper/PIPELINE-STATUS.md +72 -0
  760. package/templates/paper/paper.md +4 -0
  761. package/templates/paper/paper.tex +8 -0
  762. package/tsconfig.json +23 -0
@@ -0,0 +1,145 @@
1
+ // Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
2
+ //
3
+ // Adopted 2026-08-17 as part of the second batch. The body is the previous SKILL.md
4
+ // VERBATIM, so the compiled diff shows only what the compiler adds. No `disallowedTools`
5
+ // fence yet: the field exists on `SkillSpec` as of the branch `claude/skill-disallowed-tools`
6
+ // but is not in a release `mine` installs, so adding it here would not compile.
7
+ import { experimental_skill } from "vigiles/spec";
8
+
9
+ export default experimental_skill({
10
+ name: "find-venue",
11
+ description:
12
+ "Discover and rank real venues for a given paper, scored by authorship credit not just prestige. Fetch candidate CFPs (WebSearch/WebFetch), capture deadline / page limit / paper-type fit / indexing (ACM DL / IEEE Xplore / archival vs non-archival) / double-blind / remote-attendance / selectivity, then rank by credit-weight (peer-reviewed + indexed + parent-venue prestige) × topic fit × accept-probability × deadline feasibility × remote-friendliness. Emit a comparison table and a keep/switch recommendation. Encodes: workshop newness does NOT hurt authorship; non-archival workshops rank LOW; the prestige move is to EXTEND the accepted paper later, not hold out. Compose with research-ideate (upstream), plan-paper-timeline, the submit-paper venue data cards (submit-paper/references/venues/<venue>.md), and extend-paper.",
13
+ tools: [
14
+ "Read",
15
+ "Write",
16
+ "Grep",
17
+ "Glob",
18
+ "WebSearch",
19
+ "WebFetch",
20
+ "Agent",
21
+ "Bash(node .claude/skills/paper-pipeline/scripts/announce.mjs:*)",
22
+ "Bash(node .claude/skills/paper-pipeline/scripts/ledger.mjs:*)",
23
+ ],
24
+ body: `
25
+ # find-venue — rank real venues by what earns the credit, then keep or switch
26
+
27
+ ## Run me
28
+
29
+ 🔴 FIRST, before any other step:
30
+
31
+ \`\`\`
32
+ node .claude/skills/paper-pipeline/scripts/announce.mjs find-venue <dir>
33
+ \`\`\`
34
+
35
+ An advisory pass cannot be observed failing — silence is both its error state and its normal
36
+ state — so starting is an event, and events get written down.
37
+
38
+ The \`<dir>\` argument is **optional in spirit**: this skill can run before a paper directory exists, so
39
+ pass whichever directory the work lives in, or \`.\`. The ledger row is written either way, and a plain
40
+ dot is more honest than an invented path.
41
+
42
+ Takes a paper (or the candidate venue *types* from \`research-ideate\`) and finds the best real place to
43
+ submit it. "Best" here means **best for the publication record**, which is not the same as most prestigious —
44
+ an indexed workshop you can actually hit beats a top conference whose deadline already closed. This
45
+ skill produces a ranked table and a keep/switch call; it does NOT do the submission mechanics (that's
46
+ \`submit-paper\` + the venue card).
47
+
48
+ Grounding: the authorship criterion — why archival + indexed is the whole game.
49
+
50
+ ## Gather candidates (fetch, don't guess)
51
+
52
+ \`WebSearch\` / \`WebFetch\` the open CFPs for the paper's topic + the current cycle. For EACH candidate
53
+ capture, from the actual CFP page:
54
+ - **Deadline** (in AoE; convert to your local time for feasibility).
55
+ - **Page limit** and required format (ACM sigconf / IEEE / other) — a full-paper limit vs a
56
+ short/WIP/workshop limit changes what you must produce.
57
+ - **Paper-type fit** — does the CFP call for measurement/benchmark/short/WIP/full papers of this shape?
58
+ - **Indexing** — the single most load-bearing field. Does acceptance land in **ACM DL / IEEE Xplore /
59
+ archival proceedings** (counts for authorship) or is it **non-archival** (talk-only, no indexed
60
+ proceedings — does NOT count)?
61
+ - **Double-blind?** — determines anonymization work (see \`anonymization.md\`).
62
+ - **Remote attendance** — can the author present/attend without international travel?
63
+ - **Selectivity / prestige** — the parent venue's tier (workshop @ CCS/ASE/FSE inherits weight).
64
+
65
+ ## Rank
66
+
67
+ Score each candidate by:
68
+
69
+ \`\`\`
70
+ rank = credit-weight × topic-fit × accept-probability × deadline-feasibility × remote-friendliness
71
+ \`\`\`
72
+
73
+ - **credit-weight** = (peer-reviewed? — required) × (indexed/archival? — required) × parent-venue
74
+ prestige (a bonus, not a gate). **Non-archival ⇒ credit-weight ≈ 0** — it earns no authorship credit,
75
+ so it sinks to the bottom no matter how nice the CFP reads.
76
+ - **topic-fit** — how squarely the paper matches the CFP scope (a stretch fit raises reject risk).
77
+ - **accept-probability** — realistic odds given the paper's maturity and the venue's bar.
78
+ - **deadline-feasibility** — can the paper (and artifact) be ready by the deadline? A great venue you
79
+ miss is a zero.
80
+ - **remote-friendliness** — remote-OK is a real weight here, not a footnote.
81
+
82
+ ### Facts to encode while ranking
83
+ - **Workshop newness does NOT hurt the authorship criterion.** A brand-new workshop's indexed
84
+ proceedings count the same; venue prestige only matters at final merits, never for authorship. Do not
85
+ down-rank a venue just for being new.
86
+ - **Non-archival workshops rank LOW for authorship** — no indexed proceedings, no credit. A great talk
87
+ slot with no DOI is worth little to the dossier.
88
+ - **Prestige is a later move, not a hold-out.** Do NOT sit on a finished paper waiting for a fancier
89
+ venue. Ship to the best-fit archival venue open now, then **EXTEND** the accepted paper (≥30% new) to
90
+ a higher-prestige venue as a *second, stronger* publication — see \`extend-paper\`. Two indexed papers
91
+ (workshop → conference) beat one that missed its window.
92
+
93
+ ## Output
94
+
95
+ 1. **Comparison table** — one row per candidate: venue, parent, deadline (AoE + local), page limit,
96
+ type fit, **indexed? (Y/N + where)**, double-blind, remote, selectivity, computed rank.
97
+ 2. **Keep/switch recommendation** — the top-ranked venue with the one-line reason, and (if the paper
98
+ already has a target) an explicit **keep** or **switch** verdict against it. Note the intended
99
+ \`extend-paper\` upgrade target for later.
100
+
101
+ ## Record the verdict
102
+
103
+ 🔴 LAST step, once the deliverable exists:
104
+
105
+ \`\`\`
106
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record find-venue <dir> FINDING <count> <report-path>
107
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record find-venue <dir> ABSTAINED <reason> "<one line>"
108
+ \`\`\`
109
+
110
+ 🔴 **There is no PASS.** A shortlist is a set of findings about the world, not a certificate that
111
+ the venue question is settled.
112
+
113
+ **FINDING** — the sweep produced a ranked shortlist with an explicit keep/switch call; \`<count>\` is
114
+ the number of candidates ranked and \`<report-path>\` the comparison table. Add \`--blocking\` when
115
+ nothing open clears the peer-reviewed + indexed gate — a real answer, and not an empty run.
116
+ **ABSTAINED** — \`no-witness\`: CFPs were read and no candidate could be ranked either way.
117
+ \`input-missing\`: there is no paper description to match venues against.
118
+
119
+ Record the whole table's path, not just the winner. The next sweep starts from the candidates that were
120
+ dropped and why, and a verdict with no table behind it cannot be re-checked when a deadline moves.
121
+
122
+ ## Rules
123
+ - Fetch every CFP fact from the real page; never invent a deadline, page limit, or indexing status.
124
+ - Indexed + peer-reviewed is a gate, not a tiebreaker — a non-archival venue cannot win on charm.
125
+ - Don't hold a finished paper hostage to prestige; ship archival now, extend later.
126
+ - A missed deadline is a zero — weight feasibility honestly against the paper's real readiness.
127
+ - Convert deadlines to your local time so \`plan-paper-timeline\` can schedule against them.
128
+
129
+ ## Compose with
130
+ - \`research-ideate\` (upstream) — consumes its candidate venue *types* and sharpest framing.
131
+ - \`plan-paper-timeline\` — feed it the chosen deadline to back-plan the work.
132
+ - \`submit-paper\` venue data cards (\`submit-paper/references/venues/<venue>.md\`, e.g. \`agenticdev.md\`,
133
+ \`aisec.md\`) — the winner gets a venue-specific data card with its HotCRP quirks; save a new one per
134
+ venue as plain data, not a new skill.
135
+ - \`extend-paper\` — the prestige-upgrade target this skill names but defers.
136
+
137
+ ## Provenance
138
+ The **AgenticDev 2026 @ ASE** venue decision was made by a **9-agent analysis** that checked every open
139
+ venue against this exact rubric. It **kept AgenticDev** — nothing open beat it on fit × archival ×
140
+ timeline: NeurIPS Eval had already **closed**, and FSE/MSR each needed a **full paper** (wrong type /
141
+ too much scope for the deadline). The prestige upgrade was deliberately deferred to an **extension to
142
+ MSR/NeurIPS 2027**, not a switch — proving the rule: ship the best-fit archival venue open now, extend
143
+ later. **AISec 2026 @ ACM CCS** confirmed the archival-weight logic at a top-tier security bar. Both
144
+ papers are indexed proceedings; neither was down-ranked for the workshop's newness.`,
145
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * find-venue — the PAID tier: does this skill's description actually fire?
3
+ *
4
+ * COLOCATED ON PURPOSE (vigiles decides coverage by placement as of 2026-08-11).
5
+ * The prompts live in `.claude/lib/skill-trigger-cases.mjs` so all 21 cases
6
+ * are reviewed as one table where collisions between siblings are visible;
7
+ * copying them here would recreate the drift that rule exists to prevent.
8
+ *
9
+ * Measures recall (fires on its own territory) AND precision (stays quiet on a
10
+ * colliding sibling's territory), against the REAL `.claude` harness so the skill
11
+ * competes with every other installed description — an isolated run overstates
12
+ * recall and understates false positives.
13
+ *
14
+ * Costs money; not CI.
15
+ * node .claude/skills/find-venue/find-venue.eval.mjs [trials]
16
+ */
17
+ import { runSkillTriggerEval } from "../../lib/skill-eval-kit.mjs";
18
+
19
+ await runSkillTriggerEval("find-venue");
@@ -0,0 +1,23 @@
1
+ /**
2
+ * find-venue — the free, deterministic tier. No model, no network.
3
+ *
4
+ * COLOCATED ON PURPOSE. vigiles decides coverage by PLACEMENT as of 2026-08-11:
5
+ * a test that merely names a surface no longer counts, because that tier was
6
+ * crediting surfaces nothing touched. So each skill needs a file inside its own
7
+ * directory — this one.
8
+ *
9
+ * The assertions live in `.claude/lib/skill-checks.mjs` and are CALLED here with
10
+ * this skill's name. They are not copied: 22 copies of the same checks is the drift that
11
+ * module exists to avoid. (Until 2026-08-11 this was an env-var side channel into a
12
+ * 614-line file named after no surface; it is a function call now.)
13
+ *
14
+ * What this proves: this skill's frontmatter parses as strict YAML, its declared
15
+ * tool contract is sane, its pipeline wiring points at scripts that exist, and it
16
+ * announces/records under ITS OWN identity rather than a sibling's.
17
+ *
18
+ * What it does NOT prove: that the skill fires, or that its guidance produces a
19
+ * good result. Those need a real model — see `find-venue.eval.mjs`.
20
+ */
21
+ import { checkSkill } from "../../lib/skill-checks.mjs";
22
+
23
+ await checkSkill("find-venue");
@@ -0,0 +1,436 @@
1
+ ---
2
+ name: grade-paper-writing
3
+ description: Use when asking "does this paper read well?" / "is the writing any good?" / "it reads like a wall of text and jargon" / "grade the writing" on a draft. Grades WRITING CRAFT only — nine dimensions 1–5 (Title, Abstract, Intro architecture, Structure, Prose clarity, Jargon discipline, Landing-the-point, Figure economy, Honesty-without-hedge-stacking) against how the best-written papers read (Peyton Jones, McEnerney, Gopen & Swan; exemplars Trusting Trust, Carlini, Greshake), naming the offending sentence and the fix for each. Runs the PERSONA cold-read stall pass (a committed non-academic persona subagent, per-section) whose stall inventory — not the rubric number — is the readability gate other skills consume (pc-panel-review, paper-adversarial-review, harden-paper). Defaults to a blind multi-grader panel; after fixes, mandates the claims-preservation diff (row `claims`). NOT a content/defect review (paper-adversarial-review / pc-panel-review), NOT a structural cut plan (tighten-paper — run that first on a bloated draft), NOT venue-bar content strength (study-accepted-papers). Compose with harden-paper (which calls it), draft-paper (generative counterpart), render-paper.
4
+ allowed-tools: [Read, Write, Edit, Grep, Glob, Agent, Skill, Bash(node .claude/skills/paper-pipeline/scripts/announce.mjs:*), Bash(node .claude/skills/paper-pipeline/scripts/ledger.mjs:*)]
5
+ ---
6
+
7
+ <!-- vigiles:sha256:374531c7f64e998e compiled from skills/grade-paper-writing/SKILL.md.spec.ts -->
8
+
9
+ # grade-paper-writing — grade how the paper READS, then fix it sentence by sentence
10
+
11
+ ## Run me
12
+
13
+ 🔴 FIRST, before any other step:
14
+
15
+ ```
16
+ node .claude/skills/paper-pipeline/scripts/announce.mjs grade-paper-writing <paper-dir>
17
+ ```
18
+
19
+ An advisory pass cannot be observed failing — silence is both its error state and its normal
20
+ state — so starting is an event, and events get written down.
21
+
22
+ The review skills hunt scientific defects; `study-accepted-papers` checks whether the contribution clears
23
+ the venue's bar. Neither tells you the paper is a slog to read. This skill does exactly that: it grades
24
+ the **writing craft** against how the best-written papers actually read, and turns each low score into a
25
+ concrete, sentence-level fix. Its target failure mode is the common one — *"a wall of text and jargon that
26
+ doesn't drive home how crazy the situation is"* — which is a writing problem, not a science problem, and
27
+ which the defect-hunting skills will pass right over.
28
+
29
+ Grounding (do NOT re-derive — read it): `../paper-pipeline/references/writing-craft.md` holds the craft
30
+ rules, the exemplar lessons, and the full nine-dimension rubric with 1/5 anchors. This skill applies it.
31
+
32
+ ## The frame to hold while grading (from the reference)
33
+ The papers that make a human care share three moves: **(1) open on a problem/assumption the reader already
34
+ holds; (2) break it with the single most visceral concrete instance, not an aggregate stat; (3) land one
35
+ repeatable sentence.** Grade the draft against that trio, plus McEnerney's test — *does this create value
36
+ for the reader, or just record the author's thinking?* — and Gopen/Swan's sentence mechanics (payload in
37
+ the stress position, subject next to verb, one idea per sentence).
38
+
39
+ ## Execution model — run the graders as subagents (context forks), by default
40
+ The blind panel (≥3 graders) and the cold-read stall pass **run in fresh subagents, not inline** — for two
41
+ reasons: (a) grading dumps the whole paper + long stall inventories into context, which gunks up the main
42
+ thread (context rot); (b) fresh context is the *point* of blind grading — a grader that saw the drafting or
43
+ the "it improved from last draft" history anchors optimistic. **Spawn the graders in parallel** (one message,
44
+ multiple Agent calls), with an adversarial model (Fable) for at least one seat. The main thread only
45
+ **synthesizes the distilled scorecards** — it does not read the paper line-by-line for the grade itself.
46
+ (This is the writing-axis instance of the session working rule: delegate heavy/ context-heavy work to
47
+ subagents, keep the main thread for synthesis.)
48
+
49
+ ## The stall pass — specification
50
+
51
+ This is the pass the author cannot run on himself, and it was the weakest thing in this skill: its
52
+ spec was a pointer to a file that does not exist. On 2026-08-05 it had run six times on one paper,
53
+ and the author then found eleven unreadable passages by eye in twenty minutes. Everything below is
54
+ derived from that gap.
55
+
56
+ ### 🔴 Read the BUILT PDF, not the source
57
+
58
+ **The stall pass reads the typeset pages.** The source is for locating the fix afterwards, never for
59
+ judging the read. This was previously written as "read the `.tex`/`.md`, **or** run `render-paper`",
60
+ and that *or* is why the pass kept missing what the author saw immediately: he reads the PDF.
61
+
62
+ Things that exist only in the render, every one of which produces a real stall:
63
+
64
+ - a paragraph broken across a column or a page, so its second half arrives with no antecedent;
65
+ - a table or figure floated away from the sentence that introduces it — the caption is now the
66
+ reader's only context, and captions are written assuming the body;
67
+ - a wall of text, which is a **visual** property: nine lines of unbroken prose in a narrow column
68
+ reads as impassable at a width where six does not;
69
+ - a heading orphaned at the foot of a column;
70
+ - how much of page 1 is numbers, which is what a reviewer's first impression is actually made of;
71
+ - line numbers and two-column measure, which change where the eye stops.
72
+
73
+ `repro/build-submission.sh` produces the PDF; `render-paper` turns pages into images. Judge from
74
+ those. If only the source is available, say so in the report — a stall inventory taken from source
75
+ is a weaker artifact and must not be presented as the same thing.
76
+
77
+ ### What the reader is given, and what is withheld
78
+
79
+ **Given:** the typeset text. **Withheld:** the title's meaning, the abstract as framing, the venue,
80
+ the research area, what the paper is trying to show, and every previous stall inventory.
81
+
82
+ 🔴 **Withholding is the mechanism, not politeness.** A grader handed the paper *plus* the framing
83
+ reconstructs the idea from the surroundings and then reports that the sentence is clear. It cannot
84
+ un-know. That is precisely how six passes in a row missed *"the state to remove is not the rule but
85
+ its claim about itself"* — an expert reader supplies the missing idea for free and never notices
86
+ they supplied it.
87
+
88
+ Give the passage **as text in the prompt**, not as a file path. A path invites reading the
89
+ neighbours, and reading the neighbours is how this pass fails silently.
90
+
91
+ ### The one question, per sentence
92
+
93
+ > **What does this sentence claim? Restate it in your own words.**
94
+
95
+ Not "did you stumble" — stumbling is a feeling, and a competent model does not feel it. Restatement
96
+ is a task with a pass/fail. If the reader cannot restate without guessing, that is `CANNOT PARSE`
97
+ and it is the finding.
98
+
99
+ ### Stall classes — the taxonomy the pass was missing
100
+
101
+ The old pass logged only classes 1–3 and rated papers readable that were not. Classes 4–6 are where
102
+ every 2026-08-05 defect lived.
103
+
104
+ | # | class | test | real example |
105
+ |---|---|---|---|
106
+ | 1 | undefined term | a coined word used before any sentence says what it refers to | `admission` before the mechanism is described |
107
+ | 2 | orphan number | a figure with no denominator or no named population | "over 90 runs … none of 48 … 12 of 12" — three populations, no map |
108
+ | 3 | unreadable exhibit | a table cell or caption that needs the body to decode | — |
109
+ | 4 | 🔴 **means nothing** | every word is known, the sentence parses grammatically, and the reader still cannot say what it claims | *"the state to remove is not the rule but its claim about itself"* · *"constructions nobody built"* |
110
+ | 5 | 🔴 **sounds clever, carries nothing** | reads smoothly, feels like a payoff, and its content is a restatement or is borrowed from a section the reader has not read | *"nine deletions against four fixes is §5.1's cheap way out, winning again"* |
111
+ | 6 | 🔴 **vague heading** | a heading naming no concrete object — no linter, no configuration, no agent, no file | *"Three answers, all of them after the fact"* · *"The configuration nobody resolves"* |
112
+
113
+ Class 5 is the one a knowing reader always waves through, because it reads *well*. Ask for it by
114
+ name — "which sentences sound clever but say less than they appear to?" — or it will not be reported.
115
+
116
+ ### Report shape
117
+
118
+ Per stall: **location · quoted trigger · class · the reader's actual question · a one-line fix.**
119
+ Then the **stall inventory + density per page**, which is the artifact other skills consume — not
120
+ the rubric number. Then, separately, the sentences the reader could not restate at all: that list is
121
+ the pass's headline, above any score.
122
+
123
+ ### The fix rule
124
+
125
+ 🔴 **A fix that removes the flagged wording and keeps the compression is not a fix.** Proven twice in
126
+ one hour on 2026-08-05: *"not through any defect in how we write it, but because that is what English
127
+ is"* → *"that is what English is for"* (tic gone, meaning inverted into nonsense); *"the agent turns
128
+ out not to be the weak link"* → *"The agent obeys"* (three words, every threshold green, the wrong
129
+ finding). **Rewrite the whole thought in plain words.** The construction is usually a symptom of a
130
+ compressed idea, and decompressing it removes the construction as a side effect. Then re-read the
131
+ replacement cold — the author is least able to judge his own repair exactly when he feels most sure.
132
+
133
+ ### Scope: whole paper here, diff continuously
134
+
135
+ This pass covers the whole paper and is expensive, so it runs at gate time. The per-edit counterpart
136
+ is the `cold-read-diff` skill, which asks the same question of just-changed paragraphs and is cheap
137
+ enough to run every time. Running only this one leaves every sentence written after it unread, which
138
+ is what happened.
139
+
140
+ ## How to run it
141
+
142
+ 1. **Read the actual draft** (the `.tex`/`.md`, or run `render-paper` to read the built pages as a reader
143
+ would). Grade the writing as written — never from a summary.
144
+ 2. **Run the cold-read stall pass FIRST — the full specification is below, under "The stall pass".**
145
+ It was previously a pointer to a reference section that did not exist, which is why the pass drifted
146
+ into "log where I stumbled" and stopped catching the class it exists for.
147
+ 2. **Score all nine dimensions 1–5** using the anchors in the reference, on the **absolute scale** defined
148
+ there (5 = best-in-field, **3 = the default for a solid paper**; most dimensions are 2–3). Weight Prose
149
+ (#5), Jargon (#6), Landing (#7) ×2 — that's where "wall of jargon" lives. Report raw /45 + weighted /60.
150
+ **Do NOT trust a single grade.** A lone grader — especially one that just wrote or verified the paper —
151
+ anchors optimistic; a 52/60-looking number is suspect until confirmed. So **when the score matters, run a
152
+ blind panel: ≥3 independent graders (fresh subagents, ideally an adversarial model like Fable), each
153
+ blind to any prior score, to each other, and to the "it improved" framing — given only the current page
154
+ and the field's best.** Report the **distribution (per-dimension + overall min / median / max)**, not one
155
+ number; flag any dimension where graders disagree by >1 as genuinely ambiguous. (See "Scoring
156
+ calibration" in the reference; this is the writing-axis analogue of `pc-panel-review`.)
157
+ 3. **For every dimension scoring ≤3, name the specific offending sentence or section** and write the fix —
158
+ not "tighten the prose" but the rewritten sentence, or "move the point from ¶3 to ¶1", or "gloss
159
+ `operation-normalized` in plain words at first use." Fixes must be applyable, not vibes.
160
+ 4. **Find the paper's three-move opportunities:** what held assumption could open it? what is its single
161
+ most visceral concrete instance (lead with that, not the mean)? what one sentence should the reader
162
+ quote? If the draft is missing any, that's the highest-leverage fix.
163
+ 5. **Flag the two prose traps by name:** (a) Attention-style dense contribution-less prose used where the
164
+ audience does NOT already care; (b) hedge-stacking ("may possibly in some cases potentially") — replace
165
+ each pile with one precise scope sentence.
166
+ 6. 🔴 **Run `prose-lint.mjs` and treat every FLAG as a finding, not as context.** It is wired into
167
+ `paper-lint` on paper edits, so its output arrives whether or not this skill was invoked — but the
168
+ skill is what must ACT on it. Its thresholds are sourced; a FLAG means the text sits above a
169
+ published human or machine baseline, which is a defect with a number attached, not an opinion.
170
+ Two entries in `THRESHOLDS` exist because this skill previously ran five times without either
171
+ firing: the `"not X, but Y"` density had **no threshold at all** and printed as a neutral line
172
+ while standing at 50.8 per 10,000 words against an LLM baseline of 7.8, and the lexicon missed
173
+ both variants a reader spotted by eye — the bare inversion (*"Reading the file is not the weak
174
+ point; judging it is"*) and the appositive that reaches headings (*"Admission, not translation"*).
175
+ A number printed without a threshold is prose; that is this project's own thesis, and the linter
176
+ was violating it.
177
+
178
+ 6a. 🔴 **`prose-lint.mjs` IS NO LONGER ALONE — seven of its twelve gating metrics moved
179
+ on 2026-08-26 into ESLint rules, and running only it shows you five twelfths.** A second
180
+ run is mandatory; without it, step 6 is incomplete:
181
+
182
+ ```
183
+ npx eslint "papers/*/paper.md" "papers/*/draft.md"
184
+ ```
185
+
186
+ From there come: `paper/citation-density` · `paper/unexplained-jargon` ·
187
+ `paper/multi-claim-sentence` · `paper/conceits` · `paper/hedge-density` ·
188
+ `paper/discourse-subject` · `paper/undefined-coinage` (file — `eslint-rules/paper-craft.mjs`).
189
+ Gain from the move — `file:line:col` on each finding: the old report printed the sentence head,
190
+ and you had to find it in the article by eye. Everything step 6b says about
191
+ meaning regression applies to them just the same: this is diagnosis, not objective.
192
+
193
+ 6b. 🔴 **A lint fix that costs meaning is a REGRESSION, and no linter can see it.** The metrics above
194
+ are diagnostics, never objectives. Optimising one directly is how a sentence gets worse while the
195
+ number gets better — and the number is exactly what makes it feel like progress.
196
+
197
+ Observed 2026-08-05, twice in one pass, both by the author of this rule:
198
+ - *"English cannot be exact — not through any defect in how we write it, but because that is what
199
+ English is"* became *"English cannot be exact; that is what English is for"*. The tic went. So
200
+ did the meaning: the new clause says English **exists in order to** be inexact, which is not a
201
+ claim anyone holds. The author's reaction was *«what the fuck does that even mean»*.
202
+ - *"Yet the agent turns out not to be the weak link"* became **"The agent obeys."** Three words,
203
+ zero flags, and the wrong finding — the experiment measured whether *writing a rule down* works,
204
+ while the replacement reads as a claim about agents being submissive.
205
+
206
+ **The procedure, and it is not optional:** after replacing a flagged sentence, read the
207
+ replacement as someone who has not read the paper. Does it still say the thing? Would they know
208
+ what it means? If the honest answer is no, the original was better and the flag stays open — an
209
+ open flag is a truthful state, and a passing metric over a sentence nobody can parse is not.
210
+ Prefer rewriting the whole **thought** in plain words to surgically excising the construction:
211
+ the tic is usually a symptom of a compressed idea, and decompressing it removes the tic as a
212
+ side effect.
213
+
214
+ 7. 🔴 **Put `WORST-SECTION: <section>` on the FIRST LINE of the report.** Machine-readable, one
215
+ section, lowercase, no decoration. `pipeline-check.mjs` reads the last four reports and raises
216
+ `repeat-finding` when the same section is worst twice running. This exists because the abstract
217
+ was named worst **five consecutive times**, was faithfully recorded in the scorecard all five
218
+ times, and was never once the next task. A review loop that only appends findings converges on a
219
+ paper whose defects are all thoroughly documented and none of them fixed. **Naming the worst
220
+ section is not the deliverable — a fix for it, or a recorded decision to ship with it, is.**
221
+
222
+ 8. **Run the avoid-list grep (mechanical).** Grep the source for the slop / web-slang / filler / hype words
223
+ in `../paper-pipeline/references/writing-craft.md` → "The avoid-list", and report every hit with its line number and a
224
+ replacement. These are scrutinize-words, not absolute bans — but each hit is a readability debit against
225
+ dimension #6 (Jargon) and the "engaging + human-readable" north star. (This session's miss that motivated
226
+ it: "listicle" survived into a submitted-ready AISec draft.)
227
+ 7. **Wall-of-text sweep (see `writing-craft.md` → "The wall-of-text check").** Flag any paragraph running
228
+ >~15 source lines / ~150 words or covering >3 sub-points — a visual wall the reader's eye slides off
229
+ (distinct from stall density). Prescribe the fix: break into run-in-headed chunks. Caps dimension #4.
230
+ 8. **Conclusion & quotability sweep (explicit — see `writing-craft.md` → "The conclusion & quotability
231
+ check").** Grade the CONCLUSION on its own, not just the intro: does it pay off in plain language, name the
232
+ stakes, point past the result, and hand the reader a concrete action — or is it a limp results-recap (a 2)?
233
+ Then check the abstract AND the conclusion each carry one extractable, quotable line (the "paste onto a
234
+ talk slide" test); if a surface has none, flag it and draft the candidate line. Report both explicitly —
235
+ these feed dimension #7 (which is graded on both surfaces). This is the axis that catches "the conclusion
236
+ isn't strong enough" and "nothing here is quotable."
237
+
238
+ ## Output
239
+ 1. **Scorecard** — nine dimensions with one-line justification each; raw /45 + weighted /60. When a blind
240
+ panel was run (the default when the score matters), report the **distribution** — per-dimension and
241
+ overall min / median / max across graders — not a single number, and name any dimension they split on.
242
+ Lead with the two or three dimensions dragging it down, ranked.
243
+ 2. **Cold-read stall inventory** — the ranked list of "what does that even mean?" points (location → quoted
244
+ trigger → reader's question → fix) plus the stall density per page. This is the most directly actionable
245
+ output; a fix pass works straight off it.
246
+ 2. **Sentence-level fix list** — for every ≤3 dimension: the offending text → the concrete rewrite/move.
247
+ Ordered by leverage (the fix that most improves how it reads first).
248
+ 3. **The three-move audit** — the assumption to open on, the visceral instance to lead with, the one
249
+ repeatable sentence — supplied or flagged as missing.
250
+ 4. **A one-paragraph verdict** — is this a pleasant read for a busy, skeptical reviewer yet, and the single
251
+ change that would move it most.
252
+ 5. **SAVE the report colocated — don't let it evaporate.** A grade run in a subagent reports into a
253
+ transcript that is gone next session. Write the scorecard + stall inventory + fix list to
254
+ **`<paper-dir>/reviews/<YYYY-MM-DD>-grade-paper-writing.md`** and link it from the paper's
255
+ `PIPELINE-STATUS.md` (Wc row). Same rule as `pc-panel-review`'s ledger and `analyze-sibling-paper`'s
256
+ `siblings/` — review artifacts live colocated and ride with the paper to camera-ready/extension.
257
+
258
+ ## Record the verdict
259
+
260
+ 🔴 LAST step, once the deliverable exists:
261
+
262
+ ```
263
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record grade-paper-writing <paper-dir> FINDING <count> <report-path>
264
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record grade-paper-writing <paper-dir> ABSTAINED <reason> "<one line>"
265
+ ```
266
+
267
+ **FINDING** — `<count>` is the number of entries in the PERSONA stall inventory, and `<report-path>`
268
+ is that inventory. Add `--blocking` when a dimension scored 1–2, or stall density is over its cap.
269
+ **ABSTAINED** — `no-witness`: the inventory came back empty. `blocked`: no persona reader was run,
270
+ so there is no inventory — which is not an empty inventory and must never be filed as one.
271
+
272
+ 🔴 **There is no PASS**, and the distinction the two abstentions draw is the one that was being
273
+ lost: "a reader stalled nowhere" and "nobody read it" produced the same word.
274
+
275
+ 🔴 **Record the stall count, never the rubric number.** The inventory is what `pc-panel-review`,
276
+ `paper-adversarial-review` and `harden-paper` consume; a 44/60 in the ledger would let a paper whose
277
+ readability gate is failing look clean to every skill downstream.
278
+
279
+ `prose-lint.mjs` files separately as `grade-paper-writing/prose-lint`. One check, one row.
280
+
281
+ ## Rules
282
+ - Grade **writing, not science.** A correct paper can still score a 2 here; say so. Don't drift into
283
+ content/defect review — that's `paper-adversarial-review` / `pc-panel-review`.
284
+ - **Every low score comes with the offending sentence and its fix.** No abstract advice.
285
+ - **Preserve claims.** Suggested rewrites must not change any result, number, or hedge — only how it reads.
286
+ (This mirrors the constraint on any prose rewrite of a real submission.)
287
+ - **After applying sentence fixes, run the `claims` claim-preservation diff** (owner:
288
+ `../paper-pipeline/references/writing-craft.md` → "The claim-preservation diff") — an adversarial
289
+ (Fable) before/after diff verifying **no number moved, no hedge dropped, no claim strengthened, no
290
+ new absolute, no self-contradiction**. The fix pass is not done until it's clean; record it in the
291
+ `claims` row of the paper's `PIPELINE-STATUS.md`. This step is mandatory after EVERY rewrite, not optional.
292
+ - **Respect the page budget.** Prefer fixes that cut or hold length; a paper at its page ceiling can't grow.
293
+ - **Honesty over flattery.** If the abstract is a stat-wall, score it a 2 and show the five-move rewrite.
294
+
295
+ ## 🔴 The tell that says a machine wrote it: three findings in one sentence
296
+
297
+ The single most reliable marker of LLM prose in a paper is **the citation tricolon** — separate
298
+ findings packed into one sentence with a reference hung off each:
299
+
300
+ > *Adherence has been measured directly more than once: it decays as a session proceeds [6], and
301
+ > agents that undertake to follow a process frequently do not [7] — while a factorial study of the
302
+ > file's own structure, varying size, position and ordering, found no effect at all [4].*
303
+
304
+ Three unrelated results, one sentence, 48 words, a colon, a comma-splice and an em-dash contrast. It
305
+ reads fluently and nothing survives it. Its cousin is the **noun pile with no verb**, which exists
306
+ only to carry citations:
307
+
308
+ > *Censuses, taxonomies and labellings of what these files contain [3, 11, 12, 18–20, 25, 34].*
309
+
310
+ **Rule: one finding, one sentence.** If three works said three things, that is three sentences, and
311
+ each says what the work found rather than that it exists. A citation group belongs to a claim, not to
312
+ a list. When the related work genuinely is a survey, say what the surveys share and cite them once.
313
+
314
+ Mechanical leg: `paper-lint`'s plain-language pass flags any sentence carrying three or more separate
315
+ citation groups, or five or more reference numbers in under 45 words. It cannot judge whether the
316
+ prose is *good*; it reliably catches this one shape, which is the shape that recurs.
317
+
318
+ **And the words themselves, not only the sentences.** *Adherence* means *following the rules*. The
319
+ "Jargon discipline" dimension below does not catch this, because the word looks perfectly at home —
320
+ judgment slides right past it. What catches it is a list: `paper-lint` carries ~30 words with a plain
321
+ English equivalent (adherence · utilise · demonstrates · constitutes · prior to · necessitates ·
322
+ facilitates · methodology · leverage · albeit · comprise · entail · in order to …) and names the
323
+ replacement in the nudge. Keep the list narrow — only words where the swap does not change meaning —
324
+ and never rewrite a cited work's title to obey it.
325
+
326
+ **Other markers of the same register, all cheap to check and all worth a pass:** nominalisation
327
+ density (*an honest accounting of what the construction costs* — abstract nouns doing the work verbs
328
+ should do), stock connectives (*furthermore*, *thereby*, *it is worth noting*), and statistics chained
329
+ through a paragraph instead of sitting in a table. Numbers belong in a table the moment there are more
330
+ than about six of them in one paragraph.
331
+
332
+
333
+ ## 🔴 The class the rubric could not see, and why it kept coming back (2026-08-04)
334
+
335
+ The author of `compile-rules-2026` read the built abstract and wrote: *«what the f\*** does that
336
+ even mean, no human would write it like that»*. He had said the same thing about the same paper
337
+ **repeatedly**. Nine rubric axes, a persona cold-read at 5.9 stalls/page, an AI-tells counter and
338
+ three tighten passes all scored the text and **none of them named the defect**, because every one of
339
+ them measures words and sentences. The defect is not in the words.
340
+
341
+ **The specimen, verbatim, and it passed every check we own:**
342
+
343
+ > "Two findings about the agent come first, because they bind whatever else you build. Asked the
344
+ > same question twice with identical inputs, a frontier model changes its verdict on 21.5% of rows,
345
+ > so no harness that has a model adjudicate its own instructions can use one as the gate."
346
+
347
+ Two separable failures:
348
+
349
+ ### 1. The text talks about the text (metadiscourse)
350
+
351
+ *"Two findings come first, because they bind whatever else you build"* says nothing about rules
352
+ files, agents, or repositories. It is the paper **narrating its own structure** — the reader is
353
+ handed a table of contents where they expected a fact. This is Hyland's *frame marker*, and in this
354
+ corpus it is the single most reliable smell of machine-drafted expository prose: an
355
+ instruction-tuned model is rewarded for signposting, so it signposts where a writer would simply
356
+ say the thing.
357
+
358
+ **Countable.** Per section, count openers and connectives whose subject is the document rather than
359
+ the world: *this paper · this section · we now turn · comes first · in what follows · the rest of
360
+ this · as discussed above · it is worth noting · importantly*. Measured on this paper: **10 in the
361
+ body**, and the abstract's opener was one. Target for an abstract or conclusion: **zero**. Body:
362
+ under one per section, and every survivor must earn a reason.
363
+
364
+ **Rewrite heuristic:** delete the frame and start at the fact. *"Two findings come first, because
365
+ they bind whatever else you build. Asked the same question twice…"* → *"Asked the same question
366
+ twice with identical inputs, a frontier model changes its verdict on 21.5% of rows."* Nothing is
367
+ lost. The ordering was already visible — it is the order of the sentences.
368
+
369
+ ### 2. The qualification eats the claim
370
+
371
+ *"…though that cell does not survive our own correction for multiplicity and we report it as
372
+ suggestive (Appendix A.2)"* is 20 words of hedge welded onto a 20-word finding. Each hedge was
373
+ added honestly, by a different review round, and none was wrong. Their **placement** is the defect, and no single round can see it.
374
+
375
+ 🔴 **The obvious diagnosis is wrong, and it was measured.** Peer review does **not** ratchet hedge
376
+ words in. Keserlioglu, Kilicoglu & ter Riet (2019, *Research Integrity and Peer Review*, n = 446
377
+ manuscript–publication pairs across 28 journals) found hedge density moving 2.06% → 2.13% — and
378
+ non-significant after adjusting for journal characteristics. What review adds is **standalone
379
+ limitation sentences**: 2.48 → 3.87 per paper. So the published norm is that qualification enters a
380
+ good paper **as its own sentence**, not as particles inside a claim sentence. `compile-rules-2026`
381
+ ran at **0.37%** hedge words against that 2.13% norm — it was never over-hedged by count. It was
382
+ mis-**placed**: the caveat was welded into the result sentence, where it competes with the result for
383
+ the stress position and wins.
384
+
385
+ **Countable.** Caveats that are grammatically independent sentences versus caveats embedded as
386
+ subordinate clauses (*though · while · although · albeit*) inside a sentence that also states a
387
+ result. Target: all standalone. Also count sentences ending on a cross-reference, citation or hedge
388
+ while the sentence's own number sits earlier — Gopen & Swan's stress position, spent on a pointer.
389
+
390
+ **Rewrite heuristic — the order matters:** state the finding as a whole sentence, then qualify it in
391
+ the **next** sentence. Never inside it. *"Violations went from 17% to 100%, back to the rate with no
392
+ file at all. That is one cell of five, and it does not clear the multiplicity correction we
393
+ pre-registered (Appendix A.2)."* Same words, same honesty, and the claim survives the reading.
394
+
395
+ ### 3. Phrases that reference an unstated alternative
396
+
397
+ *"So we left the sentences alone"* — the reader has not been told what else might have been done to
398
+ them, so "left alone" refers to nothing. Same author reaction, same day. **Check:** any *instead of ·
399
+ rather than · left alone · we did not · not X but Y* whose rejected alternative is not stated within
400
+ one sentence.
401
+
402
+ ### 🎯 The abstract and the conclusion are graded on a different scale
403
+
404
+ They are the only two sections most readers finish, and the abstract is the only one every reviewer
405
+ reads before forming a view. Grade them **separately and harder**:
406
+
407
+ - **zero** frame markers, **zero** self-reference to the paper;
408
+ - first sentence is about the world, never about the document;
409
+ - no number arrives without the unit it counts (*"21.5% of rows"* — rows of what?);
410
+ - the last sentence of each is a **conclusion**, not an announcement of one;
411
+ - nothing may refer forward to a section the reader has not read.
412
+
413
+ A body section may be merely clear. These two have to be **sharp**, and if the abstract survives a
414
+ tighten pass marked `KEEP` three rounds running, that is evidence it was never really read — this
415
+ one did, and it was the worst section in the paper by measured density both times.
416
+
417
+ ### What is NOT mechanizable here
418
+
419
+ Whether a frame marker is load-bearing (*"we claim nothing there"* genuinely scopes a claim) and
420
+ whether a hedge is honest or defensive. Count them, surface them, and leave the verdict to a reader.
421
+ The counter's job is that nobody can say afterwards they did not know.
422
+
423
+ ## Compose with
424
+ - `harden-paper` — the multi-axis pre-submit gate calls this as its *writing* axis (the one a defect-hunt
425
+ and a threat-model check both miss).
426
+ - `draft-paper` — the generative counterpart (writes the prose); this grades it. Both cite the same
427
+ `../paper-pipeline/references/writing-craft.md`, so guidance and grading never diverge.
428
+ - `paper-adversarial-review` / `pc-panel-review` — run those for scientific defects; run this for readability. Complementary axes, not redundant.
429
+ - `render-paper` — build the PDF/PNGs first so you grade what the reviewer will actually see.
430
+
431
+ ## Provenance
432
+ Built from the **AISec 2026 GateBench** polish run (2026-07): the author's verdict was "wall of text and
433
+ jargon that doesn't drive home how crazy the situation is — real humans will be reading this." The rubric
434
+ was grounded by dissecting Peyton Jones / McEnerney / Gopen & Swan and honestly grading exemplars
435
+ (Attention = impact-not-prose; Trusting Trust / Carlini / Greshake = the real craft models), then applied
436
+ as the instrument that graded the rewritten paper.