A contributor opens a change request from their own branch and then pushes a
follow-up commit. The request still names the old head. vole change update <id> --head <rev> is the only way to move it, and that writes refs/heads/vole,
which contributors cannot push: the pre-receive gate keeps them inside
refs/heads/contrib/<account>/. The web has no head-update action and the SSH
server has no verb for it. So the only way to point the request at the new
commit is a maintainer with a local clone — or opening a second request, which
throws away the discussion and the approvals history.
That leaves the review loop with a hole in it: a contributor is told to push to their namespace and open a request, but cannot keep that request current themselves.
Found while adding a follow-up commit to change request
01M5XM4H99DZ71VTJC8YWYS1CC (which fixes #01M5XFSJTVQ8ZY5WWC1GMTPNFZ): moving the
head from 2841d92 to 43f98bc needed the CLI.
Why the SHA stays the head
Approvals bind to a commit — request.md records head: as a full commit id —
so a branch that moves does not carry its approval with it. That is correct and
should not change. What is missing is the authorised way for the person who owns
the branch to say “the head is now this commit”, without them being able to
edit the metadata branch generally.
Scope
- A web action on the request page, next to approve / merge / state, that moves an open request’s head to the tip of a branch.
- Or an SSH verb in the shape of
vole-change-merge(which the server resolves from the request and the ACL), sovole change update <id> --head <branch>works for a contributor without a metadata-branch write. - Apply the rule the browser already applies when opening a request: the head
must be a branch tip, and a contributor may only name a branch under
refs/heads/contrib/<their-account>/(access.IsContributorRef). A maintainer may name any normal branch. - Only an open request. Existing approvals stay as history but stop matching the
new head; the page already marks them stale and
vole change updatealready prints that note. - The action is audited like the other request writes, and the request tree is validated after it.
Acceptance criteria
- The author of an open request can move its head from the browser to the tip of a branch in their own namespace, and the request page then reviews that commit.
- A contributor cannot name another account’s branch, a tag, or an arbitrary commit; the refusal says which rule was broken.
- A maintainer can move any open request’s head to any normal branch tip.
- A closed or merged request refuses the update.
- The change lands in one metadata commit, appears in
data/audit.log, and leavesValidateRequestsclean. - Tests cover allowed (author, maintainer) and refused (another contributor, foreign namespace, missing branch, non-tip commit, closed request) cases, and prove the web/SSH path cannot name an arbitrary SHA.