Repository navigation
Description
Problem
create-pr.sh is the entry point for publication. Before anything is written it parses a flag allowlist, refuses an unsafe branch state, checks the active gh account against the machine's gh_login, validates the draft, resolves the draft's labels, milestone and issue references against GitHub (properties.sh, which only create-pr.sh calls), verifies the review stamp's bindings, runs the leak scans, lint, the independent review and the tests through the cached gate runner, and resolves the confirmation (--confirmed, then session pre-approval, then the machine delegation check). That is the authority logic for publishing a pull request, about 270 lines of shell between the two scripts.
Part of #588 and #323. Delivers in Go the behavior of packages/agents/source/skills/pr/shared/scripts/create-pr.sh up to the point of the push, and of properties.sh. This change adds Go behavior only and switches no caller.
Acceptance criteria
- AC1: Given any flag outside
--dry-run,--check-description,--rerun-gates,--rewriteand--confirmed, or--confirmedin unattended mode, when publication starts, then it refuses with the shell's usage or message before any check. - AC2: Given no draft, a rebase, merge or cherry-pick in progress, a detached
HEAD, a draft with no base, the base branch checked out, or a base naming no local or origin branch, when publication starts, then it refuses with the shell's message and nothing is pushed or written. - AC3: Given a shallow repository, a missing
origin/<base>or no merge base betweenHEADandorigin/<base>, when publication starts without--check-description, then it exits with status 2 saying the leak scan is incomplete and nothing was pushed. - AC4: Given the active
ghaccount differs from the machinegh_login, when publication starts, then it refuses before any write and prints both logins; given no configured login, then the output says the account check is skipped, except in unattended mode where it refuses. - AC5: Given the description checks run, when the draft has findings, then publication stops before property resolution, the stamp check and every other gate.
- AC6: Given draft labels, a milestone and issue or pull request references in the body, when properties are resolved, then a label GitHub lacks (matched exactly, from up to 200 labels) is refused by name; an empty,
~,null,""or''milestone requests none, a missing milestone is refused and more than 100 open milestones is refused; the distinct references are sorted as text, as the shell sorts them, and only the first 20 are looked up in total (a later reference causes no lookup and no second batch), a missing one among them is refused, and a failed lookup stops with the lookup's own exit status and the reference named; this runs after the description checks and before the stamp check. - AC7: Given
--check-description, when it runs, then only the description checks and property resolution run, no review or other gate runs, nothing is pushed or written beyond scratch copies, and it exits 0 when they pass. - AC8: Given no review stamp, or a stamp whose draft, branch name,
HEAD, base, base commit or merge base no longer matches (including a fetch that moved the base after the review), or a draft copy whose digest differs from the stamped digest, when publication checks the stamp, then it refuses, naming the review script to run again, and nothing is pushed. - AC9: Given a clean committed tree and an unchanged cache key, when the gates run, then the cached description lint and test passes are used and each is printed as cached;
--rerun-gatesforces fresh runs; the publication-scoped leak scans and the publication-scoped lint always run fresh; and the independent review always runs. - AC10: Given a failing scripted scan, lint or independent review, when publication runs, then it exits before the test gate and before any push.
- AC11: Given
--confirmed, a session pre-approval or a delegation check, when confirmation resolves, then the first source that answers wins in that order and the output names it; given none, then the run exits 75 and writes nothing; given the stamp matches before the confirmation and not after, or the draft copy changed, then it refuses and writes nothing; given--dry-run, then confirmation is never consulted and nothing is pushed or written. - AC12: Non-functional: no push and no GitHub write happens before every check above has passed.
Scope and non-goals
Scope: argument parsing, branch-state refusals, identity, the description check, property resolution, stamp verification, gates, confirmation and the hand-off to child 09's push and write.
Non-goal: the push plan, --dry-run push planning output, the push and the gh writes, which child 09 ports. Non-goal: the gate runner, its cache, the confirmation order and delegation, which #713 and #762 own. Non-goal: the GraphQL quota reader owned by #760. Non-goal: loosening any gate. Non-goal: switching the shell caller, which child 12 does.
Approach
Meet AC1 to AC12 with failing table-driven cases first, using the stubs the Bats suite uses (fake gh, checker, reviewer) in Go, and comparing messages and exit statuses with the shell's. The stamp, gate and confirmation behavior is consumed as delivered under #321 rather than reimplemented. Property resolution runs in this child, in the shell's order, because at origin/main its only caller is create-pr.sh; it is not a separate entry point.
Dependencies
Blocked by: #910, #911, #912, #916, #713 (gate runner and cache), #762 (confirmation and delegation), #760 (identity and rate-limit classification), #769 (stamps), #753 (protection of new Go enforcement paths).
Prerequisite: #321.
Size
M. One pull request. Estimated at 650 to 750 changed code lines with tests (about 270 shell lines of behavior). Property resolution (about 47 shell lines, AC6) is part of this count; if the count passes 750 while drafting, it is split into its own pull request as an earlier blocker of this one before this one is opened.
Verify plan
- AC1, AC2, AC3: tables of unknown flags, branch states and repository shapes, checking message and exit status.
- AC4: a test with a fake
ghsigned in as another account, with no configured login, and unattended. - AC5, AC7: tests that fail the description check and run
--check-description, with a recording gate runner. - AC6: Go tests with a fake
ghand call counts: unknown label, each milestone form, over 100 milestones, 25 distinct references (asserting exactly 20 lookups, the first 20 in sorted order, and none for the other 5), a missing reference, and a failing lookup (a rate-limit text for GraphQL, checking status and diagnostic). - AC8: tests that move
HEAD, the branch, the draft, the base and the base commit between steps, and a stamp-less run. - AC9, AC10: tests with a recording gate runner and cache fixtures;
tests/skills/pr/scripts/pr-workflow.batspublication-lint regression is the oracle for fresh scoped lint. - AC11: tests per source in order, the exit 75 case with no source, a stamp moved by the confirmation, and a dry run with a recording confirmation source.
- AC12: an ordering test asserts the write stubs are untouched until the last check passes.
- 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 gate that passes in Go where the shell refused would publish unreviewed work, and an extra GitHub call per reference spends quota. The refusal cases and call counts above are the control. Undo: revert the change; nothing calls the Go gates yet and the shell script 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 — Check the gates and resolve confirmation before publishing from agentrepo pr
Model: gpt-6-astra
Child 08 Check the gates and resolve confirmation before publishing from agentrepo pr
Verdict: READY
Checked: Property ownership is settled. AC6 now correctly limits lookup to the first 20 text-sorted distinct references in total. Fresh publication lint, stamp checks, refusal boundaries and dry-run confirmation bypass remain covered. Evidence:
packages/agents/source/skills/pr/shared/scripts/properties.sh:55,packages/agents/source/skills/pr/shared/scripts/create-pr.sh:189,packages/agents/source/skills/pr/shared/scripts/publish.sh:64.Gaps: None.
Split: M is plausible at 650–750 changed code lines. The properties contingency activates before the hard limit.
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