Repository navigation
Description
Problem
publish.sh performs the writes after every gate passes. It plans the push (new branch, current, fast-forward, or a rewrite that leases on the exact remote commit), pushes with the repository's pre-push hook, checks through git ls-remote that origin holds the reviewed commit, and rechecks the branch, draft and identity before writing. It then creates the pull request through gh-post, or edits an open one (base, title, body, labels, reviewers, assignees, milestone, draft state) while preserving the owner-review label. A wrong lease or a retried uncertain write is the costly failure here.
Part of #588 and #323. Delivers in Go the behavior of packages/agents/source/skills/pr/shared/scripts/publish.sh. This change adds Go behavior only and switches no caller.
Acceptance criteria
- AC1: Given a new branch, a branch origin already holds at the reviewed commit, or a fast-forward, when publication runs, then it plans the push kind from what origin holds now (read from origin itself), pushes only when there is something to push, and checks through
git ls-remotethat origin holds the reviewed commit afterwards. - AC2: Given a rebased branch and no
--rewrite, when publication runs, then it refuses to push and says to use--rewriteonly on the operator's word; given--rewrite, then it pushes with a lease on the exact commit origin holds. - AC3: Given
HEADbehind origin's branch, origin holding a commit never fetched here, or origin's branch unreadable, when publication runs with or without--rewrite, then it refuses before any push. - AC4: Given
--dry-run, when publication runs, then it prints the push plan, warns when the real push would not fast-forward, checks the identity, and pushes and writes nothing without consulting the confirmation. - AC5: Given a repository pre-push hook, when publication pushes, then the hook runs before the push completes and its failure stops publication.
- AC6: Given
HEADmoved during the push, or origin holds a commit other than the reviewed one afterwards, when publication continues, then it refuses before any pull request is touched; given unattended mode and a branch, draft or signed-in account that changed since the checks, then it refuses before the GitHub write, with the account change and the draft change as separate cases. - AC7: Given no open pull request for the branch, when publication succeeds, then a pull request is created through
gh-postwith the draft's base, head branch, title, body, draft flag, labels, reviewers, assignees and milestone, and its URL is printed. - AC8: Given an open pull request for the branch, when publication succeeds, then its base, title and body are edited, labels, reviewers and assignees are reconciled in both directions, an empty milestone value removes the milestone and a set one applies it, readiness is set or undone to match the draft's
draftvalue, and the URL is printed. - AC9: Given an open pull request that carries the owner-review label (matched in any letter case), when publication reconciles labels, then that label is preserved and never removed, and publication never adds it from the draft's properties.
- AC10: Given
ghfails while reading the open pull request's current properties, when publication edits, then no edit has been made. - AC11: Given a write's outcome is uncertain, when publication fails, then it is not retried and the output says to inspect GitHub.
- AC12: Non-functional: pull request creation and content edits (base, title, body) go through
gh-postwith the body from--body-file; property-only edits (labels, reviewers, assignees, milestone) also go throughgh-post, with empty standard input as the shell does and no body file; readiness changes usegh pr ready; no otherghwrite is made.
Scope and non-goals
Scope: push planning, the push, the remote check, the post-push rechecks, creation and editing, and handing the publication outcome (number, URL, head, base, draft state, push kind) to the caller.
Non-goal: the gates and confirmation before this, and property resolution, which child 08 ports. Non-goal: recording the publication result and the unattended report, which child 10 owns (that recording happens only in unattended mode today). Non-goal: the gh-post implementation. Non-goal: switching the shell caller, which child 12 does.
Approach
Meet AC1 to AC12 with failing table-driven cases first, using bare scratch repositories as remotes and the fake gh and gh-post the Bats suite uses, and match the shell's lease and refusal output byte for byte. The unattended recheck cases follow tests/skills/agent-pr/publish.bats.
Dependencies
Blocked by: #917, #760 (identity and rate-limit reporting), #753 (protection of new Go enforcement paths).
Prerequisite: #321.
Size
M. One pull request. Estimated under 650 changed code lines with tests (about 190 shell lines of behavior).
Verify plan
- AC1, AC2, AC3: Go tests over bare remotes with new, current, fast-forward, rebased, behind and unfetched-commit setups.
- AC4: a test runs a dry run with a recording confirmation source and asserts no push or write.
- AC5: a test with a hook that records and one that fails.
- AC6: tests where a stub moves
HEAD, rewrites the remote ref after the push, switches the signed-in account, and changes the draft;tests/skills/agent-pr/publish.batscases are the oracle. - AC7, AC8, AC9, AC10: tests with a fake
ghand a recordinggh-post, including an owner-review label in mixed case and a failing read. - AC11: a test where the create call fails after sending asserts exactly one attempt and that the output carries the instruction to inspect GitHub.
- AC12: a test asserts every
ghwrite outsidegh pr readygoes throughgh-post; the creation and content-edit calls carry--body-file, and a property-only edit carries no body file and has empty standard input. - Go tests run in the existing Go CI on macOS, Linux and Windows.
- Definition of done: D1 each AC is verified at the merged head, with the commands and results cited in the pull request's Verification. D2 an independent review approves the exact merged head, and every finding has a recorded disposition. D3 required checks pass with no gate loosened. D4 the leak scans the repository specifies are clean, and every post made for this work passes the per-post leak review before it is posted. D5 every commit is signed. D6 the documentation matches the change or the Verification says why there is no impact. D7 every commit has an
Assisted-bytrailer and the pull request has theprovenance:agent-assistedlabel. D8 the pull request stays within the size limits. D9 follow-ups are filed as issues and listed under Related. D10 the merge closes the issue through a closing reference, the board shows Done, and the finalStatus:comment names the merge commit.
Risks
A force push with the wrong lease overwrites a collaborator's commits, and a retried create can open a duplicate. The AC2, AC3 and AC11 cases are the control. Undo: revert the change; nothing calls the Go publication yet and the shell publishes as before.
Operator authority
None. The pr scripts are not on the owner-path list in .agents/agent-skills.conf; if the port touches lib.sh, agent.sh or a guard*.sh file, the pull request says so and states the owner review.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Work type
Projects
- StatusShow more project fieldsBacklog
Activity
tbhb-agent commentedon Oct 27, 2026
Refinement: READY — Push the branch and write the pull request from agentrepo pr
Model: gpt-6-astra
Child 09 Push the branch and write the pull request from agentrepo pr
Verdict: READY
Checked: Verification now distinguishes body-file content writes from property-only edits with empty stdin, while retaining readiness changes. The uncertain-create check now asserts both no retry and the inspection diagnostic. Earlier creation, owner-label and post-push corrections remain covered. Evidence:
packages/agents/source/skills/pr/shared/scripts/publish.sh:114,packages/agents/source/skills/pr/shared/scripts/publish.sh:138,packages/agents/source/skills/pr/shared/scripts/publish.sh:151,packages/agents/source/skills/pr/shared/scripts/publish.sh:179.Gaps: None.
Split: M remains plausible; no further split justified.
Definition of done
The definition of done for this issue (Feature). Tick each item and give its evidence.
check-leaks.shwith the repository's private-strings list, and the leak review of each post.docs/, CHANGELOG or help text), or the Verification section says "No doc impact" and why.provenance:agent-assistedlabel.Status:comment names the merge commit.mise run checkis green, and so are the coverage floorsmise run cover-go-checkandmise run cover-py-check, whichcheckdoesn't run.packages/agents/source/commits whatmise run generate-skills, thenmise run skill-tokens, thenapm installrewrite, in that order, andcheck-generated-skills(part oflint) passes.docs/agent-skills-migration.mdor the adoption docs, or the PR's Verification says "No consumer impact" and why.Round: 3 of 3