2026-07-17 Update-Changelogs Feature via Superpowers SDD
What I set out to do
Started from a failed update -c (the claude-settings flake check rejected the @internal skipWorkflowUsageWarning key after a schema bump). Fixed that, then the session turned into a research + build: is there tooling that resolves an arbitrary package to its changelog between two versions, and if not, build a small one for the dotfiles update script.
What I actually did
- Unblocked
update -c: addedskipWorkflowUsageWarningtoschemaLagExceptionsinnix/tests/claude-settings/default.nix(the key is@internal, never in schemastore). Committed, re-ranupdate -cclean (profile 475→476). Documented the schema-lag gotcha on the existing consent-gate memory. - Researched the changelog-resolution landscape (two verified subagent sweeps): Renovate’s
changelog/source.tshas the best reusable heuristics but isn’t a standalone lib; ecosyste.ms is the most reusable hosted engine; Libraries.io/Repology/lastversion each cover a slice. Concluded a bespoke thin resolver is justified because the dotfiles ecosystems (Nixsrc/meta.changelog, lazy-lock SHAs, PyPIproject_urls) already encode the repo. - Built
update-changelogsend-to-end via the superpowers workflow: brainstorm → ADR 0011 → plan → subagent-driven-development (5 tasks, per-task spec+quality reviews, opus whole-branch review, fix waves). New standalone bash binary (nix/nvimmodes) enriches the end-of-run summary with condensed GitHub release-note bullets + a changelog link; hermetic pytest flake check (gh/nixstubbed on PATH). Merged tomain(402f56e). - Fixed a stale nvim ref:
nvim/lua/plugins/git.luapinnedechasnovski/mini.nvim(upstream renamed the org tonvim-mini); retargeted it.
What was striking
- The live deploy-verify earned its keep. Unit tests passed on an idealized fixture, and even the opus whole-branch review (working from the diff) missed it — but running the real thing after
hm switchshowedmini.nvimresolving to the staleechasnovskiowner. The realgit.luahas that stale ref as its firstowner/repospec, which fooled the “first-spec-in-file” heuristic. Fix: resolve the owner by majority vote across all specs (nvim-mini ×2 beats echasnovski ×1). Lesson: for heuristics over real config, a diff-based review and a synthetic fixture are both blind in the same way; only exercising the live data exposed it. - A
.gitignoreunanchored*logspattern silently swallowed the newupdate-changelogsscript + test dir (basenames end in “logs”), so Nix couldn’t see them. Alsosuperpowers/blocksdocs/superpowers/, so the plan/spec had to live indocs/decisions/as an ADR. Captured as a durable memory. - The codebase already had the exact heuristic in
get_compose_input_diffs()(resolve owner/repo/rev from a lock file →gh api compare). The feature is really a generalization of an established local pattern, not an invention.
Related
- ADR:
docs/decisions/0011-update-changelog-resolution.md - 2026-06-06 Untangling the update -c Failure Cascade — prior
updatescript work - 2026-07-16 Superpowers Plugin Evaluation Research — the workflow used here
- 2026-07-09 Claude Settings Hardening and checkLinkTargets Root Cause — the claude-settings check this session extended
Follow-up: render polish (same day)
After the first live update -c, the enriched summary worked but had rough edges. Fixed on branch feat/changelog-render-polish, merged to main (1dc3e20), 31 tests:
- Prefer markdown list items in release bodies. This both drops scaffolding (headings, HTML comments, block quotes, horizontal rules) AND skips the boilerplate preamble in one move — e.g. ripgrep now shows its actual change list instead of the sponsorship/description intro; lazygit/mermaid lose their
##/<!-- -->noise. Prose fallback (no list) strips the same scaffolding. - Generalized GitHub URL parsing (
parse_github_ref): ameta.changelogpointing at a CHANGELOG file —github.com/O/R/blob/TAG/…orraw.githubusercontent.com/O/R/refs/tags/TAG/…— now yields owner/repo/tag, so opentofu, codex (non-guessablerust-v*tag), and cloudflared fetch real release notes instead of just linking. - Checksum + code-fence filtering: cloudflared-style release bodies (fenced SHA256 blocks) collapse to link-only instead of emitting junk bullets.
- Colorized output (cyan
•bullets, blue→links, bold name / cyan arrow in the header), TTY-gated and honoringNO_COLOR/CLICOLOR_FORCEso pipes/logs/tests stay plain. - zsh stays homepage-link-only: it’s a SourceForge project (no GitHub repo), so a GitHub-centric resolver can’t do better without per-package hardcoding, which I deliberately avoided.