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,100 @@
1
+ /**
2
+ * run-mutations.mjs — run EVERY mutation battery in the repository, found rather than listed.
3
+ *
4
+ * ── WHY THIS EXISTS, AND IT IS NOT TIDINESS ─────────────────────────────────
5
+ * 🔴 It replaces a hand-written list in `package.json` that had ALREADY ROTTED. On 2026-09-11
6
+ * the `mutations` script read:
7
+ *
8
+ * node eslint-rules/tex-build.mutations.mjs &&
9
+ * node eslint-rules/latex-language.mutations.mjs &&
10
+ * node scripts/rules-see-files.mutations.mjs
11
+ *
12
+ * — three of the four batteries on disk. `papers.mutations.mjs`, added the same day, was not in
13
+ * it, and nothing said so: the command exited 0 and printed three confident green tables. A
14
+ * list of paths maintained by hand is the thing that goes stale, and it goes stale SILENTLY,
15
+ * which is the same failure class the batteries themselves exist to catch.
16
+ *
17
+ * ── THE TWO GUARDS ──────────────────────────────────────────────────────────
18
+ * 1. FINDING ZERO BATTERIES IS AN ERROR, not an empty success. A run that discovers nothing and
19
+ * exits 0 is byte-identical to a run where every battery passed — the exact green zero this
20
+ * repository has a dedicated script for (`rules-see-files.mjs`), applied here to itself.
21
+ * 2. (REMOVED 2026-09-24) A harness without a battery used to be an error. It no longer is —
22
+ * see the note above the run loop.
23
+ *
24
+ * ⚠️ Batteries WRITE to the file under test and roll it back. They are safe to run on a clean
25
+ * tree and NOT safe to run with uncommitted edits to a rule: a crash between the write and the
26
+ * rollback leaves the mutant on disk. Each battery re-reads the file and verifies the rollback
27
+ * byte for byte, so the window is small, but it is not zero.
28
+ *
29
+ * Run: `node scripts/run-mutations.mjs` (also part of `npm run check`)
30
+ */
31
+ import { execFileSync } from "node:child_process";
32
+ import { readdirSync, statSync } from "node:fs";
33
+ import { dirname, join, relative } from "node:path";
34
+ import { fileURLToPath } from "node:url";
35
+
36
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
37
+ // 🔴 `.claude` IS A VIEW OF `skills/`, NOT A SECOND COPY OF IT. This repository is its own first
38
+ // consumer: `.claude/skills/<name>` are symlinks back to `skills/<name>` so that the path every
39
+ // SKILL.md's prose names resolves here too (see `skills/skill-contract.mutations.mjs`). Walking
40
+ // into it counts each harness TWICE under two spellings of one file, and the second spelling is
41
+ // never what a battery names — so every skill harness read as an orphan while being perfectly
42
+ // covered. Measured 2026-09-12: 11 phantom orphans, all of them the same files seen through the
43
+ // symlink. Skipping the view is not an exemption: the real files are still walked under `skills/`.
44
+ const SKIP = new Set(["node_modules", ".git", "fixtures", ".claude"]);
45
+
46
+ /** Every `*.mutations.mjs` on disk, as repo-relative paths. */
47
+ function collect(dir, found = { mutations: [] }) {
48
+ for (const entry of readdirSync(dir)) {
49
+ if (SKIP.has(entry)) continue;
50
+ const p = join(dir, entry);
51
+ if (statSync(p).isDirectory()) {
52
+ collect(p, found);
53
+ continue;
54
+ }
55
+ if (entry.endsWith(".mutations.mjs"))
56
+ found.mutations.push(relative(ROOT, p));
57
+ }
58
+ return found;
59
+ }
60
+
61
+ const { mutations } = collect(ROOT);
62
+ mutations.sort();
63
+
64
+ // Guard 1 — the green zero, applied to this script itself.
65
+ if (mutations.length === 0) {
66
+ console.error(
67
+ "❌ NO mutation batteries found under " +
68
+ ROOT +
69
+ ".\n" +
70
+ " This is an error rather than an empty success: a run that discovers nothing and exits " +
71
+ "0\n is indistinguishable from a run where every battery passed.",
72
+ );
73
+ process.exit(1);
74
+ }
75
+
76
+ // 🔴 NO ORPHAN GUARD ANY MORE (2026-09-24). Until then this script refused every `*.harness.mjs`
77
+ // that no battery named — so a new harness could not land without a new hand-written battery of
78
+ // string replacements over source lines. Those batteries are the pattern issue #52 is replacing:
79
+ // they break on every reformat, rerun a whole harness per case, and are slow. Forcing more of them
80
+ // into existence was the wrong direction, so the requirement is gone. Existing batteries still run
81
+ // below, and one that fails to kill its mutant still fails the run.
82
+
83
+ console.log(
84
+ `Running ${mutations.length} mutation batter${mutations.length === 1 ? "y" : "ies"}:\n`,
85
+ );
86
+ const failed = [];
87
+ for (const m of mutations) {
88
+ console.log(`──────── ${m}`);
89
+ try {
90
+ execFileSync(process.execPath, [m], { cwd: ROOT, stdio: "inherit" });
91
+ } catch {
92
+ failed.push(m);
93
+ }
94
+ }
95
+
96
+ console.log(
97
+ `\n${mutations.length - failed.length}/${mutations.length} batter${mutations.length === 1 ? "y" : "ies"} clean` +
98
+ (failed.length ? `, FAILED: ${failed.join(", ")}` : ""),
99
+ );
100
+ process.exit(failed.length ? 1 : 0);
@@ -0,0 +1,16 @@
1
+ // The two semantic-release plugins ship no types. Only what scripts/release-config.test.ts calls
2
+ // is declared: the plugin step functions, taking the plugin's options and semantic-release's
3
+ // context, as their READMEs document them.
4
+ declare module "@semantic-release/commit-analyzer" {
5
+ export function analyzeCommits(
6
+ pluginConfig: Record<string, unknown>,
7
+ context: Record<string, unknown>,
8
+ ): Promise<"major" | "minor" | "patch" | null>;
9
+ }
10
+
11
+ declare module "@semantic-release/release-notes-generator" {
12
+ export function generateNotes(
13
+ pluginConfig: Record<string, unknown>,
14
+ context: Record<string, unknown>,
15
+ ): Promise<string>;
16
+ }
@@ -0,0 +1,15 @@
1
+ # skills/
2
+
3
+ The Claude Code skills this package ships, one directory per skill, each with its `SKILL.md`.
4
+ Start with `paper-pipeline/`: it routes to the stage skills.
5
+
6
+ `paperlint init` links each skill into the project's Claude Code skills directory
7
+ (`src/link-skills.ts`), because Claude Code finds project skills there and never inside the
8
+ installed package. The directory name is `SHIPPED_SKILLS_DIR` in
9
+ `paper-pipeline/scripts/consumer.mjs`; the linker and the install e2e both read that constant, and
10
+ `files` in `package.json` puts the directory in the tarball.
11
+
12
+ <!--
13
+ In a public repository, reference private notes WITHOUT the repository's name. Keep the path
14
+ itself — it is useful to the one person who has access, and tells everyone else nothing.
15
+ -->
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: analyze-sibling-paper
3
+ description: "Deep-analyze a specific related / competing / concurrent paper — reading the ACTUAL paper, not its abstract — to decide the \"isn't this just X?\" question before a reviewer asks it: what it really does, whether it's prior or concurrent work, the strongest scoop a reviewer could claim, whether your delta is REAL or merely cosmetic, and the exact cite + positioning clause (or a scoop escalation) to apply. Saves the analysis to the paper's research folder and surfaces action points. Use whenever a paper close enough to yours surfaces — via verify-citations' nearest-neighbor, a reviewer's \"this was already done\", your own lit search, or an arXiv alert. Distinct from verify-citations (confirms a cite is real + one-line delta) and study-accepted-papers (mines a venue's accepted corpus for levers); this one does the deep per-competitor overlap/scoop analysis. Compose with verify-citations (feeds it neighbors), harden-paper (its nearest-neighbor-scoop axis calls this), and extend-paper (a scooped angle can become the extension's pivot)."
4
+ context: fork
5
+ allowed-tools: [WebSearch, WebFetch, Read, Write, Grep, Glob, Bash, Agent]
6
+ ---
7
+
8
+ <!-- vigiles:sha256:19d00fe70002d3fa compiled from skills/analyze-sibling-paper/SKILL.md.spec.ts -->
9
+
10
+ # analyze-sibling-paper — settle "isn't this just X?" before a reviewer does
11
+
12
+ ## Run me
13
+
14
+ 🔴 FIRST, before any other step:
15
+
16
+ ```
17
+ node .claude/skills/paper-pipeline/scripts/announce.mjs analyze-sibling-paper <paper-dir>
18
+ ```
19
+
20
+ An advisory pass cannot be observed failing — silence is both its error state and its normal
21
+ state — so starting is an event, and events get written down.
22
+
23
+ The `<paper-dir>` argument is **your** paper, not the sibling — the row belongs to the paper being
24
+ defended. The sibling is named by `<report-path>` when the verdict is recorded.
25
+
26
+ When a paper close to yours surfaces, the wrong move is to cite it from its abstract and move on — that
27
+ leaves a scoop risk you can't see and a reviewer can. This skill reads the *actual* competitor, judges
28
+ whether your contribution genuinely differs, and produces a saved analysis with concrete action points
29
+ (the exact positioning clause to add, or — if it's a real scoop — an escalation, not a clause).
30
+
31
+ Grounding: the original-contribution criterion (a paper a
32
+ reviewer thinks is a repackaging earns no authorship credit even if accepted). Composes with
33
+ `verify-citations` (which surfaces the nearest neighbors) and `harden-paper` (whose scoop axis calls this).
34
+
35
+ ## When it fires
36
+ Any paper a reviewer could point at and say "this was already done." Triggers: a nearest-neighbor from
37
+ `verify-citations`; a reviewer/panelist's "isn't this just X?"; a citation you're about to add that's
38
+ suspiciously close; an arXiv alert in your lane. When in doubt, run it — the cost of a 20-minute read is
39
+ far below the cost of a "novelty concern" reject.
40
+
41
+ ## How to run it
42
+
43
+ 1. **Deep-read the ACTUAL paper, not the abstract.** `WebFetch` the arXiv/ar5iv/DOI page and read
44
+ abstract → intro → method → claims (as much as is accessible). An abstract hides exactly the overlap
45
+ that matters. Try the fetch routes in order — `arxiv.org/abs/<id>` for metadata, `arxiv.org/html/<id>v1`,
46
+ `ar5iv.labs.arxiv.org/html/<id>`, then the PDF — and **a 403/404 on one route is not "inaccessible"**;
47
+ switch channel before concluding. **Record what you actually read** in the card as a
48
+ `**Read:**` line naming the sections you covered and the ones you could not — an abstract-only
49
+ verdict is PROVISIONAL and must say so in that same line.
50
+ 🔴 **Verify the abstract's numbers against the body.** They disagree more often than you would expect,
51
+ and a disagreement is itself a finding worth recording.
52
+
53
+ 2. **Mine their REFERENCE LIST — mandatory, not optional.** A close sibling's bibliography is a map of
54
+ your field drawn by someone who just surveyed it, and it is frequently worth more than the paper's own
55
+ findings. Extract every entry, then diff against your own reference list and emit three sets:
56
+ **in both** (count only) · **in theirs, not in ours, and relevant** — each with a verdict
57
+ *MUST CITE* (a reviewer would fault you for missing it) / *SHOULD CONSIDER* / *NOT RELEVANT* ·
58
+ **in ours, not in theirs** (does the gap show you are looking where they are not, or that you cited
59
+ something obscure?). Be strict: most entries will be NOT RELEVANT, and saying so is the useful part.
60
+ 🔴 **The highest-value find in the whole skill is a MUST CITE entry that is itself a scoop** — a paper
61
+ in their bibliography doing what you do. Look for it deliberately and state plainly if there is none.
62
+ Every *MUST CITE* must be **confirmed by fetching its arXiv/DOI page** before it enters your text
63
+ (`verify-citations` rule: a title is not real until a fetch says so) — mark each CONFIRMED-BY-FETCH or
64
+ NOT-CONFIRMED.
65
+ 3. **Classify by contribution TYPE** — system/defense · measurement · benchmark · framework · SoK ·
66
+ position. Two papers can share a *concept* and still not collide if their contribution types differ (a
67
+ *system* that assumes "rules can't catch semantics" and a *measurement* that proves it across a
68
+ deployed ecosystem are different contributions). Type is the first lever of a real delta.
69
+ 4. **Timing: prior vs concurrent.** Compare its arXiv/publication date to your submission.
70
+ **Prior work** (clearly earlier) — you must engage and build on it; failing to cite is a reject.
71
+ **Concurrent** (roughly within a few months) — acknowledge it, but you are NOT obligated to have built
72
+ on it, and workshop/venue norms treat it as parallel discovery. State which, with dates.
73
+ 5. **Steelman the scoop.** Write the strongest "isn't this just X?" a hostile reviewer could make,
74
+ quoting the sibling. If you can't make it hurt, you haven't understood the overlap.
75
+ 6. **Judge the delta — brutally.** Is your distinct contribution real and reviewer-proof, or only
76
+ cosmetic/scope ("same idea, different object")? **Use an adversarial model (a Fable subagent) for this
77
+ step** — you will flatter your own delta; it won't. A scope-only distinction on a shared core idea is a
78
+ yellow flag; a different contribution type + a result the sibling doesn't have is a green one.
79
+ 7. **Emit action points.** One of:
80
+ - **Cite + position** (the common case): the exact 1–2 sentence clause to add. If the overlap is
81
+ *conceptual*, acknowledge the shared idea **head-on** — "X observes this split; we measure it across
82
+ the deployed ecosystem and show the corner is reachable." Owning it reads as scholarship; hiding it
83
+ reads as not knowing the field, which is worse.
84
+ - **Escalate** (rare but real): if it's prior work with the same contribution, a clause won't save you
85
+ — reframe your contribution around what genuinely remains, or route the un-scooped angle to
86
+ `extend-paper`. Flag this LOUDLY; it's a novelty problem, not a citation fix.
87
+
88
+ ## Required shape of the saved card — two sections are machine-checked
89
+
90
+ The card is not free-form. Two of its parts are checked by `.claude/hooks/paper-lint.mjs`
91
+ (`checkSiblingCards`) and a card missing either is reported as an unfinished analysis:
92
+
93
+ - **`**Read:**`** — one line naming what of the full text you actually read and what you could
94
+ not. This exists because "I read the paper" is the single easiest thing to skip while producing a
95
+ card that looks complete.
96
+ - **`## Sibling's References`** — their bibliography mined and diffed against yours (step 2), with the
97
+ MUST CITE / SHOULD CONSIDER / NOT RELEVANT verdicts.
98
+
99
+ Enforced only for cards dated on or after 2026-07-29; older cards get one summary nudge instead of
100
+ burying every other finding. Frontmatter needs `title`, `created`, `tags` like any note.
101
+
102
+ ## Save + surface — COLOCATED with the paper (mandatory — do not leave it in context)
103
+ Each paper's competitive landscape lives **with that paper**, not in a shared research folder: write the
104
+ analysis to **`<paper-dir>/siblings/YYYY-MM-DD-<name>.md`** (e.g. `papers/<paper>/siblings/…`) and keep
105
+ a **`<paper-dir>/siblings/README.md`** index listing every sibling + its one-line verdict (scoop-safe /
106
+ must-fix-clause / escalate). Colocation is the rule: when you open the paper's dir you should see its rivals
107
+ and their verdicts right there, and they travel with the paper to camera-ready and rebuttal. Include: what
108
+ it does, contribution type, timing (prior/concurrent + dates), the steelmanned scoop, the delta verdict,
109
+ and the action points (with the exact clause text to add/replace). Per the save-research rule, a competitor
110
+ analysis that lives only in a chat is lost the moment the session ends — and it's exactly what you'll need
111
+ again at rebuttal. **A close sibling with no file in `<paper-dir>/siblings/` is an unfinished analysis.**
112
+
113
+ ## Record the verdict
114
+
115
+ 🔴 LAST step, once the deliverable exists:
116
+
117
+ ```
118
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record analyze-sibling-paper <paper-dir> FINDING <count> <report-path>
119
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record analyze-sibling-paper <paper-dir> ABSTAINED <reason> "<one line>"
120
+ ```
121
+
122
+ **FINDING** — `<count>` is the number of action points the card produced (positioning clauses plus
123
+ *MUST CITE* entries), `<report-path>` is the saved card, which names the sibling. Add `--blocking`
124
+ for a genuine scoop, which the skill already treats as an escalation rather than a clause.
125
+ **ABSTAINED** — `no-witness`: the sibling was read in full and the delta needs no text to change.
126
+ `blocked`: the sibling's full text could not be obtained, so only its abstract was seen — which is
127
+ explicitly not an analysis and must never be recorded as one.
128
+
129
+ 🔴 **There is no PASS.** "The delta is real" read identically whether the sibling had been read
130
+ whole or skimmed, and this skill's own first rule is that an abstract-only delta is not a verdict.
131
+ `no-witness` and `blocked` now say which happened.
132
+
133
+ One row per sibling analysed, filed under its own `--check=<sibling-slug>`; several finding rows
134
+ against one paper is the normal shape here, not a check that keeps failing. Before 2026-08-10 they
135
+ would have overwritten one another.
136
+
137
+ ## Rules
138
+ - **Read the paper, not the abstract.** An abstract-only "delta" is not a verdict — and the card must
139
+ say, in its `**Read:**` line, which parts you actually read.
140
+ - **Mine their references.** A sibling analysis that never opened the sibling's bibliography is half done;
141
+ the scoop you missed is more likely to be in their reference list than in their results.
142
+ - **Classify by contribution type** before judging overlap — it's the difference between a shared concept and a collision.
143
+ - **Prior vs concurrent is a date fact, not a vibe** — state the dates.
144
+ - **Own conceptual overlaps head-on**; a reviewer who spots an unacknowledged twin assumes you didn't read the field.
145
+ - **A genuine scoop is an escalation, not a clause** — don't paper over a novelty problem with a sentence.
146
+ - **Judge the delta with an adversarial model**, not your own optimism.
147
+ - **Save the analysis to the repo** and index it.
148
+
149
+ ## Compose with
150
+ - `verify-citations` — surfaces the nearest-neighbor works; hand each genuine sibling to this skill.
151
+ - `harden-paper` — its nearest-neighbor-scoop axis (axis 3) calls this for each close competitor.
152
+ - `study-accepted-papers` — venue-corpus levers (different axis: the venue's bar, not a specific rival).
153
+ - `extend-paper` — a scooped angle, or the un-scooped remainder, can become the next paper's pivot.
154
+
155
+ ## Provenance
156
+ Built from the **AISec 2026 GateBench** run: `verify-citations` flagged **AgentTrust** (yang2026agenttrust,
157
+ arXiv:2606.08539) as making the same lexical-vs-semantic split the paper's spelling→grammar→effect framing
158
+ builds on — the sharpest "isn't this just X?" in the paper. Citing it from the abstract was not enough to
159
+ know whether the framing was a repackaging; only a deep read of the actual paper, classified by
160
+ contribution type (their trust-*system* vs our *measurement + benchmark + existence result*) and dated
161
+ against submission, could settle the delta and produce the head-on positioning clause. That is exactly
162
+ the workflow this skill encodes.
163
+
164
+ **Extended 2026-07-29** — *What Breaks When LLMs Code?* (arXiv:2605.30777) was cited into the
165
+ `the reference paper` introduction **from its abstract**, and a card was written saying so. Two gaps
166
+ surfaced immediately: the full text was never read (so the "no scoop" verdict rested on an abstract),
167
+ and its reference list — assembled by authors who had just screened 68,816 papers across 22 venues —
168
+ was never opened at all. Both are now steps 1–2, and both are machine-checked in the saved card, because
169
+ the previous version of this rule already said "read the paper, not the abstract" in prose and that did
170
+ not stop it happening. Prose isn't policy.
@@ -0,0 +1,186 @@
1
+ // Compiled to SKILL.md by `vigiles compile`. Edit THIS file, never the markdown.
2
+ //
3
+ // Adopted 2026-08-17 (batch 3). Body carried over VERBATIM so the compiled diff shows
4
+ // only what the compiler adds. No `disallowedTools` fence yet — the field landed on
5
+ // `SkillSpec` in vigiles branch `claude/skill-disallowed-tools` and is not in a release
6
+ // this repo installs, so writing one here would not compile.
7
+ import { experimental_skill } from "vigiles/spec";
8
+
9
+ export default experimental_skill({
10
+ name: "analyze-sibling-paper",
11
+ description:
12
+ "Deep-analyze a specific related / competing / concurrent paper — reading the ACTUAL paper, not its abstract — to decide the \"isn't this just X?\" question before a reviewer asks it: what it really does, whether it's prior or concurrent work, the strongest scoop a reviewer could claim, whether your delta is REAL or merely cosmetic, and the exact cite + positioning clause (or a scoop escalation) to apply. Saves the analysis to the paper's research folder and surfaces action points. Use whenever a paper close enough to yours surfaces — via verify-citations' nearest-neighbor, a reviewer's \"this was already done\", your own lit search, or an arXiv alert. Distinct from verify-citations (confirms a cite is real + one-line delta) and study-accepted-papers (mines a venue's accepted corpus for levers); this one does the deep per-competitor overlap/scoop analysis. Compose with verify-citations (feeds it neighbors), harden-paper (its nearest-neighbor-scoop axis calls this), and extend-paper (a scooped angle can become the extension's pivot).",
13
+ context: "fork",
14
+ tools: [
15
+ "WebSearch",
16
+ "WebFetch",
17
+ "Read",
18
+ "Write",
19
+ "Grep",
20
+ "Glob",
21
+ "Bash",
22
+ "Agent",
23
+ ],
24
+ body: `
25
+ # analyze-sibling-paper — settle "isn't this just X?" before a reviewer does
26
+
27
+ ## Run me
28
+
29
+ 🔴 FIRST, before any other step:
30
+
31
+ \`\`\`
32
+ node .claude/skills/paper-pipeline/scripts/announce.mjs analyze-sibling-paper <paper-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 \`<paper-dir>\` argument is **your** paper, not the sibling — the row belongs to the paper being
39
+ defended. The sibling is named by \`<report-path>\` when the verdict is recorded.
40
+
41
+ When a paper close to yours surfaces, the wrong move is to cite it from its abstract and move on — that
42
+ leaves a scoop risk you can't see and a reviewer can. This skill reads the *actual* competitor, judges
43
+ whether your contribution genuinely differs, and produces a saved analysis with concrete action points
44
+ (the exact positioning clause to add, or — if it's a real scoop — an escalation, not a clause).
45
+
46
+ Grounding: the original-contribution criterion (a paper a
47
+ reviewer thinks is a repackaging earns no authorship credit even if accepted). Composes with
48
+ \`verify-citations\` (which surfaces the nearest neighbors) and \`harden-paper\` (whose scoop axis calls this).
49
+
50
+ ## When it fires
51
+ Any paper a reviewer could point at and say "this was already done." Triggers: a nearest-neighbor from
52
+ \`verify-citations\`; a reviewer/panelist's "isn't this just X?"; a citation you're about to add that's
53
+ suspiciously close; an arXiv alert in your lane. When in doubt, run it — the cost of a 20-minute read is
54
+ far below the cost of a "novelty concern" reject.
55
+
56
+ ## How to run it
57
+
58
+ 1. **Deep-read the ACTUAL paper, not the abstract.** \`WebFetch\` the arXiv/ar5iv/DOI page and read
59
+ abstract → intro → method → claims (as much as is accessible). An abstract hides exactly the overlap
60
+ that matters. Try the fetch routes in order — \`arxiv.org/abs/<id>\` for metadata, \`arxiv.org/html/<id>v1\`,
61
+ \`ar5iv.labs.arxiv.org/html/<id>\`, then the PDF — and **a 403/404 on one route is not "inaccessible"**;
62
+ switch channel before concluding. **Record what you actually read** in the card as a
63
+ \`**Read:**\` line naming the sections you covered and the ones you could not — an abstract-only
64
+ verdict is PROVISIONAL and must say so in that same line.
65
+ 🔴 **Verify the abstract's numbers against the body.** They disagree more often than you would expect,
66
+ and a disagreement is itself a finding worth recording.
67
+
68
+ 2. **Mine their REFERENCE LIST — mandatory, not optional.** A close sibling's bibliography is a map of
69
+ your field drawn by someone who just surveyed it, and it is frequently worth more than the paper's own
70
+ findings. Extract every entry, then diff against your own reference list and emit three sets:
71
+ **in both** (count only) · **in theirs, not in ours, and relevant** — each with a verdict
72
+ *MUST CITE* (a reviewer would fault you for missing it) / *SHOULD CONSIDER* / *NOT RELEVANT* ·
73
+ **in ours, not in theirs** (does the gap show you are looking where they are not, or that you cited
74
+ something obscure?). Be strict: most entries will be NOT RELEVANT, and saying so is the useful part.
75
+ 🔴 **The highest-value find in the whole skill is a MUST CITE entry that is itself a scoop** — a paper
76
+ in their bibliography doing what you do. Look for it deliberately and state plainly if there is none.
77
+ Every *MUST CITE* must be **confirmed by fetching its arXiv/DOI page** before it enters your text
78
+ (\`verify-citations\` rule: a title is not real until a fetch says so) — mark each CONFIRMED-BY-FETCH or
79
+ NOT-CONFIRMED.
80
+ 3. **Classify by contribution TYPE** — system/defense · measurement · benchmark · framework · SoK ·
81
+ position. Two papers can share a *concept* and still not collide if their contribution types differ (a
82
+ *system* that assumes "rules can't catch semantics" and a *measurement* that proves it across a
83
+ deployed ecosystem are different contributions). Type is the first lever of a real delta.
84
+ 4. **Timing: prior vs concurrent.** Compare its arXiv/publication date to your submission.
85
+ **Prior work** (clearly earlier) — you must engage and build on it; failing to cite is a reject.
86
+ **Concurrent** (roughly within a few months) — acknowledge it, but you are NOT obligated to have built
87
+ on it, and workshop/venue norms treat it as parallel discovery. State which, with dates.
88
+ 5. **Steelman the scoop.** Write the strongest "isn't this just X?" a hostile reviewer could make,
89
+ quoting the sibling. If you can't make it hurt, you haven't understood the overlap.
90
+ 6. **Judge the delta — brutally.** Is your distinct contribution real and reviewer-proof, or only
91
+ cosmetic/scope ("same idea, different object")? **Use an adversarial model (a Fable subagent) for this
92
+ step** — you will flatter your own delta; it won't. A scope-only distinction on a shared core idea is a
93
+ yellow flag; a different contribution type + a result the sibling doesn't have is a green one.
94
+ 7. **Emit action points.** One of:
95
+ - **Cite + position** (the common case): the exact 1–2 sentence clause to add. If the overlap is
96
+ *conceptual*, acknowledge the shared idea **head-on** — "X observes this split; we measure it across
97
+ the deployed ecosystem and show the corner is reachable." Owning it reads as scholarship; hiding it
98
+ reads as not knowing the field, which is worse.
99
+ - **Escalate** (rare but real): if it's prior work with the same contribution, a clause won't save you
100
+ — reframe your contribution around what genuinely remains, or route the un-scooped angle to
101
+ \`extend-paper\`. Flag this LOUDLY; it's a novelty problem, not a citation fix.
102
+
103
+ ## Required shape of the saved card — two sections are machine-checked
104
+
105
+ The card is not free-form. Two of its parts are checked by \`.claude/hooks/paper-lint.mjs\`
106
+ (\`checkSiblingCards\`) and a card missing either is reported as an unfinished analysis:
107
+
108
+ - **\`**Read:**\`** — one line naming what of the full text you actually read and what you could
109
+ not. This exists because "I read the paper" is the single easiest thing to skip while producing a
110
+ card that looks complete.
111
+ - **\`## Sibling's References\`** — their bibliography mined and diffed against yours (step 2), with the
112
+ MUST CITE / SHOULD CONSIDER / NOT RELEVANT verdicts.
113
+
114
+ Enforced only for cards dated on or after 2026-07-29; older cards get one summary nudge instead of
115
+ burying every other finding. Frontmatter needs \`title\`, \`created\`, \`tags\` like any note.
116
+
117
+ ## Save + surface — COLOCATED with the paper (mandatory — do not leave it in context)
118
+ Each paper's competitive landscape lives **with that paper**, not in a shared research folder: write the
119
+ analysis to **\`<paper-dir>/siblings/YYYY-MM-DD-<name>.md\`** (e.g. \`papers/<paper>/siblings/…\`) and keep
120
+ a **\`<paper-dir>/siblings/README.md\`** index listing every sibling + its one-line verdict (scoop-safe /
121
+ must-fix-clause / escalate). Colocation is the rule: when you open the paper's dir you should see its rivals
122
+ and their verdicts right there, and they travel with the paper to camera-ready and rebuttal. Include: what
123
+ it does, contribution type, timing (prior/concurrent + dates), the steelmanned scoop, the delta verdict,
124
+ and the action points (with the exact clause text to add/replace). Per the save-research rule, a competitor
125
+ analysis that lives only in a chat is lost the moment the session ends — and it's exactly what you'll need
126
+ again at rebuttal. **A close sibling with no file in \`<paper-dir>/siblings/\` is an unfinished analysis.**
127
+
128
+ ## Record the verdict
129
+
130
+ 🔴 LAST step, once the deliverable exists:
131
+
132
+ \`\`\`
133
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record analyze-sibling-paper <paper-dir> FINDING <count> <report-path>
134
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record analyze-sibling-paper <paper-dir> ABSTAINED <reason> "<one line>"
135
+ \`\`\`
136
+
137
+ **FINDING** — \`<count>\` is the number of action points the card produced (positioning clauses plus
138
+ *MUST CITE* entries), \`<report-path>\` is the saved card, which names the sibling. Add \`--blocking\`
139
+ for a genuine scoop, which the skill already treats as an escalation rather than a clause.
140
+ **ABSTAINED** — \`no-witness\`: the sibling was read in full and the delta needs no text to change.
141
+ \`blocked\`: the sibling's full text could not be obtained, so only its abstract was seen — which is
142
+ explicitly not an analysis and must never be recorded as one.
143
+
144
+ 🔴 **There is no PASS.** "The delta is real" read identically whether the sibling had been read
145
+ whole or skimmed, and this skill's own first rule is that an abstract-only delta is not a verdict.
146
+ \`no-witness\` and \`blocked\` now say which happened.
147
+
148
+ One row per sibling analysed, filed under its own \`--check=<sibling-slug>\`; several finding rows
149
+ against one paper is the normal shape here, not a check that keeps failing. Before 2026-08-10 they
150
+ would have overwritten one another.
151
+
152
+ ## Rules
153
+ - **Read the paper, not the abstract.** An abstract-only "delta" is not a verdict — and the card must
154
+ say, in its \`**Read:**\` line, which parts you actually read.
155
+ - **Mine their references.** A sibling analysis that never opened the sibling's bibliography is half done;
156
+ the scoop you missed is more likely to be in their reference list than in their results.
157
+ - **Classify by contribution type** before judging overlap — it's the difference between a shared concept and a collision.
158
+ - **Prior vs concurrent is a date fact, not a vibe** — state the dates.
159
+ - **Own conceptual overlaps head-on**; a reviewer who spots an unacknowledged twin assumes you didn't read the field.
160
+ - **A genuine scoop is an escalation, not a clause** — don't paper over a novelty problem with a sentence.
161
+ - **Judge the delta with an adversarial model**, not your own optimism.
162
+ - **Save the analysis to the repo** and index it.
163
+
164
+ ## Compose with
165
+ - \`verify-citations\` — surfaces the nearest-neighbor works; hand each genuine sibling to this skill.
166
+ - \`harden-paper\` — its nearest-neighbor-scoop axis (axis 3) calls this for each close competitor.
167
+ - \`study-accepted-papers\` — venue-corpus levers (different axis: the venue's bar, not a specific rival).
168
+ - \`extend-paper\` — a scooped angle, or the un-scooped remainder, can become the next paper's pivot.
169
+
170
+ ## Provenance
171
+ Built from the **AISec 2026 GateBench** run: \`verify-citations\` flagged **AgentTrust** (yang2026agenttrust,
172
+ arXiv:2606.08539) as making the same lexical-vs-semantic split the paper's spelling→grammar→effect framing
173
+ builds on — the sharpest "isn't this just X?" in the paper. Citing it from the abstract was not enough to
174
+ know whether the framing was a repackaging; only a deep read of the actual paper, classified by
175
+ contribution type (their trust-*system* vs our *measurement + benchmark + existence result*) and dated
176
+ against submission, could settle the delta and produce the head-on positioning clause. That is exactly
177
+ the workflow this skill encodes.
178
+
179
+ **Extended 2026-07-29** — *What Breaks When LLMs Code?* (arXiv:2605.30777) was cited into the
180
+ \`the reference paper\` introduction **from its abstract**, and a card was written saying so. Two gaps
181
+ surfaced immediately: the full text was never read (so the "no scoop" verdict rested on an abstract),
182
+ and its reference list — assembled by authors who had just screened 68,816 papers across 22 venues —
183
+ was never opened at all. Both are now steps 1–2, and both are machine-checked in the saved card, because
184
+ the previous version of this rule already said "read the paper, not the abstract" in prose and that did
185
+ not stop it happening. Prose isn't policy.`,
186
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * analyze-sibling-paper — 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/analyze-sibling-paper/analyze-sibling-paper.eval.mjs [trials]
16
+ */
17
+ import { runSkillTriggerEval } from "../../lib/skill-eval-kit.mjs";
18
+
19
+ await runSkillTriggerEval("analyze-sibling-paper");
@@ -0,0 +1,23 @@
1
+ /**
2
+ * analyze-sibling-paper — 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 `analyze-sibling-paper.eval.mjs`.
20
+ */
21
+ import { checkSkill } from "../../lib/skill-checks.mjs";
22
+
23
+ await checkSkill("analyze-sibling-paper");