repomatic 7.16.2__tar.gz → 7.17.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.
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/.claude-plugin/plugin.json +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/agents/qa-engineer.md +1 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/agents/sphinx-docs.md +7 -4
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/awesome-triage/SKILL.md +17 -4
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/babysit-ci/SKILL.md +18 -94
- repomatic-7.17.0/.claude/skills/babysit-ci/references/failure-patterns.md +92 -0
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/file-bug-report/SKILL.md +26 -0
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/repomatic-audit/SKILL.md +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/repomatic-deps/SKILL.md +2 -2
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/repomatic-ship/SKILL.md +92 -113
- repomatic-7.17.0/.claude/skills/repomatic-ship/references/findings-in-repomatic.md +14 -0
- repomatic-7.17.0/.claude/skills/repomatic-ship/references/short-ship.md +15 -0
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/sphinx-docs-sync/SKILL.md +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude-plugin/marketplace.json +2 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/actions/publish-pypi/action.yaml +2 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/workflows/_release-build.yaml +13 -13
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/workflows/_release-engine.yaml +48 -56
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/workflows/autofix.yaml +86 -79
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/autolock.yaml +4 -4
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/cancel-runs.yaml +4 -4
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/changelog.yaml +24 -24
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/debug.yaml +7 -7
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/workflows/docs.yaml +53 -29
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/labels.yaml +13 -13
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/lint.yaml +34 -27
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/metrics.yaml +5 -5
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/release.yaml +4 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/workflows/self-maintenance.yaml +5 -5
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/workflows/tests.yaml +13 -11
- {repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.github/workflows}/unsubscribe.yaml +4 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/.gitignore +3 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/PKG-INFO +4 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/changelog.md +57 -0
- repomatic-7.17.0/claude.md +140 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/binaries.csv +12 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/config-snippet-screen.svg +2 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/dependencies.mmd +31 -7
- repomatic-7.17.0/docs/assets/help-dark-screen.svg +31 -0
- repomatic-7.17.0/docs/assets/help-light-screen.svg +31 -0
- repomatic-7.17.0/docs/assets/matrix-grid-screen.svg +27 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/metrics.csv +1698 -1674
- repomatic-7.17.0/docs/assets/star-history-compared.svg +102 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/star-history.svg +13 -13
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/virustotal-scans.csv +11 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/binaries.md +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/claude-code-plugin.md +22 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/cloudflare.md +53 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/conf.py +7 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/configuration.md +5 -1
- repomatic-7.17.0/docs/contributing.md +7 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/docs_update.py +3 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/install.md +14 -14
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/operation-contracts.md +19 -5
- repomatic-7.17.0/docs/repomatic.cloudflare_r2.md +8 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.md +1 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/security.md +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/test-matrix.md +8 -8
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.md +2 -0
- repomatic-7.17.0/docs/tests.test_cloudflare_r2.md +8 -0
- repomatic-7.17.0/docs/tests.test_plugin_update_detection.md +8 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/upstream-development.md +4 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/workflows.md +20 -13
- {repomatic-7.16.2 → repomatic-7.17.0}/pyproject.toml +7 -7
- {repomatic-7.16.2 → repomatic-7.17.0}/pyproject.toml.orig +26 -24
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/__init__.py +2 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/awesome_toc.py +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/changelog.py +17 -14
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/github.py +4 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/lint.py +119 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/main.py +10 -13
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/release.py +34 -1
- repomatic-7.17.0/repomatic/cloudflare_r2.py +713 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/config.py +53 -8
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/_release-engine.yaml +48 -56
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/action-publish-pypi.yaml +2 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/agent-qa-engineer.md +1 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/agent-sphinx-docs.md +7 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/autofix.yaml +86 -79
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/autolock.yaml +4 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/contributing.md +2 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/contributing.zh.md +2 -0
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/cancel-runs.yaml +4 -4
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/changelog.yaml +24 -24
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/debug.yaml +7 -7
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/docs.yaml +53 -29
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/labels.yaml +13 -13
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/lint.yaml +34 -27
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/lychee.toml +5 -0
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/metrics.yaml +5 -5
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/release.yaml +4 -4
- {repomatic-7.16.2/.claude → repomatic-7.17.0/repomatic/data}/skills/awesome-triage/SKILL.md +17 -4
- {repomatic-7.16.2/.claude → repomatic-7.17.0/repomatic/data}/skills/babysit-ci/SKILL.md +18 -94
- repomatic-7.17.0/repomatic/data/skills/babysit-ci/references/failure-patterns.md +92 -0
- {repomatic-7.16.2/.claude → repomatic-7.17.0/repomatic/data}/skills/file-bug-report/SKILL.md +26 -0
- {repomatic-7.16.2/.claude → repomatic-7.17.0/repomatic/data}/skills/repomatic-audit/SKILL.md +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/repomatic-deps/SKILL.md +2 -2
- {repomatic-7.16.2/.claude → repomatic-7.17.0/repomatic/data}/skills/repomatic-ship/SKILL.md +92 -113
- repomatic-7.17.0/repomatic/data/skills/repomatic-ship/references/findings-in-repomatic.md +14 -0
- repomatic-7.17.0/repomatic/data/skills/repomatic-ship/references/short-ship.md +15 -0
- {repomatic-7.16.2/.claude → repomatic-7.17.0/repomatic/data}/skills/sphinx-docs-sync/SKILL.md +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/tests.yaml +13 -11
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/typos.toml +1 -1
- {repomatic-7.16.2/.github/workflows → repomatic-7.17.0/repomatic/data}/unsubscribe.yaml +4 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/uv.toml +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/zizmor.yaml +2 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/dep_sources.py +7 -5
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/uv.py +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/docs.py +113 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/git_ops.py +3 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/actions.py +3 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/ci_status.py +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/dev_release.py +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/gh.py +3 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/workflow_sync.py +13 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/init_project.py +2 -5
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/labels.py +12 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/lint_repo.py +365 -12
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/matrix_axes.py +9 -13
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metric_chart.py +9 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metrics.py +22 -5
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/registry.py +33 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/binaries_page.py +8 -8
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/prepare_release.py +12 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/version_sync.py +1 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/virustotal.py +57 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/runner_images.py +2 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/setup_guide.py +24 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/site_anchors.py +21 -6
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/sync_ops.py +6 -6
- repomatic-7.17.0/repomatic/templates/setup-guide-cloudflare-r2.md +24 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide.md +3 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/tooling/plugin.py +12 -7
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/tooling/tool_registry.py +32 -79
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/tooling/tool_runner.py +15 -5
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/cli-test-suite.toml +6 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/conftest.py +78 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_changelog.py +30 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_claude_assets.py +203 -34
- repomatic-7.17.0/tests/test_cloudflare_r2.py +612 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_config.py +44 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_docs.py +127 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_init_project.py +60 -17
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_labels.py +42 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_lint_repo.py +295 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_metadata.py +1 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_metrics.py +5 -2
- repomatic-7.17.0/tests/test_plugin_update_detection.py +218 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_pr_body.py +3 -24
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_prepare_release.py +1 -2
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_setup_guide.py +49 -4
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_site_anchors.py +7 -5
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_skills.py +4 -1
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_suite_hygiene.py +2 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_sync_ops.py +5 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_tool_runner.py +50 -12
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_version_sync.py +211 -210
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_virustotal.py +107 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_workflow_sync.py +4 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_workflows.py +42 -3
- {repomatic-7.16.2 → repomatic-7.17.0}/uv.lock +605 -554
- repomatic-7.16.2/claude.md +0 -111
- repomatic-7.16.2/docs/assets/help-dark-screen.svg +0 -31
- repomatic-7.16.2/docs/assets/help-light-screen.svg +0 -31
- repomatic-7.16.2/docs/assets/matrix-grid-screen.svg +0 -27
- repomatic-7.16.2/docs/assets/star-history-compared.svg +0 -102
- repomatic-7.16.2/docs/contributing.md +0 -7
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/agents/grunt-qa.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/av-false-positive/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/benchmark-update/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/brand-assets/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/github-housekeeping/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/probe-workflow/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/repomatic-changelog/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/repomatic-init/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/repomatic-test-matrix/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/repomatic-topics/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/repomatic-upgrade/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/translation-sync/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.claude/skills/upstream-audit/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/code-of-conduct.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.github/funding.yml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/.mailmap +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/404.html +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/_redirects +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/_static/custom.css +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/agent-skills.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/banner-social-dark.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/banner-social-light.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/banner-social.svg +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/desktop-autosync-warning.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/desktop-plugin-agents.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/desktop-plugin-contents.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/desktop-plugin-skills.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/favicon.svg +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/icon.icns +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/icon.ico +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/icon.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/logo-banner-dark.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/logo-banner-light.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/logo-banner.svg +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/logo-square-dark.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/logo-square-light.png +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/logo-square.svg +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/assets/sync-deps-trail-screen.svg +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/benchmark.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/changelog-archive.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/changelog.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/cli.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/code-of-conduct.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/commit-messages.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/dependencies.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/history.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/index.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/license.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/man.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/nuitka.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/packaging.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.awesome_toc.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.broken_links.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cache.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.changelog.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.github.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.lint.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.main.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.release.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.sample.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.setup.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cli.sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.cloudflare.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.compat.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.config.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.data.awesome_template.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.data.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.dep_graph.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.dep_policy.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.dep_report.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.dep_sources.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.uv.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.deps.vulnerable_deps.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.docs.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.file_inventory.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.file_ops.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.forge.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.frontmatter.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.git_ops.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.actions.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.ci_status.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.dev_release.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.gh.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.issue.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.job_timings.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.matrix.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.pr.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.pr_body.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.release_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.releases.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.sponsor.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.status.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.token.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.unsubscribe.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.github.workflow_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.gitignore.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.hashing.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.http.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.humanize.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.images.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.init_project.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.labels.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.lint_repo.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.mailmap.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.matrix_axes.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metadata.core.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metadata.env.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metadata.git.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metadata.matrix.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metadata.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metadata.project.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metric_chart.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.metrics.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.npm.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.pages_redirects.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.pypi.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.pyproject.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.registry.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.attestation.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.binaries_page.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.binary.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.checksums.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.prepare_release.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.version_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.release.virustotal.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.runner_catalog.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.runner_images.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.setup_guide.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.site_anchors.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.sync_ops.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.tabular.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.templates.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.tooling.bundle.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.tooling.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.tooling.plugin.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.tooling.tool_registry.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.tooling.tool_runner.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/repomatic.versions.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/robots.txt +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/subagents.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.conftest.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_actions.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_attestation.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_awesome_template.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_awesome_toc.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_binaries_page.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_binary.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_broken_links.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_cache.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_changelog.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_checksums.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_ci_status.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_claude_assets.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_cloudflare.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_config.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_dep_graph.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_dep_policy.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_dep_report.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_dep_sources.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_dev_release.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_docs.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_docstrings.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_forge.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_frontmatter.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_gh.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_git_ops.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_gitignore.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_hashing.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_help.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_http.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_humanize.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_images.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_imports.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_init_project.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_issue.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_job_timings.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_labels.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_lint_repo.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_mailmap.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_matrix.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_metadata.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_metrics.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_npm.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_pages_redirects.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_platform_keys.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_plugin.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_pr.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_pr_body.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_prepare_release.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_pypi.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_pyproject.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_readme.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_release_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_releases.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_runner_catalog.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_runner_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_setup_guide.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_site_anchors.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_skills.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_sphinx_crossrefs.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_status.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_suite_hygiene.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_sync_ops.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_tabular.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_todolist.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_tool_runner.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_unsubscribe.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_uv.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_version_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_versions.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_virustotal.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_vulnerable_deps.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_workflow_sync.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tests.test_workflows.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/todolist.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/docs/tool-runner.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/license +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/readme.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/__main__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/broken_links.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cache.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/sample.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/setup.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cli/sync.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/cloudflare.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/compat.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/actionlint.yaml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/agent-grunt-qa.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/ISSUE_TEMPLATE/new-link.yaml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/code-of-conduct.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/funding.yml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/.github/pull_request_template.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/awesome_template/license +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/bumpversion.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/coverage.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/labels.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/mdformat.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/mypy.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/pytest.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/ruff.toml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/av-false-positive/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/benchmark-update/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/brand-assets/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/github-housekeeping/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/probe-workflow/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/repomatic-changelog/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/repomatic-init/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/repomatic-test-matrix/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/repomatic-topics/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/repomatic-upgrade/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/translation-sync/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/skills/upstream-audit/SKILL.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/vt-trend-chart.js +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/data/yamllint.yaml +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/dep_graph.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/dep_policy.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/dep_report.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/deps/vulnerable_deps.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/file_inventory.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/file_ops.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/forge.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/frontmatter.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/issue.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/job_timings.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/matrix.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/pr.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/pr_body.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/release_sync.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/releases.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/sponsor.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/status.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/token.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/github/unsubscribe.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/gitignore.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/hashing.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/http.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/humanize.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/images.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/mailmap.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metadata/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metadata/core.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metadata/env.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metadata/git.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metadata/matrix.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/metadata/project.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/npm.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/pages_redirects.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/py.typed +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/pypi.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/pyproject.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/attestation.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/binary.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/release/checksums.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/runner_catalog.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/tabular.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/available-admonition.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/broken-links-issue.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/bump-version.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/detect-squash-merge.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/development-warning.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/fix-changelog.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/fix-typos.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/fix-vulnerable-deps.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/format-images.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/format-json.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/format-markdown.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/format-pyproject.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/format-python.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/format-shell.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/generated-footer.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/github-releases.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/immutable-releases.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/pr-metadata.md.noformat +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/prepare-release.md.noformat +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/refresh-tip.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/release-notes.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/release-sync-report.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sample-metrics.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/scan-virustotal.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-branch-ruleset.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-cloudflare-pages.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-dependabot.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-fork-pr-approval.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-notifications-pat.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-pages-source.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-pypi-trusted-publisher.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-sha-pinning-required.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-token.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-verify.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/setup-guide-virustotal.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-action-pins.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-bumpversion.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-dep-sources.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-gitignore.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-mailmap.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-repomatic-upgrade.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-repomatic.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-runner-images.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-tool-versions.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-uv-lock.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/sync-workflow-pins.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/unavailable-admonition.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/unsubscribe-phase1.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/unsubscribe-phase2.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/update-dep-graph.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/update-docs.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/upgrade-invite.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/templates/yanked-admonition.md +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/tooling/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/tooling/bundle.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/repomatic/versions.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/__init__.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_actions.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_attestation.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_awesome_template.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_awesome_toc.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_binaries_page.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_binary.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_broken_links.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_cache.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_checksums.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_ci_status.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_cloudflare.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_dep_graph.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_dep_policy.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_dep_report.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_dep_sources.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_dev_release.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_docstrings.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_forge.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_frontmatter.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_gh.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_git_ops.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_gitignore.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_hashing.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_help.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_http.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_humanize.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_images.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_imports.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_issue.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_job_timings.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_mailmap.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_matrix.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_npm.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_pages_redirects.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_platform_keys.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_plugin.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_pr.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_pypi.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_pyproject.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_readme.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_release_sync.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_releases.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_runner_catalog.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_runner_sync.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_sphinx_crossrefs.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_status.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_tabular.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_todolist.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_unsubscribe.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_uv.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_versions.py +0 -0
- {repomatic-7.16.2 → repomatic-7.17.0}/tests/test_vulnerable_deps.py +0 -0
|
@@ -42,6 +42,7 @@ Question overly verbose prose in `CLAUDE.md` and `.claude/agents/*.md`:
|
|
|
42
42
|
- Redundant examples or restated rules — cut them
|
|
43
43
|
- **Discoverable content** — cut it. Structural inventories, code examples copied from source files, and general programming knowledge do not belong in `CLAUDE.md`.
|
|
44
44
|
- **Misplaced knowledge** — move it to the audience that owns it. Lengthy "why" explanations in YAML workflows belong in Python docstrings; YAML gets a brief "what" + pointer. End-user setup details belong in `setup-guide.md`, not `readme.md`.
|
|
45
|
+
- **Code-anchored rules** — move them beside the code. A rule in `CLAUDE.md` whose subject is one function, test, workflow, setting or page belongs in that docstring or comment, where it cannot drift unseen. Compare the two first: delete the rule when the code already states it, and read the code when they disagree. `CLAUDE.md` keeps a one-line pointer.
|
|
45
46
|
|
|
46
47
|
Prefer mechanical enforcement over prose. If a rule can be a test, autofix job, or lint check — implement it instead of writing it down.
|
|
47
48
|
|
|
@@ -267,6 +267,7 @@ Cross-references that survive renames:
|
|
|
267
267
|
|
|
268
268
|
- Always cross-reference external projects through `intersphinx_mapping` and a `{role}` ref, not a bare URL. A renamed function in click-extra surfaces as a Sphinx build error; a bare URL silently 404s in the rendered HTML.
|
|
269
269
|
- For headings, prefer the auto-generated docutils anchor (e.g., `### option.name` → `option-name`). Add an explicit `(my-anchor)=` only when the natural anchor isn't unique or the target isn't a heading.
|
|
270
|
+
- **Qualify a reference that sits in a base-class docstring.** autodoc repeats the docstring of a base-class attribute on each subclass that overrides the attribute. A short `` {attr}`name` `` then resolves against the subclass, and fails for a member the subclass does not define itself. Write the full dotted target.
|
|
270
271
|
|
|
271
272
|
## Inline syntax highlighting in prose
|
|
272
273
|
|
|
@@ -584,13 +585,13 @@ User-facing pages, and when a project carries one:
|
|
|
584
585
|
|
|
585
586
|
Agent tooling toctree, in this order. Drop the whole block when the project ships none of them. Name each page for what it is portable to: skills follow a cross-vendor specification, subagents follow the component that ships them, and only the plugin, which no vendor-neutral format covers, keeps a Claude Code name.
|
|
586
587
|
|
|
587
|
-
1. `agent-skills` — Only when the project ships Agent Skills (see
|
|
588
|
+
1. `agent-skills` — Only when the project ships Agent Skills (see "Skills and subagents pages" below).
|
|
588
589
|
2. `subagents` — Only when the project ships subagent definitions.
|
|
589
590
|
3. `claude-code-plugin` — Only when those skills and subagents are also published as an installable Claude Code plugin. Both distribution paths coexist, so the page covers the marketplace install, what the archive ships, and how to wire it into a repository.
|
|
590
591
|
|
|
591
592
|
Maintainer-facing pages, and when a project carries one:
|
|
592
593
|
|
|
593
|
-
01. `contributing` — Setup, dev loop, code-style pointers (or `{include} ../contributing.md` if the root file already exists).
|
|
594
|
+
01. `contributing` — Setup, dev loop, code-style pointers (or `{include} ../contributing.md` if the root file already exists). The one home of developer setup: `readme.md` and `claude.md` link to it.
|
|
594
595
|
02. `commit-messages` — Only when automation reads or writes the project's commit subjects, which makes the subject a shared namespace rather than free text: the reserved-prefix rules, who else parses a message, and how to write a subject and body.
|
|
595
596
|
03. `upstream-development` — Project-internal release process. Mark `(upstream maintainers only)` in the page heading so readers know this is not for consumers.
|
|
596
597
|
04. `operation-contracts` — Optional, for projects with formal automated-operation contracts.
|
|
@@ -762,6 +763,8 @@ Default-pruning rule:
|
|
|
762
763
|
- If you keep a setting that *looks* default for documentation purposes, add a one-line comment explaining why ("explicit so future readers see we considered it").
|
|
763
764
|
- On every Sphinx or extension upgrade, run `sphinx-build -W -b html docs docs/_build/html`. Treat every `RemovedInSphinxX.YWarning`, `DeprecationWarning`, and `application.ExtensionError` as cleanup work, not noise. Fix them in the same PR as the upgrade.
|
|
764
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
|
+
- **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
|
+
- **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.
|
|
765
768
|
- Periodically diff against a fresh `sphinx-quickstart` output in a tmpdir to spot defaults that have shifted under you.
|
|
766
769
|
- 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.
|
|
767
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.
|
|
@@ -856,7 +859,7 @@ When you receive a new "rule" about how to write or maintain docs, ask where it
|
|
|
856
859
|
- A pattern only the upstream package itself uses (e.g., `docs/docs_update.py` internals, release-only artifacts) → `docs/upstream-development.md`.
|
|
857
860
|
- A pattern downstream Sphinx repos benefit from → this agent definition.
|
|
858
861
|
|
|
859
|
-
|
|
862
|
+
State a rule that belongs here inline, never as a pointer to a `claude.md` section. This file ships to repositories that do not receive repomatic's `claude.md`.
|
|
860
863
|
|
|
861
864
|
When a user-driven instruction explicitly conflicts with a `claude.md` or global tropes rule (e.g., the install.md compatibility-matrix range labels use a `→` arrow, which conflicts with the global `Unicode Decoration` anti-pattern), the explicit instruction takes precedence. Note the conflict in your reply so the user can confirm or override, but apply the instruction.
|
|
862
865
|
|
|
@@ -881,7 +884,7 @@ Watch for these every pass:
|
|
|
881
884
|
- A `{toctree}` that outgrew the ~12-entry threshold and is still flat, or a captioned section left holding a single entry after pages moved around it. See § Grouping pages into sidebar sections.
|
|
882
885
|
- 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.
|
|
883
886
|
- 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.
|
|
884
|
-
-
|
|
887
|
+
- 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.
|
|
885
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.
|
|
886
889
|
- `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.
|
|
887
890
|
- `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.
|
|
@@ -78,7 +78,7 @@ See also §9 for contributor and repo provenance signals — these often reinfor
|
|
|
78
78
|
- Self-promotion is allowed but must be disclosed. Undisclosed affiliation is a trust signal.
|
|
79
79
|
- Author submissions get more scrutiny on the "marketing vs. genuine content" axis but are not automatically penalized. Many accepted PRs across all four lists are author self-submissions.
|
|
80
80
|
- For commercial content, apply `contributing.md` FAQ "Why my commercial project is not in the list?": prefer open-source repository links over commercial landing pages.
|
|
81
|
-
- When a commercial brand or vendor sits behind the submission (product site, paid SaaS, or a lead-gen funnel pointing at a commercial domain), record the exact brand and domain. A declined commercial submission must close its comment with the sponsorship
|
|
81
|
+
- When a commercial brand or vendor sits behind the submission (product site, paid SaaS, or a lead-gen funnel pointing at a commercial domain), record the exact brand and domain in the triage analysis. A declined commercial or self-promotional submission must close its comment with the fixed sponsorship phrase: see § Drafting comments.
|
|
82
82
|
|
|
83
83
|
#### 7. Formatting and editorial compliance
|
|
84
84
|
|
|
@@ -89,6 +89,8 @@ Check the diff (for PRs) against `contributing.md` §§ Formatting and Editorial
|
|
|
89
89
|
- **Launched and functional**: The product or article must exist and be accessible.
|
|
90
90
|
- **Maintained**: For GitHub repos, check if the project is archived, when the last commit was. Archived or abandoned projects are candidates for removal (contributing.md FAQ "Why removes inactive GitHub projects?"). Check for forks or reboots before recommending deletion.
|
|
91
91
|
- **Generic, not product-specific**: Articles applicable to only one product are not generic enough for inclusion (contributing.md "Why my link was rejected?").
|
|
92
|
+
- **Original, not a rehash of its own sources**: Trace the candidate to its primary source before scoring it. Look for a republication notice ("Originally published at ..."), then diff the body against whatever it links under "further reading" or references. A page that paraphrases Wikipedia row by row without citing it adds an unstable hop and no data: prefer the primary source, and write the software framing into the description yourself, which `contributing.md` section Formatting licenses as "smart editorializing". Same test picks the canonical URL: the author's own domain beats a syndication, an aggregator or a mirror.
|
|
93
|
+
- **Verify every row of a small factual table, not one**: A spot-check that passes says nothing about the rows beside it. Eight rows cost one fetch of the source to check in full, and one stale row can invalidate the system-impact claim built on it. A triage that scored this check PASS on a single verified row missed both a stale postal-code claim and that the whole table was unattributed Wikipedia paraphrase.
|
|
92
94
|
|
|
93
95
|
#### 9. Contributor and repo provenance
|
|
94
96
|
|
|
@@ -134,24 +136,35 @@ After running all checks, provide one of:
|
|
|
134
136
|
- **REJECT**: Fails one or more hard criteria (duplicate, AI slop, not launched, paywalled, no value-add, section saturation, competitive context mismatch). Draft a rejection comment.
|
|
135
137
|
- **NEEDS DISCUSSION**: Borderline case where maintainer judgment is required. Summarize the arguments for and against.
|
|
136
138
|
|
|
137
|
-
After the verdict, propose 2-3 short, ready-to-post comments
|
|
139
|
+
After the verdict, propose 2-3 short, ready-to-post comments that the maintainer can copy-paste to explain the decision to the author. Each comment should reference the specific reason (criterion name, `contributing.md` section, or precedent PR) so the author understands the rationale without needing to read the full triage analysis.
|
|
140
|
+
|
|
141
|
+
**Order them shortest first.** The maintainer usually posts the first one and nothing else. The default is a tight, single-topic comment: name the one blocker that decides the case, cite it, stop. Longer variants that stack several criteria, quote the contributor's own history, or enumerate every failing check go last, and only when a criterion is genuinely contested. A rejection needs one reason stated well, not five stated thinly.
|
|
138
142
|
|
|
139
143
|
### Drafting comments
|
|
140
144
|
|
|
141
145
|
When drafting a rejection or request-for-changes comment:
|
|
142
146
|
|
|
143
147
|
- Be specific about which criteria were not met.
|
|
148
|
+
|
|
144
149
|
- Reference `contributing.md` sections where applicable.
|
|
150
|
+
|
|
145
151
|
- Stay polite and constructive. Contributors may improve and resubmit.
|
|
152
|
+
|
|
146
153
|
- For AI slop: keep it brief. State the specific tells (e.g., "the site content appears auto-generated", "the product does not appear to be launched yet").
|
|
154
|
+
|
|
147
155
|
- When a section is saturated, suggest the contributor identify weaker existing entries that could be replaced, turning an addition into a curation improvement.
|
|
148
|
-
|
|
156
|
+
|
|
157
|
+
- **Always close a declined commercial or self-promotional submission with this exact phrase, verbatim, as the last line of the comment**, whether or not the affiliation was disclosed:
|
|
158
|
+
|
|
159
|
+
> If you want to promote your product, you can purchase a sponsorship to this repository: https://github.com/sponsors/kdeldycke
|
|
160
|
+
|
|
161
|
+
Do not substitute the brand or domain into it, do not reword it, and do not backtick the product name inside it. The phrase is generic on purpose: it reads the same to every contributor, it never argues about whether the submission was commercial, and it survives being copied across the four lists unchanged. This mirrors `contributing.md` FAQ "How can I force a link into the list?", which is the paid path around the curation rules. Record the brand and domain in the triage analysis instead, where the maintainer can see them and the contributor cannot.
|
|
149
162
|
|
|
150
163
|
### Broken link triage
|
|
151
164
|
|
|
152
165
|
For issues reporting broken links (typically automated by the lychee link checker):
|
|
153
166
|
|
|
154
|
-
- **403 from
|
|
167
|
+
- **403 from a crawler-blocked domain** (Medium, Substack): not a dead link when a browser still gets the full article. Keep the URL and add the domain to `[tool.lychee] exclude` in `pyproject.toml`, per `contributing.md` § URL. The `[tool.lychee]` template that repomatic syncs already excludes `medium.com`.
|
|
155
168
|
- **404 confirmed dead**: Replace with archive.org/archive.ph/sci-hub.st per `contributing.md` § URL. Replacing a broken URL is maintenance; removing the entry is a curation decision.
|
|
156
169
|
- **Archived GitHub repos**: Check for forks or reboots. If none exist and the section has other entries covering the same ground, the entry can be removed. Leave the door open for re-inclusion if the project revives.
|
|
157
170
|
|
|
@@ -80,7 +80,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
80
80
|
|
|
81
81
|
One call returns every workflow triggered by that commit. Do not reach for `gh run list`: both its branch-wide form and its per-workflow form have put runs weeks old at the top of the list, on a repository whose workflows had in fact run on every recent commit, which reads as "this workflow has not run in a month". Give `head_sha` the **full** 40-character SHA, because an abbreviated one matches nothing and returns an empty list that looks identical to "nothing ran". Quote the whole path: zsh expands the `?` as a glob and kills the call with `no matches found` before `gh` runs. To list a single workflow across a branch instead, use `gh api 'repos/<OWNER>/<REPO>/actions/workflows/<file>/runs?branch=<BRANCH>&created=>=<DATE>'`, and keep the date filter: without it, that endpoint has returned a page twelve days stale while the branch ran every hour.
|
|
82
82
|
|
|
83
|
-
Track all five run IDs (`docs.yaml` may have none: its `paths:` filter skips pushes touching nothing docs-relevant). An empty run list for the *other* workflows is not paths-filtering: GitHub can sit on a push event for hours before materializing any run (a 4-hour lag has been observed), so when a freshly pushed SHA shows no runs, keep re-polling instead of concluding the push was filtered, and measure the wait from run creation, not from the push. The `tests.yaml` run exercises the full test matrix; `lint.yaml` runs mypy on every tracked Python file and lints YAML; `autofix.yaml` runs the mechanical fix jobs (`format-*`, `sync-*`, `fix-typos`, `fix-vulnerable-deps`) and turns red when one *crashes* instead of committing a fix; `docs.yaml` builds and deploys the Sphinx site and runs the broken-links check (an externally cancelled or link-flaky run re-runs cleanly via `gh workflow run docs.yaml --ref <BRANCH>`, no commit needed); `release.yaml` runs the Nuitka binary matrix (dev binaries: an ordinary push rebuilds only the `[tool.repomatic] nuitka.dev-targets` canary subset, while release commits, the weekly `schedule` and `workflow_dispatch` build the full target fleet) — but only on projects with `[tool.repomatic] nuitka.enabled` and a CLI entry point; with Nuitka disabled the per-platform jobs skip on every push, release commits included, and a green `release.yaml` means package build plus dev pre-release sync only. Even with Nuitka enabled, a single push can still skip the matrix: `Metadata.skip_binary_build` (`repomatic/metadata/git.py`) is the authoritative signal, true when the head commit is on a non-code branch, is a user-initiated version-bump commit, or (the common case) its changed files fall entirely outside `Metadata.binary_affecting_paths` — a docs-only or workflow-only commit, say. Don't infer the reason from the commit message or assume an unrendered/skipped matrix job name means `nuitka_matrix` itself was empty: the matrix data can be fully populated for that exact commit (verify via the `release / 🧬 Project metadata` job's logged `metadata=` JSON output) while the workflow still elects not to build it. Check `skip_binary_build`'s three conditions before asserting why a matrix skipped, since any one of them is enough on its own. All five workflows must pass — see § Autofix job failures and § Nuitka binary build failures
|
|
83
|
+
Track all five run IDs (`docs.yaml` may have none: its `paths:` filter skips pushes touching nothing docs-relevant). An empty run list for the *other* workflows is not paths-filtering: GitHub can sit on a push event for hours before materializing any run (a 4-hour lag has been observed), so when a freshly pushed SHA shows no runs, keep re-polling instead of concluding the push was filtered, and measure the wait from run creation, not from the push. The `tests.yaml` run exercises the full test matrix; `lint.yaml` runs mypy on every tracked Python file and lints YAML; `autofix.yaml` runs the mechanical fix jobs (`format-*`, `sync-*`, `fix-typos`, `fix-vulnerable-deps`) and turns red when one *crashes* instead of committing a fix; `docs.yaml` builds and deploys the Sphinx site and runs the broken-links check (an externally cancelled or link-flaky run re-runs cleanly via `gh workflow run docs.yaml --ref <BRANCH>`, no commit needed); `release.yaml` runs the Nuitka binary matrix (dev binaries: an ordinary push rebuilds only the `[tool.repomatic] nuitka.dev-targets` canary subset, while release commits, the weekly `schedule` and `workflow_dispatch` build the full target fleet) — but only on projects with `[tool.repomatic] nuitka.enabled` and a CLI entry point; with Nuitka disabled the per-platform jobs skip on every push, release commits included, and a green `release.yaml` means package build plus dev pre-release sync only. Even with Nuitka enabled, a single push can still skip the matrix: `Metadata.skip_binary_build` (`repomatic/metadata/git.py`) is the authoritative signal, true when the head commit is on a non-code branch, is a user-initiated version-bump commit, or (the common case) its changed files fall entirely outside `Metadata.binary_affecting_paths` — a docs-only or workflow-only commit, say. Don't infer the reason from the commit message or assume an unrendered/skipped matrix job name means `nuitka_matrix` itself was empty: the matrix data can be fully populated for that exact commit (verify via the `release / 🧬 Project metadata` job's logged `metadata=` JSON output) while the workflow still elects not to build it. Check `skip_binary_build`'s three conditions before asserting why a matrix skipped, since any one of them is enough on its own. All five workflows must pass — see § Autofix job failures and § Nuitka binary build failures in `references/failure-patterns.md` for how to triage them without stalling the loop.
|
|
84
84
|
|
|
85
85
|
3. **Run local tests while waiting for CI.** Don't idle while polling. Start the full test suite and linters locally in the background immediately:
|
|
86
86
|
|
|
@@ -102,6 +102,8 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
102
102
|
|
|
103
103
|
It reads every workflow a push can start (derived from `.github/workflows/`, so its list is wider than the five above), reports each one's latest run, and names the failing jobs that actually gate a merge. Three traps it settles, so no hand-rolled `jq` has to: a run's own `status` lags its jobs (every monitored workflow can read `queued` while a dozen jobs have already finished, which is indistinguishable from the runner-cap saturation a busy account genuinely hits); a `continue-on-error` probe that crashed hides inside a `success` run conclusion; and a run whose `conclusion` is `failure` with *no* failed job is a workflow-level error (an invalid `strategy.matrix` expression, malformed YAML, a missing secret) with no job log to read, which the command flags rather than letting you write off a persistently-red workflow as a known artifact.
|
|
104
104
|
|
|
105
|
+
`ci-status` reads the same endpoints as the `gh api` calls above, and it has printed a stale table the same way: re-read a surprising red or green once before acting on it.
|
|
106
|
+
|
|
105
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.
|
|
106
108
|
|
|
107
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.
|
|
@@ -112,7 +114,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
112
114
|
|
|
113
115
|
**Poll in-process; never detach a monitor.** Block on `gh run watch <RUN_ID>` or loop the polls within your own turn. A detached background monitor (a standalone process, a `run_in_background: true` Bash poller that re-invokes you when it exits, or a `Monitor`-tool stream that returns control on each tick) makes a parent-resumed run spawn *another* monitor per tick instead of driving to a terminal state; worse, a spawned sub-agent that detaches this way orphans the poll from its caller the moment it returns. Hold the turn until the run completes: starting a poller and handing back "to be notified" is the early return this loop must never make.
|
|
114
116
|
|
|
115
|
-
**Every wait between polls must be a `sleep`, never a busy-wait.** A poll loop with no delay (`until gh run view ...; do true; done`) fires thousands of requests per minute and exhausts the REST quota (5,000/hour) within minutes. The harness blocking a bare foreground `sleep` is not a reason to drop the delay: put the `sleep 60` *inside* the loop command itself, which runs fine in both foreground and background. Exhaustion does not just blind your own polling — workflows authenticating with the same PAT start failing server-side with misleading errors (see [§ GitHub API rate-limit exhaustion](#github-api-rate-limit-exhaustion)).
|
|
117
|
+
**Every wait between polls must be a `sleep`, never a busy-wait.** A poll loop with no delay (`until gh run view ...; do true; done`) fires thousands of requests per minute and exhausts the REST quota (5,000/hour) within minutes. The harness blocking a bare foreground `sleep` is not a reason to drop the delay: put the `sleep 60` *inside* the loop command itself, which runs fine in both foreground and background. Exhaustion does not just blind your own polling — workflows authenticating with the same PAT start failing server-side with misleading errors (see [§ GitHub API rate-limit exhaustion](references/failure-patterns.md#github-api-rate-limit-exhaustion)).
|
|
116
118
|
|
|
117
119
|
4. **On any CI failure**, cancel the branch's remaining runs to free runners:
|
|
118
120
|
|
|
@@ -134,9 +136,9 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
134
136
|
|
|
135
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.
|
|
136
138
|
|
|
137
|
-
Fetch each failed job's log (`gh api repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs --allow-escape-sequences`) and fix them as one batch: different sources surface different issues, and logs survive cancellation. Batch only what has *already failed*, never what might still fail. Once every harvested failure is root-caused and fixed, push immediately rather than waiting for undrained cells to surface more: the fresh run supersedes the stale one, and serially waiting out each full matrix is the slow path. Analyze following the [error triage discipline](#error-triage-discipline): stable-job `FAILED`/`AssertionError` lines only.
|
|
139
|
+
Fetch each failed job's log (`gh api repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs --allow-escape-sequences`) and fix them as one batch: different sources surface different issues, and logs survive cancellation. Batch only what has *already failed*, never what might still fail. Once every harvested failure is root-caused and fixed, push immediately rather than waiting for undrained cells to surface more: the fresh run supersedes the stale one, and serially waiting out each full matrix is the slow path. Analyze following the [error triage discipline](#error-triage-discipline): stable-job `FAILED`/`AssertionError` lines only. Then match each failure against `references/failure-patterns.md` before fixing anything.
|
|
138
140
|
|
|
139
|
-
`gh run view --log-failed` writes its log cache under `~/.cache/gh
|
|
141
|
+
`gh run view --log-failed` writes its log cache under `~/.cache/gh`. A sandbox that denies that path answers `failed to get run log: creating cache entry ... operation not permitted`, which masquerades as a `gh` bug. Run the read in the sandbox first, and disable the sandbox for it only when that error appears.
|
|
140
142
|
|
|
141
143
|
**A completed job's log is readable while the rest of the run drains, but only with `--allow-escape-sequences`.** The run-scoped reads *are* gated on the whole run going terminal (`gh run view --log-failed` answers `run <id> is still in progress; logs will be available when it is complete`), while the job-scoped `gh api repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs` answers a failed cell immediately, twenty minutes into its slowest sibling's build. What makes it look otherwise is a `gh` guard rather than the API: CI logs carry ANSI colour, so `gh` refuses to emit them and prints `the response contains terminal escape sequences; pass --allow-escape-sequences to output it anyway` — one line where a log was expected, indistinguishable from an empty body if the output went to a file. Pass the flag and strip the codes:
|
|
142
144
|
|
|
@@ -147,7 +149,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
147
149
|
|
|
148
150
|
So the diagnosis is minutes away, not an hour: harvest every failed cell as it lands and keep the run alive for the cells still to report. Cancelling to read logs is never the reason — logs survive cancellation, but they never needed it. **Make the run terminal only when you have a fix**, per the batch-and-push rule above: the stale run has no verification value left once superseded.
|
|
149
151
|
|
|
150
|
-
5. **Fix the root cause** using the combined picture from CI logs and local results. Fix the codebase, not the tests, unless the tests are genuinely wrong. Address mypy and ruff failures together (see [§ mypy/ruff fix oscillation](#mypy-ruff-fix-oscillation)).
|
|
152
|
+
5. **Fix the root cause** using the combined picture from CI logs and local results. Fix the codebase, not the tests, unless the tests are genuinely wrong. Address mypy and ruff failures together (see [§ mypy/ruff fix oscillation](references/failure-patterns.md#mypy-ruff-fix-oscillation)).
|
|
151
153
|
|
|
152
154
|
If the root cause is in a third-party dependency, check whether a change *this cycle* exposed it before treating it as upstream: `git log <last-release-tag>..HEAD` for a runner/image swap, a dependency bump, or a config change that put the dependency in a context it cannot satisfy (a Rust-built package forced to compile from an sdist on an architecture with no published wheel, say). When a cycle change is the trigger, revert or adjust *that* change; only a failure independent of everything the cycle touched warrants `/file-bug-report` for an upstream report.
|
|
153
155
|
|
|
@@ -171,7 +173,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
171
173
|
$ gh pr list --state=open --json number,title,headRefName,url
|
|
172
174
|
```
|
|
173
175
|
|
|
174
|
-
If any open autofix PR already contains your fix — a `format-python` branch (ruff's own autofixes), a `sync-repomatic`/`sync-workflow-pins` branch (a bumped workflow pin, or a spliced-in `--exclude-newer-package` cooldown exemption carrying no version bump at all — that one is the whole fix when the `metadata` job cannot resolve its own pin), or another `sync-*`/`fix-*` branch — prefer merging it over authoring your own commit: GitHub signs the merge commit server-side, so this sidesteps a local hardware-key signing prompt entirely. If it resolves the failure, merge it (`gh pr merge <n> --squash --delete-branch`), pull, and rebase your fix before pushing — or skip your own commit if the merge is the whole fix. If `gh pr merge` is denied outright (a standing `permissions.deny` on the verb, not a retryable prompt), see [§ PR-merge permission wall](#pr-merge-permission-wall).
|
|
176
|
+
If any open autofix PR already contains your fix — a `format-python` branch (ruff's own autofixes), a `sync-repomatic`/`sync-workflow-pins` branch (a bumped workflow pin, or a spliced-in `--exclude-newer-package repomatic=P0D` cooldown exemption carrying no version bump at all — that one is the whole fix when the `metadata` job cannot resolve its own pin), or another `sync-*`/`fix-*` branch — prefer merging it over authoring your own commit: GitHub signs the merge commit server-side, so this sidesteps a local hardware-key signing prompt entirely. If it resolves the failure, merge it (`gh pr merge <n> --squash --delete-branch`), pull, and rebase your fix before pushing — or skip your own commit if the merge is the whole fix. If `gh pr merge` is denied outright (a standing `permissions.deny` on the verb, not a retryable prompt), see [§ PR-merge permission wall](references/failure-patterns.md#pr-merge-permission-wall).
|
|
175
177
|
|
|
176
178
|
7. **Commit the fix** with a clear message describing what changed and why, then `git push`.
|
|
177
179
|
|
|
@@ -179,7 +181,7 @@ After fixing (step 5-7), the loop restarts from the top: push, run all three cha
|
|
|
179
181
|
|
|
180
182
|
**Time each push by what its diff rebuilds.** A source-affecting fix (`repomatic/**`, `tests/**`, `pyproject.toml`, `uv.lock`: whatever the repo's test and binary `paths:` filters name) pushes the moment it clears step 5: the runs it supersedes were verifying an obsolete tree, and its own run rebuilds everything it cancels. A commit those filters skip (changelog-only, docs-only, cosmetic prose) is the opposite case on a binaries-enabled project: `release.yaml` runs on *every* push in a per-branch cancel-in-progress group, so pushed mid-drain such a commit cancels the in-flight binary matrix while its own run skips the rebuild (`Metadata.skip_binary_build`), and the lost verification costs a full re-dispatch. That cost scales with what is actually in flight: an ordinary push builds only the `[tool.repomatic] nuitka.dev-targets` canary subset, and no push cancels a full fleet at all, since release commits, `schedule` and `workflow_dispatch` runs each sit in their own concurrency group. Hold it until the heavy matrices on the current HEAD are terminal, or bundle it into the next source-affecting push; with binaries disabled, only a canary build in flight, or nothing heavy in flight, push freely.
|
|
181
183
|
|
|
182
|
-
**If commit signing fails, do not loop on it.** The sandbox can block the SSH key or socket under `~/.ssh/*` (`Operation not permitted`): fix with `dangerouslyDisableSandbox: true` for the `git commit` and `git push` calls only. A hardware-backed key (Secretive, YubiKey, TPM) then prompts the maintainer per signature, and a refused or missed prompt surfaces as `agent refused operation?`, indistinguishable from a real failure. Retry once at most after disabling the sandbox; if it still refuses, hand off cleanly: stage the specific files you fixed (never `git add -A`), return the exact commit message and `git push` command verbatim, and exit the loop. The fix is done — only the signature is missing. If the block is instead a structural permission deny on `gh pr merge` (not a signing refusal), the escalation differs — a maintainer's in-chat approval cannot clear a deny rule: see [§ PR-merge permission wall](#pr-merge-permission-wall).
|
|
184
|
+
**If commit signing fails, do not loop on it.** The sandbox can block the SSH key or socket under `~/.ssh/*` (`Operation not permitted`): fix with `dangerouslyDisableSandbox: true` for the `git commit` and `git push` calls only. A hardware-backed key (Secretive, YubiKey, TPM) then prompts the maintainer per signature, and a refused or missed prompt surfaces as `agent refused operation?`, indistinguishable from a real failure. Retry once at most after disabling the sandbox; if it still refuses, hand off cleanly: stage the specific files you fixed (never `git add -A`), return the exact commit message and `git push` command verbatim, and exit the loop. The fix is done — only the signature is missing. If the block is instead a structural permission deny on `gh pr merge` (not a signing refusal), the escalation differs — a maintainer's in-chat approval cannot clear a deny rule: see [§ PR-merge permission wall](references/failure-patterns.md#pr-merge-permission-wall).
|
|
183
185
|
|
|
184
186
|
8. **Repeat from step 2** until the monitored workflows are green: `tests.yaml` with all stable (✅) jobs passing, `lint.yaml` with no mypy failures (test and docs files included). **Stop after 5 iterations without progress** (the set of distinct failing stable jobs did not shrink): report what was fixed and what remains, and ask for guidance rather than churning. Productive iterations never trip the cap: a release paying down a long test-debt tail legitimately takes more than five pushes.
|
|
185
187
|
|
|
@@ -235,97 +237,19 @@ Read the exact error messages before forming a hypothesis. The most common diagn
|
|
|
235
237
|
1. **Filter first.** Gating and loop cadence read stable (✅) jobs only: an unstable (⁉️) failure never blocks the loop, never sets its tempo, and never queue-jumps a stable red. When an orchestrator like `/repomatic-ship` spawned this loop for a release, ⁉️ reds are still work owed under its genuinely-green goal: once no stable red is outstanding, read their logs and fix what is repo-fixable (a crash converted to a clean availability-gated skip, a flaky live install folded into a tolerated-exit set), leaving only genuine dev-interpreter breakage unfixed and named in the final report. Human-invoked runs keep the strict filter: discard ⁉️ logs entirely unless asked.
|
|
236
238
|
2. **Quote the error.** Before proposing a fix, quote the exact failing line(s) from the log. If you cannot quote a specific error, you have not diagnosed the problem.
|
|
237
239
|
3. **One cause at a time.** Multiple failing jobs often share a root cause: identify the common thread before treating each job as independent.
|
|
238
|
-
4. **Distinguish test failures from lint failures.** A pytest `AssertionError` and a mypy `error:` have different fixes, but always analyze mypy and ruff failures together before fixing either (see [§ mypy/ruff fix oscillation](#mypy-ruff-fix-oscillation)).
|
|
240
|
+
4. **Distinguish test failures from lint failures.** A pytest `AssertionError` and a mypy `error:` have different fixes, but always analyze mypy and ruff failures together before fixing either (see [§ mypy/ruff fix oscillation](references/failure-patterns.md#mypy-ruff-fix-oscillation)).
|
|
239
241
|
5. **Do not fix warnings.** Deprecation and informational messages are not failures; ignore them unless they cause a stable job to fail.
|
|
240
242
|
|
|
241
243
|
## Common failure patterns
|
|
242
244
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
### mypy/ruff fix oscillation
|
|
246
|
-
|
|
247
|
-
mypy and ruff can enter a fix loop where each tool's fix breaks the other. Common triggers:
|
|
248
|
-
|
|
249
|
-
- **Unused import**: ruff removes an import (`F401`), mypy then complains about a missing name; re-adding triggers ruff again.
|
|
250
|
-
- **Type annotation style**: mypy requires an explicit annotation, ruff considers it redundant or wants a different form.
|
|
251
|
-
- **`noqa` vs `type: ignore`**: `# noqa` silences ruff but not mypy; `# type: ignore` silences mypy but ruff flags the unused directive.
|
|
252
|
-
|
|
253
|
-
When the same lines toggle between fixes across iterations, stop and apply a combined resolution: a `# type: ignore[code]` with a matching `# noqa: XXXX` on the same line, or a restructuring that satisfies both at once.
|
|
254
|
-
|
|
255
|
-
### mypy scope mismatch (local vs CI)
|
|
256
|
-
|
|
257
|
-
The classic false green: mypy passes locally over a subset of directories while CI checks **every tracked Python file** (`tests/` and `docs/` included). Run it as a bare `repomatic run mypy` and the runner resolves that same list, so an error in a test or docs file surfaces before the push rather than after it. A directory list is what reintroduces the gap.
|
|
258
|
-
|
|
259
|
-
### Platform-specific test skips
|
|
260
|
-
|
|
261
|
-
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.
|
|
262
|
-
|
|
263
|
-
### Cross-platform divergence
|
|
264
|
-
|
|
265
|
-
When a test passes locally but fails in CI, check platform differences before changing logic:
|
|
266
|
-
|
|
267
|
-
- **Path lengths**: `~/.config/...` is shorter on Linux than macOS/Windows equivalents, affecting text-wrapping assertions.
|
|
268
|
-
- **Terminal width**: CI runners may default differently than local dev machines.
|
|
269
|
-
- **Encoding**: Windows defaults to `cp1252`, not `utf-8`.
|
|
270
|
-
- **Line endings**: `\r\n` vs `\n` breaks exact-match assertions.
|
|
271
|
-
- **Untracked files**: tests that enumerate files (`python_files`, `doc_files` metadata) see untracked local files that CI's clean checkout lacks. When updating expected file lists, include only tracked files; run `git status` to spot the divergence.
|
|
272
|
-
|
|
273
|
-
### Workflow and infrastructure failures
|
|
274
|
-
|
|
275
|
-
Not all CI failures are code bugs:
|
|
276
|
-
|
|
277
|
-
- **Runner timeouts or OOM kills**: the log ends abruptly or shows `The runner has received a shutdown signal`. Re-run; do not change code.
|
|
278
|
-
- **A runner that died mid-step**: the step runs far past its baseline, and a cancel does not stop it. A live runner kills a cancelled step within ten seconds and keeps its partial log. A cancel does not apply to a job whose `if:` holds `always()`, so read that condition first. Any other job still `in_progress` a minute after the cancel has lost its runner: the server closes it at the five-minute [cancellation timeout](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-cancellation), and no log survives, neither at the job's log endpoint (`BlobNotFound`) nor in the run's log archive. A 404 from a job that is still running proves nothing, since every running job returns one. Re-run with `--failed`: there is nothing to diagnose.
|
|
279
|
-
- **Action version mismatches**: `Unable to resolve action`, deprecated-runtime errors. Fix the workflow YAML, not the Python.
|
|
280
|
-
- **Network/registry flakiness**: `uv`/`pip` timeouts, PyPI 503s, `ConnectionResetError`. Re-run.
|
|
281
|
-
- **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.
|
|
282
|
-
- **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.
|
|
283
|
-
- **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.
|
|
284
|
-
|
|
285
|
-
For infrastructure, re-run the failed jobs (`gh run rerun <RUN_ID> --failed`) and continue polling; never modify code to work around transient infra. **A release run is the exception**: when an orchestrator like `/repomatic-ship` spawned this loop, a flake surfaced here is debt owed under that skill's genuinely-green goal, so a red whose defect lives in the repository (the wall-clock budget above, a tolerated-exit set that needs widening) gets fixed at the source instead. "Transient infra" then names the trigger, not the remedy. A red with no repo-side defect at all, like a runner OOM or a PyPI 503, is still a re-run.
|
|
286
|
-
|
|
287
|
-
<a id="github-api-rate-limit-exhaustion"></a>
|
|
288
|
-
|
|
289
|
-
### GitHub API rate-limit exhaustion
|
|
290
|
-
|
|
291
|
-
Heavy polling from this loop spends the same REST quota (5,000 requests/hour) as every workflow authenticating as the same user (`REPOMATIC_PAT`). Exhaustion produces two failure shapes that look unrelated to quotas:
|
|
292
|
-
|
|
293
|
-
- Local `gh` calls fail with `HTTP 403: API rate limit exceeded`.
|
|
294
|
-
- Workflows fail with *permission-shaped* errors: `lint-repo` reports the PAT lacks `Contents`/`Dependabot`/`Workflows` scopes, or a `Sync pull request` step (`repomatic pr-sync`) stalls on the GitHub API until its `timeout-minutes` or the concurrency group kills the run.
|
|
295
|
-
|
|
296
|
-
Diagnose with `gh api rate_limit` **before** touching token settings: `remaining: 0` on the `core` bucket confirms it. Recovery: wait for the printed `reset` epoch, then re-run the failed workflows unchanged (`gh run rerun <RUN_ID> --failed`); they go green with no commit. While waiting, degrade to the channels that stay live: the GraphQL bucket is metered separately (`gh api graphql` for a commit's check suites, refs, and releases; `gh pr list` / `gh pr view`), and `git fetch` over SSH covers branch and commit verification.
|
|
297
|
-
|
|
298
|
-
<a id="pr-merge-permission-wall"></a>
|
|
299
|
-
|
|
300
|
-
### PR-merge permission wall
|
|
301
|
-
|
|
302
|
-
`gh pr merge` — and other write-heavy verbs (force-push, `reset --hard`, repo or release delete) — is commonly hard-denied in the operator's own Claude Code `settings.json` as a standing guard against irreversible actions, independent of any conversation. This deny is structural, not a per-call prompt: it fires identically whether or not a maintainer just authorized the exact command in chat, because it blocks the tool call itself rather than asking. Signs you have hit it, not a normal prompt: the denial is immediate with nothing to answer, and it recurs identically after a fresh, explicit, real-time go-ahead. Do not retry it, and do not read a maintainer's chat-level "yes, merge it" as actionable — a deny rule cannot be cleared from inside the session. Report the wall once and ask the maintainer to run the merge themselves, fully outside this session (their terminal, or the GitHub web UI): that is the only path this deny shape leaves open. The same holds when a hardware-key signing refusal blocks a direct commit (step 7): with both remedies walled, the release advances only by a human acting outside the tool.
|
|
303
|
-
|
|
304
|
-
### Nuitka binary build failures (release.yaml)
|
|
305
|
-
|
|
306
|
-
This section only applies to projects that build binaries (`[tool.repomatic] nuitka.enabled` with a CLI entry point); on a Nuitka-disabled project the per-platform jobs skip on every push and there is no matrix to fail. When enabled, the engine runs Nuitka across a 6-way OS/arch matrix on release commits, on the weekly `schedule` and on `workflow_dispatch`, narrowing an ordinary push to the `[tool.repomatic] nuitka.dev-targets` canary subset (job names are templated per platform, like `✅ {os}, {sha} build`); catching a break while the version is still `.dev0` avoids shipping a release with missing or broken binaries, which the immutable-release wall makes unrecoverable. Triage by category:
|
|
307
|
-
|
|
308
|
-
- **Infrastructure** (runner OOM, shutdown signal, macOS runner crash, registry timeout): re-run the failed job (`gh run rerun <RELEASE_RUN_ID> --failed`); binary builds are resource-heavy and macOS runners crash more than most.
|
|
309
|
-
- **Nuitka configuration** (`Error, unsupported ...`, an unknown `--flag`, a missing data file): fix `[tool.nuitka]` in `pyproject.toml`, not the Python source; verify each key maps to a current Nuitka option.
|
|
310
|
-
- **Real compile or runtime errors** (the binary builds but its smoke test fails, a `ModuleNotFoundError` at runtime): fix the code or the `include-package`/`include-data-files` configuration, then push and re-monitor.
|
|
311
|
-
|
|
312
|
-
The matrix is slow: let `tests.yaml` and `lint.yaml` set the loop cadence, but act on a red build cell the moment it lands, like any stable failure (every faster channel has already reported by then): fix, push, supersede. Never idle out the rest of a matrix you already know is doomed.
|
|
313
|
-
|
|
314
|
-
**A *cancelled* canary cell is a coverage gap, not a failure, and `--failed` closes it cheaply.** Supersession routinely kills the canary mid-build (an automation PR merges, the concurrency group cancels it), and the pushes behind it often skip the matrix outright, so the binary signal for the last code-affecting tree is simply missing with nothing in flight to supply it. Reach for `gh run rerun <cancelled-run-id> --failed` rather than `gh workflow run release.yaml`: the rerun rebuilds only the cancelled cell and its dependents, leaving every skipped job skipped, where a dispatch compiles the whole platform fleet. The precondition is that the cancelled run's binary-affecting tree still matches `HEAD`, since the rerun rebuilds that run's commit and not the current one: check with `git diff --name-only <that run's headSha>..HEAD` and confirm nothing in it touches `Metadata.binary_affecting_paths`.
|
|
315
|
-
|
|
316
|
-
**On a release run, a red build cell means that version ships short, permanently.** When the run's head commit is a `[changelog] Release vX.Y.Z` push, `publish-release` sits at the end of that same run and flips the draft to published once the asset jobs settle, locking the asset list. Whatever the matrix failed to produce by then is missing from that version forever: no re-run, no later upload.
|
|
317
|
-
|
|
318
|
-
**This is by design, so do not try to stop it.** Publishing a release short beats holding it, and the recovery is the next version, not a draft the maintainer has to babysit. Keep doing exactly what you do for any stable red: fix the cause, push, and let the fix ride the next release. The one addition is reporting: name the platforms that version lost, so the maintainer knows the gap exists and can note it in the release. A short ship also leaves the changelog section, the release body and `docs/install.md` still advertising binaries that are not there (the `repomatic-ship` skill's § Repairing a short ship covers the cleanup); flag it rather than fixing it silently mid-loop.
|
|
319
|
-
|
|
320
|
-
### Autofix job failures (autofix.yaml)
|
|
321
|
-
|
|
322
|
-
`autofix.yaml`'s jobs normally commit their fixes; a job that *crashes* turns the workflow red without producing one. Fetch the failed log (`gh run view <AUTOFIX_RUN_ID> --log-failed`) and triage:
|
|
245
|
+
When a job fails, read `references/failure-patterns.md` before fixing anything. It names the failures that are not code bugs, and what each one needs:
|
|
323
246
|
|
|
324
|
-
-
|
|
325
|
-
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
247
|
+
- mypy/ruff fix oscillation, and the mypy scope mismatch between a local run and CI.
|
|
248
|
+
- Platform-specific test skips, and cross-platform divergence.
|
|
249
|
+
- Workflow and infrastructure failures, and GitHub API rate-limit exhaustion.
|
|
250
|
+
- The PR-merge permission wall.
|
|
251
|
+
- Nuitka binary build failures, and autofix job failures.
|
|
328
252
|
|
|
329
|
-
|
|
253
|
+
## End-of-loop retrospective
|
|
330
254
|
|
|
331
|
-
After the loop converges (or hits the iteration cap), review whether any finding is worth feeding back: a failure pattern that recurred across iterations, or a diagnosis needing non-obvious knowledge, belongs in [
|
|
255
|
+
After the loop converges (or hits the iteration cap), review whether any finding is worth feeding back: a failure pattern that recurred across iterations, or a diagnosis needing non-obvious knowledge, belongs in [`references/failure-patterns.md`](references/failure-patterns.md). Propose the addition; do not push it unreviewed.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Common failure patterns
|
|
2
|
+
|
|
3
|
+
Failure shapes the `babysit-ci` loop meets, and what each one needs. `SKILL.md` holds the loop itself.
|
|
4
|
+
|
|
5
|
+
<a id="mypy-ruff-fix-oscillation"></a>
|
|
6
|
+
|
|
7
|
+
## mypy/ruff fix oscillation
|
|
8
|
+
|
|
9
|
+
mypy and ruff can enter a fix loop where each tool's fix breaks the other. Common triggers:
|
|
10
|
+
|
|
11
|
+
- **Unused import**: ruff removes an import (`F401`), mypy then complains about a missing name; re-adding triggers ruff again.
|
|
12
|
+
- **Type annotation style**: mypy requires an explicit annotation, ruff considers it redundant or wants a different form.
|
|
13
|
+
- **`noqa` vs `type: ignore`**: `# noqa` silences ruff but not mypy; `# type: ignore` silences mypy but ruff flags the unused directive.
|
|
14
|
+
|
|
15
|
+
When the same lines toggle between fixes across iterations, stop and apply a combined resolution: a `# type: ignore[code]` with a matching `# noqa: XXXX` on the same line, or a restructuring that satisfies both at once.
|
|
16
|
+
|
|
17
|
+
## mypy scope mismatch (local vs CI)
|
|
18
|
+
|
|
19
|
+
The classic false green: mypy passes locally over a subset of directories while CI checks **every tracked Python file** (`tests/` and `docs/` included). Run it as a bare `repomatic run mypy` and the runner resolves that same list, so an error in a test or docs file surfaces before the push rather than after it. A directory list is what reintroduces the gap.
|
|
20
|
+
|
|
21
|
+
## Platform-specific test skips
|
|
22
|
+
|
|
23
|
+
Some tests are skipped on certain platforms (`windows-11-arm` has no Python 3.10 ARM64 build). Before investigating missing results, check the matrix `exclude` section in `tests.yaml` and the `skip_platforms` entries in the binary self-test plan (`tests/cli-test-suite.toml`): individual cases can opt out of platforms without affecting the CI matrix.
|
|
24
|
+
|
|
25
|
+
## Cross-platform divergence
|
|
26
|
+
|
|
27
|
+
When a test passes locally but fails in CI, check platform differences before changing logic:
|
|
28
|
+
|
|
29
|
+
- **Path lengths**: `~/.config/...` is shorter on Linux than macOS/Windows equivalents, affecting text-wrapping assertions.
|
|
30
|
+
- **Terminal width**: CI runners may default differently than local dev machines.
|
|
31
|
+
- **Encoding**: Windows defaults to `cp1252`, not `utf-8`.
|
|
32
|
+
- **Line endings**: `\r\n` vs `\n` breaks exact-match assertions.
|
|
33
|
+
- **Untracked files**: tests that enumerate files (`python_files`, `doc_files` metadata) see untracked local files that CI's clean checkout lacks. When updating expected file lists, include only tracked files; run `git status` to spot the divergence.
|
|
34
|
+
|
|
35
|
+
## Workflow and infrastructure failures
|
|
36
|
+
|
|
37
|
+
Not all CI failures are code bugs:
|
|
38
|
+
|
|
39
|
+
- **Runner timeouts or OOM kills**: the log ends abruptly or shows `The runner has received a shutdown signal`. Re-run; do not change code.
|
|
40
|
+
- **A runner that died mid-step**: the step runs far past its baseline, and a cancel does not stop it. A live runner kills a cancelled step within ten seconds and keeps its partial log. A cancel does not apply to a job whose `if:` holds `always()`, so read that condition first. Any other job still `in_progress` a minute after the cancel has lost its runner: the server closes it at the five-minute [cancellation timeout](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-cancellation), and no log survives, neither at the job's log endpoint (`BlobNotFound`) nor in the run's log archive. A 404 from a job that is still running proves nothing, since every running job returns one. Re-run with `--failed`: there is nothing to diagnose.
|
|
41
|
+
- **Action version mismatches**: `Unable to resolve action`, deprecated-runtime errors. Fix the workflow YAML, not the Python.
|
|
42
|
+
- **Network/registry flakiness**: `uv`/`pip` timeouts, PyPI 503s, `ConnectionResetError`. Re-run.
|
|
43
|
+
- **A wall-clock budget assertion** (`assert elapsed_ms < N`) failing on a shared runner: infrastructure is the *trigger*, but the defect is the test, which took one sample and so measured that runner's worst moment rather than the code. A re-run only re-rolls the dice, and the tell that it has been re-rolled before is a budget already ratcheted upward in an earlier cycle for the same runner class. Assert on the fastest of several samples instead: a real regression slows every sample, a scheduling stall slows one. Raising the budget again is the fix that stops working.
|
|
44
|
+
- **Permission errors**: `Resource not accessible by integration`, 403s. Check `gh api rate_limit` first ([§ GitHub API rate-limit exhaustion](#github-api-rate-limit-exhaustion)), then token permissions; never code.
|
|
45
|
+
- **A whole workflow red with nothing executed**, every job reporting failure and the `metadata` job unable to resolve its own toolkit pin: the inline `uvx 'repomatic==X.Y.Z'` command is missing `--exclude-newer-package repomatic=P0D`, so the workflow-wide `UV_EXCLUDE_NEWER` refuses a pin naming a release younger than the window, and each `needs: metadata` job dies with it. Splice the flag onto that command line — `uvx` reads no project configuration, so there is nowhere else the bypass can live — or merge the `sync-workflow-pins` PR that backfills it. `lint-repo`'s fatal `self-pin-cooldown-exemption` check names the offending files. Re-running changes nothing.
|
|
46
|
+
- **A Cloudflare deploy that ends red after publishing**: the `docs.yaml` workflow's `deploy-docs-cloudflare` job dropped a file over 25 MiB, so the live site links to a file it does not have. The offload step's error annotation names each file and the reason. Re-run only when the reason is a failed upload. Any other reason, like an undeclared R2 bucket or missing R2 secrets, needs a repository change or maintainer setup: report it instead.
|
|
47
|
+
|
|
48
|
+
For infrastructure, re-run the failed jobs (`gh run rerun <RUN_ID> --failed`) and continue polling; never modify code to work around transient infra. **A release run is the exception**: when an orchestrator like `/repomatic-ship` spawned this loop, a flake surfaced here is debt owed under that skill's genuinely-green goal, so a red whose defect lives in the repository (the wall-clock budget above, a tolerated-exit set that needs widening) gets fixed at the source instead. "Transient infra" then names the trigger, not the remedy. A red with no repo-side defect at all, like a runner OOM or a PyPI 503, is still a re-run.
|
|
49
|
+
|
|
50
|
+
**`--failed` also re-runs the jobs skipped behind a failure.** Each failed or cancelled job re-runs with every job that `needs:` it, skipped ones included. So one rerun restores the whole chain: never re-run the whole workflow to reach a skipped dependent.
|
|
51
|
+
|
|
52
|
+
<a id="github-api-rate-limit-exhaustion"></a>
|
|
53
|
+
|
|
54
|
+
## GitHub API rate-limit exhaustion
|
|
55
|
+
|
|
56
|
+
Heavy polling from this loop spends the same REST quota (5,000 requests/hour) as every workflow authenticating as the same user (`REPOMATIC_PAT`). Exhaustion produces two failure shapes that look unrelated to quotas:
|
|
57
|
+
|
|
58
|
+
- Local `gh` calls fail with `HTTP 403: API rate limit exceeded`.
|
|
59
|
+
- Workflows fail with *permission-shaped* errors: `lint-repo` reports the PAT lacks `Contents`/`Dependabot`/`Workflows` scopes, or a `Sync pull request` step (`repomatic pr-sync`) stalls on the GitHub API until its `timeout-minutes` or the concurrency group kills the run.
|
|
60
|
+
|
|
61
|
+
Diagnose with `gh api rate_limit` **before** touching token settings: `remaining: 0` on the `core` bucket confirms it. Recovery: wait for the printed `reset` epoch, then re-run the failed workflows unchanged (`gh run rerun <RUN_ID> --failed`); they go green with no commit. While waiting, degrade to the channels that stay live: the GraphQL bucket is metered separately (`gh api graphql` for a commit's check suites, refs, and releases; `gh pr list` / `gh pr view`), and `git fetch` over SSH covers branch and commit verification.
|
|
62
|
+
|
|
63
|
+
<a id="pr-merge-permission-wall"></a>
|
|
64
|
+
|
|
65
|
+
## PR-merge permission wall
|
|
66
|
+
|
|
67
|
+
`gh pr merge` — and other write-heavy verbs (force-push, `reset --hard`, repo or release delete) — is commonly hard-denied in the operator's own Claude Code `settings.json` as a standing guard against irreversible actions, independent of any conversation. This deny is structural, not a per-call prompt: it fires identically whether or not a maintainer just authorized the exact command in chat, because it blocks the tool call itself rather than asking. Signs you have hit it, not a normal prompt: the denial is immediate with nothing to answer, and it recurs identically after a fresh, explicit, real-time go-ahead. Do not retry it, and do not read a maintainer's chat-level "yes, merge it" as actionable — a deny rule cannot be cleared from inside the session. Report the wall once and ask the maintainer to run the merge themselves, fully outside this session (their terminal, or the GitHub web UI): that is the only path this deny shape leaves open. The same holds when a hardware-key signing refusal blocks a direct commit (step 7 of `SKILL.md`): with both remedies walled, the release advances only by a human acting outside the tool.
|
|
68
|
+
|
|
69
|
+
## Nuitka binary build failures (release.yaml)
|
|
70
|
+
|
|
71
|
+
This section only applies to projects that build binaries (`[tool.repomatic] nuitka.enabled` with a CLI entry point); on a Nuitka-disabled project the per-platform jobs skip on every push and there is no matrix to fail. When enabled, the engine runs Nuitka across a 6-way OS/arch matrix on release commits, on the weekly `schedule` and on `workflow_dispatch`, narrowing an ordinary push to the `[tool.repomatic] nuitka.dev-targets` canary subset (job names are templated per platform, like `✅ {os}, {sha} build`); catching a break while the version is still `.dev0` avoids shipping a release with missing or broken binaries, which the immutable-release wall makes unrecoverable. Triage by category:
|
|
72
|
+
|
|
73
|
+
- **Infrastructure** (runner OOM, shutdown signal, macOS runner crash, registry timeout): re-run the failed job (`gh run rerun <RELEASE_RUN_ID> --failed`); binary builds are resource-heavy and macOS runners crash more than most.
|
|
74
|
+
- **Nuitka configuration** (`Error, unsupported ...`, an unknown `--flag`, a missing data file): fix `[tool.nuitka]` in `pyproject.toml`, not the Python source; verify each key maps to a current Nuitka option.
|
|
75
|
+
- **Real compile or runtime errors** (the binary builds but its smoke test fails, a `ModuleNotFoundError` at runtime): fix the code or the `include-package`/`include-data-files` configuration, then push and re-monitor.
|
|
76
|
+
|
|
77
|
+
The matrix is slow: let `tests.yaml` and `lint.yaml` set the loop cadence, but act on a red build cell the moment it lands, like any stable failure (every faster channel has already reported by then): fix, push, supersede. Never idle out the rest of a matrix you already know is doomed.
|
|
78
|
+
|
|
79
|
+
**A *cancelled* canary cell is a coverage gap, not a failure, and `--failed` closes it cheaply.** Supersession routinely kills the canary mid-build (an automation PR merges, the concurrency group cancels it), and the pushes behind it often skip the matrix outright, so the binary signal for the last code-affecting tree is simply missing with nothing in flight to supply it. Reach for `gh run rerun <cancelled-run-id> --failed` rather than `gh workflow run release.yaml`: the rerun rebuilds only the cancelled cell and its dependents, leaving every skipped job skipped, where a dispatch compiles the whole platform fleet. The precondition is that the cancelled run's binary-affecting tree still matches `HEAD`, since the rerun rebuilds that run's commit and not the current one: check with `git diff --name-only <that run's headSha>..HEAD` and confirm nothing in it touches `Metadata.binary_affecting_paths`.
|
|
80
|
+
|
|
81
|
+
**On a release run, a red build cell means that version ships short, permanently.** When the run's head commit is a `[changelog] Release vX.Y.Z` push, `publish-release` sits at the end of that same run and flips the draft to published once the asset jobs settle, locking the asset list. Whatever the matrix failed to produce by then is missing from that version forever: no re-run, no later upload.
|
|
82
|
+
|
|
83
|
+
**This is by design, so do not try to stop it.** Publishing a release short beats holding it, and the recovery is the next version, not a draft the maintainer has to babysit. Keep doing exactly what you do for any stable red: fix the cause, push, and let the fix ride the next release. The one addition is reporting: name the platforms that version lost, so the maintainer knows the gap exists and can note it in the release. A short ship also leaves the changelog section, the release body and `docs/install.md` still advertising binaries that are not there (the `repomatic-ship` skill's § Repairing a short ship covers the cleanup); flag it rather than fixing it silently mid-loop.
|
|
84
|
+
|
|
85
|
+
## Autofix job failures (autofix.yaml)
|
|
86
|
+
|
|
87
|
+
`autofix.yaml`'s jobs normally commit their fixes; a job that *crashes* turns the workflow red without producing one. Fetch the failed log (`gh run view <AUTOFIX_RUN_ID> --log-failed`) and triage:
|
|
88
|
+
|
|
89
|
+
- **Tool-runner checksum mismatch** (`ValueError: SHA-256 mismatch for https://...`): the pinned binary's hash no longer matches the published artifact, usually an upstream re-publish. Regenerate with `repomatic update-checksums`, then confirm with `repomatic run <tool>`.
|
|
90
|
+
- **External-tool output parse error** (a `RuntimeError`/`KeyError` in a parser, like `fix-vulnerable-deps` reading `uv audit` JSON): the tool's output schema drifted. Fix the parser and update the test fixture encoding the old shape.
|
|
91
|
+
- **Dependency fails to build on the runner** (`Failed to build <pkg>`, a `maturin`/`cargo`/native-compiler error during install): usually self-inflicted, not upstream: a `runs-on` change *this cycle* moved the job to an architecture with no published wheel, forcing a doomed source build. Check `git log <last-tag>..HEAD` for the runner swap and revert it; a genuinely broken upstream artifact (failing on *every* platform) is the rarer case.
|
|
92
|
+
- **Genuine content the job fixes** (real typos, an actual vulnerability): the job commits the fix and goes green on its own; nothing to do.
|
{repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/file-bug-report/SKILL.md
RENAMED
|
@@ -157,6 +157,8 @@ Search with multiple keyword variations (error messages, function names, symptom
|
|
|
157
157
|
|
|
158
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).
|
|
159
159
|
|
|
160
|
+
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
|
+
|
|
160
162
|
### 3. Gather evidence
|
|
161
163
|
|
|
162
164
|
Collect the actual error output, environment details, and reproduction steps from the current conversation context, CI logs, or local files. Always include:
|
|
@@ -178,6 +180,29 @@ Maintainers can diagnose faster when they can see the original context themselve
|
|
|
178
180
|
|
|
179
181
|
Ask yourself: "Can the maintainer click a link and immediately see what I'm describing?" If yes, include the link. If the context is private, quote the relevant snippet inline instead.
|
|
180
182
|
|
|
183
|
+
#### Observations, not conclusions
|
|
184
|
+
|
|
185
|
+
The maintainer of the code is the authority on it. Hand over observations they can verify in one click, and leave the diagnosis to them:
|
|
186
|
+
|
|
187
|
+
- **Link every factual claim to the exact line that proves it.** A claim drawn from a CI log links the log line (see § GitHub Actions log anchors below); a claim that exists only in an uploaded artifact links the artifact, since no log line proves it.
|
|
188
|
+
- **Check a claim about the upstream tool against its source or manual before writing it.** Memory is not a source. Where a code comment in the tool says it better, quote the comment verbatim and link it.
|
|
189
|
+
- **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
|
+
- **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
|
+
- **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.
|
|
192
|
+
- **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
|
+
- **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
|
+
|
|
195
|
+
#### GitHub Actions log anchors
|
|
196
|
+
|
|
197
|
+
A `…/actions/runs/{run}/job/{job}#step:{N}:{line}` link follows non-obvious numbering, verified against live runs:
|
|
198
|
+
|
|
199
|
+
- **Fetch the raw log** with `gh api repos/{owner}/{repo}/actions/jobs/{id}/logs --allow-escape-sequences`. Without the flag, `gh` refuses the escape sequences and writes an empty file. The job's numeric ID is `id` in `gh api repos/{owner}/{repo}/actions/runs/{run}/jobs`, and `databaseId` in `gh run view {run} --json jobs`, which has no `id` field: reading `.id` there returns `null`.
|
|
200
|
+
- **The step number counts "Set up job" as 1**, so a workflow's sixth step is `step:7`.
|
|
201
|
+
- **Read that number from the API, never by counting log sections.** The raw log omits a skipped step while the fragment still counts it, so one `if:`-guarded step shifts every anchor below it by one, and only on the runs where it was skipped. `gh api repos/{owner}/{repo}/actions/jobs/{id}` returns `steps[].number` and `steps[].conclusion`: line the non-skipped steps up against the log's `##[group]Run ` markers in order, then take the number off the step. Its `name` is also the cheapest check that an anchor landed where intended.
|
|
202
|
+
- **The line number starts at the step's `##[group]Run …` marker**, which is line 1, and includes the echoed script plus the `shell:`/`env:` preamble before any output.
|
|
203
|
+
- **Strip the leading timestamp** (`^\S+Z `) from each raw line before counting or matching.
|
|
204
|
+
- **Anchors rot on every rerun.** Any change in a job's output shifts every line below it, and a tool printing one extra banner line moves anchors nobody touched. After a rerun, repoint every anchor programmatically and re-resolve each one against the new logs to confirm it still lands on the intended line; never trust the arithmetic.
|
|
205
|
+
|
|
181
206
|
### 4. Select the right template
|
|
182
207
|
|
|
183
208
|
Based on step 1d, pick the correct template:
|
|
@@ -227,6 +252,7 @@ What happens instead, with exact error output in code blocks.
|
|
|
227
252
|
- Use first-person singular ("I", "my") per user conventions.
|
|
228
253
|
- Include exact error messages in code blocks, not paraphrases.
|
|
229
254
|
- If multiple distinct failures exist, group them under numbered sub-sections but keep them in one report if they share a root cause. File separate issues if root causes differ.
|
|
255
|
+
- File a second finding as its own issue, cross-referenced, never by broadening the first one's title. The title must still name the fix that closes it.
|
|
230
256
|
- Keep reproduction steps minimal: strip everything not needed to trigger the bug.
|
|
231
257
|
- Link to CI runs or logs when available.
|
|
232
258
|
- Do not speculate about fixes unless the root cause is clear from the evidence.
|
{repomatic-7.16.2/repomatic/data → repomatic-7.17.0/.claude}/skills/repomatic-audit/SKILL.md
RENAMED
|
@@ -26,7 +26,7 @@ Before flagging an issue, verify that the gap isn't **deliberate** or covered by
|
|
|
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
28
|
- **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".
|
|
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
30
|
- **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
31
|
- **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
32
|
|
|
@@ -130,7 +130,7 @@ Read the full `pyproject.toml`. `lint-deps` already reports the specifier style,
|
|
|
130
130
|
Comments and changelogs can lie; the codebase is the source of truth. For each dependency with a weak or suspicious comment, verify the floor against actual usage:
|
|
131
131
|
|
|
132
132
|
1. **Grep for imports.** Search the source tree for all imports from the package. List the specific APIs used (functions, classes, constants).
|
|
133
|
-
2. **Determine the oldest version providing those APIs.** Check when the API was introduced — changelogs, release notes, or `pip index versions <pkg>` to see what exists on PyPI.
|
|
133
|
+
2. **Determine the oldest version providing those APIs.** Check when the API was introduced — changelogs, release notes, or `pip index versions <pkg>` to see what exists on PyPI. A floor that rests on a behavior (comments kept, output formatting) needs a bisect instead, since a changelog can credit it to a later release than the one that shipped it. Run one probe per release with `uv run --no-project --exclude-newer '1 week' --with '<pkg>==<version>' python probe.py`, and compare each output byte for byte with the locked release.
|
|
134
134
|
3. **Lower the floor** when it exceeds the oldest compatible version. Prefer conservative minimums (the major version that introduced the API) over aggressive ones. Update both the version specifier and the comment.
|
|
135
135
|
4. **Run `uv lock`** after any floor change to verify the lock still resolves.
|
|
136
136
|
|
|
@@ -289,7 +289,7 @@ Common false-positive patterns to reject early:
|
|
|
289
289
|
|
|
290
290
|
- A new helper that replaces hand-rolled logic.
|
|
291
291
|
- A bug fix that lets us delete a workaround — search comments for the package name, `work around`, `TODO`, and version-guarded branches.
|
|
292
|
-
- A deprecation we still call, which must move to the replacement before the dependency removes it.
|
|
292
|
+
- A deprecation we still call, which must move to the replacement before the dependency removes it. The test suite's warnings summary names each deprecated call the tests reach, with its file and line.
|
|
293
293
|
|
|
294
294
|
4. **Apply one dependency at a time.** Make the edits for a single package, keeping each behavior-preserving. If adopting an API needs a higher floor, raise it and rewrite the comment per [Floor bumps to adopt new APIs](#floor-bumps-to-adopt-new-apis), then run `uv lock`.
|
|
295
295
|
|