Skip to content

Commit 6671c83

Browse files
kdeldyckeclaude
andcommitted
Reconcile the tree for 7.10.0
Eleven `sync-deps` steps in `autofix.yaml` had silently stopped gating: a folded block scalar wrapped around a `${{ }}` condition appends a trailing newline, so GitHub Actions interpolated the value into a truthy string instead of evaluating it. Converted them to the bare multi-line form and added a conformance test covering every `if:` in the Actions tree. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent fbd9148 commit 6671c83

16 files changed

Lines changed: 183 additions & 60 deletions

File tree

.claude/agents/sphinx-docs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ Watch for these every pass:
824824
- Cross-references to docs/ pages from skills/agents that don't degrade gracefully when the target page is excluded downstream.
825825
- 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.
826826
- A `## Development` section in `readme.md` that should have been removed when the project added a `claude.md`. Once `claude.md` exists, the developer-facing setup goes there; keeping a duplicated section in the readme creates two places to update.
827-
- 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 the autofix workflow; manual regeneration drifts.
827+
- 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.
828828
- `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.
829829
- `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.
830830
- `click_extra.sphinx` listed in `extensions` without `click_extra_enable_exec_directives = True` in `conf.py`. Since click-extra `v7.15.0` the directives are off by default; without the flag, every `{click:run}` / `{click:source}` / `{python:*}` reference logs an "Unknown directive" warning and the page renders without the live block.

.claude/skills/repomatic-deps/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ You help users understand and maintain their project's dependencies. This skill
3838

3939
### Mechanical layer
4040

41-
The `autofix.yaml` workflow's `update-dep-graph` job regenerates the dependency graph on release commits only, to avoid noise from transitive dependency changes. This mode is useful for **interactive analysis** — understanding the graph, spotting concerns, or generating it before pushing.
41+
The `_release-engine.yaml` workflow's `update-dep-graph` job regenerates the dependency graph on release commits only, to avoid noise from transitive dependency changes. This mode is useful for **interactive analysis** — understanding the graph, spotting concerns, or generating it before pushing.
4242

4343
### Argument handling
4444

.claude/skills/repomatic-ship/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ The three substance passes own disjoint lanes (code owns Python including docstr
7070
- Manually-maintained version examples (install commands, binary download URLs, `uses:` refs) track the latest *released* tag, never the version being prepared, because the docs site deploys on every push to `main`. "Manually-maintained" is the load-bearing word and it is not a synonym for "under `docs/`": the freeze reaches into that tree in at least one repo (the canonical one rewrites `docs/install.md`), so decide file by file from the freeze's actual scope per the next bullet, never from the path. The tracking runs both ways: advance a sample that *lags* the released tag (still at N-1 after release N published) up to it, applying the bump directly rather than deferring it as a version advisory; only bumping a sample forward to the not-yet-released version is off-limits. A stale sample hides in plain sight, so grep every version string in `docs/` and `readme.md` rather than trusting a sub-agent's list.
7171
- What the freeze rewrites varies by repo (the canonical repo pins workflow refs and CLI invocations; a downstream freeze may touch only `changelog.md`, `citation.cff`, `__init__.py`, and `pyproject.toml`). Read the last freeze commit's file list (`git show <last-freeze-sha> --stat`) and treat every version sample outside it, `readme.md` quick-start output included, as hand-maintained tracking the released tag: samples presumed freeze-managed have shipped stale through a release. On a cycle that migrated the release tooling itself, the historical freeze under-predicts the new one (a pre-repomatic freeze touching only `changelog.md` says nothing about the repomatic freeze, which also rewrites `citation.cff`, `__init__.py`, and `pyproject.toml`): treat every version sample as hand-maintained until the regenerated release PR's diff shows the new freeze's actual scope.
7272
- The mirror of the hand-maintained rule: a freeze-managed field legitimately shows the *dev* version between releases, so never flag one as stale against the released tag or as a dead link. `pyproject.toml`'s `urls.Download` reading `.../releases/tag/vX.Y.Z.devN` (a tag that has no GitHub release yet) is the expected post-bump state that the freeze rewrites to the release tag at cut. Hand-maintained samples track the *released* tag while freeze-managed fields track the *dev* version, so classify a version string by which mechanism owns it before judging it stale.
73-
- A third owner sits beside hand-maintained and freeze-managed: artifacts regenerated by `autofix.yaml`'s `update-dep-graph` job, whose `if:` gates on `release_commits_matrix`, so it fires **only on release commits** ("only update dependency graph on release to avoid noise from transitive dependency changes"). `docs/assets/dependencies.mmd` therefore lags `pyproject.toml` for the whole cycle: a runtime dependency added since the last release is *expected* to be missing from it, and the graph catches up through its own PR once the release lands. Never hand-forge the file, and never run `<cmd> update-dep-graph` to "fix" it mid-sweep: a local run uses whatever repomatic version the sweep resolved rather than the version the job pins, so it produces churn the next regeneration reverts. Classify a stale-looking generated artifact by the job that owns it before reporting it as drift.
73+
- A third owner sits beside hand-maintained and freeze-managed: artifacts regenerated by `_release-engine.yaml`'s `update-dep-graph` job, whose `if:` gates on `release_commits_matrix`, so it fires **only on release commits** (never on ordinary pushes, to avoid noise from transitive dependency churn). It sits in the release engine rather than `autofix.yaml` because a release push is its only firing moment, and that is exactly the push `autofix.yaml` now skips wholesale, so do not go looking for it there. `docs/assets/dependencies.mmd` therefore lags `pyproject.toml` for the whole cycle: a runtime dependency added since the last release is *expected* to be missing from it, and the graph catches up through its own PR once the release lands. Never hand-forge the file, and never run `<cmd> update-dep-graph` to "fix" it mid-sweep: a local run uses whatever repomatic version the sweep resolved rather than the version the job pins, so it produces churn the next regeneration reverts. Classify a stale-looking generated artifact by the job that owns it before reporting it as drift.
7474
- Executable doc blocks fail open: a `{click:run}` invocation that no longer parses renders the usage error into the published page instead of failing the build (`docs.yaml` stayed green while a stale option printed `No such option`; only `click:tree` and `click:config` hard-error). Verify each `{click:run}` invocation against the current CLI, or grep the built HTML for `Error: No such option`-class output.
7575
- Correcting one description of a convention means correcting *every* description of it in the same pass: a rule restated in more than one place (an overview line and its worked example, two docs pages) drifts as a set, so grep for the sibling statements and align them together — fixing one in isolation leaves the others contradicting the fix (a freeze-cutoff overview still said "the day after" while its worked example had been corrected to "the second day after", reconciled only on a second pass).
7676
- The same "align the siblings" rule governs *quantities*, not just wording. A cycle that measured the same thing twice ships two answers, so cross-check every timing, size, count and ratio a page states against the other statements of it, the changelog's copy included (a performance page opened "every timing below comes from one batch of runs" while two of its tables disagreed `2.3x` on the same step at the same settings, each table internally consistent, because two commits had each measured their own batch; the changelog repeated the wrong figure). Surrounding prose that quotes a ratio the tables no longer support is the tell. Report the contradiction with the conflicting values and which one the other statements corroborate, rather than silently re-deriving numbers on hardware that is not the maintainer's: the figures are theirs to own, but they cannot fix what nobody flagged.

.github/workflows/autofix.yaml

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -723,14 +723,14 @@ jobs:
723723
724724
# --- sync-dep-sources: adopt released dependencies (Python projects). ---
725725
- if: >
726-
${{ !cancelled()
727-
&& fromJSON(needs.metadata.outputs.metadata).is_python_project }}
726+
!cancelled()
727+
&& fromJSON(needs.metadata.outputs.metadata).is_python_project
728728
name: Reset tree before sync-dep-sources
729729
run: git checkout -- .
730730
- id: sync-dep-sources
731731
if: >
732-
${{ !cancelled()
733-
&& fromJSON(needs.metadata.outputs.metadata).is_python_project }}
732+
!cancelled()
733+
&& fromJSON(needs.metadata.outputs.metadata).is_python_project
734734
name: Sync dependency sources
735735
run: >
736736
uv --no-progress run --frozen -- repomatic sync-dep-sources
@@ -746,8 +746,8 @@ jobs:
746746
--template sync-dep-sources
747747
--output "$GITHUB_OUTPUT"
748748
- if: >
749-
${{ !cancelled()
750-
&& steps.sync-dep-sources-meta.outcome == 'success' }}
749+
!cancelled()
750+
&& steps.sync-dep-sources-meta.outcome == 'success'
751751
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
752752
with:
753753
token: ${{ secrets.REPOMATIC_PAT || github.token }}
@@ -761,14 +761,14 @@ jobs:
761761
762762
# --- sync-uv-lock: re-lock dependencies (Python projects). ---
763763
- if: >
764-
${{ !cancelled()
765-
&& fromJSON(needs.metadata.outputs.metadata).is_python_project }}
764+
!cancelled()
765+
&& fromJSON(needs.metadata.outputs.metadata).is_python_project
766766
name: Reset tree before sync-uv-lock
767767
run: git checkout -- .
768768
- id: sync-uv-lock
769769
if: >
770-
${{ !cancelled()
771-
&& fromJSON(needs.metadata.outputs.metadata).is_python_project }}
770+
!cancelled()
771+
&& fromJSON(needs.metadata.outputs.metadata).is_python_project
772772
name: Sync uv.lock
773773
run: >
774774
uv --no-progress run --frozen -- repomatic sync-uv-lock
@@ -797,14 +797,14 @@ jobs:
797797

798798
# --- sync-action-pins: bump SHA-pinned actions (repos with workflows). ---
799799
- if: >
800-
${{ !cancelled()
801-
&& fromJSON(needs.metadata.outputs.metadata).workflow_files }}
800+
!cancelled()
801+
&& fromJSON(needs.metadata.outputs.metadata).workflow_files
802802
name: Reset tree before sync-action-pins
803803
run: git checkout -- .
804804
- id: sync-action-pins
805805
if: >
806-
${{ !cancelled()
807-
&& fromJSON(needs.metadata.outputs.metadata).workflow_files }}
806+
!cancelled()
807+
&& fromJSON(needs.metadata.outputs.metadata).workflow_files
808808
name: Sync action pins
809809
# GH_TOKEN raises the GitHub releases API rate limit when resolving
810810
# the latest tag and its commit SHA for each pinned action.
@@ -823,8 +823,8 @@ jobs:
823823
--template sync-action-pins
824824
--output "$GITHUB_OUTPUT"
825825
- if: >
826-
${{ !cancelled()
827-
&& steps.sync-action-pins-meta.outcome == 'success' }}
826+
!cancelled()
827+
&& steps.sync-action-pins-meta.outcome == 'success'
828828
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
829829
with:
830830
token: ${{ secrets.REPOMATIC_PAT || github.token }}
@@ -838,14 +838,14 @@ jobs:
838838
839839
# --- sync-workflow-pins: bump npm/PyPI literals (repos with workflows). ---
840840
- if: >
841-
${{ !cancelled()
842-
&& fromJSON(needs.metadata.outputs.metadata).workflow_files }}
841+
!cancelled()
842+
&& fromJSON(needs.metadata.outputs.metadata).workflow_files
843843
name: Reset tree before sync-workflow-pins
844844
run: git checkout -- .
845845
- id: sync-workflow-pins
846846
if: >
847-
${{ !cancelled()
848-
&& fromJSON(needs.metadata.outputs.metadata).workflow_files }}
847+
!cancelled()
848+
&& fromJSON(needs.metadata.outputs.metadata).workflow_files
849849
name: Sync workflow pins
850850
env:
851851
GH_TOKEN: ${{ secrets.REPOMATIC_PAT || github.token }}
@@ -862,8 +862,8 @@ jobs:
862862
--template sync-workflow-pins
863863
--output "$GITHUB_OUTPUT"
864864
- if: >
865-
${{ !cancelled()
866-
&& steps.sync-workflow-pins-meta.outcome == 'success' }}
865+
!cancelled()
866+
&& steps.sync-workflow-pins-meta.outcome == 'success'
867867
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
868868
with:
869869
token: ${{ secrets.REPOMATIC_PAT || github.token }}

.github/workflows/debug.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,8 @@ jobs:
5454
uv --no-progress run --frozen -- repomatic --verbosity DEBUG metadata
5555
--format github-json --output "$GITHUB_OUTPUT"
5656
build_targets
57-
# Unwraps the nested JSON string the metadata output carries. This used to
58-
# append `ubuntu-slim` as well, so the dump covered the one image outside
59-
# the test axes; now that every job runs on an axis, the build targets
60-
# already span the fleet.
57+
# Unwraps the nested JSON string the metadata output carries. Every job
58+
# runs on a test axis, so the build targets already span the fleet.
6159
- name: Unwrap build targets
6260
id: extend-matrix
6361
env:

changelog.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,21 @@
55
> [!WARNING]
66
> This version is **not released yet** and is under active development.
77
8-
- Teach the `repomatic-ship` skill to reconcile bundled skills and agents as a third pass, judge a false-positive autofix PR against current `main` before writing a lint rule for it, and tell a superseded intra-cycle measurement from a genuine contradiction.
98
- **Breaking:** the `update-dep-graph` job moved from `autofix.yaml` into the release engine, its only firing moment being a release push. A required check or `needs:` edge naming it under Autofix must follow.
109
- **Breaking:** manual version-bump commits now read `` [changelog] Bump minor version to `vX.Y.0` ``: every version-machinery commit carries the `[changelog] ` prefix, and anything matching the old unprefixed titles must follow.
10+
- **Breaking:** the default test matrix moved to `ubuntu-26.04-arm` and `ubuntu-26.04`, retiring `ubuntu-slim`: every job now runs on a test-matrix runner. Pin the old images back with `test-matrix.replace.os = { "ubuntu-26.04-arm" = "ubuntu-24.04-arm" }`.
11+
- **Breaking:** a report emitted with `--output-format github-actions` now travels as a file: the step output is named `<key>_file` and holds a path, so a large report reaches a PR body intact. A workflow reading `steps.<id>.outputs.diff_table` must read `.diff_table_file` instead.
1112
- New `lint-deps` command and release-lane job, blocking a release whose dependencies do not all resolve from PyPI: git branches, forks, local paths, direct URLs and private indexes. Exempt a package with `[tool.repomatic] lint-deps.allow`.
12-
- **Breaking:** the default test matrix moved from `ubuntu-24.04-arm` and `ubuntu-slim` to `ubuntu-26.04-arm` and `ubuntu-26.04`, which also moves the PR Linux slot and the `3.14t` smoke test. The docs link-crawl job, the Linux Nuitka build hosts and every light mechanical job move with them: `ubuntu-slim` is retired, measured 27-32% slower on whole-job wall-clock, so every job now runs on a test-matrix runner. Pin the old images back with `test-matrix.replace.os = { "ubuntu-26.04-arm" = "ubuntu-24.04-arm" }`.
13-
- **Breaking:** a report emitted with `--output-format github-actions` now travels as a file: the step output is named `<key>_file` and holds a path. A workflow reading `steps.<id>.outputs.diff_table` or `.markdown` must read `.diff_table_file` or `.markdown_file` instead.
1413
- New `runner-images` job and CLI command, opening an issue that lists GitHub's open runner-image announcements and flags the ones retiring an image the repo runs on. Opt out with `runner-images = false`.
15-
- Autofix jobs no longer run on version-bump pushes: the 16 remaining jobs only re-checked machine-generated, ship-gated commits, and drift stays covered by the next push and the weekly sweep.
14+
- New `is_python_package` metadata key. `sync-bumpversion` now gates on it instead of `is_python_project`, so the job no longer opens `[tool.bumpversion]` PRs against a uv virtual project (`[tool.uv] package = false`).
15+
- New `--prefix-file` option on `pr-body`, and a matching `GHA_PR_BODY_PREFIX_FILE` variable, reading the body prefix from a file.
16+
- Autofix jobs no longer run on version-bump pushes, which only re-checked machine-generated commits; drift stays covered by the next push and the weekly sweep.
17+
- `repomatic init` no longer writes the running version's workflow content beside a pin the cooldown held back: a repository that already carries workflows keeps them untouched until the release is adopted.
18+
- The `repomatic-ship` skill now reconciles bundled skills and agents as a third pass, judges a false-positive autofix PR against current `main`, and distinguishes a superseded intra-cycle measurement from a genuine contradiction.
19+
- macOS Nuitka builds now hit their compile cache: ccache hashes paths relative to the runner root (`base_dir`), so uv's randomly-named cache path no longer changes the hashed compiler arguments every run.
1620
- The tool runner now retries a download up to 3 times on transient network failures, instead of failing the job on a one-off TLS or truncation error.
1721
- Standalone binary tests now run for every healthy target when a sibling build fails, instead of being skipped wholesale.
18-
- Root-caused the macOS compile-cache misses: uv's randomly-named cache path leaks into Nuitka's include flags, changing the hashed compiler arguments every run. ccache now hashes paths relative to the runner root (`base_dir`), insuring the Linux cache against the same leak.
19-
- `repomatic init` no longer writes the running version's workflow content beside a pin the cooldown held back. A repository that already carries workflows keeps them untouched until the release is adopted, instead of receiving the new triggers, `concurrency` groups and `env:` blocks against the pinned release's reusable-workflow surface.
20-
- New `is_python_package` metadata key. `sync-bumpversion` now gates on it instead of `is_python_project`, so the job no longer opens `[tool.bumpversion]` PRs against a uv virtual project (`[tool.uv] package = false`).
2122
- Oversized step outputs are trimmed instead of killing the step that reads them with `Argument list too long`.
22-
- A PR body keeps its whole report: a dependency sweep whose release notes outgrow what an environment variable carries now reaches the body through a file instead of being cut to fit.
23-
- New `--prefix-file` option on `pr-body`, and a matching `GHA_PR_BODY_PREFIX_FILE` variable, reading the body prefix from a file.
2423
- The setup guide issue now reopens when Actions SHA pinning is turned off, instead of closing while reporting every repository setting complete.
2524

2625
## [`7.9.0` (2026-08-10)](https://github.com/kdeldycke/repomatic/compare/v7.8.0...v7.9.0)

0 commit comments

Comments
 (0)