Repository navigation
Description
Problem
The commit workflow's reading of repository state lives in shell spread across preflight.sh, commit.sh, review.sh and the shared agent.sh: the head (or unborn), an in-progress rebase, cherry-pick or base merge, the merge head, the default branch, ahead/behind counts and the recommended rebase base. The same shell decides whether a base merge is authorized: it rejects reverts and other interrupted operations, selects the open pull request's base, fetches it, and accepts only that base's current tip as the merge head. Each script re-derives these facts its own way, and the shell freeze in #588 rules out porting any of the three scripts until one tested implementation exists.
Part of #322, within #588. Child 01 in #322's Children list. Delivers in Go the behavior of the state-reading functions in packages/agents/source/skills/commit/shared/scripts/preflight.sh and of dt_commit_context and dt_commit_merge_head in packages/agents/source/lib/agent.sh, which only this child ports.
Acceptance criteria
- AC1: Given a repository with no commit, when the workflow state is read, then the head is reported as unborn and the recommended base is "none (root commit)".
- AC2: Given a rebase, cherry-pick or base merge in progress, when the state is read, then the operation is named with the same guidance text the shell prints today.
- AC3: Given
origin/HEADis set, when the default branch is resolved, then that name wins; given it is unset, thenmainwins, andmasterwins only whenmainis absent andmasterexists. - AC4: Given local and origin copies of the default branch in each combination (both, origin only, local only, neither, local behind origin), when the base is recommended, then the recommendation and its reason line match the shell output.
- AC5: Given two refs where one is missing, when ahead/behind is asked, then the answer is "unknown (missing ref)" and no error is raised.
- AC6: Given a base merge in progress, when the merge head is read, then it is the value of
MERGE_HEAD; given none, then "none". - AC7: Given a bounded fetch is requested and the fetch times out or fails, when the state is read for reporting, then the report says "failed (origin counts below may be stale)" and continues.
- AC8: Given the commit guard mark is written, when HEAD later moves, then the mark records the head it was armed at, in the same file the guard hook reads.
- AC9: Given a base merge in progress on a branch with an open pull request, when merge authorization is checked, then it fetches that pull request's base, and it passes only when
MERGE_HEADis exactly that base's current tip and the merge has a single other parent. - AC10: Given a base merge in progress and a pull request lookup that succeeds but finds no pull request for the branch, when merge authorization is checked, then it selects the trusted default branch, fetches it, and passes only when
MERGE_HEADis exactly that fetched tip; this outcome is distinct from a failed lookup. - AC11: Given a revert, a cherry-pick or rebase in progress, a merge head that is another branch or a stale base tip, an octopus merge, or a failed pull request lookup or fetch, when merge authorization is checked, then it refuses with the same message and exit status as the shell, and nothing is authorized on a failure to look up or fetch.
- AC12: Non-functional: the optional reporting fetch (AC7) and the authorization fetch (AC9, AC10) retain the effects of today's plain
git fetchcommands (fetched objects, remote-tracking refs,FETCH_HEAD, automatically fetched tags, reference-log updates and automatic maintenance); apart from those and the guard mark the state reads write nothing, and the only network use is those fetches and the single pull request lookup that merge authorization needs. A reporting-fetch failure never changes an authorization result.
Scope and non-goals
Scope: reading commit-workflow state, merge authorization and the guard mark in Go, exposed as an agentrepo commit state plumbing subcommand.
Non-goal: printing the preflight report, which child 02 does. Non-goal: reading review or confirmation state, which #321 owns. Non-goal: changing guard-git.sh, agent.sh or any generated copy of them; the shell stays frozen with no new logic. Non-goal: switching any shell wrapper to call the subcommand, which child 07 does once. This child alone owns the Go port of dt_commit_context and dt_commit_merge_head; Their port belongs to this child rather than the shared-library area (#321); the #321 body still needs this ownership boundary recorded.
Approach
Meet AC1 to AC12 with failing table-driven cases first, using real scratch repositories for refs and injected runners for the fetch and the pull request lookup, and mirroring the existing merge cases in tests/skills/agent-commit/base-merge.bats. Reuse the repository and worktree context that #321 delivers rather than duplicating it. Merge authorization gates what an agent may commit, so the pull request receives heightened agent review; it is not an owner-tier path.
Dependencies
Blocked by: #753 (the golden-pattern edit covering the new Go enforcement paths).
Prerequisite: the repository and worktree context delivered by #321.
Size
M. One pull request.
Verify plan
- AC1, AC2, AC3, AC4, AC5, AC6: Go tests over scratch repositories compare each case with the captured shell output.
- AC7: a test with a stub
gitthat sleeps past the bound. - AC8: a test reads the mark file and the guard's own check.
- AC9, AC11: tests over scratch repositories with a stub pull request lookup and fetch, covering the cases in
tests/skills/agent-commit/base-merge.bats(other branch, stale tip, octopus, revert, lookup failure, fetch failure). - AC10: a test with a stub lookup that succeeds with an empty result, passing on the fetched default tip and refusing on a stale one, beside a failed-lookup case that refuses.
- AC12: tests record every network call and compare repository and guard-directory state before and after the reporting fetch alone and authorization fetch alone, permitting only the ordinary fetch effects listed in AC12 and the guard mark. Include remote-tracking advancement and a reachable-tag fetch, and verify that a reporting-fetch failure leaves the authorization result unchanged.
- 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 subtle ref-resolution difference would recommend the wrong rebase base, and a lenient merge check would let a foreign merge commit through; the merge authorization is a gate on agent commits, which is why it needs heightened agent review. The parity and refusal cases above are the controls. Undo: revert the change; no caller uses the subcommand until child 07.
Operator authority
None.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Work type
Projects
- StatusShow more project fieldsBacklog
Activity
tbhb-agent commentedon Oct 27, 2026
Refinement: READY — Read commit workflow state in Go instead of shell
Model: gpt-6-astra
Child 01 Read commit workflow state in Go instead of shell
Verdict: READY
Checked: Reviewed against an independent clone with origin verified as
tbhb-dev/devtools, atorigin/maincommitfd7b680432ed2040c6e40626778acdf79dc8e317. Relevant live issues were read using GET requests. No builds, tests or GitHub mutations were performed.The binding allocation resolves ownership of
dt_commit_contextanddt_commit_merge_head. #753 now precedes this child. The successful empty PR lookup is distinguished from lookup failure, and reporting and authorization fetches have separate failure contracts. These matchpackages/agents/source/lib/agent.sh:72,packages/agents/source/lib/agent.sh:81andpackages/agents/source/skills/commit/shared/scripts/preflight.sh:165.AC1–AC12 have corresponding checks. Scope excludes shell-library edits and caller switching, making authority consistent with
.agents/agent-skills.conf:9. Risks and revert-based undo are appropriate.Gaps: None.
Split: None. M remains credible with shared context supplied by #321.
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