repomatic 7.17.0__tar.gz → 7.18.0__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 (588) hide show
  1. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/.claude-plugin/plugin.json +1 -1
  2. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/agents/grunt-qa.md +3 -3
  3. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/agents/sphinx-docs.md +11 -9
  4. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/babysit-ci/SKILL.md +10 -8
  5. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/babysit-ci/references/failure-patterns.md +2 -1
  6. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/benchmark-update/SKILL.md +4 -0
  7. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/file-bug-report/SKILL.md +13 -1
  8. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/github-housekeeping/SKILL.md +1 -1
  9. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/repomatic-audit/SKILL.md +18 -2
  10. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/repomatic-deps/SKILL.md +38 -17
  11. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/repomatic-init/SKILL.md +0 -1
  12. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/repomatic-ship/SKILL.md +18 -9
  13. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/repomatic-test-matrix/SKILL.md +24 -4
  14. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/repomatic-upgrade/SKILL.md +3 -2
  15. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.claude}/skills/upstream-audit/SKILL.md +23 -12
  16. {repomatic-7.17.0 → repomatic-7.18.0}/.claude-plugin/marketplace.json +2 -2
  17. {repomatic-7.17.0 → repomatic-7.18.0}/.github/ISSUE_TEMPLATE/bug-report.yml +3 -5
  18. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/_release-build.yaml +4 -4
  19. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/_release-engine.yaml +64 -99
  20. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/autofix.yaml +86 -52
  21. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/autolock.yaml +1 -1
  22. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/cancel-runs.yaml +1 -1
  23. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/changelog.yaml +14 -14
  24. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/debug.yaml +2 -2
  25. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/docs.yaml +13 -21
  26. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/labels.yaml +4 -4
  27. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/lint.yaml +9 -9
  28. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/metrics.yaml +2 -2
  29. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/release.yaml +2 -2
  30. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/self-maintenance.yaml +2 -2
  31. {repomatic-7.17.0 → repomatic-7.18.0}/.github/workflows/tests.yaml +27 -9
  32. {repomatic-7.17.0/repomatic/data → repomatic-7.18.0/.github/workflows}/unsubscribe.yaml +1 -1
  33. {repomatic-7.17.0 → repomatic-7.18.0}/PKG-INFO +10 -10
  34. {repomatic-7.17.0 → repomatic-7.18.0}/changelog.md +90 -1
  35. {repomatic-7.17.0 → repomatic-7.18.0}/claude.md +2 -1
  36. {repomatic-7.17.0 → repomatic-7.18.0}/docs/agent-skills.md +1 -1
  37. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/binaries.csv +12 -0
  38. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/config-snippet-screen.svg +2 -2
  39. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/dependencies.mmd +7 -7
  40. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/help-dark-screen.svg +7 -7
  41. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/help-light-screen.svg +7 -7
  42. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/matrix-grid-screen.svg +3 -3
  43. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/metrics.csv +848 -831
  44. repomatic-7.18.0/docs/assets/star-history-compared.svg +102 -0
  45. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/star-history.svg +11 -11
  46. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/virustotal-scans.csv +12 -0
  47. {repomatic-7.17.0 → repomatic-7.18.0}/docs/benchmark.md +2 -2
  48. {repomatic-7.17.0 → repomatic-7.18.0}/docs/binaries.md +1 -1
  49. {repomatic-7.17.0 → repomatic-7.18.0}/docs/claude-code-plugin.md +2 -2
  50. {repomatic-7.17.0 → repomatic-7.18.0}/docs/cloudflare.md +11 -7
  51. repomatic-7.18.0/docs/code-of-conduct.md +5 -0
  52. {repomatic-7.17.0 → repomatic-7.18.0}/docs/commit-messages.md +1 -1
  53. {repomatic-7.17.0 → repomatic-7.18.0}/docs/conf.py +95 -15
  54. {repomatic-7.17.0 → repomatic-7.18.0}/docs/configuration.md +16 -1
  55. {repomatic-7.17.0 → repomatic-7.18.0}/docs/dependencies.md +53 -25
  56. {repomatic-7.17.0 → repomatic-7.18.0}/docs/index.md +1 -0
  57. {repomatic-7.17.0 → repomatic-7.18.0}/docs/install.md +6 -6
  58. repomatic-7.18.0/docs/nuitka.md +138 -0
  59. {repomatic-7.17.0 → repomatic-7.18.0}/docs/operation-contracts.md +1 -1
  60. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.md +0 -1
  61. {repomatic-7.17.0 → repomatic-7.18.0}/docs/security.md +2 -2
  62. {repomatic-7.17.0 → repomatic-7.18.0}/docs/test-matrix.md +33 -7
  63. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.md +0 -1
  64. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tool-runner.md +19 -7
  65. {repomatic-7.17.0 → repomatic-7.18.0}/docs/upstream-development.md +7 -7
  66. repomatic-7.18.0/docs/upstream.md +297 -0
  67. {repomatic-7.17.0 → repomatic-7.18.0}/docs/workflows.md +45 -55
  68. {repomatic-7.17.0 → repomatic-7.18.0}/pyproject.toml +29 -12
  69. {repomatic-7.17.0 → repomatic-7.18.0}/pyproject.toml.orig +73 -53
  70. {repomatic-7.17.0 → repomatic-7.18.0}/readme.md +3 -3
  71. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/__init__.py +2 -2
  72. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/__main__.py +3 -3
  73. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cache.py +1 -1
  74. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/changelog.py +8 -8
  75. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/github.py +25 -0
  76. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/lint.py +7 -107
  77. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/main.py +5 -0
  78. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/release.py +1 -1
  79. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/setup.py +5 -1
  80. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/sync.py +4 -3
  81. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cloudflare.py +1 -1
  82. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cloudflare_r2.py +23 -10
  83. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/config.py +80 -4
  84. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/_release-engine.yaml +64 -99
  85. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/agent-grunt-qa.md +3 -3
  86. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/agent-sphinx-docs.md +11 -9
  87. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/autofix.yaml +86 -52
  88. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/autolock.yaml +1 -1
  89. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/contributing.md +5 -3
  90. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/contributing.zh.md +3 -1
  91. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/cancel-runs.yaml +1 -1
  92. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/changelog.yaml +14 -14
  93. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/debug.yaml +2 -2
  94. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/docs.yaml +13 -21
  95. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/labels.yaml +4 -4
  96. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/lint.yaml +9 -9
  97. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/lychee.toml +3 -0
  98. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/metrics.yaml +2 -2
  99. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/mypy.toml +9 -0
  100. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/release.yaml +2 -2
  101. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/babysit-ci/SKILL.md +10 -8
  102. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/babysit-ci/references/failure-patterns.md +2 -1
  103. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/benchmark-update/SKILL.md +4 -0
  104. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/file-bug-report/SKILL.md +13 -1
  105. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/github-housekeeping/SKILL.md +1 -1
  106. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/repomatic-audit/SKILL.md +18 -2
  107. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/repomatic-deps/SKILL.md +38 -17
  108. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/repomatic-init/SKILL.md +0 -1
  109. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/repomatic-ship/SKILL.md +18 -9
  110. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/repomatic-test-matrix/SKILL.md +24 -4
  111. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/repomatic-upgrade/SKILL.md +3 -2
  112. {repomatic-7.17.0/.claude → repomatic-7.18.0/repomatic/data}/skills/upstream-audit/SKILL.md +23 -12
  113. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/tests.yaml +27 -9
  114. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/typos.toml +10 -2
  115. {repomatic-7.17.0/.github/workflows → repomatic-7.18.0/repomatic/data}/unsubscribe.yaml +1 -1
  116. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/uv.toml +4 -3
  117. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/dep_report.py +26 -8
  118. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/uv.py +161 -58
  119. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/docs.py +28 -11
  120. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/file_inventory.py +19 -4
  121. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/actions.py +80 -2
  122. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/ci_status.py +231 -88
  123. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/dev_release.py +3 -3
  124. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/job_timings.py +6 -22
  125. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/matrix.py +5 -5
  126. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/pr.py +1 -1
  127. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/pr_body.py +23 -10
  128. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/sponsor.py +1 -1
  129. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/token.py +5 -3
  130. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/unsubscribe.py +2 -2
  131. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/workflow_sync.py +3 -3
  132. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/init_project.py +96 -23
  133. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/lint_repo.py +711 -60
  134. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metadata/core.py +6 -5
  135. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metadata/git.py +6 -5
  136. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metadata/matrix.py +17 -56
  137. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/pages_redirects.py +114 -18
  138. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/pypi.py +1 -1
  139. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/registry.py +14 -2
  140. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/checksums.py +11 -8
  141. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/prepare_release.py +3 -3
  142. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/version_sync.py +14 -8
  143. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/runner_catalog.py +3 -3
  144. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/runner_images.py +1 -1
  145. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/setup_guide.py +36 -15
  146. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/sync_ops.py +29 -8
  147. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/detect-squash-merge.md +2 -2
  148. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/immutable-releases.md +1 -1
  149. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sample-metrics.md +1 -3
  150. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide-branch-ruleset.md +1 -3
  151. repomatic-7.18.0/repomatic/templates/setup-guide-cloudflare-pages.md +32 -0
  152. repomatic-7.18.0/repomatic/templates/setup-guide-cloudflare-r2.md +30 -0
  153. repomatic-7.18.0/repomatic/templates/setup-guide-dependabot.md +17 -0
  154. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide-fork-pr-approval.md +2 -2
  155. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide-notifications-pat.md +1 -4
  156. repomatic-7.18.0/repomatic/templates/setup-guide-pages-source.md +21 -0
  157. repomatic-7.18.0/repomatic/templates/setup-guide-pypi-trusted-publisher.md +19 -0
  158. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide-sha-pinning-required.md +1 -1
  159. repomatic-7.18.0/repomatic/templates/setup-guide-virustotal.md +20 -0
  160. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide.md +1 -1
  161. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-dep-sources.md +1 -1
  162. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-runner-images.md +1 -1
  163. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/update-dep-graph.md +1 -0
  164. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/tooling/bundle.py +2 -2
  165. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/tooling/plugin.py +3 -3
  166. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/tooling/tool_registry.py +114 -36
  167. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/tooling/tool_runner.py +176 -92
  168. {repomatic-7.17.0 → repomatic-7.18.0}/tests/cli-test-suite.toml +0 -6
  169. {repomatic-7.17.0 → repomatic-7.18.0}/tests/conftest.py +39 -0
  170. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_actions.py +70 -0
  171. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_checksums.py +30 -2
  172. repomatic-7.18.0/tests/test_ci_status.py +765 -0
  173. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_claude_assets.py +121 -0
  174. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_cloudflare_r2.py +6 -3
  175. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_config.py +50 -0
  176. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_dep_graph.py +26 -0
  177. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_dep_report.py +10 -5
  178. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_docs.py +71 -0
  179. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_gh.py +0 -15
  180. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_http.py +11 -0
  181. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_init_project.py +128 -7
  182. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_job_timings.py +44 -0
  183. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_lint_repo.py +484 -18
  184. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_metadata.py +119 -22
  185. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_metrics.py +3 -2
  186. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_pages_redirects.py +100 -10
  187. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_plugin_update_detection.py +96 -7
  188. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_pr_body.py +38 -3
  189. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_runner_catalog.py +4 -3
  190. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_setup_guide.py +36 -4
  191. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_sphinx_crossrefs.py +32 -3
  192. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_status.py +13 -0
  193. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_sync_ops.py +41 -10
  194. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_tool_runner.py +294 -59
  195. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_uv.py +138 -6
  196. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_version_sync.py +15 -1
  197. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_vulnerable_deps.py +5 -5
  198. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_workflow_sync.py +2 -2
  199. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_workflows.py +126 -6
  200. {repomatic-7.17.0 → repomatic-7.18.0}/uv.lock +643 -515
  201. repomatic-7.17.0/docs/assets/star-history-compared.svg +0 -102
  202. repomatic-7.17.0/docs/code-of-conduct.md +0 -3
  203. repomatic-7.17.0/docs/nuitka.md +0 -106
  204. repomatic-7.17.0/docs/repomatic.site_anchors.md +0 -8
  205. repomatic-7.17.0/docs/tests.test_site_anchors.md +0 -8
  206. repomatic-7.17.0/repomatic/site_anchors.py +0 -257
  207. repomatic-7.17.0/repomatic/templates/setup-guide-cloudflare-pages.md +0 -30
  208. repomatic-7.17.0/repomatic/templates/setup-guide-cloudflare-r2.md +0 -24
  209. repomatic-7.17.0/repomatic/templates/setup-guide-dependabot.md +0 -13
  210. repomatic-7.17.0/repomatic/templates/setup-guide-pages-source.md +0 -19
  211. repomatic-7.17.0/repomatic/templates/setup-guide-pypi-trusted-publisher.md +0 -20
  212. repomatic-7.17.0/repomatic/templates/setup-guide-virustotal.md +0 -21
  213. repomatic-7.17.0/tests/test_ci_status.py +0 -313
  214. repomatic-7.17.0/tests/test_site_anchors.py +0 -250
  215. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/agents/qa-engineer.md +0 -0
  216. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/av-false-positive/SKILL.md +0 -0
  217. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/awesome-triage/SKILL.md +0 -0
  218. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/brand-assets/SKILL.md +0 -0
  219. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/probe-workflow/SKILL.md +0 -0
  220. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/repomatic-changelog/SKILL.md +0 -0
  221. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/repomatic-ship/references/findings-in-repomatic.md +0 -0
  222. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/repomatic-ship/references/short-ship.md +0 -0
  223. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/repomatic-topics/SKILL.md +0 -0
  224. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/sphinx-docs-sync/SKILL.md +0 -0
  225. {repomatic-7.17.0 → repomatic-7.18.0}/.claude/skills/translation-sync/SKILL.md +0 -0
  226. {repomatic-7.17.0 → repomatic-7.18.0}/.github/actions/publish-pypi/action.yaml +0 -0
  227. {repomatic-7.17.0 → repomatic-7.18.0}/.github/code-of-conduct.md +0 -0
  228. {repomatic-7.17.0 → repomatic-7.18.0}/.github/funding.yml +0 -0
  229. {repomatic-7.17.0 → repomatic-7.18.0}/.gitignore +0 -0
  230. {repomatic-7.17.0 → repomatic-7.18.0}/.mailmap +0 -0
  231. {repomatic-7.17.0 → repomatic-7.18.0}/docs/404.html +0 -0
  232. {repomatic-7.17.0 → repomatic-7.18.0}/docs/_redirects +0 -0
  233. {repomatic-7.17.0 → repomatic-7.18.0}/docs/_static/custom.css +0 -0
  234. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/banner-social-dark.png +0 -0
  235. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/banner-social-light.png +0 -0
  236. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/banner-social.svg +0 -0
  237. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/desktop-autosync-warning.png +0 -0
  238. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/desktop-plugin-agents.png +0 -0
  239. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/desktop-plugin-contents.png +0 -0
  240. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/desktop-plugin-skills.png +0 -0
  241. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/favicon.svg +0 -0
  242. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/icon.icns +0 -0
  243. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/icon.ico +0 -0
  244. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/icon.png +0 -0
  245. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/logo-banner-dark.png +0 -0
  246. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/logo-banner-light.png +0 -0
  247. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/logo-banner.svg +0 -0
  248. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/logo-square-dark.png +0 -0
  249. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/logo-square-light.png +0 -0
  250. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/logo-square.svg +0 -0
  251. {repomatic-7.17.0 → repomatic-7.18.0}/docs/assets/sync-deps-trail-screen.svg +0 -0
  252. {repomatic-7.17.0 → repomatic-7.18.0}/docs/changelog-archive.md +0 -0
  253. {repomatic-7.17.0 → repomatic-7.18.0}/docs/changelog.md +0 -0
  254. {repomatic-7.17.0 → repomatic-7.18.0}/docs/cli.md +0 -0
  255. {repomatic-7.17.0 → repomatic-7.18.0}/docs/contributing.md +0 -0
  256. {repomatic-7.17.0 → repomatic-7.18.0}/docs/docs_update.py +0 -0
  257. {repomatic-7.17.0 → repomatic-7.18.0}/docs/history.md +0 -0
  258. {repomatic-7.17.0 → repomatic-7.18.0}/docs/license.md +0 -0
  259. {repomatic-7.17.0 → repomatic-7.18.0}/docs/man.md +0 -0
  260. {repomatic-7.17.0 → repomatic-7.18.0}/docs/packaging.md +0 -0
  261. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.awesome_toc.md +0 -0
  262. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.broken_links.md +0 -0
  263. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cache.md +0 -0
  264. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.changelog.md +0 -0
  265. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.github.md +0 -0
  266. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.lint.md +0 -0
  267. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.main.md +0 -0
  268. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.md +0 -0
  269. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.release.md +0 -0
  270. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.sample.md +0 -0
  271. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.setup.md +0 -0
  272. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cli.sync.md +0 -0
  273. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cloudflare.md +0 -0
  274. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.cloudflare_r2.md +0 -0
  275. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.compat.md +0 -0
  276. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.config.md +0 -0
  277. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.data.awesome_template.md +0 -0
  278. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.data.md +0 -0
  279. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.dep_graph.md +0 -0
  280. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.dep_policy.md +0 -0
  281. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.dep_report.md +0 -0
  282. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.dep_sources.md +0 -0
  283. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.md +0 -0
  284. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.uv.md +0 -0
  285. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.deps.vulnerable_deps.md +0 -0
  286. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.docs.md +0 -0
  287. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.file_inventory.md +0 -0
  288. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.file_ops.md +0 -0
  289. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.forge.md +0 -0
  290. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.frontmatter.md +0 -0
  291. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.git_ops.md +0 -0
  292. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.actions.md +0 -0
  293. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.ci_status.md +0 -0
  294. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.dev_release.md +0 -0
  295. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.gh.md +0 -0
  296. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.issue.md +0 -0
  297. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.job_timings.md +0 -0
  298. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.matrix.md +0 -0
  299. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.md +0 -0
  300. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.pr.md +0 -0
  301. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.pr_body.md +0 -0
  302. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.release_sync.md +0 -0
  303. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.releases.md +0 -0
  304. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.sponsor.md +0 -0
  305. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.status.md +0 -0
  306. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.token.md +0 -0
  307. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.unsubscribe.md +0 -0
  308. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.github.workflow_sync.md +0 -0
  309. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.gitignore.md +0 -0
  310. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.hashing.md +0 -0
  311. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.http.md +0 -0
  312. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.humanize.md +0 -0
  313. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.images.md +0 -0
  314. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.init_project.md +0 -0
  315. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.labels.md +0 -0
  316. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.lint_repo.md +0 -0
  317. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.mailmap.md +0 -0
  318. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.matrix_axes.md +0 -0
  319. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metadata.core.md +0 -0
  320. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metadata.env.md +0 -0
  321. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metadata.git.md +0 -0
  322. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metadata.matrix.md +0 -0
  323. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metadata.md +0 -0
  324. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metadata.project.md +0 -0
  325. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metric_chart.md +0 -0
  326. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.metrics.md +0 -0
  327. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.npm.md +0 -0
  328. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.pages_redirects.md +0 -0
  329. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.pypi.md +0 -0
  330. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.pyproject.md +0 -0
  331. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.registry.md +0 -0
  332. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.attestation.md +0 -0
  333. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.binaries_page.md +0 -0
  334. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.binary.md +0 -0
  335. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.checksums.md +0 -0
  336. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.md +0 -0
  337. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.prepare_release.md +0 -0
  338. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.version_sync.md +0 -0
  339. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.release.virustotal.md +0 -0
  340. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.runner_catalog.md +0 -0
  341. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.runner_images.md +0 -0
  342. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.setup_guide.md +0 -0
  343. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.sync_ops.md +0 -0
  344. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.tabular.md +0 -0
  345. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.templates.md +0 -0
  346. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.tooling.bundle.md +0 -0
  347. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.tooling.md +0 -0
  348. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.tooling.plugin.md +0 -0
  349. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.tooling.tool_registry.md +0 -0
  350. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.tooling.tool_runner.md +0 -0
  351. {repomatic-7.17.0 → repomatic-7.18.0}/docs/repomatic.versions.md +0 -0
  352. {repomatic-7.17.0 → repomatic-7.18.0}/docs/robots.txt +0 -0
  353. {repomatic-7.17.0 → repomatic-7.18.0}/docs/subagents.md +0 -0
  354. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.conftest.md +0 -0
  355. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_actions.md +0 -0
  356. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_attestation.md +0 -0
  357. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_awesome_template.md +0 -0
  358. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_awesome_toc.md +0 -0
  359. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_binaries_page.md +0 -0
  360. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_binary.md +0 -0
  361. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_broken_links.md +0 -0
  362. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_cache.md +0 -0
  363. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_changelog.md +0 -0
  364. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_checksums.md +0 -0
  365. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_ci_status.md +0 -0
  366. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_claude_assets.md +0 -0
  367. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_cloudflare.md +0 -0
  368. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_cloudflare_r2.md +0 -0
  369. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_config.md +0 -0
  370. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_dep_graph.md +0 -0
  371. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_dep_policy.md +0 -0
  372. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_dep_report.md +0 -0
  373. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_dep_sources.md +0 -0
  374. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_dev_release.md +0 -0
  375. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_docs.md +0 -0
  376. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_docstrings.md +0 -0
  377. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_forge.md +0 -0
  378. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_frontmatter.md +0 -0
  379. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_gh.md +0 -0
  380. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_git_ops.md +0 -0
  381. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_gitignore.md +0 -0
  382. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_hashing.md +0 -0
  383. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_help.md +0 -0
  384. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_http.md +0 -0
  385. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_humanize.md +0 -0
  386. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_images.md +0 -0
  387. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_imports.md +0 -0
  388. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_init_project.md +0 -0
  389. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_issue.md +0 -0
  390. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_job_timings.md +0 -0
  391. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_labels.md +0 -0
  392. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_lint_repo.md +0 -0
  393. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_mailmap.md +0 -0
  394. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_matrix.md +0 -0
  395. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_metadata.md +0 -0
  396. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_metrics.md +0 -0
  397. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_npm.md +0 -0
  398. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_pages_redirects.md +0 -0
  399. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_platform_keys.md +0 -0
  400. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_plugin.md +0 -0
  401. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_plugin_update_detection.md +0 -0
  402. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_pr.md +0 -0
  403. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_pr_body.md +0 -0
  404. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_prepare_release.md +0 -0
  405. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_pypi.md +0 -0
  406. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_pyproject.md +0 -0
  407. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_readme.md +0 -0
  408. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_release_sync.md +0 -0
  409. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_releases.md +0 -0
  410. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_runner_catalog.md +0 -0
  411. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_runner_sync.md +0 -0
  412. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_setup_guide.md +0 -0
  413. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_skills.md +0 -0
  414. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_sphinx_crossrefs.md +0 -0
  415. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_status.md +0 -0
  416. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_suite_hygiene.md +0 -0
  417. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_sync_ops.md +0 -0
  418. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_tabular.md +0 -0
  419. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_todolist.md +0 -0
  420. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_tool_runner.md +0 -0
  421. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_unsubscribe.md +0 -0
  422. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_uv.md +0 -0
  423. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_version_sync.md +0 -0
  424. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_versions.md +0 -0
  425. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_virustotal.md +0 -0
  426. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_vulnerable_deps.md +0 -0
  427. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_workflow_sync.md +0 -0
  428. {repomatic-7.17.0 → repomatic-7.18.0}/docs/tests.test_workflows.md +0 -0
  429. {repomatic-7.17.0 → repomatic-7.18.0}/docs/todolist.md +0 -0
  430. {repomatic-7.17.0 → repomatic-7.18.0}/license +0 -0
  431. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/awesome_toc.py +0 -0
  432. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/broken_links.py +0 -0
  433. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/__init__.py +0 -0
  434. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/cli/sample.py +0 -0
  435. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/compat.py +0 -0
  436. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/__init__.py +0 -0
  437. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/action-publish-pypi.yaml +0 -0
  438. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/actionlint.yaml +0 -0
  439. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/agent-qa-engineer.md +0 -0
  440. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/config.yml +0 -0
  441. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/new-link.yaml +0 -0
  442. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/code-of-conduct.md +0 -0
  443. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/funding.yml +0 -0
  444. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/.github/pull_request_template.md +0 -0
  445. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/__init__.py +0 -0
  446. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/awesome_template/license +0 -0
  447. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/bumpversion.toml +0 -0
  448. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/coverage.toml +0 -0
  449. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/labels.toml +0 -0
  450. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/mdformat.toml +0 -0
  451. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/pytest.toml +0 -0
  452. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/ruff.toml +0 -0
  453. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/av-false-positive/SKILL.md +0 -0
  454. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/awesome-triage/SKILL.md +0 -0
  455. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/brand-assets/SKILL.md +0 -0
  456. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/probe-workflow/SKILL.md +0 -0
  457. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/repomatic-changelog/SKILL.md +0 -0
  458. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/repomatic-ship/references/findings-in-repomatic.md +0 -0
  459. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/repomatic-ship/references/short-ship.md +0 -0
  460. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/repomatic-topics/SKILL.md +0 -0
  461. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/sphinx-docs-sync/SKILL.md +0 -0
  462. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/skills/translation-sync/SKILL.md +0 -0
  463. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/vt-trend-chart.js +0 -0
  464. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/yamllint.yaml +0 -0
  465. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/data/zizmor.yaml +0 -0
  466. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/__init__.py +0 -0
  467. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/dep_graph.py +0 -0
  468. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/dep_policy.py +0 -0
  469. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/dep_sources.py +0 -0
  470. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/deps/vulnerable_deps.py +0 -0
  471. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/file_ops.py +0 -0
  472. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/forge.py +0 -0
  473. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/frontmatter.py +0 -0
  474. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/git_ops.py +0 -0
  475. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/__init__.py +0 -0
  476. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/gh.py +0 -0
  477. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/issue.py +0 -0
  478. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/release_sync.py +0 -0
  479. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/releases.py +0 -0
  480. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/github/status.py +0 -0
  481. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/gitignore.py +0 -0
  482. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/hashing.py +0 -0
  483. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/http.py +0 -0
  484. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/humanize.py +0 -0
  485. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/images.py +0 -0
  486. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/labels.py +0 -0
  487. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/mailmap.py +0 -0
  488. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/matrix_axes.py +0 -0
  489. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metadata/__init__.py +0 -0
  490. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metadata/env.py +0 -0
  491. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metadata/project.py +0 -0
  492. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metric_chart.py +0 -0
  493. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/metrics.py +0 -0
  494. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/npm.py +0 -0
  495. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/py.typed +0 -0
  496. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/pyproject.py +0 -0
  497. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/__init__.py +0 -0
  498. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/attestation.py +0 -0
  499. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/binaries_page.py +0 -0
  500. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/binary.py +0 -0
  501. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/release/virustotal.py +0 -0
  502. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/tabular.py +0 -0
  503. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/__init__.py +0 -0
  504. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/available-admonition.md +0 -0
  505. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/broken-links-issue.md +0 -0
  506. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/bump-version.md +0 -0
  507. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/development-warning.md +0 -0
  508. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/fix-changelog.md +0 -0
  509. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/fix-typos.md +0 -0
  510. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/fix-vulnerable-deps.md +0 -0
  511. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/format-images.md +0 -0
  512. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/format-json.md +0 -0
  513. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/format-markdown.md +0 -0
  514. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/format-pyproject.md +0 -0
  515. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/format-python.md +0 -0
  516. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/format-shell.md +0 -0
  517. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/generated-footer.md +0 -0
  518. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/github-releases.md +0 -0
  519. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/pr-metadata.md.noformat +0 -0
  520. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/prepare-release.md.noformat +0 -0
  521. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/refresh-tip.md +0 -0
  522. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/release-notes.md +0 -0
  523. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/release-sync-report.md +0 -0
  524. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/scan-virustotal.md +0 -0
  525. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide-token.md +0 -0
  526. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/setup-guide-verify.md +0 -0
  527. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-action-pins.md +0 -0
  528. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-bumpversion.md +0 -0
  529. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-gitignore.md +0 -0
  530. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-mailmap.md +0 -0
  531. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-repomatic-upgrade.md +0 -0
  532. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-repomatic.md +0 -0
  533. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-tool-versions.md +0 -0
  534. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-uv-lock.md +0 -0
  535. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/sync-workflow-pins.md +0 -0
  536. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/unavailable-admonition.md +0 -0
  537. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/unsubscribe-phase1.md +0 -0
  538. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/unsubscribe-phase2.md +0 -0
  539. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/update-docs.md +0 -0
  540. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/upgrade-invite.md +0 -0
  541. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/templates/yanked-admonition.md +0 -0
  542. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/tooling/__init__.py +0 -0
  543. {repomatic-7.17.0 → repomatic-7.18.0}/repomatic/versions.py +0 -0
  544. {repomatic-7.17.0 → repomatic-7.18.0}/tests/__init__.py +0 -0
  545. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_attestation.py +0 -0
  546. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_awesome_template.py +0 -0
  547. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_awesome_toc.py +0 -0
  548. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_binaries_page.py +0 -0
  549. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_binary.py +0 -0
  550. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_broken_links.py +0 -0
  551. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_cache.py +0 -0
  552. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_changelog.py +0 -0
  553. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_cloudflare.py +0 -0
  554. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_dep_policy.py +0 -0
  555. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_dep_sources.py +0 -0
  556. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_dev_release.py +0 -0
  557. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_docstrings.py +0 -0
  558. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_forge.py +0 -0
  559. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_frontmatter.py +0 -0
  560. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_git_ops.py +0 -0
  561. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_gitignore.py +0 -0
  562. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_hashing.py +0 -0
  563. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_help.py +0 -0
  564. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_humanize.py +0 -0
  565. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_images.py +0 -0
  566. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_imports.py +0 -0
  567. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_issue.py +0 -0
  568. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_labels.py +0 -0
  569. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_mailmap.py +0 -0
  570. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_matrix.py +0 -0
  571. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_npm.py +0 -0
  572. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_platform_keys.py +0 -0
  573. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_plugin.py +0 -0
  574. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_pr.py +0 -0
  575. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_prepare_release.py +0 -0
  576. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_pypi.py +0 -0
  577. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_pyproject.py +0 -0
  578. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_readme.py +0 -0
  579. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_release_sync.py +0 -0
  580. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_releases.py +0 -0
  581. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_runner_sync.py +0 -0
  582. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_skills.py +0 -0
  583. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_suite_hygiene.py +0 -0
  584. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_tabular.py +0 -0
  585. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_todolist.py +0 -0
  586. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_unsubscribe.py +0 -0
  587. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_versions.py +0 -0
  588. {repomatic-7.17.0 → repomatic-7.18.0}/tests/test_virustotal.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.17.0"
23
+ "version": "7.18.0"
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
@@ -187,7 +187,7 @@ The reader's eye lands on line 7 of the Python and line 2 of the captured table
187
187
 
188
188
  ### Emitting raw HTML from `{python:render}`
189
189
 
190
- `{python:render}` parses captured stdout as MyST, and MyST passes block-level raw HTML straight through to the rendered page. So a generator that produces HTML can just `print(html)` — no `{raw} html` wrap, no extra plumbing:
190
+ `{python:render}` parses captured stdout as MyST, and MyST passes block-level raw HTML straight through to the rendered page. So a generator that produces HTML can just `print(html)` — no `{raw} html` wrap:
191
191
 
192
192
  ````markdown
193
193
  ```{python:render}
@@ -221,7 +221,7 @@ Conversion lifecycle:
221
221
 
222
222
  - Authors write **MyST** in `*.py` docstrings (`` {role}`target` ``, `[text](url)`, single-backtick inline code, ```` ```{directive} ```` admonitions).
223
223
  - The `click_extra.sphinx.myst_docstrings` Sphinx extension hooks `autodoc-process-docstring` at priority 400 and converts MyST to reST at build time, before `sphinx_autodoc_typehints` runs. So the rendered HTML is the same as if the docstrings were always reST, while the source files stay editable in MyST.
224
- - Run `uvx click-extra convert-to-myst` (or `click-extra convert-to-myst path/to/pkg/`) to migrate an existing reST codebase. The converter is idempotent — already-MyST docstrings are a no-op.
224
+ - Run `uvx --exclude-newer '1 week' click-extra convert-to-myst` (or `click-extra convert-to-myst path/to/pkg/`) to migrate an existing reST codebase. The converter is idempotent — already-MyST docstrings are a no-op.
225
225
 
226
226
  Extension load order (the rule, with the rationale):
227
227
 
@@ -428,10 +428,10 @@ def _link(kind, target):
428
428
  for path in Path(".").rglob("*"):
429
429
  if path.suffix not in {".md", ".rst", ".py"} or not path.is_file():
430
430
  continue
431
- text = path.read_text(encoding="utf-8")
431
+ text = path.read_text(encoding="UTF-8")
432
432
  for pattern, replacement in PATTERNS:
433
433
  text = pattern.sub(replacement, text)
434
- path.write_text(text, encoding="utf-8")
434
+ path.write_text(text, encoding="UTF-8")
435
435
  ```
436
436
 
437
437
  For Python source files (where the role appeared inside docstrings or comments), the replacement keeps the same `[#N](url)` form since `click_extra.sphinx.myst_docstrings` recognizes Markdown links inside docstrings; `:issue:` in a `# comment` was never rendered anyway and becomes a plain link.
@@ -765,9 +765,10 @@ Default-pruning rule:
765
765
  - **Match the deployed builder, which is not always `html`.** `[tool.repomatic] sphinx.builder` is what the Docs workflow passes to `sphinx-build -b`, and a project serving extension-less URLs sets it to `dirhtml` (`page/index.html` instead of `page.html`). Read it before assuming a local `-b html` reproduces CI. The builder is chosen on the command line, so it is the one Sphinx setting `conf.py` cannot carry: never "fix" its absence there.
766
766
  - **A warning count only covers the pages that build re-read.** Sphinx reuses cached doctrees, so an incremental rebuild reports the warnings of the changed pages alone, and reading that number against a cold build's count shows a drop nothing caused. A `conf.py` edit invalidates the whole cache, which is why the build right after one reports many more. Build into a clean `_build/` before comparing two counts.
767
767
  - **Compare two builds only when both hold the same dependency groups.** autodoc imports each module it documents. A build that lacks one group fails those imports, like the test group for a `tests` API page, and each reference into such a module then reports as unresolved. Build the baseline from an export of `HEAD` and the candidate from the working tree, both with `uv run --isolated --frozen --all-extras --all-groups`: neither touches the shared virtual environment.
768
+ - **Run `sphinx-build` with the command sandbox off.** Inside the Claude Code sandbox (`2.1.284`, macOS, 2026-10-02), `sphinx_sitemap` aborts the build at `builder-inited` with `PermissionError: [Errno 1] Operation not permitted`. Intersphinx also fails to fetch its inventories there. Neither failure says anything about the docs.
768
769
  - Periodically diff against a fresh `sphinx-quickstart` output in a tmpdir to spot defaults that have shifted under you.
769
770
  - Drop conditional import shims once the project's minimum Python no longer needs them. The `try: import tomllib / except: import tomli` pattern is dead code on `requires-python = ">=3.11"`. Same for any `if sys.version_info < (3, X):` branch where `X` is now below the floor. The deps group should lose the corresponding fallback dependency in the same PR.
770
- - Always pass `encoding="utf-8"` to `Path.read_text()` calls in `conf.py`. Bare `read_text()` picks up the locale, which on minimal CI runners has bitten many projects.
771
+ - Always pass `encoding="UTF-8"` to `Path.read_text()` calls in `conf.py`. Bare `read_text()` picks up the locale, which on minimal CI runners has bitten many projects.
771
772
  - `exclude_patterns = ["_build", "_linkcheck", "html", "Thumbs.db", ".DS_Store"]` is the canonical set: `_build` and `_linkcheck` are the build and linkcheck output directories (both also gitignored), and `html` catches stray in-tree builds left by ad-hoc `sphinx-build` invocations.
772
773
  - Publish content, not build scaffolding. `html_copy_source = False` and `html_show_sourcelink = False` together drop the `_sources/` copy of every document, which no page in this lineage links to and only a hand-typed URL could reach. Name both: they gate different halves of the feature, and a theme reading only the second offers a link to files that are no longer there. Sphinx still creates the (now empty) directory and writes `.buildinfo` from an unconditional finish task, so a `build-finished` hook removing `.buildinfo`, `.buildinfo.bak` and the empty `_sources/` is what actually keeps them out of the deployed tree.
773
774
  - `sphinx_sitemap` earns its place on any site big enough that a crawler would have to walk the whole link graph to find the API pages. It needs `html_baseurl`, and **that value must end in a slash**: sphinx-sitemap concatenates it with each page link (its own normalization line computes the slash-terminated form and discards the result), so a slash-less base emits `https://example.netinstall.html`. Derive it once from `project.urls.Documentation` with `.rstrip("/") + "/"`, feed both `html_baseurl` and `ogp_site_url` from it, and set `sitemap_url_scheme = "{link}"`: the default `{lang}{version}{link}` layout is for sites publishing translations or versions side by side, and yields 404s anywhere else. Pair it with a self-contained `404.html` in `html_extra_path`: when none is present, Cloudflare Pages answers an unmatched route with the home page and a `200`, which tells a crawler every misspelled URL is real. A site on its own host also gets a `robots.txt` there that names the sitemap. A GitHub Pages project site under `{user}.github.io/{project}/` gets none, because crawlers read `robots.txt` only at the host root. The links in its `404.html` start from `/{project}/`, because the page can answer at any depth.
@@ -806,8 +807,9 @@ Linkcheck and intersphinx:
806
807
 
807
808
  Strictness flags:
808
809
 
809
- - `nitpicky = True` is the default in this lineage. Missing references fail the build instead of producing a half-rendered page. Don't disable it; fix the missing target.
810
- - `autosectionlabel_prefix_document = True` avoids duplicate-label warnings when two pages have the same heading. Pair with `autosectionlabel = True` in extensions.
810
+ - `nitpicky = True` is the default in this lineage. Each missing reference then logs a warning, which fails a build run with `-W`. Don't disable it; fix the missing target.
811
+ - `click_extra_fail_on_warnings = ["myst.xref_missing"]` fails the build on a `[text](#anchor)` or `[text](page.md#anchor)` link that lands nowhere. myst-parser only logs that warning, and ships the link as written. Set it on a build that logs too many warnings to run with `-W`. The setting needs click-extra `9.4.0`: an older release ignores it, and the build passes. A `page.md#anchor` link to an ID that autodoc generates reports the same warning, though the ID exists: write it as a `{role}` cross-reference.
812
+ - `autosectionlabel_prefix_document = True` avoids duplicate-label warnings when two pages have the same heading. Pair with `"sphinx.ext.autosectionlabel"` in `extensions`.
811
813
 
812
814
  `suppress_warnings` governance:
813
815
 
@@ -816,11 +818,11 @@ Strictness flags:
816
818
  - Canonical entries observed across sibling repos:
817
819
  - `sphinx_autodoc_typehints.forward_reference` — pytest decorators dynamically generated at import time; pytest's `Mark` type is unavailable during the docs build. Cosmetic.
818
820
  - `myst.directive` — empty mermaid directives produced by automated diagram generators with sparse data.
819
- - `myst.xref_missing` — MyST validates anchors before autodoc generates them; false positives only.
820
821
  - `myst.domains` — upstream limitation in `click_extra.sphinx` (no `resolve_any_xref` method on the click domain).
821
822
  - `myst.strikethrough` — `~~text~~` marks deprecated/incorrect spellings in docstrings; the project ships HTML only.
822
823
  - `myst.header` — `readme.md` starts at `## ` because GitHub supplies the H1 from the repo name; intentional.
823
824
  - `docutils` — code examples in docstrings whose indentation trips reST parsing; usually in test fixtures.
825
+ - Never list `myst.xref_missing` here: it reports a fragment link that lands nowhere, and `click_extra_fail_on_warnings` skips a suppressed type. See § Strictness flags.
824
826
  - On every Sphinx or extension upgrade, sweep `suppress_warnings` and re-run a clean build with the entry removed. If the warning no longer fires, drop the entry in the same PR.
825
827
 
826
828
  `nitpick_ignore` governance:
@@ -885,7 +887,7 @@ Watch for these every pass:
885
887
  - An `automodule` block on a narrative page, repeating what the module's own API page already documents. Every such pair costs a duplicate object description per member and buries the guide's message; see § Guide pages carry the prose, API pages carry the API.
886
888
  - Stale `.rst` files in `docs/` left over from package renames or earlier `sphinx-apidoc` runs that reference modules or packages no longer in the source tree. They build silently (autodoc skips missing modules with a warning, not an error) but pollute search results and the modindex. Sweep with `git status` after `update-docs`; delete orphans in the same PR.
887
889
  - Developer setup held in `readme.md` (a `## Development` section) or in `claude.md`. Setup, dev loop and test commands belong on the `contributing` page of the roster, where a contributor looks for them. `claude.md` loads into every agent session, so it keeps conventions and links to that page. A second copy creates two places to update.
888
- - A `dependencies.md` page whose embedded Mermaid graph hasn't been regenerated since the last `uv lock` change. The graph stays in sync only if `repomatic update-dep-graph` is wired into a workflow job; manual regeneration drifts. Upstream that job lives in `_release-engine.yaml` and fires on release commits only, so a graph lagging `pyproject.toml` mid-cycle is expected rather than drift.
890
+ - A `packaging.md` page whose embedded Mermaid graph hasn't been regenerated since the last `uv lock` change. The graph stays in sync only if `repomatic update-dep-graph` is wired into a workflow job; manual regeneration drifts. Upstream that job lives in `autofix.yaml` and runs on every push, so a graph lagging `pyproject.toml` means its pull request is still open, not drift. With `[tool.repomatic] dependency-graph.update = false`, the command writes no graph and the job opens no pull request.
889
891
  - `pyproject.toml` declaring a docs dependency that's no longer imported by `conf.py` (or vice-versa: importing one not declared). The mismatch passes Sphinx but trips a fresh `uv sync --group docs` run on a CI runner.
890
892
  - `click_extra.sphinx.myst_docstrings` listed in `extensions` without `click-extra[sphinx]` declared in `[dependency-groups] docs`. Builds work on the maintainer's machine if the package is installed globally, then break in CI.
891
893
  - `click_extra.sphinx` listed in `extensions` without `click_extra_enable_exec_directives = True` in `conf.py`. Since click-extra `v7.15.0` the directives are off by default; without the flag, every `{click:run}` / `{click:source}` / `{python:*}` reference logs an "Unknown directive" warning and the page renders without the live block.
@@ -80,12 +80,12 @@ 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 in `references/failure-patterns.md` 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-*`, `update-*`, `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
 
87
87
  ```shell-session
88
- $ uv run pytest --no-header -q &
88
+ $ uv run --frozen --all-extras --group test pytest --no-header -q &
89
89
  $ uv run --group typing repomatic run mypy &
90
90
  $ uv run repomatic run ruff -- check repomatic tests docs &
91
91
  ```
@@ -100,13 +100,13 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
100
100
  $ uv run repomatic ci-status --branch=<BRANCH> --no-fatal
101
101
  ```
102
102
 
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.
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. Four 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; 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; and a run that was cancelled, or that ran no job, has no failed job and still gives its commit no result, so its verdict reads `cancelled` or `skipped`, never `green`.
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 that ran no job on the tip, like `tests.yaml` on a version-bump commit, is read on an earlier commit, and the command names it. A `cancelled` or `skipped` verdict is not a pass: see [§ When supersession never lets a run conclude](#when-supersession-never-lets-a-run-conclude). A workflow with no run on the newest commits falls back to its own run listing, filtered by creation date. 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
 
@@ -134,7 +134,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
134
134
  $ gh run view <LINT_RUN_ID> --json jobs --jq '[.jobs[] | select(.conclusion == "failure")] | .[].databaseId'
135
135
  ```
136
136
 
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.
137
+ The first filter negates the unstable glyph rather than matching a `✅` prefix, mirroring `JobStatus.required` on every name GitHub expanded. `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
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
 
@@ -156,7 +156,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
156
156
  After applying fixes, re-run the full local validation:
157
157
 
158
158
  ```shell-session
159
- $ uv run pytest --no-header -q
159
+ $ uv run --frozen --all-extras --group test pytest --no-header -q
160
160
  $ uv run --group typing repomatic run mypy
161
161
  $ uv run repomatic run ruff -- check repomatic tests docs
162
162
  $ uv run repomatic run ruff -- format repomatic tests docs
@@ -195,6 +195,8 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
195
195
 
196
196
  A busy default branch can cancel the same workflow indefinitely. Every push shares the `${{ github.workflow }}-${{ github.ref }}` concurrency group, so an unrelated commit landing mid-matrix cancels yours, and the next one cancels its replacement. Three consecutive heads leaving `tests.yaml` cancelled is an ordinary afternoon, not a fault. Dispatching a fresh run does not escape it: a `workflow_dispatch` run joins the same group and is cancelled by the next push like any other.
197
197
 
198
+ A dispatch does settle one case: a version-bump commit, whose subject starts with `[changelog] Bump`, merged right after your push. It cancels your runs, and `tests.yaml` skips the bump commit itself, so `ci-status` reads `cancelled` on your commit. Run `gh workflow run tests.yaml --ref <BRANCH>` once: the dispatched run tests the head, which holds your change.
199
+
198
200
  **A cancelled run is neither a failure nor a pass, and the run-level conclusion hides which.** Read the jobs:
199
201
 
200
202
  ```shell-session
@@ -228,7 +230,7 @@ Report the union explicitly: which cells passed in CI, which you closed locally,
228
230
 
229
231
  The workflow uses `continue-on-error` for unstable jobs, so the run can succeed even when they fail.
230
232
 
231
- `repomatic ci-status` does this classification, and doing it by hand is where it goes wrong: job-name shapes differ across workflows — `tests.yaml` names carry no workflow prefix (`✅ ubuntu-26.04 / py3.10`) while the release engine's arrive through the reusable call (`release / ✅ ubuntu-26.04, abc1234 build`) — so a test anchored at the start of the name misfiles one shape and a split on `" / "` misfiles the other, either way masking a real failure as green. Containment is the one test both shapes satisfy. Only `✅`/`⁉️` carry stability: a job whose name opens on some other emoji (`🛡️ Lint types`, `1️⃣ Run-once tests`) is required, so test for the absence of `⁉️` rather than for the presence of any glyph. If you reformat job names for display, keep the raw string for the test.
233
+ `repomatic ci-status` does this classification, and doing it by hand is where it goes wrong: job-name shapes differ across workflows — `tests.yaml` names carry no workflow prefix (`✅ ubuntu-26.04 / py3.10`) while the release engine's arrive through the reusable call (`release / ✅ ubuntu-26.04, abc1234 build`) — so a test anchored at the start of the name misfiles one shape and a split on `" / "` misfiles the other, either way masking a real failure as green. Containment is the one test both shapes satisfy. Only `✅`/`⁉️` carry stability: a job whose name opens on some other emoji (`🛡️ Lint types`, `1️⃣ Run-once tests`) is required, so test for the absence of `⁉️` rather than for the presence of any glyph. A name that still holds both glyphs is a matrix GitHub never expanded, on a run stopped before the matrix got its cells: `ci-status` reads it as required. If you reformat job names for display, keep the raw string for the test.
232
234
 
233
235
  ## Error triage discipline
234
236
 
@@ -20,7 +20,7 @@ The classic false green: mypy passes locally over a subset of directories while
20
20
 
21
21
  ## Platform-specific test skips
22
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.
23
+ Some tests are skipped on certain platforms (`windows-11-arm` has no Python 3.10 ARM64 build). Before investigating missing results, check which cells the matrix excludes. `repomatic show-test-matrix` lists the computed matrix that the bundled `tests.yaml` runs, with the built-in exclusions and the `[tool.repomatic] test-matrix.exclude` entries applied. A `tests.yaml` with a hand-written matrix carries its own `exclude` section. Then check 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
24
 
25
25
  ## Cross-platform divergence
26
26
 
@@ -41,6 +41,7 @@ Not all CI failures are code bugs:
41
41
  - **Action version mismatches**: `Unable to resolve action`, deprecated-runtime errors. Fix the workflow YAML, not the Python.
42
42
  - **Network/registry flakiness**: `uv`/`pip` timeouts, PyPI 503s, `ConnectionResetError`. Re-run.
43
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
+ - **A stable job that turns red with no change to the tree or to the runner image**: a setup step met a different outside world, like a package manager that started a cleanup or a migration because its upstream metadata moved. The failing test only shows the symptom. Compare the setup output of the last green job with the red one before you read the test output: a step that prints new lines, or runs in one log only, names the cause. Fix that step. A re-run changes nothing, and a tolerated exit code hides the defect.
44
45
  - **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
46
  - **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
47
  - **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.
@@ -177,6 +177,10 @@ Stale or abandoned projects should be moved to the "Excluded projects" section w
177
177
 
178
178
  For each feature row, spot-check 2-3 projects against their current documentation or changelog. Flag cells that look wrong (features added or removed since the benchmark was written).
179
179
 
180
+ A row added since the last pass gets every competitor cell assessed, not a sample: its cells start unassessed, and an empty cell reads as "unsupported".
181
+
182
+ Re-anchor the version-pinned evidence links of a competitor that shipped a new release. A link pinned to a tag or a commit with a line range (`blob/v17.12.2/src/steps.rs#L120-L140`) keeps pointing at the old release. Find the same snippet in the new release by its content, never by the old line numbers, then repoint the link to the new tag and range. A snippet that is gone means the cell needs a fresh assessment.
183
+
180
184
  #### 3. Gap analysis freshness
181
185
 
182
186
  For each item in "Gaps and opportunities", check whether the linked upstream issues have changed status:
@@ -83,6 +83,8 @@ $ gh api repos/<owner/repo>/contents/.github/CODE_OF_CONDUCT.md --jq '.download_
83
83
  $ gh api repos/<owner/repo>/community/code_of_conduct --jq '.body'
84
84
  ```
85
85
 
86
+ Read each file to its end. When the repository file only points to a code of conduct hosted elsewhere, fetch that page and read it too.
87
+
86
88
  #### 1d. Issue templates and forms
87
89
 
88
90
  List all issue templates. Repos may use classic markdown templates, YAML issue forms, or both:
@@ -155,10 +157,19 @@ $ gh issue list --repo <owner/repo> --state all --json title,url,state
155
157
 
156
158
  Search with multiple keyword variations (error messages, function names, symptoms). Check both open and closed issues: the bug may have been reported and closed as "won't fix", or fixed in a version the user hasn't upgraded to.
157
159
 
158
- If a matching open issue exists, report it to the user and stop. If a matching closed issue exists, mention it in the report with a link and explain why this is a new occurrence (different version, different context, regression).
160
+ If a matching open issue exists, report it to the user and stop. Do not offer a comment on an issue that a maintainer has already answered as in progress, unless the user asks for one. If a matching closed issue exists, mention it in the report with a link and explain why this is a new occurrence (different version, different context, regression).
159
161
 
160
162
  A matching issue closed for lack of a reproducer is not a dead end: cite it, because that closure is part of the record, and supply what it lacked.
161
163
 
164
+ A keyword search over issues is not enough. Run these four checks too before you report the result to the user:
165
+
166
+ - **Pull requests.** Run the same keywords through `gh search prs`: a fix under review answers the report before it is filed.
167
+ - **Everything since the behavior appeared.** List the issues and pull requests created since the commit that introduced it, and read every title. A body search is noisy, because pasted logs hold the tool's own vocabulary.
168
+ - **Branches and release notes.** Read the development branches and the release notes for a fix in progress, and for the maintainer's own words on the topic.
169
+ - **Overlap.** Name the threads that share the theme without being duplicates. Cross-reference in the report the ones a reader can confuse with it.
170
+
171
+ Tell the user which checks ran, and what each one could not reach: a deleted issue, a truncated search, a chat server.
172
+
162
173
  ### 3. Gather evidence
163
174
 
164
175
  Collect the actual error output, environment details, and reproduction steps from the current conversation context, CI logs, or local files. Always include:
@@ -189,6 +200,7 @@ The maintainer of the code is the authority on it. Hand over observations they c
189
200
  - **Date a behavior by the commit that added it, not by the release note that announced it.** Release notes list what is worth reading about now, not what shipped now: `git tag --contains {sha} | sort -V | head -1` names the first release that carried the commit.
190
201
  - **Report what varied, where, and the link to it, then stop.** Leave the diagnosis, its implications for CI or users, and the next step to the maintainer, who reaches them faster from the facts than from a summary of them.
191
202
  - **Give every failing reproducer a passing control beside it.** Without a near-identical case that passes, red cannot be told apart from a broken harness, a missing dependency or a mistake in the reproducer. Assert the control too, and have the job report the test as void when the control breaks.
203
+ - **Run the reproducer in a second implementation before naming one.** When the target implements a shared standard (a browser engine, an interpreter, a compiler), the same result elsewhere moves the report to the standard, or to the code under test.
192
204
  - **Freeze the reproducer's vocabulary once the prose quotes it.** Renaming a log line, an artifact or a path that the report quotes forces a rerun, then a repoint of every link and quoted phrase.
193
205
  - **Re-read the draft before handing anyone steps to reproduce.** Give only the steps the draft records as reproducible, and flag a symptom seen only once as a one-off.
194
206
 
@@ -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.
@@ -25,8 +25,9 @@ You perform a comprehensive audit of a downstream repository against the upstrea
25
25
  Before flagging an issue, verify that the gap isn't **deliberate** or covered by a runtime mechanism. Common false positives:
26
26
 
27
27
  - **`[tool.repomatic] exclude` is authoritative.** Files listed there (like `workflows/changelog.yaml` or `labels`) are intentionally absent on disk. Do **not** report them as MISSING.
28
+ - **`[tool.repomatic] lint-repo.declined` records a decision.** Each entry names one bundled template entry that a `[tool.X]` section leaves out, with the reason. Do **not** report that entry as DRIFT. Report the record itself when `lint-repo` says it declines nothing.
28
29
  - **Bundled defaults applied at runtime.** Some config is materialized from the bundled template at runtime when the file is absent, so no on-disk copy is needed. **Absence of these files is not a problem**: it is the intended state when the user is happy with the bundled policy. Only flag DRIFT if the user wants to deviate from it. Exactly five tools carry such a fallback, the ones whose `ToolSpec` sets `default_config` in `repomatic/tooling/tool_registry.py`: `actionlint`, `mdformat`, `ruff`, `yamllint` and `zizmor`.
29
- - **A `[tool.X]` section is never a candidate for deletion.** The inverse of the rule above, and the more expensive mistake. Every other tool has no `default_config`, so its resolution chain has no level 3 to fall back on: `lychee`, `typos`, `mypy`, `pytest`, `coverage`, `bumpversion` and `uv` are *deployed* into `pyproject.toml` by `repomatic init`, and that section is the only config the tool will ever see. Deleting it does not restore inheritance from a bundled default, it drops the tool to level 4 and runs it bare, silently discarding every rule the section held. Read the tool's `default_config` before proposing a section be dropped "to inherit upstream updates". Re-running `repomatic init` fixes a stale section only for the components marked `SyncMode.ONGOING` in `repomatic/registry.py` (`lychee`, `typos`, `bumpversion`, `uv`). It never revisits a `mypy`, `pytest` or `coverage` section after the first write: `lint-repo` warns on each bundled template entry such a section lacks, to copy by hand or decline on purpose.
30
+ - **A `[tool.X]` section is never a candidate for deletion.** The inverse of the rule above, and the more expensive mistake. Every other tool has no `default_config`, so its resolution chain has no level 3 to fall back on: `lychee`, `typos`, `mypy`, `pytest`, `coverage`, `bumpversion` and `uv` are *deployed* into `pyproject.toml` by `repomatic init`, and that section is the only config the tool will ever see. Deleting it does not restore inheritance from a bundled default, it drops the tool to level 4 and runs it bare, silently discarding every rule the section held. Read the tool's `default_config` before proposing a section be dropped "to inherit upstream updates". Re-running `repomatic init` fixes a stale section only for the components marked `SyncMode.ONGOING` in `repomatic/registry.py` (`lychee`, `typos`, `bumpversion`, `uv`). It never revisits a `mypy`, `pytest` or `coverage` section after the first write: `lint-repo` warns on each bundled template entry such a section lacks, to copy by hand or to decline with a reason under `[tool.repomatic] lint-repo.declined`.
30
31
  - **Generator artifacts vs user error.** When local thin-callers diverge from upstream (e.g., extra `workflow_dispatch:`, missing `paths:`), the cause may be the **upstream generator**, not downstream tampering. Inspect `repomatic/github/workflow_sync.py` (`generate_thin_caller`, `_adapt_trigger_paths`, `generate_workflow_header`) before recommending the user re-run `repomatic init` to "fix" something `init` itself produced.
31
32
  - **Project-level `claude.md` may live under a sub-directory.** `[tool.repomatic] subagents.location` and `skills.location` indicate a project where `.claude/` is not at the root (e.g., dotfiles repos with `dotfiles/.claude/CLAUDE.md`). Search the configured location, not just `./CLAUDE.md`.
32
33
 
@@ -57,6 +58,21 @@ Keep the two axes apart in the report, because only one of them is actionable:
57
58
 
58
59
  ### 1. Workflow audit (`workflows`)
59
60
 
61
+ #### Ask the generator first
62
+
63
+ Before you compare a managed file by hand, run the adopted release's generator on a throwaway copy of `HEAD`:
64
+
65
+ ```shell-session
66
+ $ git worktree add --detach {scratch}/audit HEAD
67
+ $ uvx --no-progress --exclude-newer '1 week' --exclude-newer-package repomatic=P0D --directory {scratch}/audit 'repomatic==X.Y.Z' init
68
+ $ git -C {scratch}/audit diff
69
+ $ git worktree remove --force {scratch}/audit
70
+ ```
71
+
72
+ An empty diff means every thin caller, each header-only workflow header and each ongoing-sync `[tool.X]` section equals what that release generates. Any hunk is DRIFT that the sync would rewrite. Keep `--directory`: `--output-dir` alone writes into the copy but reads `[tool.repomatic]` from the directory the command started in.
73
+
74
+ The generator does not read hand-owned jobs, the comment beside a synced key, or an entry only the local file carries. Compare those yourself, in the sections below.
75
+
60
76
  #### Thin-caller workflows
61
77
 
62
78
  Compare each local thin-caller workflow against its reference. These should be identical (except for files listed in `exclude`). Flag:
@@ -106,7 +122,7 @@ Compare these files against the upstream reference. **Before flagging absence as
106
122
  | `.gitignore` | Must be a real file: git skips an in-tree `.gitignore` reached via symlink; otherwise content vs upstream | Auto-generated by repomatic; drift means the user should re-run sync. |
107
123
  | `pyproject.toml` `[tool.lychee]` | Note differences (usually project-specific, just flag for review); a root `lychee.toml` wins as native config | Project doesn't run lychee. |
108
124
 
109
- **Skip** files that are intentionally excluded via `exclude` in `[tool.repomatic]`. Cross-check `[tool.ruff] extend-exclude` and similar before flagging "missing" entries.
125
+ **Skip** files that are intentionally excluded via `exclude` in `[tool.repomatic]`, and settings declined under `lint-repo.declined`. Cross-check `[tool.ruff] extend-exclude` and similar before flagging "missing" entries.
110
126
 
111
127
  ### 3. Upstream contribution opportunities (`upstream`)
112
128
 
@@ -38,7 +38,9 @@ You help users understand and maintain their project's dependencies. This skill
38
38
 
39
39
  ### Mechanical layer
40
40
 
41
- The `_release-engine.yaml` workflow's `update-dep-graph` job regenerates the dependency graph on release commits only, to avoid noise from transitive dependency changes. This mode is useful for **interactive analysis** — understanding the graph, spotting concerns, or generating it before pushing.
41
+ The `autofix.yaml` workflow's `update-dep-graph` job regenerates the dependency graph on every push, for packages and uv virtual projects alike. This mode is useful for **interactive analysis** — understanding the graph, spotting concerns, or generating it before pushing.
42
+
43
+ With `[tool.repomatic] dependency-graph.update = false`, the `update-dep-graph` command exits without writing a graph, and the job opens no pull request. Tell the user so, and skip this mode.
42
44
 
43
45
  ### Argument handling
44
46
 
@@ -77,21 +79,27 @@ These conventions are derived from the `pyproject.toml` files across all `kdeldy
77
79
  1. **Use `>=` (not `~=` or `==`).** Relaxed lower bounds give packagers freedom to release security hotfixes without waiting for an upstream bump. Upper bounds are forbidden per [https://iscinumpy.dev/post/bound-version-constraints/](https://iscinumpy.dev/post/bound-version-constraints/).
78
80
  2. **Every version bound needs a comment tying the floor to a concrete code dependency.** The comment goes on the line above the dependency and states which feature, method, or API from that version the project actually uses. Prefer referencing the call site or module that depends on it:
79
81
  ```toml
80
- # wcmatch 10.0 changed globbing semantics; our sync_gitignore() relies on
81
- # the new symlink-aware matching behavior.
82
- "wcmatch>=10",
82
+ dependencies = [
83
+ # wcmatch 10.0 changed globbing semantics; our sync_gitignore() relies on
84
+ # the new symlink-aware matching behavior.
85
+ "wcmatch>=10",
86
+ ]
83
87
  ```
84
88
  A good floor comment answers: "if someone installed an older version, what would break and where?" If you cannot point to a concrete usage, the floor may be unnecessarily high.
85
89
  **A floor comment documents the floor as it stands, in one short paragraph.** It is not a record of how the floor got there. Left alone it drifts that way on its own: each bump appends a paragraph about the newly required version, nothing is deleted, and the comment becomes a private changelog of the dependency with the declared version buried under the floors it replaced. When raising a floor, **rewrite the comment rather than extending it**: keep what the new version buys (API, fix, `requires-python` alignment, the call site consuming it, a CVE or upstream issue identifier), delete every superseded floor (`git log -- pyproject.toml` keeps that history), and move out what is not about this floor (usage detail belongs in the module using it, a comparison against an alternative package in an `XXX` pointer to the upstream ticket). `lint-deps` warns past 40 words, which is the ceiling to write to even where it is not run.
86
90
  **Security fixes are also a valid floor bump reason.** A CVE or advisory in an older version justifies raising the floor even when the API is unchanged. The comment should cite the CVE or advisory:
87
91
  ```toml
88
- # requests 2.32.0 fixes CVE-2024-35195 (session credential leak on redirects).
89
- "requests>=2.32",
92
+ dependencies = [
93
+ # requests 2.32.0 fixes CVE-2024-35195 (session credential leak on redirects).
94
+ "requests>=2.32",
95
+ ]
90
96
  ```
91
- 3. **Python version support is not a valid reason to bump a floor.** The dependency resolver already picks the right version via `requires-python` metadata. If `boltons>=20` works and boltons 25 merely adds Python 3.13 support, keep `>=20` — the resolver handles it. **Exception:** when a dependency *drops* a Python version your project still supports (or your project drops one, aligning minimum `requires-python`), that alignment is a valid floor bump reason. The comment should state the version range alignment, not the Python support:
97
+ 3. **Python version support is not a valid reason to bump a floor.** The dependency resolver already picks the right version via `requires-python` metadata. If `mango>=2` works and mango 5 merely adds Python 3.13 support, keep `>=2` — the resolver handles it. **Exception:** when a dependency *drops* a Python version your project still supports (or your project drops one, aligning minimum `requires-python`), that alignment is a valid floor bump reason. The comment should state the version range alignment, not the Python support:
92
98
  ```toml
93
- # boltons 25.0.0 dropped Python 3.9, matching our requires-python >= 3.10.
94
- "boltons>=25",
99
+ dependencies = [
100
+ # coverage 7.11.0 dropped Python 3.9, matching our requires-python >= 3.10.
101
+ "coverage>=7.11",
102
+ ]
95
103
  ```
96
104
  4. **Use conditional markers for Python-version-gated deps.** Example: `"tomli>=2; python_version<'3.11'"`. When a dep has a version marker, the floor rationale must make sense for the Python versions where the dep is actually installed — not for versions excluded by the marker.
97
105
  5. **Alphabetical order** within the list.
@@ -120,6 +128,7 @@ Read the full `pyproject.toml`. `lint-deps` already reports the specifier style,
120
128
  | Stale comment | Comment references a reason that no longer applies (the cited method was replaced, or the Python version left the support matrix) |
121
129
  | Accreted comment | Comment narrates superseded floors beside the declared one. Rewrite it around the version in force; `lint-deps` catches only the long ones |
122
130
  | Inflated floor | Floor higher than the oldest version providing the APIs actually used (see [floor verification](#floor-verification) below) |
131
+ | Understated floor | Floor lower than the oldest version the code runs on (see [lowest-version check](#lowest-version-check) below) |
123
132
  | Marker/rationale mismatch | Floor rationale contradicts the conditional marker (e.g., "Python 3.14 wheels" on a dep gated by `python_version<'3.11'` — that dep is never installed on 3.14) |
124
133
  | Section style | `[project.optional-dependencies]` used where `[dependency-groups]` would be appropriate |
125
134
  | Conditional markers | Missing Python version marker for backport packages |
@@ -132,7 +141,19 @@ Comments and changelogs can lie; the codebase is the source of truth. For each d
132
141
  1. **Grep for imports.** Search the source tree for all imports from the package. List the specific APIs used (functions, classes, constants).
133
142
  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
143
  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
- 4. **Run `uv lock`** after any floor change to verify the lock still resolves.
144
+ 4. **Run `uv lock`** after any floor change to verify the lock still resolves. Run it with the uv version the workflows pin on their `setup-uv` steps, like `uvx --exclude-newer '1 week' --from 'uv==X.Y.Z' uv lock`: a newer local uv rewrites the lockfile `revision` and adds tables that CI never writes. After a floor raised in one dependency group only, add `--upgrade-package <pkg>`: a group with its own `requires-python` resolves as a separate fork, and a plain `uv lock` keeps the old pin in the other one.
145
+
146
+ #### Lowest-version check
147
+
148
+ A floor can also be too low: the code calls an API that the declared version lacks. The lockfile holds the newest release of each dependency, so no ordinary test run shows it, and the first to see it is a user on an old environment.
149
+
150
+ 1. **Resolve every direct dependency at its floor.** Run `uv pip compile pyproject.toml --resolution lowest-direct --exclude-newer '1 week' --python-version <floor>`, with the lowest Python the project supports. It prints the set and installs nothing.
151
+ 2. **Compare the output with the declared floors.** A package resolved above its floor is held there by another requirement, so no install can reach the declared version. Report it as **Info**, with the requirement that holds it.
152
+ 3. **Run the suite on the lowest set.** In a throwaway `git worktree`, `uv sync --resolution lowest-direct --all-extras --group test` installs it and `uv run --frozen -- pytest` tests it. The sync rewrites `uv.lock`, so keep it out of the main checkout. When the test matrix carries a `lowest-direct` cell, read its last CI result instead.
153
+ 4. **Probe what the suite cannot see.** Two cases pass the suite and still break a user. The test tooling can hold a dependency above its floor, as pytest does for `packaging`. A mocked client hides the library behind it. For each one, write a script that makes the call the code makes, and run it against the floor: `uv run --no-project --exclude-newer '1 week' --with '<pkg>==<floor>' python probe.py`.
154
+ 5. **Raise a floor that fails**, to the first release that passes. Name the failing call in the comment.
155
+
156
+ To test one floor alone, build an environment from the lockfile and swap that package in with `uv pip install --exclude-newer '1 week' --no-deps '<pkg>==<floor>'`. `uv run --with` resolves the package's own dependencies again, so a failure there can come from another package.
136
157
 
137
158
  #### Special cases
138
159
 
@@ -165,12 +186,12 @@ These comment patterns typically signal a floor set at adoption or auto-bump tim
165
186
 
166
187
  The `[tool.uv]` section may contain `exclude-newer-package` entries that exempt specific packages from the global `exclude-newer` cooldown window. They arrive from two places: written by hand (the package is published by the same maintainer, or is developed in-repo), or written by `audit --fix`, which reaches a CVE fix still inside the window through an entry rather than lifting `exclude-newer` for the whole tree.
167
188
 
168
- **Expiry is mechanical, so do not audit for it.** `sync-uv-lock` owns the lifecycle of every entry and reports each move in its PR body: it rewrites a relative span (`"0 day"`) into a fixed cutoff pinned to the locked version's upload time, which *holds* the package instead of letting it track latest, then prunes the entry outright once that held version ages past the global cooldown and the package rejoins normal resolution. A live fixed cutoff is therefore a freeze doing its job, not a leftover: proposing its deletion un-holds a package the freeze was deliberately pinning. A surviving relative span means the freeze has not run yet, not that a span is the steady state.
189
+ **Expiry is mechanical, so do not audit for it.** `sync-uv-lock` owns the lifecycle of every entry and reports each move in its PR body: it rewrites a relative span (`"0 day"`) into a fixed cutoff pinned to the locked version's upload time, which *holds* the package instead of letting it track latest, then prunes the entry outright once that held version ages past the global cooldown and the package rejoins normal resolution. A live fixed cutoff is therefore a freeze doing its job, not a leftover: proposing its deletion un-holds a package the freeze was deliberately pinning. A surviving relative span means the freeze has not run yet, except on a package with no upload time in the lockfile: one consumed from a git or path source, or one the lockfile does not hold. That span stays as written.
169
190
 
170
191
  What is left for this audit is the part no schedule settles:
171
192
 
172
- 1. **Is the package still a dependency?** If it was removed from `[project].dependencies` and all `[dependency-groups]`, the entry is dead weight that no prune will ever reach, since pruning keys off the locked version's age and the package is no longer in the lock.
173
- 2. **Is a hand-written exemption still justified?** A same-maintainer or in-repo package keeps its span indefinitely and correctly. An external package exempted during a migration that has since finished no longer needs one.
193
+ 1. **Is the package still a dependency?** If it was removed from `[project].dependencies` and all `[dependency-groups]`, a relative span on it is dead weight that no prune will ever reach. A fixed cutoff needs no audit there: `sync-uv-lock` prunes it once the cooldown window has passed the cutoff itself.
194
+ 2. **Is a hand-written exemption still justified?** A package consumed from a git or path source keeps its span indefinitely and correctly. A same-maintainer package on an index does not: its entry admits one release, and is written again for the next one that must not wait. An external package exempted during a migration that has since finished no longer needs one.
174
195
  3. **Does the comment explain the reason?** Like version floors, a hand-written exemption should carry a comment naming why the cooldown does not apply to it.
175
196
 
176
197
  Flag those as warnings. Never flag an entry merely for existing or for looking old.
@@ -188,10 +209,10 @@ Produce:
188
209
 
189
210
  1. **Policy compliance summary**: A table with one row per dependency: name, specifier, has comment (yes/no), issues found.
190
211
  2. **Grouped findings** by severity:
191
- - **Errors**: Wrong specifier style, missing version, upper bounds.
212
+ - **Errors**: Wrong specifier style, missing version, upper bounds, understated floors.
192
213
  - **Warnings**: Missing or stale comments, ordering issues, inflated floors, marker/rationale mismatches.
193
- - **Info**: Suggestions for floor adjustments based on API verification or cross-repo data.
194
- 3. **Suggested fixes**: For each error/warning, show the current line and the recommended replacement. For inflated floors, include the verified API minimum and a rewritten comment.
214
+ - **Info**: Suggestions for floor adjustments based on API verification or cross-repo data, and floors that no install can reach.
215
+ 3. **Suggested fixes**: For each error/warning, show the current line and the recommended replacement. For inflated floors, include the verified API minimum and a rewritten comment. For understated floors, include the failing call and the first release that passes.
195
216
 
196
217
  ---
197
218
 
@@ -279,7 +300,7 @@ Common false-positive patterns to reject early:
279
300
 
280
301
  1. **Find the version deltas.** Determine which dependencies changed, and from and to which version, cheapest source first:
281
302
 
282
- - The most recent `sync-uv-lock` PR — its body lists every bump with its old and new version and a changelog or compare link per package. Find it with `gh pr list --search 'head:sync-uv-lock' --state all --limit 1`, then `gh pr view <number> --json body`.
303
+ - The most recent `sync-uv-lock` PR — its body lists every bump with its old and new version and a changelog or compare link per package. Find it with `gh pr list --search 'head:sync-uv-lock' --state all --limit 1`, then `gh pr view <number> --json body`. That body covers one sync only: when several merged since the last release tag, diff the lockfile against the tag to get the whole range.
283
304
  - Failing that, find the last release tag (`git tag --sort=-v:refname | head -1`) and diff the lockfile against it (`git diff <tag> -- uv.lock`), reading the version pairs.
284
305
  - For a single named package, read its locked version and the `pyproject.toml` floor.
285
306
 
@@ -38,4 +38,3 @@ You help users bootstrap a repository to use the reusable GitHub Actions workflo
38
38
  Suggest the user run:
39
39
 
40
40
  - `/repomatic-audit` to check the generated files against upstream conventions.
41
- - After pushing, the `autofix.yaml` and `lint.yaml` workflows keep the workflow callers synced and validated automatically.