fix(workflow): insert ### Changed in Keep-a-Changelog order on auto-CHANGELOG (#26)#41
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…HANGELOG (closes #26) Cascades the validated cmeans/mcp-synology PR #63 fix (squash 8a4df0d, merged 2026-04-26 23:24Z) to this repo's .github/workflows/dependabot-changelog.yml. The bug: When `## [Unreleased]` already contained a subsection (e.g., `### Added`) but no `### Changed` block, the auto-CHANGELOG workflow's else-branch inserted the new `### Changed` block at `unreleased_idx + 1` regardless of what subsections already existed. With `### Added` at unreleased_idx + 2, the new `### Changed` landed ABOVE the existing `### Added`, violating Keep-a-Changelog v1.1.0's mandated order: Added → Changed → Deprecated → Removed → Fixed → Security Dormant on this repo until #36 release wave: post-PR #25 cascade the workflow ran on PRs #23 and #24 with both `### Added` and `### Changed` already populated in `## [Unreleased]`, so the if-branch (insert under existing `### Changed`) fired both times — the buggy else-branch never executed. The next time it WOULD fire is post-v0.1.1 release: fresh empty Unreleased section, then a feature PR adds `### Added`, then the next weekly Dependabot Monday bump triggers the workflow's else-branch and produces an out-of-order CHANGELOG. The fix: Walk forward from `## Unreleased` to find either: (a) the first subsection that should sort AFTER `### Changed` per KaC ordering (i.e., `### Deprecated`, `### Removed`, `### Fixed`, `### Security`), or (b) the next `## ` release heading. Insert the new `### Changed` block immediately before whichever comes first. Default insertion point is the end of the Unreleased section (just before the next `## ` heading) when no later-sorting subsections exist. Adaptation preserved from our heading-tolerant variant: the matcher accepts both `## Unreleased` (mcp-synology's form) and `## [Unreleased]` (this repo's Keep-a-Changelog bracketed form). Only the else-branch changes; the if-branch (insert under existing `### Changed`) and the loop guard / idempotency guard / token mint / Dependabot filter are byte-for-byte unchanged. Verification: Reproduced upstream QA's algorithm-extraction smoke test against six KaC layouts on the cascaded fix: A. Empty Unreleased → Changed ✓ B. Added only (the bug case) → Added → Changed ✓ C. Changed already exists → Added → Changed ✓ D. Added + Fixed → Added → Changed → Fixed ✓ E. Fixed only → Changed → Fixed ✓ F. Bracketless heading (## Unreleased) → Added → Changed ✓ All six KaC arrangements produce correctly-ordered subsections. Workflow YAML parses (PyYAML safe_load). The verification gate from the dependabot-pr-hygiene-playbook ("validate on real data before cascading") was met on mcp-synology side via the upstream QA smoke test; live Dependabot validation via @dependabot recreate is belt-and- suspenders that can be exercised on this repo's next weekly Dependabot bump. Per CLAUDE.md: this is a CI/automation fix (not user-visible library behavior), so no operator-impact framing in the CHANGELOG bullet — just the categorization-correctness description.
2975d46 to
9320d16
Compare
|
Rebased on The conflict. Both branches inserted text after Resolution. Both stay; no content lost. Final order under No substantive change to PR scope. The Verification on rebased branch.
New head: |
cmeans
left a comment
There was a problem hiding this comment.
QA round 1 — FAIL (one observation)
Verified the workflow change end-to-end at head 9320d16. Algorithm is correct; one wording observation in the CHANGELOG bullet.
What I verified
-
Diff scope:
.github/workflows/dependabot-changelog.yml(+13/-3) andCHANGELOG.md(+4) only — matches PR claim. -
If-branch unchanged:
git diff f7ff312 9320d16 -- .github/workflows/dependabot-changelog.ymlshows exactly one hunk, in the else-branch (lines 169–188 region). The if-branch (changed_idx is not Nonepath), theunreleased_idxmatcher (accepts both## Unreleasedand## [Unreleased]), the loop guard, idempotency check, App-token mint, anddependabot[bot]filter are byte-for-byte unchanged from the parent commit. -
Workflow YAML parses:
yaml.safe_loadsucceeds;jobs: ['changelog'], triggerpull_request_targeton[opened, synchronize, reopened]. -
Algorithm-extraction smoke test, six PR-claimed layouts (extracted into a standalone
qa_smoke.pymirroring the inline Python verbatim):Layout Result Final order A. Empty Unreleased PASS ### ChangedB. Added only (the bug case) PASS ### Added → ### ChangedC. Changed already exists (if-branch) PASS ### Added → ### ChangedD. Added + Fixed PASS ### Added → ### Changed → ### FixedE. Fixed only PASS ### Changed → ### FixedF. Bracketless ## UnreleasedPASS ### Added → ### Changed -
Five extra adversarial layouts (not in the PR table — covering the rest of the KaC subsection vocabulary):
Layout Result Final order G. Added + Removed PASS ### Added → ### Changed → ### RemovedH. Added + Deprecated PASS ### Added → ### Changed → ### DeprecatedI. Security only PASS ### Changed → ### SecurityJ. Already-have-Changed + Fixed (if-branch path) PASS ### Added → ### Changed → ### FixedK. No Unreleased section at all (orthogonal code path) PASS fresh ## [Unreleased]with### ChangedAll four
after_changedmembers (### Deprecated,### Removed,### Fixed,### Security) get walked correctly. Blank-line invariants verified for B/D/E (the new### Changedheading has a blank line before AND after). -
Repo's own pytest suite at PR head:
uv run pytest --cov→ 71/71 passed, 100.00% coverage, gate satisfied.ruff check/ruff format --check/mypyclean. -
CI all green at
9320d16: lint, typecheck, test 3.11 / 3.12 / 3.13, deploy-smoke. (Test-plan CI checkbox in the PR body is now ticked.) -
Issue #26 scope: the issue's suggested algorithm — "search forward from
unreleased_idx + 1until either (a) a subsection that should sort after### Changedper KaC, or (b) the next##heading" — matches the implementation line-for-line. No scope drift.
Findings
- (observation, CHANGELOG wording) The new
## [Unreleased]### Fixedbullet says "Dormant on this repo until #36 release". PR #36 is thestale_threshold_dayswarning fix that landed during v0.1.1's pre-release cycle, not a release in itself — and PR #38 was actually the last feature-class merge before the v0.1.1 release PR #39. The PR body's narrative gets this right ("Dormant on this repo until v0.1.1 ship"), but the CHANGELOG bullet conflates a PR number with a release version. Future readers of the CHANGELOG will not be able to map#36 releaseto a release tag without spelunking. Suggest replacing#36 releasewithv0.1.1 release(orthe v0.1.1 release tag) so the dormancy timeline reads cleanly against the project's release history.
Recommendation
Edit the CHANGELOG bullet only — one phrase. Re-apply Ready for QA; I'll re-verify in round 2 (CHANGELOG-only diff, fast turnaround).
Switching label: QA Active → QA Failed.
|
Switching label: |
…release" QA round 1 finding: the CHANGELOG bullet conflated PR #36 (the stale_threshold_days warning fix that landed during the v0.1.1 pre-release cycle) with a release version. PR #36 is not a release — v0.1.1 is. Future readers couldn't map "#36 release" to a release tag without spelunking. PR body's narrative already says "v0.1.1 ship" correctly; only the CHANGELOG bullet was off. CHANGELOG-only edit. No workflow change, no test change. Verified at HEAD: pytest 71/71, ruff clean, mypy clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QA round 2 — single CHANGELOG wording fixAddressed the round-1 finding. Replaced Diff: Scope: CHANGELOG-only, single phrase, one line changed (+1/-1). No workflow change, no test change. Workflow algorithm at head Verification:
New head: |
cmeans
left a comment
There was a problem hiding this comment.
QA round 2 — PASS
Round-1 observation resolved in commit 837f575 (CHANGELOG-only diff):
- "Dormant on this repo until #36 release" → "Dormant on this repo until the v0.1.1 release" — exactly the suggested phrasing, dormancy timeline now reads cleanly against the project's release history.
Re-verification
- Workflow YAML byte-identical to round-1 head:
diff <(git show 9320d16:.github/workflows/dependabot-changelog.yml) <(git show 837f575:.github/workflows/dependabot-changelog.yml)is empty. Round 1's algorithm verification (11/11 layouts: A–F from the PR table + G/H/I/J/K adversarial extras) carries forward unchanged. - Diff scope round 1 → round 2:
CHANGELOG.md(+1/-1) only — single line edit, no other surface touched. - CI all green at
837f575: lint, typecheck, test 3.11 / 3.12 / 3.13, deploy-smoke.
Verdict
Zero findings. Awaiting maintainer QA Approved.
|
Switching label: |
… hygiene (#48) Bumps version 0.1.2 → 0.1.3 and promotes the [Unreleased] section to [0.1.3] - 2026-04-28. Five PRs land in this release; full bullets in CHANGELOG.md. ### Added - ci(publish): auto-create GitHub release page on v* tag from CHANGELOG (#47, eae5e80) — first release that exercises this end-to-end. ### Fixed - chore(docker): bump uv pin from `==0.4.*` to `>=0.5,<1` (#44, 2679f07, closes #34) - docs(issue-template): refactor bug_report version placeholder to durable form (#45, 75a6384, closes #40) - docs(readme): refresh dogfood blockquote — count > 0, drop M3 reference (#46, eacbf60, closes #43) - fix(workflow): insert ### Changed in Keep-a-Changelog order on auto-CHANGELOG (#41, 4bb8584, closes #26) uv.lock refreshed to pick up the version bump (single source of truth in pyproject.toml; uv lock writes 0.1.3 into uv.lock automatically). Co-authored-by: cmeans-claude-dev[bot] <272174644+cmeans-claude-dev[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…le block each Round 1 QA flagged that the v0.2.0 section had `### Changed` (Alpha→Beta) → `### Added` (PR #49) → `### Changed` (PR #50) — both wrong order (KaC v1.1.0 specifies Added → Changed → Deprecated → Removed → Fixed → Security) and duplicate `### Changed` blocks (standard KaC has one block per category per release). PR #41 specifically enforces this ordering on auto-CHANGELOG runs; hand-authored release commit shouldn't regress it. Reorders the v0.2.0 section so `### Added` comes first, then a single `### Changed` block containing both the README modernization bullet (PR #50) and the Alpha → Beta promotion bullet, in that order. The auto-release-page workflow added in PR #47 will now render the v0.2.0 GitHub Release page with the standard KaC shape. No content change — just structural fix. Same words, regrouped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…51) * release: v0.2.0 — installer-mix v2 + uv-first README modernization Bumps version 0.1.3 → 0.2.0 and promotes the [Unreleased] section to [0.2.0] - 2026-04-29. Two PRs land in this release; full bullets in CHANGELOG.md. Minor bump (rather than patch) is justified because run_pypinfo's return type changed from `int` to `dict[str, int]` in PR #49 — not a public API but a public-ish internal contract that tests and future callers depend on. The feature surface is also new (7 new badge files per package per window), making 0.2.0 the right semantic line. ### Added - feat(collector): add per-installer badge files (installer-mix v2) (#49, 2898ee9). Six individual installer badges + pip-family aggregate per package; v1 hero unchanged. Already verified end-to-end on the live CT 112 deploy. ### Changed - docs: uv-first install everywhere + by-installer dogfood layout + breakdown narrative (#50, 830c051). Hero in top metadata row; by-installer breakdown below blockquote; uv tool install leads in README and deploy/README.md; SECURITY.md mentions both uv and pip. uv.lock refreshed to pick up the version bump (single source of truth in pyproject.toml; uv lock writes 0.2.0 into uv.lock automatically). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * release: promote Alpha → Beta on v0.2.0 Trigger: four v0.1.x releases shipped, real production deploy running since 2026-04-25 producing daily badges for four packages, 100% test coverage on src/, additive-only schema evolution (v2 added new badge files alongside the unchanged v1 hero rather than mutating anything). Folding into the v0.2.0 release PR so the bump lands with the minor version cut. - pyproject.toml: `Development Status :: 3 - Alpha` → `Development Status :: 4 - Beta`. PyPI's classifier display picks this up on next ship. - README.md ## Status section rewritten: leads with "Beta as of v0.2.0", names the live-since date, mentions the 100% coverage, and adds the explicit guarantee that the v1 hero badge JSON shape and filename are stable through 1.0 (so README readers and downstream maintainers know what's frozen). - CHANGELOG.md gets a new ### Changed bullet under [0.2.0] with the rationale + scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(changelog): fix v0.2.0 KaC ordering — Added before Changed, single block each Round 1 QA flagged that the v0.2.0 section had `### Changed` (Alpha→Beta) → `### Added` (PR #49) → `### Changed` (PR #50) — both wrong order (KaC v1.1.0 specifies Added → Changed → Deprecated → Removed → Fixed → Security) and duplicate `### Changed` blocks (standard KaC has one block per category per release). PR #41 specifically enforces this ordering on auto-CHANGELOG runs; hand-authored release commit shouldn't regress it. Reorders the v0.2.0 section so `### Added` comes first, then a single `### Changed` block containing both the README modernization bullet (PR #50) and the Alpha → Beta promotion bullet, in that order. The auto-release-page workflow added in PR #47 will now render the v0.2.0 GitHub Release page with the standard KaC shape. No content change — just structural fix. Same words, regrouped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: cmeans-claude-dev[bot] <272174644+cmeans-claude-dev[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Closes #26. Cascades the validated
cmeans/mcp-synologyPR #63 fix (squash8a4df0d, merged 2026-04-26 23:24Z) for the auto-CHANGELOG workflow's subsection-ordering bug. The else-branch in_check_staleness's peer subsection-insertion logic was inserting a new### Changedblock above existing### Added(or any other subsection that sorts after Changed per Keep-a-Changelog v1.1.0), violating the mandated Added → Changed → Deprecated → Removed → Fixed → Security order.The bug, when it manifests
## [Unreleased]Dormant on this repo until v0.1.1 ship: post-PR #25 cascade, the workflow ran on PRs #23 and #24 with both
### Addedand### Changedalready populated in## [Unreleased], so the if-branch (insert under existing### Changed) fired both times. The next time the buggy else-branch WOULD fire is post-v0.1.1: fresh empty Unreleased, a feature PR adds### Added, the next weekly Dependabot Monday bump fires the workflow's else-branch.The fix
Walk forward from
## Unreleasedto find either (a) the first subsection that sorts AFTER### Changedper KaC ordering (### Deprecated,### Removed,### Fixed,### Security), or (b) the next##release heading. Insert the new### Changedblock immediately before whichever comes first.Adaptation preserved from our heading-tolerant variant: matcher accepts both
## Unreleased(mcp-synology's form) and## [Unreleased](this repo's KaC-bracketed form). Only the else-branch changes (~13 lines); the if-branch, loop guard, idempotency guard, App-token mint, and dependabot[bot] filter are byte-for-byte unchanged.Verification
Reproduced upstream QA's algorithm-extraction smoke test against six KaC layouts on the cascaded fix locally:
```
A. Empty Unreleased → Changed ✓
B. Added only (the bug case) → Added → Changed ✓
C. Changed already exists → Added → Changed ✓
D. Added + Fixed → Added → Changed → Fixed ✓
E. Fixed only → Changed → Fixed ✓
F. Bracketless heading (## Unreleased) → Added → Changed ✓
ALL PASS
```
All six layouts produce correctly-ordered subsections. Workflow YAML parses via
yaml.safe_load.Test plan
.github/workflows/dependabot-changelog.yml(+13/-3) andCHANGELOG.md(+4) only — matches PR claim## Unreleased)### Changed) is byte-for-byte unchanged from main, verified by inspecting the diff### Addedto a fresh## [Unreleased]; the next Dependabot bump after that triggers the buggy else-branch on the OLD workflow but the fixed path on the new one. If you want belt-and-suspenders, the existing two open Dependabot PRs (none currently — Dependabot is on weekly Monday cycle) could be@dependabot recreate-ed to re-exercise the workflow.Source
8a4df0d, merged 2026-04-26 23:24Z, validated by upstream QA via the same six-layout smoke test.add_contextiddd3123d2(the cross-repo finding I posted yesterday for upstream Dev to pick up) — informational entry, the upstream Dev acted on it and shipped the fix in PR chore(deps): refresh uv.lock transitive pins (2026-05-07) #63.dependabot-pr-hygiene-playbook, fix lands in one repo first + algorithm-extraction smoke test by upstream QA + reproduced locally → cascade approved.Closes #26