Skip to content

release: 0.37.0, and move the argv entry out of the shipped 0.36.0 - #594

Merged
blooop merged 2 commits into
mainfrom
release/0.37.0
Sep 9, 2026
Merged

release: 0.37.0, and move the argv entry out of the shipped 0.36.0#594
blooop merged 2 commits into
mainfrom
release/0.37.0

Conversation

@blooop

@blooop blooop commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Why this exists

#593 — Cut 0.36.0 released 0.36.0 while #591 — dl -- re-splits every quoted argument it is given was in review. #591 carried its own release: 0.36.0 commit, so it re-cut a version that already existed. On merge the publish job did the right thing:

v0.36.0 is already tagged; nothing to publish

So the dl <ws> -- <command> quoting fix is on main and in no released artifact. The v0.36.0 wheel, conda package and GitHub release are all built from 2f05c38 and do not contain it. That fix is the one where a $(...) in a PR title or review body executes in a workspace holding the forwarded GH_TOKEN.

Why it was silent

Both sides set version = "0.36.0", so git saw an identical edit and merged it with nothing to resolve. Both inserted a byte-identical ## [0.36.0] - 2026-09-09 heading, so git merged the differing bodies underneath as separate additions. Picking the colliding number is what bought the silence: 0.37.0 would have conflicted loudly in rust/Cargo.toml.

main therefore claimed 0.36.0 fixed the quoting, and 0.36.0 does not.

What this does

1. Restores the record and cuts 0.37.0. The entry moves into a new ## [0.37.0], and the version goes to 0.37.0 so the fix actually ships. The 0.36.0 section is now byte-identical to git show v0.36.0:CHANGELOG.md:

$ diff <(git show v0.36.0:CHANGELOG.md | sed -n '/^## \[0.36.0\]/,/^## \[0.35.0\]/p') \
       <(sed -n '/^## \[0.36.0\]/,/^## \[0.35.0\]/p' CHANGELOG.md)
$

2. Gives changelog_frozen.py a way out of a merged misfile. The guard compares head against the base branch, which works only while the bad entry is still on a branch. Once it merges it is the base: every honest correction changes a released section, the guard refuses all of them, and the false record becomes the only text CI accepts. This PR hit that state.

A released section may now move in exactly one direction: back to git show v<version>:CHANGELOG.md, byte for byte. The tag is what makes that safe rather than a loophole, since it is written by the release and not by the branch asking to be let through. Anything short of a confident answer from git (no tag, no git, an unparsable file at that tag) refuses, so the arm only ever permits a restoration it has positively proved.

Three tests, the first of which fails without the change: a restoration proved by its tag passes, an edit to anything else is still refused, and a restoration with no tag to prove it is refused rather than waved through. ci.yml fetches tags shallowly, since actions/checkout fetches none.

What this does not do

It cleans up the consequence, not the cause. Neither of these is here, and both are worth doing:

  • A PR-time collision check — fail if the PR's rust/Cargo.toml version already has a v<version> tag. That catches it before merge, and would have failed fix: dl -- <cmd> re-splits every quoted argument it is given #591 the moment Cut 0.36.0 #593 landed.
  • Make publish.yml loud on collision — its decision step tests "already tagged?" before "did the version change?", so a real bump onto a taken version reports nothing to publish, the same message an ordinary push gets. If the version changed and is already tagged, that is an error, not a skip. A reordering of two checks it already performs.

The standing convention is the other half: every release for the last eight versions was cut on its own release/X.Y.Z branch doing nothing but the bump, which is why this is the first time it has happened.

Verification

Full CI green, including the freeze guard, which now reports:

'## [0.36.0]' changed, and now matches v0.36.0 exactly: restored
every released section is untouched or restored (75 compared)

761 passed in the Python guards, prek clean, pylint 10.00/10, and dl --version / aid --version both report 0.37.0.

🤖 Generated with Claude Code

0.36.0 was cut and published by #593 while #591 was in review, so #591's own
`release: 0.36.0` commit re-cut a version that already existed. The publish job
did the right thing on merge -- `v0.36.0 is already tagged; nothing to publish`
-- which left the `dl <ws> -- <command>` quoting fix merged to main and not in
any released artifact. The v0.36.0 wheel, conda package and GitHub release are
all built from 2f05c38 and do not contain it.

What made that worse than a wasted version number is the changelog. #591's
entry merged in under the `## [0.36.0]` heading that #593 had just created, with
no conflict -- exactly the failure #527 added
`scripts/changelog_frozen.py` for, arriving from the one direction the guard
cannot see, since the guard compares against a base that already has the entry
misfiled. So main claimed 0.36.0 fixed the quoting and 0.36.0 does not.

The entry moves into a new 0.37.0. The 0.36.0 section is now byte-identical to
`git show v0.36.0:CHANGELOG.md`, which is the check that says this restores the
record rather than editing it.

**`changelog_frozen` is red on this branch, deliberately.** It sees 0.36.0
change and cannot tell a restoration from a corruption; its own message asks for
this to be said out loud in the pull request rather than worked around. Nothing
is skipped, loosened or ignored to get it green.

Claude-Session: https://claude.ai/code/session_01XvY78XEnrkzNjxZE5EtnyW
@sourcery-ai

sourcery-ai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Reviewer's Guide

This release correction publishes the already-merged argv quoting fix as 0.37.0, moves its changelog entry out of the shipped 0.36.0 section to preserve release history, and updates Rust and README version metadata accordingly.

Sequence diagram for argv-preserving remote command execution

sequenceDiagram
    participant User
    participant dl
    participant RemoteShell
    participant Program
    User->>dl: dl workspace -- command args
    dl->>dl: shell::join(args)
    dl->>RemoteShell: Execute quoted argv
    RemoteShell->>Program: Preserve each argument as one word
    Program-->>User: Run with original argv
Loading

Flow diagram for publishing the corrected 0.37.0 release

flowchart LR
    Existing["0.36.0 artifact lacks argv fix"] --> Move["Move fix entry to 0.37.0"]
    Move --> Metadata["Update Cargo and README to 0.37.0"]
    Metadata --> Publish["Publish 0.37.0"]
    Publish --> Artifact["Released artifact contains argv quoting fix"]
Loading

File-Level Changes

Change Details Files
Moves the shipped command-argument quoting fix into a new 0.37.0 release while restoring the 0.36.0 changelog section.
  • Adds the quoting, shell-injection, argv, and compatibility behavior to the 0.37.0 changelog entry.
  • Removes the misfiled entry from 0.36.0 so that section matches the tagged release exactly.
CHANGELOG.md
Bumps project and user-facing version metadata to 0.37.0.
  • Updates the Rust workspace package version.
  • Regenerates the corresponding lockfile version entries.
  • Updates README badges and version output examples.
rust/Cargo.toml
rust/Cargo.lock
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

`changelog_frozen.py` compares head against the base branch, which works only
while the bad entry is still on a branch. Once it merges, it *is* the base: every
honest correction then changes a released section, the guard refuses all of them,
and the false record becomes the only text CI will accept. That is the opposite
of what the guard is for, and it is not hypothetical -- #591 re-cut a version #593
had already published, so its entry landed under the shipped `## [0.36.0]`
heading from the one direction a base-versus-head comparison cannot see.

A released section may now move in exactly one direction: back to
`git show v<version>:CHANGELOG.md`, byte for byte. The tag is what makes that
safe rather than a loophole -- it is written by the release, not by the branch
asking to be let through, so agreement with it cannot be forged. Anything short
of a confident answer from git (no tag, no git, an unparsable file at that tag)
refuses, so the arm only ever permits a restoration it has positively proved.

Three tests, and the first fails without the change: a restoration proved by its
tag passes, an edit to anything else is still refused, and a restoration with no
tag to prove it is refused rather than waved through. `ci.yml` fetches tags
shallowly, since `actions/checkout` fetches none and the oracle is unreachable
without them.

Claude-Session: https://claude.ai/code/session_01XvY78XEnrkzNjxZE5EtnyW
@blooop
blooop merged commit 07eccdd into main Sep 9, 2026
15 checks passed
@blooop
blooop deleted the release/0.37.0 branch September 9, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant