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,211 @@
1
+ ---
2
+ name: map-prior-work
3
+ description: Sweep the competitive landscape for a paper idea BEFORE drafting — find everyone already working on it, date each against your submission (prior vs concurrent is a five-month question, not a vibe), triage by whether they threaten your claimed contribution, deep-read the ones that do, and emit a verdict on WHAT YOU CAN STILL CLAIM plus a related-work skeleton. Saves the full map, not a summary. Use right after research-ideate and before draft-paper, and re-run as a cheap delta pass before submit (hot fields move). Distinct from analyze-sibling-paper (one known competitor, deep) — this one FINDS the competitors and decides which deserve that treatment; distinct from verify-citations (checks cites you already wrote, too late to reshape a contribution); distinct from study-accepted-papers (mines a venue's bar, not your rivals). Compose with research-ideate (upstream), analyze-sibling-paper (it hands off), draft-paper and find-venue (downstream).
4
+ context: fork
5
+ allowed-tools: [WebSearch, WebFetch, Read, Write, Grep, Glob, Bash, Agent]
6
+ ---
7
+
8
+ <!-- vigiles:sha256:353e5a21b731a548 compiled from skills/map-prior-work/SKILL.md.spec.ts -->
9
+
10
+ # map-prior-work — find out who already did it, while you can still change course
11
+
12
+ ## Run me
13
+
14
+ 🔴 FIRST, before any other step:
15
+
16
+ ```
17
+ node .claude/skills/paper-pipeline/scripts/announce.mjs map-prior-work <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 expensive failure this prevents, in one sentence: **you discover the paper that already did your
24
+ contribution after the draft is finished, when the only move left is rewriting the claim under deadline.**
25
+
26
+ Grounding: the original-contribution criterion. A paper
27
+ a reviewer reads as a repackaging earns no authorship credit even if it is accepted. Composes with
28
+ `research-ideate` (upstream: it validated *whether* the idea is worth doing; this validates whether it is
29
+ still *yours*), `analyze-sibling-paper` (this hands it the papers that need a full read), and
30
+ `draft-paper` (which consumes the related-work skeleton).
31
+
32
+ ## Why this exists — the failure it was written from
33
+
34
+ **Real case, 2026-07 (paper #3).** The idea was validated, the venue picked, the study run, the paper
35
+ drafted, the artifact built. At **T−10 days** a *citation audit* — a late mechanical check, not a search —
36
+ stumbled onto a paper that had shipped the same construction **five months earlier**, with an
37
+ implementation matching the paper's own §6. Consequences:
38
+
39
+ - The headline contribution had to be rewritten under deadline.
40
+ - The related-work section had described that paper **incorrectly**, in exactly the direction that made
41
+ room for the claimed novelty — the reading a reviewer punishes hardest.
42
+ - Two more neighbors then had to be read in one night, and one of them overturned a second claim.
43
+
44
+ None of that was bad luck. **No unit of work in the pipeline was responsible for looking.**
45
+ `verify-citations` surfaces neighbors, but it is a CONTINUOUS check over cites **already written** —
46
+ it fires after the draft exists, and it can only see what you already decided to cite. This skill is
47
+ the work that was missing.
48
+
49
+ ## Two modes, and they live in different parts of the pipeline
50
+
51
+ This skill is deliberately **not one thing in one place**. It has two modes, and the scorecard
52
+ (`paper-pipeline/references/pipeline-status-template.md`) gives them two separate rows, because a
53
+ green sweep from month one says nothing about the field today.
54
+
55
+ | Mode | Where it lives | Scorecard row | When it fires |
56
+ |---|---|---|---|
57
+ | **SETUP sweep** (the full thing below) | SETUP, right after `research-ideate` says go | **`priorwork`** | Once, before any drafting. Cheapest moment — the contribution is still a sentence, not a structure. |
58
+ | **CONTINUOUS delta** (re-sweep, restricted to work posted since) | CONTINUOUS — a trigger, never "done" | **`priordelta`** | **Whenever the contribution's framing moves**, and again before `harden-paper`. In a hot area a two-month-old sweep is stale. |
59
+
60
+ Also fires **reactively** in delta mode: a reviewer says "this was already done", an arXiv alert
61
+ surfaces something close, or a `verify-citations` run turns up a neighbor you had never seen.
62
+
63
+ ⚠️ **If a rival first surfaces during citation checking, the SETUP sweep (`priorwork`) was skipped** — and
64
+ you are now reshaping the contribution under deadline, which is exactly the failure above. Treat that
65
+ as a finding about the process, not only about the rival.
66
+
67
+ *The two modes used to be one entry in a numbered stage list, which could only show one of them; that
68
+ list was replaced on 2026-08-03 by the four kinds of work in `paper-pipeline`.*
69
+
70
+ ---
71
+
72
+ ## Step 1 — write down what you are claiming, before searching
73
+
74
+ One sentence, falsifiable, in the form: **"We are first to ___."** Then split it:
75
+
76
+ | Layer | Example | Who can take it |
77
+ |---|---|---|
78
+ | **Construction** | "compile prose rules into executable checks" | anyone who built it first, *regardless of quality* |
79
+ | **Measurement** | "measure how often stated rules are enforced in real repos" | anyone with the same corpus study |
80
+ | **Guarantee** | "abstain unless the synthesized checker survives a blind gold set" | anyone with the same decision procedure |
81
+
82
+ 🔴 **These are lost independently.** Losing the construction does not lose the guarantee. Write all three
83
+ down *now* — otherwise a single hit feels like total loss and you rewrite more than you must.
84
+
85
+ ## Step 2 — sweep, from multiple angles
86
+
87
+ Do not run one query. Run **at least five angles**, because a neighbor that uses different vocabulary is
88
+ exactly the one you will miss:
89
+
90
+ 1. **Your own terms** — the phrasing you use in the claim.
91
+ 2. **Their likely terms** — what would a group from a different subfield call this? (Same idea travels as
92
+ "policy", "constraint", "specification", "guardrail", "contract", "config".)
93
+ 3. **By artifact** — the thing you built, not the idea (tool names, file formats, benchmark names).
94
+ 4. **By venue** — recent proceedings of the venues you'd submit to, and their workshops.
95
+ 5. **By citation graph** — who cites the 2–3 works you consider closest, and what those works cite.
96
+
97
+ Sources, in order of reliability: **arXiv listings + full-text search · ACL Anthology · DBLP · Semantic
98
+ Scholar · venue proceedings pages · OpenReview**. Blogs and social posts count as leads, never as
99
+ findings.
100
+
101
+ **Parallelize.** One subagent per angle, each returning candidates with title, authors, venue, date, and
102
+ two sentences on what it does. Deduplicate afterwards in plain code, not by another agent.
103
+
104
+ ## Step 3 — date everything against YOUR submission date
105
+
106
+ For each candidate record **v1 date**, latest revision, and acceptance status.
107
+
108
+ | Gap to your submission | Status | What you may write |
109
+ |---|---|---|
110
+ | Published **before** by more than ~3 months | **prior work** | Cite it. You may not call it concurrent. |
111
+ | Within roughly ±3 months | **concurrent** | "independently and concurrently" is defensible — say so explicitly |
112
+ | After your submission | not your problem | ignore for this cycle; note for the extension |
113
+
114
+ 🔴 **Five months is prior work, not concurrent.** Wanting it to be concurrent does not make it so, and a
115
+ reviewer checks the arXiv date in one click. Also record **acceptance**: a preprint and a paper accepted
116
+ at a real venue carry different weight, and describing an *accepted* work incorrectly costs more.
117
+
118
+ ## Step 4 — triage against the three layers
119
+
120
+ For each candidate, mark which layer it threatens:
121
+
122
+ | Verdict | Meaning | Action |
123
+ |---|---|---|
124
+ | 🔴 **SCOOPED** | takes a layer outright | that layer is gone — reshape the claim **now**, while it's cheap |
125
+ | 🟠 **OVERLAP** | same territory, different question or method | must be read in full and positioned precisely |
126
+ | 🟡 **ADJACENT** | cited for context, threatens nothing | one accurate sentence in related work |
127
+ | ⚪ **IRRELEVANT** | surfaced by the sweep, doesn't apply | list it anyway, so the next sweep doesn't re-litigate |
128
+
129
+ ## Step 5 — deep-read everything 🔴 and 🟠 — hand off to `analyze-sibling-paper`
130
+
131
+ **Never triage a close paper from its abstract.** Two abstracts in the real case above were actively
132
+ misleading:
133
+
134
+ - one made a *constructive* system read as a measurement tool (the word its title implies appears **zero
135
+ times** in its body);
136
+ - another **omitted its matched-pair design**, so a check based on the abstract concluded "no present/absent
137
+ control" when the full text has one, with real effect sizes in a table.
138
+
139
+ Both errors pointed the same way: **toward believing we were more novel than we were, or that a rival was
140
+ weaker than it was.** Read the paper.
141
+
142
+ **Formulate the read as refutation:** *"try to show this scoops us."* A clean negative is a valid result;
143
+ a confirmation you did not try to break is not.
144
+
145
+ ## Step 6 — the output that matters: what you can still claim
146
+
147
+ Do not stop at a list of papers. The deliverable is a **verdict on the claim**:
148
+
149
+ - ✅ **HOLDS** — the sentence from Step 1 survives as written.
150
+ - ⚠️ **HOLDS NARROWED** — give the exact replacement sentence, ready to paste.
151
+ - 🔴 **DOES NOT HOLD** — say which layer is gone and what remains. If nothing remains, say that: killing
152
+ an idea at sweep stage costs days, killing it at review stage costs a cycle.
153
+
154
+ Plus a **related-work skeleton**: for each 🔴/🟠, two to four sentences in English, correct about *them*
155
+ first and about your delta second. Correctness about the rival is the load-bearing half — a reviewer who
156
+ knows the work reads a wrong description as a stretch, and that contaminates trust in your measurements.
157
+
158
+ ## Step 7 — save the map, not a summary
159
+
160
+ Per `../../CLAUDE.md` (research is recorded verbatim, in detail):
161
+
162
+ ```
163
+ <papers-root>/<paper>/siblings/
164
+ ├── README.md # index: table of every candidate + verdict + what's unread
165
+ ├── <date>-<name>.md # one file per deep-read (analyze-sibling-paper's output)
166
+ └── <date>-sweep.md # the sweep itself: queries run, sources hit, candidates
167
+ # dropped and WHY, coverage gaps stated honestly
168
+ ```
169
+
170
+ **Record what you did NOT find and could not reach** — a paywalled venue, a dead repo link, a search that
171
+ returned nothing. The next sweep starts from that, and "nothing found" is only useful if it says where
172
+ you looked.
173
+
174
+ ---
175
+
176
+ ## Step 8 — record the verdict
177
+
178
+ 🔴 LAST step, once the deliverable exists:
179
+
180
+ ```
181
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record map-prior-work <paper-dir> FINDING <count> <report-path>
182
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record map-prior-work <paper-dir> ABSTAINED <reason> "<one line>"
183
+ ```
184
+
185
+ **FINDING** — `<count>` is the number of rivals triaged 🔴 or 🟠 (they threaten the claim),
186
+ `<report-path>` is the sweep file. Add `--blocking` when a rival did the contribution first and the
187
+ claim has to change.
188
+ **ABSTAINED** — `no-witness`: swept, and nothing found threatens what you claim. `blocked`: the
189
+ paper has no stated contribution yet, so there is nothing to sweep against.
190
+
191
+ That blocking finding is the outcome this skill was written from, discovered at T−10 days by
192
+ accident. Recorded here it is a dated fact about the field rather than a memory of a bad night.
193
+
194
+ 🔴 **There is no PASS**, and this skill is where the reason is easiest to see. "Nothing threatens
195
+ the claim" is a statement about everything that exists, made by a sweep that read a bounded list —
196
+ so it can never be witnessed, only ever failed to be refuted. `no-witness` says that in one word,
197
+ and the sweep's own coverage-gaps section says how far the reading actually went.
198
+
199
+ ## Rules
200
+
201
+ - **Mark evidence level on every claim:** `[A]` full text · `[B]` abstract/metadata · `[C]` your
202
+ inference. The distinction between "I read this" and "I concluded this" must survive being retold —
203
+ it is precisely what erodes when a finding is summarized twice.
204
+ - **Dates are facts, not judgment calls.** Record them; do not characterize a five-month-old paper as
205
+ concurrent because it reads better.
206
+ - **A rival being weak does not restore your precedence.** Their evidence quality and who was first are
207
+ independent questions. "Second with better evidence" is an honest, publishable position; "first" when
208
+ you are second is what gets caught and taints the rest of the paper.
209
+ - **Their weaknesses are your motivation, quotable from their own text.** A gap in a rival's validation
210
+ that you can quote justifies your section far better than any adjective.
211
+ - **Do not delegate the claim decision.** A subagent maps; you decide what the paper claims.
@@ -0,0 +1,227 @@
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: "map-prior-work",
11
+ description:
12
+ "Sweep the competitive landscape for a paper idea BEFORE drafting — find everyone already working on it, date each against your submission (prior vs concurrent is a five-month question, not a vibe), triage by whether they threaten your claimed contribution, deep-read the ones that do, and emit a verdict on WHAT YOU CAN STILL CLAIM plus a related-work skeleton. Saves the full map, not a summary. Use right after research-ideate and before draft-paper, and re-run as a cheap delta pass before submit (hot fields move). Distinct from analyze-sibling-paper (one known competitor, deep) — this one FINDS the competitors and decides which deserve that treatment; distinct from verify-citations (checks cites you already wrote, too late to reshape a contribution); distinct from study-accepted-papers (mines a venue's bar, not your rivals). Compose with research-ideate (upstream), analyze-sibling-paper (it hands off), draft-paper and find-venue (downstream).",
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
+ # map-prior-work — find out who already did it, while you can still change course
26
+
27
+ ## Run me
28
+
29
+ 🔴 FIRST, before any other step:
30
+
31
+ \`\`\`
32
+ node .claude/skills/paper-pipeline/scripts/announce.mjs map-prior-work <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 expensive failure this prevents, in one sentence: **you discover the paper that already did your
39
+ contribution after the draft is finished, when the only move left is rewriting the claim under deadline.**
40
+
41
+ Grounding: the original-contribution criterion. A paper
42
+ a reviewer reads as a repackaging earns no authorship credit even if it is accepted. Composes with
43
+ \`research-ideate\` (upstream: it validated *whether* the idea is worth doing; this validates whether it is
44
+ still *yours*), \`analyze-sibling-paper\` (this hands it the papers that need a full read), and
45
+ \`draft-paper\` (which consumes the related-work skeleton).
46
+
47
+ ## Why this exists — the failure it was written from
48
+
49
+ **Real case, 2026-07 (paper #3).** The idea was validated, the venue picked, the study run, the paper
50
+ drafted, the artifact built. At **T−10 days** a *citation audit* — a late mechanical check, not a search —
51
+ stumbled onto a paper that had shipped the same construction **five months earlier**, with an
52
+ implementation matching the paper's own §6. Consequences:
53
+
54
+ - The headline contribution had to be rewritten under deadline.
55
+ - The related-work section had described that paper **incorrectly**, in exactly the direction that made
56
+ room for the claimed novelty — the reading a reviewer punishes hardest.
57
+ - Two more neighbors then had to be read in one night, and one of them overturned a second claim.
58
+
59
+ None of that was bad luck. **No unit of work in the pipeline was responsible for looking.**
60
+ \`verify-citations\` surfaces neighbors, but it is a CONTINUOUS check over cites **already written** —
61
+ it fires after the draft exists, and it can only see what you already decided to cite. This skill is
62
+ the work that was missing.
63
+
64
+ ## Two modes, and they live in different parts of the pipeline
65
+
66
+ This skill is deliberately **not one thing in one place**. It has two modes, and the scorecard
67
+ (\`paper-pipeline/references/pipeline-status-template.md\`) gives them two separate rows, because a
68
+ green sweep from month one says nothing about the field today.
69
+
70
+ | Mode | Where it lives | Scorecard row | When it fires |
71
+ |---|---|---|---|
72
+ | **SETUP sweep** (the full thing below) | SETUP, right after \`research-ideate\` says go | **\`priorwork\`** | Once, before any drafting. Cheapest moment — the contribution is still a sentence, not a structure. |
73
+ | **CONTINUOUS delta** (re-sweep, restricted to work posted since) | CONTINUOUS — a trigger, never "done" | **\`priordelta\`** | **Whenever the contribution's framing moves**, and again before \`harden-paper\`. In a hot area a two-month-old sweep is stale. |
74
+
75
+ Also fires **reactively** in delta mode: a reviewer says "this was already done", an arXiv alert
76
+ surfaces something close, or a \`verify-citations\` run turns up a neighbor you had never seen.
77
+
78
+ ⚠️ **If a rival first surfaces during citation checking, the SETUP sweep (\`priorwork\`) was skipped** — and
79
+ you are now reshaping the contribution under deadline, which is exactly the failure above. Treat that
80
+ as a finding about the process, not only about the rival.
81
+
82
+ *The two modes used to be one entry in a numbered stage list, which could only show one of them; that
83
+ list was replaced on 2026-08-03 by the four kinds of work in \`paper-pipeline\`.*
84
+
85
+ ---
86
+
87
+ ## Step 1 — write down what you are claiming, before searching
88
+
89
+ One sentence, falsifiable, in the form: **"We are first to ___."** Then split it:
90
+
91
+ | Layer | Example | Who can take it |
92
+ |---|---|---|
93
+ | **Construction** | "compile prose rules into executable checks" | anyone who built it first, *regardless of quality* |
94
+ | **Measurement** | "measure how often stated rules are enforced in real repos" | anyone with the same corpus study |
95
+ | **Guarantee** | "abstain unless the synthesized checker survives a blind gold set" | anyone with the same decision procedure |
96
+
97
+ 🔴 **These are lost independently.** Losing the construction does not lose the guarantee. Write all three
98
+ down *now* — otherwise a single hit feels like total loss and you rewrite more than you must.
99
+
100
+ ## Step 2 — sweep, from multiple angles
101
+
102
+ Do not run one query. Run **at least five angles**, because a neighbor that uses different vocabulary is
103
+ exactly the one you will miss:
104
+
105
+ 1. **Your own terms** — the phrasing you use in the claim.
106
+ 2. **Their likely terms** — what would a group from a different subfield call this? (Same idea travels as
107
+ "policy", "constraint", "specification", "guardrail", "contract", "config".)
108
+ 3. **By artifact** — the thing you built, not the idea (tool names, file formats, benchmark names).
109
+ 4. **By venue** — recent proceedings of the venues you'd submit to, and their workshops.
110
+ 5. **By citation graph** — who cites the 2–3 works you consider closest, and what those works cite.
111
+
112
+ Sources, in order of reliability: **arXiv listings + full-text search · ACL Anthology · DBLP · Semantic
113
+ Scholar · venue proceedings pages · OpenReview**. Blogs and social posts count as leads, never as
114
+ findings.
115
+
116
+ **Parallelize.** One subagent per angle, each returning candidates with title, authors, venue, date, and
117
+ two sentences on what it does. Deduplicate afterwards in plain code, not by another agent.
118
+
119
+ ## Step 3 — date everything against YOUR submission date
120
+
121
+ For each candidate record **v1 date**, latest revision, and acceptance status.
122
+
123
+ | Gap to your submission | Status | What you may write |
124
+ |---|---|---|
125
+ | Published **before** by more than ~3 months | **prior work** | Cite it. You may not call it concurrent. |
126
+ | Within roughly ±3 months | **concurrent** | "independently and concurrently" is defensible — say so explicitly |
127
+ | After your submission | not your problem | ignore for this cycle; note for the extension |
128
+
129
+ 🔴 **Five months is prior work, not concurrent.** Wanting it to be concurrent does not make it so, and a
130
+ reviewer checks the arXiv date in one click. Also record **acceptance**: a preprint and a paper accepted
131
+ at a real venue carry different weight, and describing an *accepted* work incorrectly costs more.
132
+
133
+ ## Step 4 — triage against the three layers
134
+
135
+ For each candidate, mark which layer it threatens:
136
+
137
+ | Verdict | Meaning | Action |
138
+ |---|---|---|
139
+ | 🔴 **SCOOPED** | takes a layer outright | that layer is gone — reshape the claim **now**, while it's cheap |
140
+ | 🟠 **OVERLAP** | same territory, different question or method | must be read in full and positioned precisely |
141
+ | 🟡 **ADJACENT** | cited for context, threatens nothing | one accurate sentence in related work |
142
+ | ⚪ **IRRELEVANT** | surfaced by the sweep, doesn't apply | list it anyway, so the next sweep doesn't re-litigate |
143
+
144
+ ## Step 5 — deep-read everything 🔴 and 🟠 — hand off to \`analyze-sibling-paper\`
145
+
146
+ **Never triage a close paper from its abstract.** Two abstracts in the real case above were actively
147
+ misleading:
148
+
149
+ - one made a *constructive* system read as a measurement tool (the word its title implies appears **zero
150
+ times** in its body);
151
+ - another **omitted its matched-pair design**, so a check based on the abstract concluded "no present/absent
152
+ control" when the full text has one, with real effect sizes in a table.
153
+
154
+ Both errors pointed the same way: **toward believing we were more novel than we were, or that a rival was
155
+ weaker than it was.** Read the paper.
156
+
157
+ **Formulate the read as refutation:** *"try to show this scoops us."* A clean negative is a valid result;
158
+ a confirmation you did not try to break is not.
159
+
160
+ ## Step 6 — the output that matters: what you can still claim
161
+
162
+ Do not stop at a list of papers. The deliverable is a **verdict on the claim**:
163
+
164
+ - ✅ **HOLDS** — the sentence from Step 1 survives as written.
165
+ - ⚠️ **HOLDS NARROWED** — give the exact replacement sentence, ready to paste.
166
+ - 🔴 **DOES NOT HOLD** — say which layer is gone and what remains. If nothing remains, say that: killing
167
+ an idea at sweep stage costs days, killing it at review stage costs a cycle.
168
+
169
+ Plus a **related-work skeleton**: for each 🔴/🟠, two to four sentences in English, correct about *them*
170
+ first and about your delta second. Correctness about the rival is the load-bearing half — a reviewer who
171
+ knows the work reads a wrong description as a stretch, and that contaminates trust in your measurements.
172
+
173
+ ## Step 7 — save the map, not a summary
174
+
175
+ Per \`../../CLAUDE.md\` (research is recorded verbatim, in detail):
176
+
177
+ \`\`\`
178
+ <papers-root>/<paper>/siblings/
179
+ ├── README.md # index: table of every candidate + verdict + what's unread
180
+ ├── <date>-<name>.md # one file per deep-read (analyze-sibling-paper's output)
181
+ └── <date>-sweep.md # the sweep itself: queries run, sources hit, candidates
182
+ # dropped and WHY, coverage gaps stated honestly
183
+ \`\`\`
184
+
185
+ **Record what you did NOT find and could not reach** — a paywalled venue, a dead repo link, a search that
186
+ returned nothing. The next sweep starts from that, and "nothing found" is only useful if it says where
187
+ you looked.
188
+
189
+ ---
190
+
191
+ ## Step 8 — record the verdict
192
+
193
+ 🔴 LAST step, once the deliverable exists:
194
+
195
+ \`\`\`
196
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record map-prior-work <paper-dir> FINDING <count> <report-path>
197
+ node .claude/skills/paper-pipeline/scripts/ledger.mjs record map-prior-work <paper-dir> ABSTAINED <reason> "<one line>"
198
+ \`\`\`
199
+
200
+ **FINDING** — \`<count>\` is the number of rivals triaged 🔴 or 🟠 (they threaten the claim),
201
+ \`<report-path>\` is the sweep file. Add \`--blocking\` when a rival did the contribution first and the
202
+ claim has to change.
203
+ **ABSTAINED** — \`no-witness\`: swept, and nothing found threatens what you claim. \`blocked\`: the
204
+ paper has no stated contribution yet, so there is nothing to sweep against.
205
+
206
+ That blocking finding is the outcome this skill was written from, discovered at T−10 days by
207
+ accident. Recorded here it is a dated fact about the field rather than a memory of a bad night.
208
+
209
+ 🔴 **There is no PASS**, and this skill is where the reason is easiest to see. "Nothing threatens
210
+ the claim" is a statement about everything that exists, made by a sweep that read a bounded list —
211
+ so it can never be witnessed, only ever failed to be refuted. \`no-witness\` says that in one word,
212
+ and the sweep's own coverage-gaps section says how far the reading actually went.
213
+
214
+ ## Rules
215
+
216
+ - **Mark evidence level on every claim:** \`[A]\` full text · \`[B]\` abstract/metadata · \`[C]\` your
217
+ inference. The distinction between "I read this" and "I concluded this" must survive being retold —
218
+ it is precisely what erodes when a finding is summarized twice.
219
+ - **Dates are facts, not judgment calls.** Record them; do not characterize a five-month-old paper as
220
+ concurrent because it reads better.
221
+ - **A rival being weak does not restore your precedence.** Their evidence quality and who was first are
222
+ independent questions. "Second with better evidence" is an honest, publishable position; "first" when
223
+ you are second is what gets caught and taints the rest of the paper.
224
+ - **Their weaknesses are your motivation, quotable from their own text.** A gap in a rival's validation
225
+ that you can quote justifies your section far better than any adjective.
226
+ - **Do not delegate the claim decision.** A subagent maps; you decide what the paper claims.`,
227
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * map-prior-work — 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/map-prior-work/map-prior-work.eval.mjs [trials]
16
+ */
17
+ import { runSkillTriggerEval } from "../../lib/skill-eval-kit.mjs";
18
+
19
+ await runSkillTriggerEval("map-prior-work");
@@ -0,0 +1,23 @@
1
+ /**
2
+ * map-prior-work — 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 `map-prior-work.eval.mjs`.
20
+ */
21
+ import { checkSkill } from "../../lib/skill-checks.mjs";
22
+
23
+ await checkSkill("map-prior-work");
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: osf-artifact-upload
3
+ description: Upload or replace a paper's reproduction artifact file on an OSF project via the OSF API — for anonymized/view-only artifacts hosted for peer review (AISec/AgenticDev etc.). Use when a paper's OSF-hosted artifact needs a file added or a new version pushed (e.g. after fixing the artifact README or regenerating artifact.zip), and the OSF web UI is inconvenient. Composes with submit-paper / submit-paper-<venue>.
4
+ allowed-tools: [Read, Write, Grep, Glob, Bash]
5
+ ---
6
+
7
+ <!-- vigiles:sha256:334c907233abc97c compiled from skills/osf-artifact-upload/SKILL.md.spec.ts -->
8
+
9
+ # osf-artifact-upload — push/replace a file on an OSF project via API
10
+
11
+ Verified working 2026-07-18 (replaced `artifact.zip` on the node of a real submission's artifact).
12
+
13
+ ## Prereq — an OSF personal access token
14
+ - Create at **osf.io/settings/tokens** → scope **`osf.full_write`** (read-only cannot write). Shown once.
15
+ - Put it in the env as `OSF_TOKEN` for the session, OR the user pastes it. **NEVER commit it, never echo it,
16
+ never write it into a file or the skill.** Remind the user to **revoke it** after the upload.
17
+ - ⚠️ Note: a token stored as a gzipped/base64 blob in some other env var may be **blocked from decoding by
18
+ the auto-mode classifier** (correctly). Don't fight it — ask for a fresh `osf.full_write` token instead.
19
+
20
+ ## Gotchas learned (bake these in)
21
+ - **curl globbing:** OSF API URLs with `[ ]` (e.g. `?page[size]=50`) make curl fail silently (empty body,
22
+ no status). Always use **`curl -g`** (disable globbing) or drop the bracketed param.
23
+ - **Flaky proxy:** calls intermittently return 0 bytes / empty. **Retry** (loop until valid JSON;
24
+ `--retry 3`). Verify by API metadata, not only by the waterbutler download (download-back flakes most).
25
+ - **CA bundle:** in this env, add `--cacert /root/.ccr/ca-bundle.crt` to every curl.
26
+ - **Node GUID:** the `osf.io/<guid>` in the paper's Availability (a five-character guid, e.g. `ab12c`) IS the node id; the
27
+ `?view_only=…` is a separate anonymized link. With the owner token you address the node by its guid.
28
+ - **`set +x`** and keep the token only in a shell variable — never in printed output.
29
+
30
+ ## Recipe (all curl; `$T`=token, `$CA`=/root/.ccr/ca-bundle.crt, `$NODE`=guid, `$ZIP`=local file)
31
+ ```bash
32
+ set +x; CA=/root/.ccr/ca-bundle.crt; T="$OSF_TOKEN"; AUTH="Authorization: Bearer $T"; NODE=<guid> # the node from YOUR paper's Availability line
33
+ # 1. verify auth (expect HTTP 200 + your name)
34
+ curl -g -s --retry 3 --cacert $CA -H "$AUTH" https://api.osf.io/v2/users/me/ \
35
+ | python3 -c "import sys,json;d=json.load(sys.stdin);print('auth:',d['data']['attributes']['full_name'])"
36
+ # 2. list osfstorage files → each file's links.upload is its waterbutler URL (for a NEW VERSION)
37
+ curl -g -s --retry 3 --cacert $CA -H "$AUTH" "https://api.osf.io/v2/nodes/$NODE/files/osfstorage/" >/tmp/f.json
38
+ # parse: find the target file's attributes.name==X → f['links']['upload'] (call it $UP)
39
+ # to ADD a new file instead: use the folder's upload link from /v2/nodes/$NODE/files/ (osfstorage provider)
40
+ # 3. push new version (PUT the bytes; append kind=file)
41
+ curl -g -s --retry 3 --cacert $CA -H "$AUTH" -X PUT --data-binary @"$ZIP" "${UP}?kind=file" -o /tmp/up.json
42
+ # success = HTTP 200 + data.attributes.extra.version incremented + size matches
43
+ # 4. VERIFY by API metadata: re-list files, confirm attributes.size and extra.hashes.md5 == md5sum of $ZIP
44
+ ```
45
+ Verification that actually holds: **OSF-stored md5 == `md5sum $ZIP`**. The upload response also returns the
46
+ md5; matching it to the local file is proof even when the download-back call flakes.
47
+
48
+ ## After
49
+ - Confirm the paper's Availability `\url{}` still points at the same node (it does — same guid).
50
+ - Tell the user to **revoke the token** (osf.io/settings/tokens → Delete).
51
+ - If the artifact is stored unpacked (README.md, reproduce.py, data/…) rather than as a zip, replace each
52
+ stale file the same way (each has its own `links.upload`).
@@ -0,0 +1,59 @@
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: "osf-artifact-upload",
11
+ description:
12
+ "Upload or replace a paper's reproduction artifact file on an OSF project via the OSF API — for anonymized/view-only artifacts hosted for peer review (AISec/AgenticDev etc.). Use when a paper's OSF-hosted artifact needs a file added or a new version pushed (e.g. after fixing the artifact README or regenerating artifact.zip), and the OSF web UI is inconvenient. Composes with submit-paper / submit-paper-<venue>.",
13
+ tools: ["Read", "Write", "Grep", "Glob", "Bash"],
14
+ body: `
15
+ # osf-artifact-upload — push/replace a file on an OSF project via API
16
+
17
+ Verified working 2026-07-18 (replaced \`artifact.zip\` on the node of a real submission's artifact).
18
+
19
+ ## Prereq — an OSF personal access token
20
+ - Create at **osf.io/settings/tokens** → scope **\`osf.full_write\`** (read-only cannot write). Shown once.
21
+ - Put it in the env as \`OSF_TOKEN\` for the session, OR the user pastes it. **NEVER commit it, never echo it,
22
+ never write it into a file or the skill.** Remind the user to **revoke it** after the upload.
23
+ - ⚠️ Note: a token stored as a gzipped/base64 blob in some other env var may be **blocked from decoding by
24
+ the auto-mode classifier** (correctly). Don't fight it — ask for a fresh \`osf.full_write\` token instead.
25
+
26
+ ## Gotchas learned (bake these in)
27
+ - **curl globbing:** OSF API URLs with \`[ ]\` (e.g. \`?page[size]=50\`) make curl fail silently (empty body,
28
+ no status). Always use **\`curl -g\`** (disable globbing) or drop the bracketed param.
29
+ - **Flaky proxy:** calls intermittently return 0 bytes / empty. **Retry** (loop until valid JSON;
30
+ \`--retry 3\`). Verify by API metadata, not only by the waterbutler download (download-back flakes most).
31
+ - **CA bundle:** in this env, add \`--cacert /root/.ccr/ca-bundle.crt\` to every curl.
32
+ - **Node GUID:** the \`osf.io/<guid>\` in the paper's Availability (a five-character guid, e.g. \`ab12c\`) IS the node id; the
33
+ \`?view_only=…\` is a separate anonymized link. With the owner token you address the node by its guid.
34
+ - **\`set +x\`** and keep the token only in a shell variable — never in printed output.
35
+
36
+ ## Recipe (all curl; \`$T\`=token, \`$CA\`=/root/.ccr/ca-bundle.crt, \`$NODE\`=guid, \`$ZIP\`=local file)
37
+ \`\`\`bash
38
+ set +x; CA=/root/.ccr/ca-bundle.crt; T="$OSF_TOKEN"; AUTH="Authorization: Bearer $T"; NODE=<guid> # the node from YOUR paper's Availability line
39
+ # 1. verify auth (expect HTTP 200 + your name)
40
+ curl -g -s --retry 3 --cacert $CA -H "$AUTH" https://api.osf.io/v2/users/me/ \\
41
+ | python3 -c "import sys,json;d=json.load(sys.stdin);print('auth:',d['data']['attributes']['full_name'])"
42
+ # 2. list osfstorage files → each file's links.upload is its waterbutler URL (for a NEW VERSION)
43
+ curl -g -s --retry 3 --cacert $CA -H "$AUTH" "https://api.osf.io/v2/nodes/$NODE/files/osfstorage/" >/tmp/f.json
44
+ # parse: find the target file's attributes.name==X → f['links']['upload'] (call it $UP)
45
+ # to ADD a new file instead: use the folder's upload link from /v2/nodes/$NODE/files/ (osfstorage provider)
46
+ # 3. push new version (PUT the bytes; append kind=file)
47
+ curl -g -s --retry 3 --cacert $CA -H "$AUTH" -X PUT --data-binary @"$ZIP" "\${UP}?kind=file" -o /tmp/up.json
48
+ # success = HTTP 200 + data.attributes.extra.version incremented + size matches
49
+ # 4. VERIFY by API metadata: re-list files, confirm attributes.size and extra.hashes.md5 == md5sum of $ZIP
50
+ \`\`\`
51
+ Verification that actually holds: **OSF-stored md5 == \`md5sum $ZIP\`**. The upload response also returns the
52
+ md5; matching it to the local file is proof even when the download-back call flakes.
53
+
54
+ ## After
55
+ - Confirm the paper's Availability \`\\url{}\` still points at the same node (it does — same guid).
56
+ - Tell the user to **revoke the token** (osf.io/settings/tokens → Delete).
57
+ - If the artifact is stored unpacked (README.md, reproduce.py, data/…) rather than as a zip, replace each
58
+ stale file the same way (each has its own \`links.upload\`).`,
59
+ });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * osf-artifact-upload — 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 every case is
6
+ * reviewed as one table where collisions between siblings are visible; copying
7
+ * 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
+ * ⚠️ NEVER RUN. This case was written 2026-08-11 with the other two the coverage
15
+ * sweep surfaced; its rate is UNKNOWN, not assumed good.
16
+ *
17
+ * Costs money; not CI.
18
+ * node .claude/skills/osf-artifact-upload/osf-artifact-upload.eval.mjs [trials]
19
+ */
20
+ import { runSkillTriggerEval } from "../../lib/skill-eval-kit.mjs";
21
+
22
+ await runSkillTriggerEval("osf-artifact-upload");