repomatic 7.16.3__tar.gz → 7.17.1__tar.gz

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 (580) hide show
  1. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/.claude-plugin/plugin.json +1 -1
  2. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/agents/grunt-qa.md +3 -3
  3. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/agents/sphinx-docs.md +1 -1
  4. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.claude}/skills/awesome-triage/SKILL.md +16 -3
  5. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/babysit-ci/SKILL.md +18 -98
  6. repomatic-7.17.1/.claude/skills/babysit-ci/references/failure-patterns.md +92 -0
  7. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.claude}/skills/github-housekeeping/SKILL.md +1 -1
  8. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/repomatic-deps/SKILL.md +2 -2
  9. repomatic-7.17.1/.claude/skills/repomatic-ship/SKILL.md +315 -0
  10. repomatic-7.17.1/.claude/skills/repomatic-ship/references/findings-in-repomatic.md +14 -0
  11. repomatic-7.17.1/.claude/skills/repomatic-ship/references/short-ship.md +15 -0
  12. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.claude}/skills/repomatic-test-matrix/SKILL.md +6 -3
  13. {repomatic-7.16.3 → repomatic-7.17.1}/.claude-plugin/marketplace.json +2 -2
  14. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/_release-build.yaml +3 -3
  15. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/_release-engine.yaml +16 -16
  16. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/autofix.yaml +52 -45
  17. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/autolock.yaml +1 -1
  18. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/cancel-runs.yaml +1 -1
  19. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/changelog.yaml +14 -14
  20. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/debug.yaml +1 -1
  21. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/docs.yaml +41 -17
  22. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/labels.yaml +4 -4
  23. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/lint.yaml +16 -9
  24. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/metrics.yaml +2 -2
  25. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/release.yaml +1 -1
  26. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/self-maintenance.yaml +2 -2
  27. {repomatic-7.16.3 → repomatic-7.17.1}/.github/workflows/tests.yaml +1 -1
  28. {repomatic-7.16.3/repomatic/data → repomatic-7.17.1/.github/workflows}/unsubscribe.yaml +1 -1
  29. {repomatic-7.16.3 → repomatic-7.17.1}/PKG-INFO +3 -3
  30. {repomatic-7.16.3 → repomatic-7.17.1}/changelog.md +34 -0
  31. repomatic-7.17.1/claude.md +140 -0
  32. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/binaries.csv +12 -0
  33. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/dependencies.mmd +2 -2
  34. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/help-dark-screen.svg +6 -6
  35. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/help-light-screen.svg +6 -6
  36. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/virustotal-scans.csv +11 -0
  37. {repomatic-7.16.3 → repomatic-7.17.1}/docs/binaries.md +1 -1
  38. {repomatic-7.16.3 → repomatic-7.17.1}/docs/cloudflare.md +53 -3
  39. {repomatic-7.16.3 → repomatic-7.17.1}/docs/configuration.md +3 -1
  40. {repomatic-7.16.3 → repomatic-7.17.1}/docs/install.md +6 -6
  41. {repomatic-7.16.3 → repomatic-7.17.1}/docs/operation-contracts.md +17 -3
  42. repomatic-7.17.1/docs/repomatic.cloudflare_r2.md +8 -0
  43. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.md +1 -0
  44. {repomatic-7.16.3 → repomatic-7.17.1}/docs/test-matrix.md +3 -3
  45. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.md +1 -0
  46. repomatic-7.17.1/docs/tests.test_cloudflare_r2.md +8 -0
  47. {repomatic-7.16.3 → repomatic-7.17.1}/docs/upstream-development.md +2 -2
  48. {repomatic-7.16.3 → repomatic-7.17.1}/docs/workflows.md +29 -8
  49. {repomatic-7.16.3 → repomatic-7.17.1}/pyproject.toml +14 -6
  50. {repomatic-7.16.3 → repomatic-7.17.1}/pyproject.toml.orig +17 -10
  51. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/__init__.py +2 -2
  52. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/awesome_toc.py +1 -1
  53. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/github.py +9 -0
  54. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/lint.py +122 -39
  55. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/main.py +10 -13
  56. repomatic-7.17.1/repomatic/cloudflare_r2.py +713 -0
  57. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/config.py +46 -3
  58. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/_release-engine.yaml +16 -16
  59. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/agent-grunt-qa.md +3 -3
  60. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/agent-sphinx-docs.md +1 -1
  61. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/autofix.yaml +52 -45
  62. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/autolock.yaml +1 -1
  63. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/cancel-runs.yaml +1 -1
  64. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/changelog.yaml +14 -14
  65. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/debug.yaml +1 -1
  66. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/docs.yaml +41 -17
  67. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/labels.yaml +4 -4
  68. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/lint.yaml +16 -9
  69. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/metrics.yaml +2 -2
  70. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/release.yaml +1 -1
  71. {repomatic-7.16.3/.claude → repomatic-7.17.1/repomatic/data}/skills/awesome-triage/SKILL.md +16 -3
  72. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/babysit-ci/SKILL.md +18 -98
  73. repomatic-7.17.1/repomatic/data/skills/babysit-ci/references/failure-patterns.md +92 -0
  74. {repomatic-7.16.3/.claude → repomatic-7.17.1/repomatic/data}/skills/github-housekeeping/SKILL.md +1 -1
  75. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/repomatic-deps/SKILL.md +2 -2
  76. repomatic-7.17.1/repomatic/data/skills/repomatic-ship/SKILL.md +315 -0
  77. repomatic-7.17.1/repomatic/data/skills/repomatic-ship/references/findings-in-repomatic.md +14 -0
  78. repomatic-7.17.1/repomatic/data/skills/repomatic-ship/references/short-ship.md +15 -0
  79. {repomatic-7.16.3/.claude → repomatic-7.17.1/repomatic/data}/skills/repomatic-test-matrix/SKILL.md +6 -3
  80. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/tests.yaml +1 -1
  81. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/typos.toml +8 -0
  82. {repomatic-7.16.3/.github/workflows → repomatic-7.17.1/repomatic/data}/unsubscribe.yaml +1 -1
  83. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/actions.py +2 -0
  84. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/ci_status.py +121 -70
  85. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/pr_body.py +19 -7
  86. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/init_project.py +37 -11
  87. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/labels.py +1 -1
  88. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/lint_repo.py +262 -19
  89. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/registry.py +7 -0
  90. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/binaries_page.py +8 -8
  91. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/virustotal.py +2 -2
  92. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/runner_catalog.py +3 -3
  93. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/setup_guide.py +38 -7
  94. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/sync_ops.py +6 -6
  95. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-cloudflare-pages.md +2 -4
  96. repomatic-7.17.1/repomatic/templates/setup-guide-cloudflare-r2.md +29 -0
  97. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-notifications-pat.md +1 -2
  98. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-pypi-trusted-publisher.md +1 -2
  99. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-virustotal.md +1 -2
  100. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide.md +3 -1
  101. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/tooling/tool_registry.py +8 -55
  102. {repomatic-7.16.3 → repomatic-7.17.1}/tests/cli-test-suite.toml +6 -0
  103. {repomatic-7.16.3 → repomatic-7.17.1}/tests/conftest.py +12 -0
  104. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_ci_status.py +195 -66
  105. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_claude_assets.py +38 -5
  106. repomatic-7.17.1/tests/test_cloudflare_r2.py +612 -0
  107. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_config.py +44 -0
  108. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_init_project.py +74 -6
  109. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_lint_repo.py +84 -2
  110. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_pr_body.py +1 -0
  111. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_runner_catalog.py +1 -1
  112. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_setup_guide.py +82 -5
  113. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_sync_ops.py +5 -3
  114. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_tool_runner.py +24 -12
  115. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_version_sync.py +211 -210
  116. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_workflow_sync.py +4 -0
  117. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_workflows.py +23 -0
  118. {repomatic-7.16.3 → repomatic-7.17.1}/uv.lock +32 -13
  119. repomatic-7.16.3/.claude/skills/repomatic-ship/SKILL.md +0 -337
  120. repomatic-7.16.3/claude.md +0 -155
  121. repomatic-7.16.3/repomatic/data/skills/repomatic-ship/SKILL.md +0 -337
  122. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/agents/qa-engineer.md +0 -0
  123. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/av-false-positive/SKILL.md +0 -0
  124. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/benchmark-update/SKILL.md +0 -0
  125. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/brand-assets/SKILL.md +0 -0
  126. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/file-bug-report/SKILL.md +0 -0
  127. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/probe-workflow/SKILL.md +0 -0
  128. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/repomatic-audit/SKILL.md +0 -0
  129. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/repomatic-changelog/SKILL.md +0 -0
  130. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/repomatic-init/SKILL.md +0 -0
  131. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/repomatic-topics/SKILL.md +0 -0
  132. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/repomatic-upgrade/SKILL.md +0 -0
  133. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/sphinx-docs-sync/SKILL.md +0 -0
  134. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/translation-sync/SKILL.md +0 -0
  135. {repomatic-7.16.3 → repomatic-7.17.1}/.claude/skills/upstream-audit/SKILL.md +0 -0
  136. {repomatic-7.16.3 → repomatic-7.17.1}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  137. {repomatic-7.16.3 → repomatic-7.17.1}/.github/actions/publish-pypi/action.yaml +0 -0
  138. {repomatic-7.16.3 → repomatic-7.17.1}/.github/code-of-conduct.md +0 -0
  139. {repomatic-7.16.3 → repomatic-7.17.1}/.github/funding.yml +0 -0
  140. {repomatic-7.16.3 → repomatic-7.17.1}/.gitignore +0 -0
  141. {repomatic-7.16.3 → repomatic-7.17.1}/.mailmap +0 -0
  142. {repomatic-7.16.3 → repomatic-7.17.1}/docs/404.html +0 -0
  143. {repomatic-7.16.3 → repomatic-7.17.1}/docs/_redirects +0 -0
  144. {repomatic-7.16.3 → repomatic-7.17.1}/docs/_static/custom.css +0 -0
  145. {repomatic-7.16.3 → repomatic-7.17.1}/docs/agent-skills.md +0 -0
  146. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/banner-social-dark.png +0 -0
  147. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/banner-social-light.png +0 -0
  148. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/banner-social.svg +0 -0
  149. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/config-snippet-screen.svg +0 -0
  150. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/desktop-autosync-warning.png +0 -0
  151. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/desktop-plugin-agents.png +0 -0
  152. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/desktop-plugin-contents.png +0 -0
  153. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/desktop-plugin-skills.png +0 -0
  154. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/favicon.svg +0 -0
  155. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/icon.icns +0 -0
  156. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/icon.ico +0 -0
  157. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/icon.png +0 -0
  158. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/logo-banner-dark.png +0 -0
  159. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/logo-banner-light.png +0 -0
  160. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/logo-banner.svg +0 -0
  161. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/logo-square-dark.png +0 -0
  162. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/logo-square-light.png +0 -0
  163. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/logo-square.svg +0 -0
  164. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/matrix-grid-screen.svg +0 -0
  165. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/metrics.csv +0 -0
  166. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/star-history-compared.svg +0 -0
  167. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/star-history.svg +0 -0
  168. {repomatic-7.16.3 → repomatic-7.17.1}/docs/assets/sync-deps-trail-screen.svg +0 -0
  169. {repomatic-7.16.3 → repomatic-7.17.1}/docs/benchmark.md +0 -0
  170. {repomatic-7.16.3 → repomatic-7.17.1}/docs/changelog-archive.md +0 -0
  171. {repomatic-7.16.3 → repomatic-7.17.1}/docs/changelog.md +0 -0
  172. {repomatic-7.16.3 → repomatic-7.17.1}/docs/claude-code-plugin.md +0 -0
  173. {repomatic-7.16.3 → repomatic-7.17.1}/docs/cli.md +0 -0
  174. {repomatic-7.16.3 → repomatic-7.17.1}/docs/code-of-conduct.md +0 -0
  175. {repomatic-7.16.3 → repomatic-7.17.1}/docs/commit-messages.md +0 -0
  176. {repomatic-7.16.3 → repomatic-7.17.1}/docs/conf.py +0 -0
  177. {repomatic-7.16.3 → repomatic-7.17.1}/docs/contributing.md +0 -0
  178. {repomatic-7.16.3 → repomatic-7.17.1}/docs/dependencies.md +0 -0
  179. {repomatic-7.16.3 → repomatic-7.17.1}/docs/docs_update.py +0 -0
  180. {repomatic-7.16.3 → repomatic-7.17.1}/docs/history.md +0 -0
  181. {repomatic-7.16.3 → repomatic-7.17.1}/docs/index.md +0 -0
  182. {repomatic-7.16.3 → repomatic-7.17.1}/docs/license.md +0 -0
  183. {repomatic-7.16.3 → repomatic-7.17.1}/docs/man.md +0 -0
  184. {repomatic-7.16.3 → repomatic-7.17.1}/docs/nuitka.md +0 -0
  185. {repomatic-7.16.3 → repomatic-7.17.1}/docs/packaging.md +0 -0
  186. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.awesome_toc.md +0 -0
  187. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.broken_links.md +0 -0
  188. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cache.md +0 -0
  189. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.changelog.md +0 -0
  190. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.github.md +0 -0
  191. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.lint.md +0 -0
  192. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.main.md +0 -0
  193. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.md +0 -0
  194. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.release.md +0 -0
  195. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.sample.md +0 -0
  196. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.setup.md +0 -0
  197. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cli.sync.md +0 -0
  198. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.cloudflare.md +0 -0
  199. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.compat.md +0 -0
  200. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.config.md +0 -0
  201. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.data.awesome_template.md +0 -0
  202. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.data.md +0 -0
  203. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.dep_graph.md +0 -0
  204. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.dep_policy.md +0 -0
  205. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.dep_report.md +0 -0
  206. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.dep_sources.md +0 -0
  207. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.md +0 -0
  208. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.uv.md +0 -0
  209. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.deps.vulnerable_deps.md +0 -0
  210. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.docs.md +0 -0
  211. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.file_inventory.md +0 -0
  212. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.file_ops.md +0 -0
  213. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.forge.md +0 -0
  214. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.frontmatter.md +0 -0
  215. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.git_ops.md +0 -0
  216. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.actions.md +0 -0
  217. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.ci_status.md +0 -0
  218. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.dev_release.md +0 -0
  219. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.gh.md +0 -0
  220. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.issue.md +0 -0
  221. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.job_timings.md +0 -0
  222. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.matrix.md +0 -0
  223. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.md +0 -0
  224. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.pr.md +0 -0
  225. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.pr_body.md +0 -0
  226. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.release_sync.md +0 -0
  227. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.releases.md +0 -0
  228. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.sponsor.md +0 -0
  229. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.status.md +0 -0
  230. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.token.md +0 -0
  231. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.unsubscribe.md +0 -0
  232. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.github.workflow_sync.md +0 -0
  233. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.gitignore.md +0 -0
  234. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.hashing.md +0 -0
  235. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.http.md +0 -0
  236. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.humanize.md +0 -0
  237. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.images.md +0 -0
  238. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.init_project.md +0 -0
  239. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.labels.md +0 -0
  240. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.lint_repo.md +0 -0
  241. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.mailmap.md +0 -0
  242. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.matrix_axes.md +0 -0
  243. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metadata.core.md +0 -0
  244. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metadata.env.md +0 -0
  245. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metadata.git.md +0 -0
  246. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metadata.matrix.md +0 -0
  247. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metadata.md +0 -0
  248. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metadata.project.md +0 -0
  249. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metric_chart.md +0 -0
  250. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.metrics.md +0 -0
  251. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.npm.md +0 -0
  252. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.pages_redirects.md +0 -0
  253. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.pypi.md +0 -0
  254. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.pyproject.md +0 -0
  255. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.registry.md +0 -0
  256. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.attestation.md +0 -0
  257. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.binaries_page.md +0 -0
  258. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.binary.md +0 -0
  259. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.checksums.md +0 -0
  260. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.md +0 -0
  261. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.prepare_release.md +0 -0
  262. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.version_sync.md +0 -0
  263. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.release.virustotal.md +0 -0
  264. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.runner_catalog.md +0 -0
  265. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.runner_images.md +0 -0
  266. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.setup_guide.md +0 -0
  267. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.site_anchors.md +0 -0
  268. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.sync_ops.md +0 -0
  269. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.tabular.md +0 -0
  270. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.templates.md +0 -0
  271. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.tooling.bundle.md +0 -0
  272. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.tooling.md +0 -0
  273. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.tooling.plugin.md +0 -0
  274. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.tooling.tool_registry.md +0 -0
  275. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.tooling.tool_runner.md +0 -0
  276. {repomatic-7.16.3 → repomatic-7.17.1}/docs/repomatic.versions.md +0 -0
  277. {repomatic-7.16.3 → repomatic-7.17.1}/docs/robots.txt +0 -0
  278. {repomatic-7.16.3 → repomatic-7.17.1}/docs/security.md +0 -0
  279. {repomatic-7.16.3 → repomatic-7.17.1}/docs/subagents.md +0 -0
  280. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.conftest.md +0 -0
  281. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_actions.md +0 -0
  282. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_attestation.md +0 -0
  283. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_awesome_template.md +0 -0
  284. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_awesome_toc.md +0 -0
  285. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_binaries_page.md +0 -0
  286. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_binary.md +0 -0
  287. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_broken_links.md +0 -0
  288. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_cache.md +0 -0
  289. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_changelog.md +0 -0
  290. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_checksums.md +0 -0
  291. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_ci_status.md +0 -0
  292. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_claude_assets.md +0 -0
  293. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_cloudflare.md +0 -0
  294. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_config.md +0 -0
  295. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_dep_graph.md +0 -0
  296. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_dep_policy.md +0 -0
  297. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_dep_report.md +0 -0
  298. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_dep_sources.md +0 -0
  299. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_dev_release.md +0 -0
  300. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_docs.md +0 -0
  301. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_docstrings.md +0 -0
  302. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_forge.md +0 -0
  303. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_frontmatter.md +0 -0
  304. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_gh.md +0 -0
  305. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_git_ops.md +0 -0
  306. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_gitignore.md +0 -0
  307. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_hashing.md +0 -0
  308. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_help.md +0 -0
  309. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_http.md +0 -0
  310. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_humanize.md +0 -0
  311. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_images.md +0 -0
  312. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_imports.md +0 -0
  313. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_init_project.md +0 -0
  314. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_issue.md +0 -0
  315. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_job_timings.md +0 -0
  316. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_labels.md +0 -0
  317. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_lint_repo.md +0 -0
  318. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_mailmap.md +0 -0
  319. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_matrix.md +0 -0
  320. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_metadata.md +0 -0
  321. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_metrics.md +0 -0
  322. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_npm.md +0 -0
  323. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_pages_redirects.md +0 -0
  324. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_platform_keys.md +0 -0
  325. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_plugin.md +0 -0
  326. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_plugin_update_detection.md +0 -0
  327. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_pr.md +0 -0
  328. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_pr_body.md +0 -0
  329. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_prepare_release.md +0 -0
  330. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_pypi.md +0 -0
  331. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_pyproject.md +0 -0
  332. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_readme.md +0 -0
  333. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_release_sync.md +0 -0
  334. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_releases.md +0 -0
  335. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_runner_catalog.md +0 -0
  336. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_runner_sync.md +0 -0
  337. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_setup_guide.md +0 -0
  338. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_site_anchors.md +0 -0
  339. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_skills.md +0 -0
  340. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_sphinx_crossrefs.md +0 -0
  341. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_status.md +0 -0
  342. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_suite_hygiene.md +0 -0
  343. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_sync_ops.md +0 -0
  344. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_tabular.md +0 -0
  345. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_todolist.md +0 -0
  346. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_tool_runner.md +0 -0
  347. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_unsubscribe.md +0 -0
  348. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_uv.md +0 -0
  349. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_version_sync.md +0 -0
  350. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_versions.md +0 -0
  351. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_virustotal.md +0 -0
  352. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_vulnerable_deps.md +0 -0
  353. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_workflow_sync.md +0 -0
  354. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tests.test_workflows.md +0 -0
  355. {repomatic-7.16.3 → repomatic-7.17.1}/docs/todolist.md +0 -0
  356. {repomatic-7.16.3 → repomatic-7.17.1}/docs/tool-runner.md +0 -0
  357. {repomatic-7.16.3 → repomatic-7.17.1}/license +0 -0
  358. {repomatic-7.16.3 → repomatic-7.17.1}/readme.md +0 -0
  359. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/__main__.py +0 -0
  360. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/broken_links.py +0 -0
  361. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cache.py +0 -0
  362. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/changelog.py +0 -0
  363. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/__init__.py +0 -0
  364. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/release.py +0 -0
  365. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/sample.py +0 -0
  366. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/setup.py +0 -0
  367. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cli/sync.py +0 -0
  368. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/cloudflare.py +0 -0
  369. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/compat.py +0 -0
  370. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/__init__.py +0 -0
  371. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/action-publish-pypi.yaml +0 -0
  372. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/actionlint.yaml +0 -0
  373. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/agent-qa-engineer.md +0 -0
  374. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/config.yml +0 -0
  375. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/new-link.yaml +0 -0
  376. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/code-of-conduct.md +0 -0
  377. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/contributing.md +0 -0
  378. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/contributing.zh.md +0 -0
  379. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/funding.yml +0 -0
  380. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/.github/pull_request_template.md +0 -0
  381. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/__init__.py +0 -0
  382. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/awesome_template/license +0 -0
  383. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/bumpversion.toml +0 -0
  384. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/coverage.toml +0 -0
  385. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/labels.toml +0 -0
  386. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/lychee.toml +0 -0
  387. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/mdformat.toml +0 -0
  388. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/mypy.toml +0 -0
  389. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/pytest.toml +0 -0
  390. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/ruff.toml +0 -0
  391. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/av-false-positive/SKILL.md +0 -0
  392. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/benchmark-update/SKILL.md +0 -0
  393. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/brand-assets/SKILL.md +0 -0
  394. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/file-bug-report/SKILL.md +0 -0
  395. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/probe-workflow/SKILL.md +0 -0
  396. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/repomatic-audit/SKILL.md +0 -0
  397. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/repomatic-changelog/SKILL.md +0 -0
  398. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/repomatic-init/SKILL.md +0 -0
  399. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/repomatic-topics/SKILL.md +0 -0
  400. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/repomatic-upgrade/SKILL.md +0 -0
  401. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/sphinx-docs-sync/SKILL.md +0 -0
  402. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/translation-sync/SKILL.md +0 -0
  403. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/skills/upstream-audit/SKILL.md +0 -0
  404. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/uv.toml +0 -0
  405. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/vt-trend-chart.js +0 -0
  406. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/yamllint.yaml +0 -0
  407. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/data/zizmor.yaml +0 -0
  408. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/__init__.py +0 -0
  409. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/dep_graph.py +0 -0
  410. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/dep_policy.py +0 -0
  411. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/dep_report.py +0 -0
  412. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/dep_sources.py +0 -0
  413. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/uv.py +0 -0
  414. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/deps/vulnerable_deps.py +0 -0
  415. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/docs.py +0 -0
  416. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/file_inventory.py +0 -0
  417. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/file_ops.py +0 -0
  418. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/forge.py +0 -0
  419. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/frontmatter.py +0 -0
  420. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/git_ops.py +0 -0
  421. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/__init__.py +0 -0
  422. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/dev_release.py +0 -0
  423. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/gh.py +0 -0
  424. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/issue.py +0 -0
  425. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/job_timings.py +0 -0
  426. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/matrix.py +0 -0
  427. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/pr.py +0 -0
  428. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/release_sync.py +0 -0
  429. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/releases.py +0 -0
  430. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/sponsor.py +0 -0
  431. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/status.py +0 -0
  432. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/token.py +0 -0
  433. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/unsubscribe.py +0 -0
  434. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/github/workflow_sync.py +0 -0
  435. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/gitignore.py +0 -0
  436. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/hashing.py +0 -0
  437. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/http.py +0 -0
  438. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/humanize.py +0 -0
  439. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/images.py +0 -0
  440. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/mailmap.py +0 -0
  441. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/matrix_axes.py +0 -0
  442. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metadata/__init__.py +0 -0
  443. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metadata/core.py +0 -0
  444. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metadata/env.py +0 -0
  445. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metadata/git.py +0 -0
  446. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metadata/matrix.py +0 -0
  447. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metadata/project.py +0 -0
  448. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metric_chart.py +0 -0
  449. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/metrics.py +0 -0
  450. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/npm.py +0 -0
  451. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/pages_redirects.py +0 -0
  452. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/py.typed +0 -0
  453. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/pypi.py +0 -0
  454. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/pyproject.py +0 -0
  455. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/__init__.py +0 -0
  456. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/attestation.py +0 -0
  457. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/binary.py +0 -0
  458. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/checksums.py +0 -0
  459. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/prepare_release.py +0 -0
  460. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/release/version_sync.py +0 -0
  461. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/runner_images.py +0 -0
  462. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/site_anchors.py +0 -0
  463. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/tabular.py +0 -0
  464. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/__init__.py +0 -0
  465. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/available-admonition.md +0 -0
  466. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/broken-links-issue.md +0 -0
  467. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/bump-version.md +0 -0
  468. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/detect-squash-merge.md +0 -0
  469. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/development-warning.md +0 -0
  470. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/fix-changelog.md +0 -0
  471. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/fix-typos.md +0 -0
  472. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/fix-vulnerable-deps.md +0 -0
  473. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/format-images.md +0 -0
  474. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/format-json.md +0 -0
  475. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/format-markdown.md +0 -0
  476. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/format-pyproject.md +0 -0
  477. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/format-python.md +0 -0
  478. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/format-shell.md +0 -0
  479. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/generated-footer.md +0 -0
  480. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/github-releases.md +0 -0
  481. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/immutable-releases.md +0 -0
  482. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/pr-metadata.md.noformat +0 -0
  483. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/prepare-release.md.noformat +0 -0
  484. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/refresh-tip.md +0 -0
  485. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/release-notes.md +0 -0
  486. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/release-sync-report.md +0 -0
  487. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sample-metrics.md +0 -0
  488. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/scan-virustotal.md +0 -0
  489. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-branch-ruleset.md +0 -0
  490. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-dependabot.md +0 -0
  491. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-fork-pr-approval.md +0 -0
  492. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-pages-source.md +0 -0
  493. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-sha-pinning-required.md +0 -0
  494. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-token.md +0 -0
  495. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/setup-guide-verify.md +0 -0
  496. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-action-pins.md +0 -0
  497. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-bumpversion.md +0 -0
  498. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-dep-sources.md +0 -0
  499. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-gitignore.md +0 -0
  500. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-mailmap.md +0 -0
  501. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-repomatic-upgrade.md +0 -0
  502. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-repomatic.md +0 -0
  503. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-runner-images.md +0 -0
  504. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-tool-versions.md +0 -0
  505. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-uv-lock.md +0 -0
  506. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/sync-workflow-pins.md +0 -0
  507. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/unavailable-admonition.md +0 -0
  508. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/unsubscribe-phase1.md +0 -0
  509. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/unsubscribe-phase2.md +0 -0
  510. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/update-dep-graph.md +0 -0
  511. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/update-docs.md +0 -0
  512. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/upgrade-invite.md +0 -0
  513. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/templates/yanked-admonition.md +0 -0
  514. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/tooling/__init__.py +0 -0
  515. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/tooling/bundle.py +0 -0
  516. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/tooling/plugin.py +0 -0
  517. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/tooling/tool_runner.py +0 -0
  518. {repomatic-7.16.3 → repomatic-7.17.1}/repomatic/versions.py +0 -0
  519. {repomatic-7.16.3 → repomatic-7.17.1}/tests/__init__.py +0 -0
  520. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_actions.py +0 -0
  521. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_attestation.py +0 -0
  522. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_awesome_template.py +0 -0
  523. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_awesome_toc.py +0 -0
  524. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_binaries_page.py +0 -0
  525. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_binary.py +0 -0
  526. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_broken_links.py +0 -0
  527. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_cache.py +0 -0
  528. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_changelog.py +0 -0
  529. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_checksums.py +0 -0
  530. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_cloudflare.py +0 -0
  531. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_dep_graph.py +0 -0
  532. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_dep_policy.py +0 -0
  533. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_dep_report.py +0 -0
  534. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_dep_sources.py +0 -0
  535. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_dev_release.py +0 -0
  536. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_docs.py +0 -0
  537. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_docstrings.py +0 -0
  538. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_forge.py +0 -0
  539. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_frontmatter.py +0 -0
  540. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_gh.py +0 -0
  541. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_git_ops.py +0 -0
  542. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_gitignore.py +0 -0
  543. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_hashing.py +0 -0
  544. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_help.py +0 -0
  545. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_http.py +0 -0
  546. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_humanize.py +0 -0
  547. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_images.py +0 -0
  548. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_imports.py +0 -0
  549. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_issue.py +0 -0
  550. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_job_timings.py +0 -0
  551. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_labels.py +0 -0
  552. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_mailmap.py +0 -0
  553. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_matrix.py +0 -0
  554. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_metadata.py +0 -0
  555. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_metrics.py +0 -0
  556. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_npm.py +0 -0
  557. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_pages_redirects.py +0 -0
  558. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_platform_keys.py +0 -0
  559. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_plugin.py +0 -0
  560. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_plugin_update_detection.py +0 -0
  561. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_pr.py +0 -0
  562. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_prepare_release.py +0 -0
  563. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_pypi.py +0 -0
  564. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_pyproject.py +0 -0
  565. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_readme.py +0 -0
  566. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_release_sync.py +0 -0
  567. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_releases.py +0 -0
  568. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_runner_sync.py +0 -0
  569. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_site_anchors.py +0 -0
  570. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_skills.py +0 -0
  571. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_sphinx_crossrefs.py +0 -0
  572. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_status.py +0 -0
  573. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_suite_hygiene.py +0 -0
  574. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_tabular.py +0 -0
  575. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_todolist.py +0 -0
  576. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_unsubscribe.py +0 -0
  577. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_uv.py +0 -0
  578. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_versions.py +0 -0
  579. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_virustotal.py +0 -0
  580. {repomatic-7.16.3 → repomatic-7.17.1}/tests/test_vulnerable_deps.py +0 -0
@@ -20,5 +20,5 @@
20
20
  "license": "GPL-2.0-or-later",
21
21
  "name": "repomatic",
22
22
  "repository": "https://github.com/kdeldycke/repomatic",
23
- "version": "7.16.3"
23
+ "version": "7.17.1"
24
24
  }
@@ -17,8 +17,8 @@ Work beyond the local repository: check issues, PRs, and CI runs on GitHub. Fix
17
17
 
18
18
  ## Tools of the trade
19
19
 
20
- - `gh issue list`, `gh pr list`, `gh pr view`, `gh run list`, `gh run view`
21
- - `repomatic lint-repo`, `repomatic show-metadata`, and every other subcommand. Inside `kdeldycke/repomatic` itself (a `repomatic/__init__.py` exists) reach it as `uv run repomatic`; anywhere else it is not a project dependency, so use `uvx --exclude-newer '1 week' --exclude-newer-package repomatic=P0D -- repomatic`, which holds the dependency tree to the supply-chain cooldown while keeping a fresh repomatic release installable. A bare `uv run repomatic` downstream dies on `Failed to spawn: repomatic`.
20
+ - `gh issue list`, `gh pr list`, `gh pr view`, `gh run view`
21
+ - `repomatic ci-status`, `repomatic lint-repo`, `repomatic show-metadata`, and every other subcommand. Inside `kdeldycke/repomatic` itself (a `repomatic/__init__.py` exists) reach it as `uv run repomatic`; anywhere else it is not a project dependency, so use `uvx --exclude-newer '1 week' --exclude-newer-package repomatic=P0D -- repomatic`, which holds the dependency tree to the supply-chain cooldown while keeping a fresh repomatic release installable. A bare `uv run repomatic` downstream dies on `Failed to spawn: repomatic`.
22
22
  - Tests, type checking, linting
23
23
 
24
24
  ## Checks
@@ -37,7 +37,7 @@ These issues recur across sessions — check them every pass:
37
37
 
38
38
  - CLI help output in `readme.md` stale after new subcommands or option changes
39
39
  - Version references (`@vX.Y.Z`, `--version` examples) not bumped after releases
40
- - `GitHub Actions` miscapitalized as "GitHub actions" or "Github Actions"
40
+ - `GitHub Actions` miscapitalized, with a lowercase `h` or `a`
41
41
  - Workflow job descriptions missing or outdated after job renames/additions
42
42
  - Grammar errors in CLI help strings (`"does not exists"`, missing periods)
43
43
  - Verbose "why" explanations in YAML workflow comments that belong in Python docstrings
@@ -585,7 +585,7 @@ User-facing pages, and when a project carries one:
585
585
 
586
586
  Agent tooling toctree, in this order. Drop the whole block when the project ships none of them. Name each page for what it is portable to: skills follow a cross-vendor specification, subagents follow the component that ships them, and only the plugin, which no vendor-neutral format covers, keeps a Claude Code name.
587
587
 
588
- 1. `agent-skills` — Only when the project ships Agent Skills (see § Recipes › skills and subagents pages below).
588
+ 1. `agent-skills` — Only when the project ships Agent Skills (see "Skills and subagents pages" below).
589
589
  2. `subagents` — Only when the project ships subagent definitions.
590
590
  3. `claude-code-plugin` — Only when those skills and subagents are also published as an installable Claude Code plugin. Both distribution paths coexist, so the page covers the marketplace install, what the archive ships, and how to wire it into a repository.
591
591
 
@@ -78,7 +78,7 @@ See also §9 for contributor and repo provenance signals — these often reinfor
78
78
  - Self-promotion is allowed but must be disclosed. Undisclosed affiliation is a trust signal.
79
79
  - Author submissions get more scrutiny on the "marketing vs. genuine content" axis but are not automatically penalized. Many accepted PRs across all four lists are author self-submissions.
80
80
  - For commercial content, apply `contributing.md` FAQ "Why my commercial project is not in the list?": prefer open-source repository links over commercial landing pages.
81
- - When a commercial brand or vendor sits behind the submission (product site, paid SaaS, or a lead-gen funnel pointing at a commercial domain), record the exact brand and domain. A declined commercial submission must close its comment with the sponsorship offer: see § Drafting comments.
81
+ - When a commercial brand or vendor sits behind the submission (product site, paid SaaS, or a lead-gen funnel pointing at a commercial domain), record the exact brand and domain in the triage analysis. A declined commercial or self-promotional submission must close its comment with the fixed sponsorship phrase: see § Drafting comments.
82
82
 
83
83
  #### 7. Formatting and editorial compliance
84
84
 
@@ -89,6 +89,8 @@ Check the diff (for PRs) against `contributing.md` §§ Formatting and Editorial
89
89
  - **Launched and functional**: The product or article must exist and be accessible.
90
90
  - **Maintained**: For GitHub repos, check if the project is archived, when the last commit was. Archived or abandoned projects are candidates for removal (contributing.md FAQ "Why removes inactive GitHub projects?"). Check for forks or reboots before recommending deletion.
91
91
  - **Generic, not product-specific**: Articles applicable to only one product are not generic enough for inclusion (contributing.md "Why my link was rejected?").
92
+ - **Original, not a rehash of its own sources**: Trace the candidate to its primary source before scoring it. Look for a republication notice ("Originally published at ..."), then diff the body against whatever it links under "further reading" or references. A page that paraphrases Wikipedia row by row without citing it adds an unstable hop and no data: prefer the primary source, and write the software framing into the description yourself, which `contributing.md` section Formatting licenses as "smart editorializing". Same test picks the canonical URL: the author's own domain beats a syndication, an aggregator or a mirror.
93
+ - **Verify every row of a small factual table, not one**: A spot-check that passes says nothing about the rows beside it. Eight rows cost one fetch of the source to check in full, and one stale row can invalidate the system-impact claim built on it. A triage that scored this check PASS on a single verified row missed both a stale postal-code claim and that the whole table was unattributed Wikipedia paraphrase.
92
94
 
93
95
  #### 9. Contributor and repo provenance
94
96
 
@@ -134,18 +136,29 @@ After running all checks, provide one of:
134
136
  - **REJECT**: Fails one or more hard criteria (duplicate, AI slop, not launched, paywalled, no value-add, section saturation, competitive context mismatch). Draft a rejection comment.
135
137
  - **NEEDS DISCUSSION**: Borderline case where maintainer judgment is required. Summarize the arguments for and against.
136
138
 
137
- After the verdict, propose 2-3 short, ready-to-post comments (one line each) that the maintainer can copy-paste to explain the decision to the author. Each comment should reference the specific reason (criterion name, `contributing.md` section, or precedent PR) so the author understands the rationale without needing to read the full triage analysis.
139
+ After the verdict, propose 2-3 short, ready-to-post comments that the maintainer can copy-paste to explain the decision to the author. Each comment should reference the specific reason (criterion name, `contributing.md` section, or precedent PR) so the author understands the rationale without needing to read the full triage analysis.
140
+
141
+ **Order them shortest first.** The maintainer usually posts the first one and nothing else. The default is a tight, single-topic comment: name the one blocker that decides the case, cite it, stop. Longer variants that stack several criteria, quote the contributor's own history, or enumerate every failing check go last, and only when a criterion is genuinely contested. A rejection needs one reason stated well, not five stated thinly.
138
142
 
139
143
  ### Drafting comments
140
144
 
141
145
  When drafting a rejection or request-for-changes comment:
142
146
 
143
147
  - Be specific about which criteria were not met.
148
+
144
149
  - Reference `contributing.md` sections where applicable.
150
+
145
151
  - Stay polite and constructive. Contributors may improve and resubmit.
152
+
146
153
  - For AI slop: keep it brief. State the specific tells (e.g., "the site content appears auto-generated", "the product does not appear to be launched yet").
154
+
147
155
  - When a section is saturated, suggest the contributor identify weaker existing entries that could be replaced, turning an addition into a curation improvement.
148
- - For commercially affiliated submissions: always close the comment with a sponsorship offer, whether or not the affiliation was disclosed. Name the specific brand or website in backticks so the call-out is explicit, then point to the sponsorship link as the paid way to get featured: https://github.com/sponsors/kdeldycke. This mirrors `contributing.md` FAQ "How can I force a link into the list?". Example close, for a submission promoting `acme-billing.com`: "If you want to promote `acme-billing.com`, you can purchase a sponsorship to this repository: https://github.com/sponsors/kdeldycke".
156
+
157
+ - **Always close a declined commercial or self-promotional submission with this exact phrase, verbatim, as the last line of the comment**, whether or not the affiliation was disclosed:
158
+
159
+ > If you want to promote your product, you can purchase a sponsorship to this repository: https://github.com/sponsors/kdeldycke
160
+
161
+ Do not substitute the brand or domain into it, do not reword it, and do not backtick the product name inside it. The phrase is generic on purpose: it reads the same to every contributor, it never argues about whether the submission was commercial, and it survives being copied across the four lists unchanged. This mirrors `contributing.md` FAQ "How can I force a link into the list?", which is the paid path around the curation rules. Record the brand and domain in the triage analysis instead, where the maintainer can see them and the contributor cannot.
149
162
 
150
163
  ### Broken link triage
151
164
 
@@ -80,7 +80,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
80
80
 
81
81
  One call returns every workflow triggered by that commit. Do not reach for `gh run list`: both its branch-wide form and its per-workflow form have put runs weeks old at the top of the list, on a repository whose workflows had in fact run on every recent commit, which reads as "this workflow has not run in a month". Give `head_sha` the **full** 40-character SHA, because an abbreviated one matches nothing and returns an empty list that looks identical to "nothing ran". Quote the whole path: zsh expands the `?` as a glob and kills the call with `no matches found` before `gh` runs. To list a single workflow across a branch instead, use `gh api 'repos/<OWNER>/<REPO>/actions/workflows/<file>/runs?branch=<BRANCH>&created=>=<DATE>'`, and keep the date filter: without it, that endpoint has returned a page twelve days stale while the branch ran every hour.
82
82
 
83
- Track all five run IDs (`docs.yaml` may have none: its `paths:` filter skips pushes touching nothing docs-relevant). An empty run list for the *other* workflows is not paths-filtering: GitHub can sit on a push event for hours before materializing any run (a 4-hour lag has been observed), so when a freshly pushed SHA shows no runs, keep re-polling instead of concluding the push was filtered, and measure the wait from run creation, not from the push. The `tests.yaml` run exercises the full test matrix; `lint.yaml` runs mypy on every tracked Python file and lints YAML; `autofix.yaml` runs the mechanical fix jobs (`format-*`, `sync-*`, `fix-typos`, `fix-vulnerable-deps`) and turns red when one *crashes* instead of committing a fix; `docs.yaml` builds and deploys the Sphinx site and runs the broken-links check (an externally cancelled or link-flaky run re-runs cleanly via `gh workflow run docs.yaml --ref <BRANCH>`, no commit needed); `release.yaml` runs the Nuitka binary matrix (dev binaries: an ordinary push rebuilds only the `[tool.repomatic] nuitka.dev-targets` canary subset, while release commits, the weekly `schedule` and `workflow_dispatch` build the full target fleet) — but only on projects with `[tool.repomatic] nuitka.enabled` and a CLI entry point; with Nuitka disabled the per-platform jobs skip on every push, release commits included, and a green `release.yaml` means package build plus dev pre-release sync only. Even with Nuitka enabled, a single push can still skip the matrix: `Metadata.skip_binary_build` (`repomatic/metadata/git.py`) is the authoritative signal, true when the head commit is on a non-code branch, is a user-initiated version-bump commit, or (the common case) its changed files fall entirely outside `Metadata.binary_affecting_paths` — a docs-only or workflow-only commit, say. Don't infer the reason from the commit message or assume an unrendered/skipped matrix job name means `nuitka_matrix` itself was empty: the matrix data can be fully populated for that exact commit (verify via the `release / 🧬 Project metadata` job's logged `metadata=` JSON output) while the workflow still elects not to build it. Check `skip_binary_build`'s three conditions before asserting why a matrix skipped, since any one of them is enough on its own. All five workflows must pass — see § Autofix job failures and § Nuitka binary build failures below for how to triage them without stalling the loop.
83
+ Track all five run IDs (`docs.yaml` may have none: its `paths:` filter skips pushes touching nothing docs-relevant). An empty run list for the *other* workflows is not paths-filtering: GitHub can sit on a push event for hours before materializing any run (a 4-hour lag has been observed), so when a freshly pushed SHA shows no runs, keep re-polling instead of concluding the push was filtered, and measure the wait from run creation, not from the push. The `tests.yaml` run exercises the full test matrix; `lint.yaml` runs mypy on every tracked Python file and lints YAML; `autofix.yaml` runs the mechanical fix jobs (`format-*`, `sync-*`, `fix-typos`, `fix-vulnerable-deps`) and turns red when one *crashes* instead of committing a fix; `docs.yaml` builds and deploys the Sphinx site and runs the broken-links check (an externally cancelled or link-flaky run re-runs cleanly via `gh workflow run docs.yaml --ref <BRANCH>`, no commit needed); `release.yaml` runs the Nuitka binary matrix (dev binaries: an ordinary push rebuilds only the `[tool.repomatic] nuitka.dev-targets` canary subset, while release commits, the weekly `schedule` and `workflow_dispatch` build the full target fleet) — but only on projects with `[tool.repomatic] nuitka.enabled` and a CLI entry point; with Nuitka disabled the per-platform jobs skip on every push, release commits included, and a green `release.yaml` means package build plus dev pre-release sync only. Even with Nuitka enabled, a single push can still skip the matrix: `Metadata.skip_binary_build` (`repomatic/metadata/git.py`) is the authoritative signal, true when the head commit is on a non-code branch, is a user-initiated version-bump commit, or (the common case) its changed files fall entirely outside `Metadata.binary_affecting_paths` — a docs-only or workflow-only commit, say. Don't infer the reason from the commit message or assume an unrendered/skipped matrix job name means `nuitka_matrix` itself was empty: the matrix data can be fully populated for that exact commit (verify via the `release / 🧬 Project metadata` job's logged `metadata=` JSON output) while the workflow still elects not to build it. Check `skip_binary_build`'s three conditions before asserting why a matrix skipped, since any one of them is enough on its own. All five workflows must pass — see § Autofix job failures and § Nuitka binary build failures in `references/failure-patterns.md` for how to triage them without stalling the loop.
84
84
 
85
85
  3. **Run local tests while waiting for CI.** Don't idle while polling. Start the full test suite and linters locally in the background immediately:
86
86
 
@@ -102,11 +102,11 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
102
102
 
103
103
  It reads every workflow a push can start (derived from `.github/workflows/`, so its list is wider than the five above), reports each one's latest run, and names the failing jobs that actually gate a merge. Three traps it settles, so no hand-rolled `jq` has to: a run's own `status` lags its jobs (every monitored workflow can read `queued` while a dozen jobs have already finished, which is indistinguishable from the runner-cap saturation a busy account genuinely hits); a `continue-on-error` probe that crashed hides inside a `success` run conclusion; and a run whose `conclusion` is `failure` with *no* failed job is a workflow-level error (an invalid `strategy.matrix` expression, malformed YAML, a missing secret) with no job log to read, which the command flags rather than letting you write off a persistently-red workflow as a known artifact.
104
104
 
105
- `ci-status` reads the same endpoints as the `gh api` calls above, and it has printed a stale table the same way: re-read a surprising red or green once before acting on it.
105
+ `ci-status` reads runs through the same `head_sha` endpoint, commit by commit back from the branch tip, and says when the tip has no run yet. A workflow with no run on the newest commits falls back to `gh run list`, so its row can be stale. Re-read a surprising red or green once before acting on it.
106
106
 
107
107
  Run state *does* gate the run-scoped log read (step 4): `gh run view --log-failed` refuses to answer until the parent run reaches a terminal state. A completed job's own log is readable at once.
108
108
 
109
- **A queue is not a hang, and elapsed time alone cannot tell them apart.** A long stall invites the theory that some run is stuck and that cancelling it would free the pool, which is a conclusion worth reaching only on evidence, because acting on it destroys work that was progressing fine. Two readings settle it, and neither is the elapsed clock. Get a **baseline** from that workflow's recent successful runs (`gh run list --workflow <wf> --repo <owner/repo> --status success --json createdAt,updatedAt`): a suite whose normal duration is two hours is not hung at ninety minutes. Then read **per-job `completedAt` timestamps** (`gh run view <id> --json jobs`) rather than an aggregate: a flat count of `in_progress` jobs is not evidence of a stall, since jobs finish and others start into the freed slots, holding the count steady while real progress continues. Watch for the self-contradiction that exposes the mistake, a report that the count "dropped from 11 to 9" *and* that nothing has changed. Two smaller traps live here too: `gh` reports a pending job's `conclusion` as `""`, not `null`, so a `select(.conclusion == null)` filter silently matches nothing and reads as "no pending jobs"; and jobs queue against the runner pool their `runs-on` names, so a stall confined to macOS cells says nothing about Linux capacity. **Never cancel another repository's run to free slots without the maintainer's explicit go-ahead**, and never ask for that go-ahead on a diagnosis you have not backed with a baseline and timestamps.
109
+ **A queue is not a hang, and elapsed time alone cannot tell them apart.** A long stall invites the theory that some run is stuck and that cancelling it would free the pool, which is a conclusion worth reaching only on evidence, because acting on it destroys work that was progressing fine. Two readings settle it, and neither is the elapsed clock. Get a **baseline** from that workflow's recent successful runs (`gh api 'repos/<OWNER>/<REPO>/actions/workflows/<wf>/runs?status=success&created=>=<DATE>' --jq '.workflow_runs[] | [.created_at, .updated_at] | @tsv'`): a suite whose normal duration is two hours is not hung at ninety minutes. Then read **per-job `completedAt` timestamps** (`gh run view <id> --json jobs`) rather than an aggregate: a flat count of `in_progress` jobs is not evidence of a stall, since jobs finish and others start into the freed slots, holding the count steady while real progress continues. Watch for the self-contradiction that exposes the mistake, a report that the count "dropped from 11 to 9" *and* that nothing has changed. Two smaller traps live here too: `gh` reports a pending job's `conclusion` as `""`, not `null`, so a `select(.conclusion == null)` filter silently matches nothing and reads as "no pending jobs"; and jobs queue against the runner pool their `runs-on` names, so a stall confined to macOS cells says nothing about Linux capacity. **Never cancel another repository's run to free slots without the maintainer's explicit go-ahead**, and never ask for that go-ahead on a diagnosis you have not backed with a baseline and timestamps.
110
110
 
111
111
  **Gate 2 (lint.yaml, ~4 min):** `lint.yaml` finishes before `tests.yaml`. If "Lint types" (mypy) fails, proceed to step 4 immediately.
112
112
 
@@ -114,7 +114,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
114
114
 
115
115
  **Poll in-process; never detach a monitor.** Block on `gh run watch <RUN_ID>` or loop the polls within your own turn. A detached background monitor (a standalone process, a `run_in_background: true` Bash poller that re-invokes you when it exits, or a `Monitor`-tool stream that returns control on each tick) makes a parent-resumed run spawn *another* monitor per tick instead of driving to a terminal state; worse, a spawned sub-agent that detaches this way orphans the poll from its caller the moment it returns. Hold the turn until the run completes: starting a poller and handing back "to be notified" is the early return this loop must never make.
116
116
 
117
- **Every wait between polls must be a `sleep`, never a busy-wait.** A poll loop with no delay (`until gh run view ...; do true; done`) fires thousands of requests per minute and exhausts the REST quota (5,000/hour) within minutes. The harness blocking a bare foreground `sleep` is not a reason to drop the delay: put the `sleep 60` *inside* the loop command itself, which runs fine in both foreground and background. Exhaustion does not just blind your own polling — workflows authenticating with the same PAT start failing server-side with misleading errors (see [§ GitHub API rate-limit exhaustion](#github-api-rate-limit-exhaustion)).
117
+ **Every wait between polls must be a `sleep`, never a busy-wait.** A poll loop with no delay (`until gh run view ...; do true; done`) fires thousands of requests per minute and exhausts the REST quota (5,000/hour) within minutes. The harness blocking a bare foreground `sleep` is not a reason to drop the delay: put the `sleep 60` *inside* the loop command itself, which runs fine in both foreground and background. Exhaustion does not just blind your own polling — workflows authenticating with the same PAT start failing server-side with misleading errors (see [§ GitHub API rate-limit exhaustion](references/failure-patterns.md#github-api-rate-limit-exhaustion)).
118
118
 
119
119
  4. **On any CI failure**, cancel the branch's remaining runs to free runners:
120
120
 
@@ -136,9 +136,9 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
136
136
 
137
137
  The first filter negates the unstable glyph rather than matching a `✅` prefix, mirroring `JobStatus.required`. `tests.yaml` runs four required jobs whose names carry no `✅` at all (`🧬 Project metadata`, `1️⃣ Run-once tests`, `📦 Package install`, `🖥️ Validate …`), and the release engine prefixes the workflow ahead of the glyph, so a prefix test silently drops a real failure from the batch.
138
138
 
139
- Fetch each failed job's log (`gh api repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs --allow-escape-sequences`) and fix them as one batch: different sources surface different issues, and logs survive cancellation. Batch only what has *already failed*, never what might still fail. Once every harvested failure is root-caused and fixed, push immediately rather than waiting for undrained cells to surface more: the fresh run supersedes the stale one, and serially waiting out each full matrix is the slow path. Analyze following the [error triage discipline](#error-triage-discipline): stable-job `FAILED`/`AssertionError` lines only.
139
+ Fetch each failed job's log (`gh api repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs --allow-escape-sequences`) and fix them as one batch: different sources surface different issues, and logs survive cancellation. Batch only what has *already failed*, never what might still fail. Once every harvested failure is root-caused and fixed, push immediately rather than waiting for undrained cells to surface more: the fresh run supersedes the stale one, and serially waiting out each full matrix is the slow path. Analyze following the [error triage discipline](#error-triage-discipline): stable-job `FAILED`/`AssertionError` lines only. Then match each failure against `references/failure-patterns.md` before fixing anything.
140
140
 
141
- `gh run view --log-failed` writes its log cache under `~/.cache/gh`, which the harness sandbox denies: the resulting `failed to get run log: creating cache entry ... operation not permitted` masquerades as a `gh` bug. Disable the sandbox for that read, exactly like the signing calls in step 7.
141
+ `gh run view --log-failed` writes its log cache under `~/.cache/gh`. A sandbox that denies that path answers `failed to get run log: creating cache entry ... operation not permitted`, which masquerades as a `gh` bug. Run the read in the sandbox first, and disable the sandbox for it only when that error appears.
142
142
 
143
143
  **A completed job's log is readable while the rest of the run drains, but only with `--allow-escape-sequences`.** The run-scoped reads *are* gated on the whole run going terminal (`gh run view --log-failed` answers `run <id> is still in progress; logs will be available when it is complete`), while the job-scoped `gh api repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs` answers a failed cell immediately, twenty minutes into its slowest sibling's build. What makes it look otherwise is a `gh` guard rather than the API: CI logs carry ANSI colour, so `gh` refuses to emit them and prints `the response contains terminal escape sequences; pass --allow-escape-sequences to output it anyway` — one line where a log was expected, indistinguishable from an empty body if the output went to a file. Pass the flag and strip the codes:
144
144
 
@@ -149,7 +149,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
149
149
 
150
150
  So the diagnosis is minutes away, not an hour: harvest every failed cell as it lands and keep the run alive for the cells still to report. Cancelling to read logs is never the reason — logs survive cancellation, but they never needed it. **Make the run terminal only when you have a fix**, per the batch-and-push rule above: the stale run has no verification value left once superseded.
151
151
 
152
- 5. **Fix the root cause** using the combined picture from CI logs and local results. Fix the codebase, not the tests, unless the tests are genuinely wrong. Address mypy and ruff failures together (see [§ mypy/ruff fix oscillation](#mypy-ruff-fix-oscillation)).
152
+ 5. **Fix the root cause** using the combined picture from CI logs and local results. Fix the codebase, not the tests, unless the tests are genuinely wrong. Address mypy and ruff failures together (see [§ mypy/ruff fix oscillation](references/failure-patterns.md#mypy-ruff-fix-oscillation)).
153
153
 
154
154
  If the root cause is in a third-party dependency, check whether a change *this cycle* exposed it before treating it as upstream: `git log <last-release-tag>..HEAD` for a runner/image swap, a dependency bump, or a config change that put the dependency in a context it cannot satisfy (a Rust-built package forced to compile from an sdist on an architecture with no published wheel, say). When a cycle change is the trigger, revert or adjust *that* change; only a failure independent of everything the cycle touched warrants `/file-bug-report` for an upstream report.
155
155
 
@@ -173,7 +173,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
173
173
  $ gh pr list --state=open --json number,title,headRefName,url
174
174
  ```
175
175
 
176
- If any open autofix PR already contains your fix — a `format-python` branch (ruff's own autofixes), a `sync-repomatic`/`sync-workflow-pins` branch (a bumped workflow pin, or a spliced-in `--exclude-newer-package` cooldown exemption carrying no version bump at all — that one is the whole fix when the `metadata` job cannot resolve its own pin), or another `sync-*`/`fix-*` branch — prefer merging it over authoring your own commit: GitHub signs the merge commit server-side, so this sidesteps a local hardware-key signing prompt entirely. If it resolves the failure, merge it (`gh pr merge <n> --squash --delete-branch`), pull, and rebase your fix before pushing — or skip your own commit if the merge is the whole fix. If `gh pr merge` is denied outright (a standing `permissions.deny` on the verb, not a retryable prompt), see [§ PR-merge permission wall](#pr-merge-permission-wall).
176
+ If any open autofix PR already contains your fix — a `format-python` branch (ruff's own autofixes), a `sync-repomatic`/`sync-workflow-pins` branch (a bumped workflow pin, or a spliced-in `--exclude-newer-package repomatic=P0D` cooldown exemption carrying no version bump at all — that one is the whole fix when the `metadata` job cannot resolve its own pin), or another `sync-*`/`fix-*` branch — prefer merging it over authoring your own commit: GitHub signs the merge commit server-side, so this sidesteps a local hardware-key signing prompt entirely. If it resolves the failure, merge it (`gh pr merge <n> --squash --delete-branch`), pull, and rebase your fix before pushing — or skip your own commit if the merge is the whole fix. If `gh pr merge` is denied outright (a standing `permissions.deny` on the verb, not a retryable prompt), see [§ PR-merge permission wall](references/failure-patterns.md#pr-merge-permission-wall).
177
177
 
178
178
  7. **Commit the fix** with a clear message describing what changed and why, then `git push`.
179
179
 
@@ -181,7 +181,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
181
181
 
182
182
  **Time each push by what its diff rebuilds.** A source-affecting fix (`repomatic/**`, `tests/**`, `pyproject.toml`, `uv.lock`: whatever the repo's test and binary `paths:` filters name) pushes the moment it clears step 5: the runs it supersedes were verifying an obsolete tree, and its own run rebuilds everything it cancels. A commit those filters skip (changelog-only, docs-only, cosmetic prose) is the opposite case on a binaries-enabled project: `release.yaml` runs on *every* push in a per-branch cancel-in-progress group, so pushed mid-drain such a commit cancels the in-flight binary matrix while its own run skips the rebuild (`Metadata.skip_binary_build`), and the lost verification costs a full re-dispatch. That cost scales with what is actually in flight: an ordinary push builds only the `[tool.repomatic] nuitka.dev-targets` canary subset, and no push cancels a full fleet at all, since release commits, `schedule` and `workflow_dispatch` runs each sit in their own concurrency group. Hold it until the heavy matrices on the current HEAD are terminal, or bundle it into the next source-affecting push; with binaries disabled, only a canary build in flight, or nothing heavy in flight, push freely.
183
183
 
184
- **If commit signing fails, do not loop on it.** The sandbox can block the SSH key or socket under `~/.ssh/*` (`Operation not permitted`): fix with `dangerouslyDisableSandbox: true` for the `git commit` and `git push` calls only. A hardware-backed key (Secretive, YubiKey, TPM) then prompts the maintainer per signature, and a refused or missed prompt surfaces as `agent refused operation?`, indistinguishable from a real failure. Retry once at most after disabling the sandbox; if it still refuses, hand off cleanly: stage the specific files you fixed (never `git add -A`), return the exact commit message and `git push` command verbatim, and exit the loop. The fix is done — only the signature is missing. If the block is instead a structural permission deny on `gh pr merge` (not a signing refusal), the escalation differs — a maintainer's in-chat approval cannot clear a deny rule: see [§ PR-merge permission wall](#pr-merge-permission-wall).
184
+ **If commit signing fails, do not loop on it.** The sandbox can block the SSH key or socket under `~/.ssh/*` (`Operation not permitted`): fix with `dangerouslyDisableSandbox: true` for the `git commit` and `git push` calls only. A hardware-backed key (Secretive, YubiKey, TPM) then prompts the maintainer per signature, and a refused or missed prompt surfaces as `agent refused operation?`, indistinguishable from a real failure. Retry once at most after disabling the sandbox; if it still refuses, hand off cleanly: stage the specific files you fixed (never `git add -A`), return the exact commit message and `git push` command verbatim, and exit the loop. The fix is done — only the signature is missing. If the block is instead a structural permission deny on `gh pr merge` (not a signing refusal), the escalation differs — a maintainer's in-chat approval cannot clear a deny rule: see [§ PR-merge permission wall](references/failure-patterns.md#pr-merge-permission-wall).
185
185
 
186
186
  8. **Repeat from step 2** until the monitored workflows are green: `tests.yaml` with all stable (✅) jobs passing, `lint.yaml` with no mypy failures (test and docs files included). **Stop after 5 iterations without progress** (the set of distinct failing stable jobs did not shrink): report what was fixed and what remains, and ask for guidance rather than churning. Productive iterations never trip the cap: a release paying down a long test-debt tail legitimately takes more than five pushes.
187
187
 
@@ -237,99 +237,19 @@ Read the exact error messages before forming a hypothesis. The most common diagn
237
237
  1. **Filter first.** Gating and loop cadence read stable (✅) jobs only: an unstable (⁉️) failure never blocks the loop, never sets its tempo, and never queue-jumps a stable red. When an orchestrator like `/repomatic-ship` spawned this loop for a release, ⁉️ reds are still work owed under its genuinely-green goal: once no stable red is outstanding, read their logs and fix what is repo-fixable (a crash converted to a clean availability-gated skip, a flaky live install folded into a tolerated-exit set), leaving only genuine dev-interpreter breakage unfixed and named in the final report. Human-invoked runs keep the strict filter: discard ⁉️ logs entirely unless asked.
238
238
  2. **Quote the error.** Before proposing a fix, quote the exact failing line(s) from the log. If you cannot quote a specific error, you have not diagnosed the problem.
239
239
  3. **One cause at a time.** Multiple failing jobs often share a root cause: identify the common thread before treating each job as independent.
240
- 4. **Distinguish test failures from lint failures.** A pytest `AssertionError` and a mypy `error:` have different fixes, but always analyze mypy and ruff failures together before fixing either (see [§ mypy/ruff fix oscillation](#mypy-ruff-fix-oscillation)).
240
+ 4. **Distinguish test failures from lint failures.** A pytest `AssertionError` and a mypy `error:` have different fixes, but always analyze mypy and ruff failures together before fixing either (see [§ mypy/ruff fix oscillation](references/failure-patterns.md#mypy-ruff-fix-oscillation)).
241
241
  5. **Do not fix warnings.** Deprecation and informational messages are not failures; ignore them unless they cause a stable job to fail.
242
242
 
243
243
  ## Common failure patterns
244
244
 
245
- <a id="mypy-ruff-fix-oscillation"></a>
245
+ When a job fails, read `references/failure-patterns.md` before fixing anything. It names the failures that are not code bugs, and what each one needs:
246
246
 
247
- ### mypy/ruff fix oscillation
247
+ - mypy/ruff fix oscillation, and the mypy scope mismatch between a local run and CI.
248
+ - Platform-specific test skips, and cross-platform divergence.
249
+ - Workflow and infrastructure failures, and GitHub API rate-limit exhaustion.
250
+ - The PR-merge permission wall.
251
+ - Nuitka binary build failures, and autofix job failures.
248
252
 
249
- mypy and ruff can enter a fix loop where each tool's fix breaks the other. Common triggers:
253
+ ## End-of-loop retrospective
250
254
 
251
- - **Unused import**: ruff removes an import (`F401`), mypy then complains about a missing name; re-adding triggers ruff again.
252
- - **Type annotation style**: mypy requires an explicit annotation, ruff considers it redundant or wants a different form.
253
- - **`noqa` vs `type: ignore`**: `# noqa` silences ruff but not mypy; `# type: ignore` silences mypy but ruff flags the unused directive.
254
-
255
- When the same lines toggle between fixes across iterations, stop and apply a combined resolution: a `# type: ignore[code]` with a matching `# noqa: XXXX` on the same line, or a restructuring that satisfies both at once.
256
-
257
- ### mypy scope mismatch (local vs CI)
258
-
259
- The classic false green: mypy passes locally over a subset of directories while CI checks **every tracked Python file** (`tests/` and `docs/` included). Run it as a bare `repomatic run mypy` and the runner resolves that same list, so an error in a test or docs file surfaces before the push rather than after it. A directory list is what reintroduces the gap.
260
-
261
- ### Platform-specific test skips
262
-
263
- Some tests are skipped on certain platforms (`windows-11-arm` has no Python 3.10 ARM64 build). Before investigating missing results, check the matrix `exclude` section in `tests.yaml` and the `skip_platforms` entries in the binary self-test plan (`tests/cli-test-suite.toml`): individual cases can opt out of platforms without affecting the CI matrix.
264
-
265
- ### Cross-platform divergence
266
-
267
- When a test passes locally but fails in CI, check platform differences before changing logic:
268
-
269
- - **Path lengths**: `~/.config/...` is shorter on Linux than macOS/Windows equivalents, affecting text-wrapping assertions.
270
- - **Terminal width**: CI runners may default differently than local dev machines.
271
- - **Encoding**: Windows defaults to `cp1252`, not `utf-8`.
272
- - **Line endings**: `\r\n` vs `\n` breaks exact-match assertions.
273
- - **Untracked files**: tests that enumerate files (`python_files`, `doc_files` metadata) see untracked local files that CI's clean checkout lacks. When updating expected file lists, include only tracked files; run `git status` to spot the divergence.
274
-
275
- ### Workflow and infrastructure failures
276
-
277
- Not all CI failures are code bugs:
278
-
279
- - **Runner timeouts or OOM kills**: the log ends abruptly or shows `The runner has received a shutdown signal`. Re-run; do not change code.
280
- - **A runner that died mid-step**: the step runs far past its baseline, and a cancel does not stop it. A live runner kills a cancelled step within ten seconds and keeps its partial log. A cancel does not apply to a job whose `if:` holds `always()`, so read that condition first. Any other job still `in_progress` a minute after the cancel has lost its runner: the server closes it at the five-minute [cancellation timeout](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-cancellation), and no log survives, neither at the job's log endpoint (`BlobNotFound`) nor in the run's log archive. A 404 from a job that is still running proves nothing, since every running job returns one. Re-run with `--failed`: there is nothing to diagnose.
281
- - **Action version mismatches**: `Unable to resolve action`, deprecated-runtime errors. Fix the workflow YAML, not the Python.
282
- - **Network/registry flakiness**: `uv`/`pip` timeouts, PyPI 503s, `ConnectionResetError`. Re-run.
283
- - **A wall-clock budget assertion** (`assert elapsed_ms < N`) failing on a shared runner: infrastructure is the *trigger*, but the defect is the test, which took one sample and so measured that runner's worst moment rather than the code. A re-run only re-rolls the dice, and the tell that it has been re-rolled before is a budget already ratcheted upward in an earlier cycle for the same runner class. Assert on the fastest of several samples instead: a real regression slows every sample, a scheduling stall slows one. Raising the budget again is the fix that stops working.
284
- - **Permission errors**: `Resource not accessible by integration`, 403s. Check `gh api rate_limit` first ([§ GitHub API rate-limit exhaustion](#github-api-rate-limit-exhaustion)), then token permissions; never code.
285
- - **A whole workflow red with nothing executed**, every job reporting failure and the `metadata` job unable to resolve its own toolkit pin: the inline `uvx 'repomatic==X.Y.Z'` command is missing `--exclude-newer-package repomatic=P0D`, so the workflow-wide `UV_EXCLUDE_NEWER` refuses a pin naming a release younger than the window, and each `needs: metadata` job dies with it. Splice the flag onto that command line — `uvx` reads no project configuration, so there is nowhere else the bypass can live — or merge the `sync-workflow-pins` PR that backfills it. `lint-repo`'s fatal `self-pin-cooldown-exemption` check names the offending files. Re-running changes nothing.
286
-
287
- For infrastructure, re-run the failed jobs (`gh run rerun <RUN_ID> --failed`) and continue polling; never modify code to work around transient infra. **A release run is the exception**: when an orchestrator like `/repomatic-ship` spawned this loop, a flake surfaced here is debt owed under that skill's genuinely-green goal, so a red whose defect lives in the repository (the wall-clock budget above, a tolerated-exit set that needs widening) gets fixed at the source instead. "Transient infra" then names the trigger, not the remedy. A red with no repo-side defect at all, like a runner OOM or a PyPI 503, is still a re-run.
288
-
289
- **`--failed` also re-runs the jobs skipped behind a failure.** Each failed or cancelled job re-runs with every job that `needs:` it, skipped ones included. So one rerun restores the whole chain: never re-run the whole workflow to reach a skipped dependent.
290
-
291
- <a id="github-api-rate-limit-exhaustion"></a>
292
-
293
- ### GitHub API rate-limit exhaustion
294
-
295
- Heavy polling from this loop spends the same REST quota (5,000 requests/hour) as every workflow authenticating as the same user (`REPOMATIC_PAT`). Exhaustion produces two failure shapes that look unrelated to quotas:
296
-
297
- - Local `gh` calls fail with `HTTP 403: API rate limit exceeded`.
298
- - Workflows fail with *permission-shaped* errors: `lint-repo` reports the PAT lacks `Contents`/`Dependabot`/`Workflows` scopes, or a `Sync pull request` step (`repomatic pr-sync`) stalls on the GitHub API until its `timeout-minutes` or the concurrency group kills the run.
299
-
300
- Diagnose with `gh api rate_limit` **before** touching token settings: `remaining: 0` on the `core` bucket confirms it. Recovery: wait for the printed `reset` epoch, then re-run the failed workflows unchanged (`gh run rerun <RUN_ID> --failed`); they go green with no commit. While waiting, degrade to the channels that stay live: the GraphQL bucket is metered separately (`gh api graphql` for a commit's check suites, refs, and releases; `gh pr list` / `gh pr view`), and `git fetch` over SSH covers branch and commit verification.
301
-
302
- <a id="pr-merge-permission-wall"></a>
303
-
304
- ### PR-merge permission wall
305
-
306
- `gh pr merge` — and other write-heavy verbs (force-push, `reset --hard`, repo or release delete) — is commonly hard-denied in the operator's own Claude Code `settings.json` as a standing guard against irreversible actions, independent of any conversation. This deny is structural, not a per-call prompt: it fires identically whether or not a maintainer just authorized the exact command in chat, because it blocks the tool call itself rather than asking. Signs you have hit it, not a normal prompt: the denial is immediate with nothing to answer, and it recurs identically after a fresh, explicit, real-time go-ahead. Do not retry it, and do not read a maintainer's chat-level "yes, merge it" as actionable — a deny rule cannot be cleared from inside the session. Report the wall once and ask the maintainer to run the merge themselves, fully outside this session (their terminal, or the GitHub web UI): that is the only path this deny shape leaves open. The same holds when a hardware-key signing refusal blocks a direct commit (step 7): with both remedies walled, the release advances only by a human acting outside the tool.
307
-
308
- ### Nuitka binary build failures (release.yaml)
309
-
310
- This section only applies to projects that build binaries (`[tool.repomatic] nuitka.enabled` with a CLI entry point); on a Nuitka-disabled project the per-platform jobs skip on every push and there is no matrix to fail. When enabled, the engine runs Nuitka across a 6-way OS/arch matrix on release commits, on the weekly `schedule` and on `workflow_dispatch`, narrowing an ordinary push to the `[tool.repomatic] nuitka.dev-targets` canary subset (job names are templated per platform, like `✅ {os}, {sha} build`); catching a break while the version is still `.dev0` avoids shipping a release with missing or broken binaries, which the immutable-release wall makes unrecoverable. Triage by category:
311
-
312
- - **Infrastructure** (runner OOM, shutdown signal, macOS runner crash, registry timeout): re-run the failed job (`gh run rerun <RELEASE_RUN_ID> --failed`); binary builds are resource-heavy and macOS runners crash more than most.
313
- - **Nuitka configuration** (`Error, unsupported ...`, an unknown `--flag`, a missing data file): fix `[tool.nuitka]` in `pyproject.toml`, not the Python source; verify each key maps to a current Nuitka option.
314
- - **Real compile or runtime errors** (the binary builds but its smoke test fails, a `ModuleNotFoundError` at runtime): fix the code or the `include-package`/`include-data-files` configuration, then push and re-monitor.
315
-
316
- The matrix is slow: let `tests.yaml` and `lint.yaml` set the loop cadence, but act on a red build cell the moment it lands, like any stable failure (every faster channel has already reported by then): fix, push, supersede. Never idle out the rest of a matrix you already know is doomed.
317
-
318
- **A *cancelled* canary cell is a coverage gap, not a failure, and `--failed` closes it cheaply.** Supersession routinely kills the canary mid-build (an automation PR merges, the concurrency group cancels it), and the pushes behind it often skip the matrix outright, so the binary signal for the last code-affecting tree is simply missing with nothing in flight to supply it. Reach for `gh run rerun <cancelled-run-id> --failed` rather than `gh workflow run release.yaml`: the rerun rebuilds only the cancelled cell and its dependents, leaving every skipped job skipped, where a dispatch compiles the whole platform fleet. The precondition is that the cancelled run's binary-affecting tree still matches `HEAD`, since the rerun rebuilds that run's commit and not the current one: check with `git diff --name-only <that run's headSha>..HEAD` and confirm nothing in it touches `Metadata.binary_affecting_paths`.
319
-
320
- **On a release run, a red build cell means that version ships short, permanently.** When the run's head commit is a `[changelog] Release vX.Y.Z` push, `publish-release` sits at the end of that same run and flips the draft to published once the asset jobs settle, locking the asset list. Whatever the matrix failed to produce by then is missing from that version forever: no re-run, no later upload.
321
-
322
- **This is by design, so do not try to stop it.** Publishing a release short beats holding it, and the recovery is the next version, not a draft the maintainer has to babysit. Keep doing exactly what you do for any stable red: fix the cause, push, and let the fix ride the next release. The one addition is reporting: name the platforms that version lost, so the maintainer knows the gap exists and can note it in the release. A short ship also leaves the changelog section, the release body and `docs/install.md` still advertising binaries that are not there (the `repomatic-ship` skill's § Repairing a short ship covers the cleanup); flag it rather than fixing it silently mid-loop.
323
-
324
- ### Autofix job failures (autofix.yaml)
325
-
326
- `autofix.yaml`'s jobs normally commit their fixes; a job that *crashes* turns the workflow red without producing one. Fetch the failed log (`gh run view <AUTOFIX_RUN_ID> --log-failed`) and triage:
327
-
328
- - **Tool-runner checksum mismatch** (`ValueError: SHA-256 mismatch for https://...`): the pinned binary's hash no longer matches the published artifact, usually an upstream re-publish. Regenerate with `repomatic update-checksums`, then confirm with `repomatic run <tool>`.
329
- - **External-tool output parse error** (a `RuntimeError`/`KeyError` in a parser, like `fix-vulnerable-deps` reading `uv audit` JSON): the tool's output schema drifted. Fix the parser and update the test fixture encoding the old shape.
330
- - **Dependency fails to build on the runner** (`Failed to build <pkg>`, a `maturin`/`cargo`/native-compiler error during install): usually self-inflicted, not upstream: a `runs-on` change *this cycle* moved the job to an architecture with no published wheel, forcing a doomed source build. Check `git log <last-tag>..HEAD` for the runner swap and revert it; a genuinely broken upstream artifact (failing on *every* platform) is the rarer case.
331
- - **Genuine content the job fixes** (real typos, an actual vulnerability): the job commits the fix and goes green on its own; nothing to do.
332
-
333
- ### End-of-loop retrospective
334
-
335
- After the loop converges (or hits the iteration cap), review whether any finding is worth feeding back: a failure pattern that recurred across iterations, or a diagnosis needing non-obvious knowledge, belongs in [§ Common failure patterns](#common-failure-patterns). Propose the addition; do not push it unreviewed.
255
+ After the loop converges (or hits the iteration cap), review whether any finding is worth feeding back: a failure pattern that recurred across iterations, or a diagnosis needing non-obvious knowledge, belongs in [`references/failure-patterns.md`](references/failure-patterns.md). Propose the addition; do not push it unreviewed.
@@ -0,0 +1,92 @@
1
+ # Common failure patterns
2
+
3
+ Failure shapes the `babysit-ci` loop meets, and what each one needs. `SKILL.md` holds the loop itself.
4
+
5
+ <a id="mypy-ruff-fix-oscillation"></a>
6
+
7
+ ## mypy/ruff fix oscillation
8
+
9
+ mypy and ruff can enter a fix loop where each tool's fix breaks the other. Common triggers:
10
+
11
+ - **Unused import**: ruff removes an import (`F401`), mypy then complains about a missing name; re-adding triggers ruff again.
12
+ - **Type annotation style**: mypy requires an explicit annotation, ruff considers it redundant or wants a different form.
13
+ - **`noqa` vs `type: ignore`**: `# noqa` silences ruff but not mypy; `# type: ignore` silences mypy but ruff flags the unused directive.
14
+
15
+ When the same lines toggle between fixes across iterations, stop and apply a combined resolution: a `# type: ignore[code]` with a matching `# noqa: XXXX` on the same line, or a restructuring that satisfies both at once.
16
+
17
+ ## mypy scope mismatch (local vs CI)
18
+
19
+ The classic false green: mypy passes locally over a subset of directories while CI checks **every tracked Python file** (`tests/` and `docs/` included). Run it as a bare `repomatic run mypy` and the runner resolves that same list, so an error in a test or docs file surfaces before the push rather than after it. A directory list is what reintroduces the gap.
20
+
21
+ ## Platform-specific test skips
22
+
23
+ Some tests are skipped on certain platforms (`windows-11-arm` has no Python 3.10 ARM64 build). Before investigating missing results, check the matrix `exclude` section in `tests.yaml` and the `skip_platforms` entries in the binary self-test plan (`tests/cli-test-suite.toml`): individual cases can opt out of platforms without affecting the CI matrix.
24
+
25
+ ## Cross-platform divergence
26
+
27
+ When a test passes locally but fails in CI, check platform differences before changing logic:
28
+
29
+ - **Path lengths**: `~/.config/...` is shorter on Linux than macOS/Windows equivalents, affecting text-wrapping assertions.
30
+ - **Terminal width**: CI runners may default differently than local dev machines.
31
+ - **Encoding**: Windows defaults to `cp1252`, not `utf-8`.
32
+ - **Line endings**: `\r\n` vs `\n` breaks exact-match assertions.
33
+ - **Untracked files**: tests that enumerate files (`python_files`, `doc_files` metadata) see untracked local files that CI's clean checkout lacks. When updating expected file lists, include only tracked files; run `git status` to spot the divergence.
34
+
35
+ ## Workflow and infrastructure failures
36
+
37
+ Not all CI failures are code bugs:
38
+
39
+ - **Runner timeouts or OOM kills**: the log ends abruptly or shows `The runner has received a shutdown signal`. Re-run; do not change code.
40
+ - **A runner that died mid-step**: the step runs far past its baseline, and a cancel does not stop it. A live runner kills a cancelled step within ten seconds and keeps its partial log. A cancel does not apply to a job whose `if:` holds `always()`, so read that condition first. Any other job still `in_progress` a minute after the cancel has lost its runner: the server closes it at the five-minute [cancellation timeout](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-cancellation), and no log survives, neither at the job's log endpoint (`BlobNotFound`) nor in the run's log archive. A 404 from a job that is still running proves nothing, since every running job returns one. Re-run with `--failed`: there is nothing to diagnose.
41
+ - **Action version mismatches**: `Unable to resolve action`, deprecated-runtime errors. Fix the workflow YAML, not the Python.
42
+ - **Network/registry flakiness**: `uv`/`pip` timeouts, PyPI 503s, `ConnectionResetError`. Re-run.
43
+ - **A wall-clock budget assertion** (`assert elapsed_ms < N`) failing on a shared runner: infrastructure is the *trigger*, but the defect is the test, which took one sample and so measured that runner's worst moment rather than the code. A re-run only re-rolls the dice, and the tell that it has been re-rolled before is a budget already ratcheted upward in an earlier cycle for the same runner class. Assert on the fastest of several samples instead: a real regression slows every sample, a scheduling stall slows one. Raising the budget again is the fix that stops working.
44
+ - **Permission errors**: `Resource not accessible by integration`, 403s. Check `gh api rate_limit` first ([§ GitHub API rate-limit exhaustion](#github-api-rate-limit-exhaustion)), then token permissions; never code.
45
+ - **A whole workflow red with nothing executed**, every job reporting failure and the `metadata` job unable to resolve its own toolkit pin: the inline `uvx 'repomatic==X.Y.Z'` command is missing `--exclude-newer-package repomatic=P0D`, so the workflow-wide `UV_EXCLUDE_NEWER` refuses a pin naming a release younger than the window, and each `needs: metadata` job dies with it. Splice the flag onto that command line — `uvx` reads no project configuration, so there is nowhere else the bypass can live — or merge the `sync-workflow-pins` PR that backfills it. `lint-repo`'s fatal `self-pin-cooldown-exemption` check names the offending files. Re-running changes nothing.
46
+ - **A Cloudflare deploy that ends red after publishing**: the `docs.yaml` workflow's `deploy-docs-cloudflare` job dropped a file over 25 MiB, so the live site links to a file it does not have. The offload step's error annotation names each file and the reason. Re-run only when the reason is a failed upload. Any other reason, like an undeclared R2 bucket or missing R2 secrets, needs a repository change or maintainer setup: report it instead.
47
+
48
+ For infrastructure, re-run the failed jobs (`gh run rerun <RUN_ID> --failed`) and continue polling; never modify code to work around transient infra. **A release run is the exception**: when an orchestrator like `/repomatic-ship` spawned this loop, a flake surfaced here is debt owed under that skill's genuinely-green goal, so a red whose defect lives in the repository (the wall-clock budget above, a tolerated-exit set that needs widening) gets fixed at the source instead. "Transient infra" then names the trigger, not the remedy. A red with no repo-side defect at all, like a runner OOM or a PyPI 503, is still a re-run.
49
+
50
+ **`--failed` also re-runs the jobs skipped behind a failure.** Each failed or cancelled job re-runs with every job that `needs:` it, skipped ones included. So one rerun restores the whole chain: never re-run the whole workflow to reach a skipped dependent.
51
+
52
+ <a id="github-api-rate-limit-exhaustion"></a>
53
+
54
+ ## GitHub API rate-limit exhaustion
55
+
56
+ Heavy polling from this loop spends the same REST quota (5,000 requests/hour) as every workflow authenticating as the same user (`REPOMATIC_PAT`). Exhaustion produces two failure shapes that look unrelated to quotas:
57
+
58
+ - Local `gh` calls fail with `HTTP 403: API rate limit exceeded`.
59
+ - Workflows fail with *permission-shaped* errors: `lint-repo` reports the PAT lacks `Contents`/`Dependabot`/`Workflows` scopes, or a `Sync pull request` step (`repomatic pr-sync`) stalls on the GitHub API until its `timeout-minutes` or the concurrency group kills the run.
60
+
61
+ Diagnose with `gh api rate_limit` **before** touching token settings: `remaining: 0` on the `core` bucket confirms it. Recovery: wait for the printed `reset` epoch, then re-run the failed workflows unchanged (`gh run rerun <RUN_ID> --failed`); they go green with no commit. While waiting, degrade to the channels that stay live: the GraphQL bucket is metered separately (`gh api graphql` for a commit's check suites, refs, and releases; `gh pr list` / `gh pr view`), and `git fetch` over SSH covers branch and commit verification.
62
+
63
+ <a id="pr-merge-permission-wall"></a>
64
+
65
+ ## PR-merge permission wall
66
+
67
+ `gh pr merge` — and other write-heavy verbs (force-push, `reset --hard`, repo or release delete) — is commonly hard-denied in the operator's own Claude Code `settings.json` as a standing guard against irreversible actions, independent of any conversation. This deny is structural, not a per-call prompt: it fires identically whether or not a maintainer just authorized the exact command in chat, because it blocks the tool call itself rather than asking. Signs you have hit it, not a normal prompt: the denial is immediate with nothing to answer, and it recurs identically after a fresh, explicit, real-time go-ahead. Do not retry it, and do not read a maintainer's chat-level "yes, merge it" as actionable — a deny rule cannot be cleared from inside the session. Report the wall once and ask the maintainer to run the merge themselves, fully outside this session (their terminal, or the GitHub web UI): that is the only path this deny shape leaves open. The same holds when a hardware-key signing refusal blocks a direct commit (step 7 of `SKILL.md`): with both remedies walled, the release advances only by a human acting outside the tool.
68
+
69
+ ## Nuitka binary build failures (release.yaml)
70
+
71
+ This section only applies to projects that build binaries (`[tool.repomatic] nuitka.enabled` with a CLI entry point); on a Nuitka-disabled project the per-platform jobs skip on every push and there is no matrix to fail. When enabled, the engine runs Nuitka across a 6-way OS/arch matrix on release commits, on the weekly `schedule` and on `workflow_dispatch`, narrowing an ordinary push to the `[tool.repomatic] nuitka.dev-targets` canary subset (job names are templated per platform, like `✅ {os}, {sha} build`); catching a break while the version is still `.dev0` avoids shipping a release with missing or broken binaries, which the immutable-release wall makes unrecoverable. Triage by category:
72
+
73
+ - **Infrastructure** (runner OOM, shutdown signal, macOS runner crash, registry timeout): re-run the failed job (`gh run rerun <RELEASE_RUN_ID> --failed`); binary builds are resource-heavy and macOS runners crash more than most.
74
+ - **Nuitka configuration** (`Error, unsupported ...`, an unknown `--flag`, a missing data file): fix `[tool.nuitka]` in `pyproject.toml`, not the Python source; verify each key maps to a current Nuitka option.
75
+ - **Real compile or runtime errors** (the binary builds but its smoke test fails, a `ModuleNotFoundError` at runtime): fix the code or the `include-package`/`include-data-files` configuration, then push and re-monitor.
76
+
77
+ The matrix is slow: let `tests.yaml` and `lint.yaml` set the loop cadence, but act on a red build cell the moment it lands, like any stable failure (every faster channel has already reported by then): fix, push, supersede. Never idle out the rest of a matrix you already know is doomed.
78
+
79
+ **A *cancelled* canary cell is a coverage gap, not a failure, and `--failed` closes it cheaply.** Supersession routinely kills the canary mid-build (an automation PR merges, the concurrency group cancels it), and the pushes behind it often skip the matrix outright, so the binary signal for the last code-affecting tree is simply missing with nothing in flight to supply it. Reach for `gh run rerun <cancelled-run-id> --failed` rather than `gh workflow run release.yaml`: the rerun rebuilds only the cancelled cell and its dependents, leaving every skipped job skipped, where a dispatch compiles the whole platform fleet. The precondition is that the cancelled run's binary-affecting tree still matches `HEAD`, since the rerun rebuilds that run's commit and not the current one: check with `git diff --name-only <that run's headSha>..HEAD` and confirm nothing in it touches `Metadata.binary_affecting_paths`.
80
+
81
+ **On a release run, a red build cell means that version ships short, permanently.** When the run's head commit is a `[changelog] Release vX.Y.Z` push, `publish-release` sits at the end of that same run and flips the draft to published once the asset jobs settle, locking the asset list. Whatever the matrix failed to produce by then is missing from that version forever: no re-run, no later upload.
82
+
83
+ **This is by design, so do not try to stop it.** Publishing a release short beats holding it, and the recovery is the next version, not a draft the maintainer has to babysit. Keep doing exactly what you do for any stable red: fix the cause, push, and let the fix ride the next release. The one addition is reporting: name the platforms that version lost, so the maintainer knows the gap exists and can note it in the release. A short ship also leaves the changelog section, the release body and `docs/install.md` still advertising binaries that are not there (the `repomatic-ship` skill's § Repairing a short ship covers the cleanup); flag it rather than fixing it silently mid-loop.
84
+
85
+ ## Autofix job failures (autofix.yaml)
86
+
87
+ `autofix.yaml`'s jobs normally commit their fixes; a job that *crashes* turns the workflow red without producing one. Fetch the failed log (`gh run view <AUTOFIX_RUN_ID> --log-failed`) and triage:
88
+
89
+ - **Tool-runner checksum mismatch** (`ValueError: SHA-256 mismatch for https://...`): the pinned binary's hash no longer matches the published artifact, usually an upstream re-publish. Regenerate with `repomatic update-checksums`, then confirm with `repomatic run <tool>`.
90
+ - **External-tool output parse error** (a `RuntimeError`/`KeyError` in a parser, like `fix-vulnerable-deps` reading `uv audit` JSON): the tool's output schema drifted. Fix the parser and update the test fixture encoding the old shape.
91
+ - **Dependency fails to build on the runner** (`Failed to build <pkg>`, a `maturin`/`cargo`/native-compiler error during install): usually self-inflicted, not upstream: a `runs-on` change *this cycle* moved the job to an architecture with no published wheel, forcing a doomed source build. Check `git log <last-tag>..HEAD` for the runner swap and revert it; a genuinely broken upstream artifact (failing on *every* platform) is the rarer case.
92
+ - **Genuine content the job fixes** (real typos, an actual vulnerability): the job commits the fix and goes green on its own; nothing to do.
@@ -83,7 +83,7 @@ Hybrid pipeline, cheapest signal first:
83
83
 
84
84
  1. **Already labeled** items need nothing: record them as settled.
85
85
  2. **Keyword heuristics** derived from each label's own description. Score title hits heavily (a title match with no rival label is high confidence) and cap body-match contributions so long bodies cannot fake a signal. This confidently resolves roughly half of a typical backlog for free.
86
- 3. **Agent batches** for the residual: parallel subagents, ~70 items each, given the taxonomy with calibration examples, item titles plus bodies truncated to ~500 chars, and the heuristic's best guess as a hint. Demand strict machine-parseable output (`number|label|confidence|rationale`, one line per item, every item exactly once) and validate on merge: unknown labels, missing items, and unparseable lines get retried or fall through.
86
+ 3. **Agent batches** for the residual: parallel subagents, ~70 items each, given the taxonomy with calibration examples, item titles plus bodies truncated to ~500 chars, and the heuristic's best guess as a hint. Demand strict machine-parseable output (`number|label|confidence|rationale`, one line per item, every item exactly once) and validate on merge: unknown labels, missing items, and unparsable lines get retried or fall through.
87
87
  4. **Fallback**: anything dropped by an agent gets classified by hand so coverage stays total.
88
88
 
89
89
  Review gates before applying: all low-confidence calls, plus every proposed `🪫 AI slop`/`🚫 wont do/fix`, go in a "needs review first" section of the plan, open items sorted first. Offer to open candidate batches in the browser (`xargs open < urls.txt`) so the maintainer can eyeball them quickly.
@@ -130,7 +130,7 @@ Read the full `pyproject.toml`. `lint-deps` already reports the specifier style,
130
130
  Comments and changelogs can lie; the codebase is the source of truth. For each dependency with a weak or suspicious comment, verify the floor against actual usage:
131
131
 
132
132
  1. **Grep for imports.** Search the source tree for all imports from the package. List the specific APIs used (functions, classes, constants).
133
- 2. **Determine the oldest version providing those APIs.** Check when the API was introduced — changelogs, release notes, or `pip index versions <pkg>` to see what exists on PyPI.
133
+ 2. **Determine the oldest version providing those APIs.** Check when the API was introduced — changelogs, release notes, or `pip index versions <pkg>` to see what exists on PyPI. A floor that rests on a behavior (comments kept, output formatting) needs a bisect instead, since a changelog can credit it to a later release than the one that shipped it. Run one probe per release with `uv run --no-project --exclude-newer '1 week' --with '<pkg>==<version>' python probe.py`, and compare each output byte for byte with the locked release.
134
134
  3. **Lower the floor** when it exceeds the oldest compatible version. Prefer conservative minimums (the major version that introduced the API) over aggressive ones. Update both the version specifier and the comment.
135
135
  4. **Run `uv lock`** after any floor change to verify the lock still resolves.
136
136
 
@@ -289,7 +289,7 @@ Common false-positive patterns to reject early:
289
289
 
290
290
  - A new helper that replaces hand-rolled logic.
291
291
  - A bug fix that lets us delete a workaround — search comments for the package name, `work around`, `TODO`, and version-guarded branches.
292
- - A deprecation we still call, which must move to the replacement before the dependency removes it.
292
+ - A deprecation we still call, which must move to the replacement before the dependency removes it. The test suite's warnings summary names each deprecated call the tests reach, with its file and line.
293
293
 
294
294
  4. **Apply one dependency at a time.** Make the edits for a single package, keeping each behavior-preserving. If adopting an API needs a higher floor, raise it and rewrite the comment per [Floor bumps to adopt new APIs](#floor-bumps-to-adopt-new-apis), then run `uv lock`.
295
295